From ef92291e281f6571e317e5a5aae02c47ab47d7f2 Mon Sep 17 00:00:00 2001 From: Thomas Walker Lynch Date: Mon, 24 Nov 2025 15:49:49 +0000 Subject: [PATCH] adding a git empty directory tool --- developer/{derived => made}/.gitkeep | 0 developer/tool/{release => promote} | 0 document/Harmony/00_Project_Structure.org | 178 ++++++++--- .../01_Workflow_and_Build_Contract.org | 157 ++++++++-- document/Harmony/02_RT_Code_Format.org | 164 +++++++--- .../03_Naming_and_Directory_Conventions.org | 33 +++ document/Harmony/04_Language_Addenda.org | 170 +++++++++++ document/Harmony/style/rt_dark_doc.css | 44 +++ release/tool/.gitkeep | 0 tool/git-empty-dir | 1 + tool/git-tar | 280 ++++++++++++++++++ tool/skeleton_compare | 1 - tool/source_git-empty-dir/CLI.py | 251 ++++++++++++++++ tool/source_git-empty-dir/Harmony.py | 1 + .../load_command_module.py | 1 + tool/source_git-empty-dir/meta.py | 97 ++++++ tool/source_git-empty-dir/source_sync | 1 + .../A_minus_B | 0 .../CLI.py | 0 .../GitIgnore.py | 0 .../Harmony.py | 0 .../Harmony_where | 0 .../README.org | 0 .../command.py | 0 .../doc.py | 0 .../in_between_and_below | 0 .../load_command_module.py | 0 .../make_Harmony_tree_dict | 0 .../manus_2025_11_20_215471873762383.txt | 0 .../meta.py | 0 .../newer | 0 .../older | 0 .../skeleton.py | 0 tool/sync | 1 + tool_2.tar | Bin 0 -> 215040 bytes 35 files changed, 1290 insertions(+), 90 deletions(-) rename developer/{derived => made}/.gitkeep (100%) rename developer/tool/{release => promote} (100%) create mode 100644 document/Harmony/03_Naming_and_Directory_Conventions.org create mode 100644 document/Harmony/04_Language_Addenda.org create mode 100644 document/Harmony/style/rt_dark_doc.css create mode 100644 release/tool/.gitkeep create mode 120000 tool/git-empty-dir create mode 100755 tool/git-tar delete mode 120000 tool/skeleton_compare create mode 100755 tool/source_git-empty-dir/CLI.py create mode 120000 tool/source_git-empty-dir/Harmony.py create mode 120000 tool/source_git-empty-dir/load_command_module.py create mode 100644 tool/source_git-empty-dir/meta.py create mode 120000 tool/source_git-empty-dir/source_sync rename tool/{source_skeleton_compare => source_sync}/A_minus_B (100%) rename tool/{source_skeleton_compare => source_sync}/CLI.py (100%) rename tool/{source_skeleton_compare => source_sync}/GitIgnore.py (100%) rename tool/{source_skeleton_compare => source_sync}/Harmony.py (100%) rename tool/{source_skeleton_compare => source_sync}/Harmony_where (100%) rename tool/{source_skeleton_compare => source_sync}/README.org (100%) rename tool/{source_skeleton_compare => source_sync}/command.py (100%) rename tool/{source_skeleton_compare => source_sync}/doc.py (100%) rename tool/{source_skeleton_compare => source_sync}/in_between_and_below (100%) rename tool/{source_skeleton_compare => source_sync}/load_command_module.py (100%) rename tool/{source_skeleton_compare => source_sync}/make_Harmony_tree_dict (100%) rename tool/{source_skeleton_compare => source_sync}/manus_2025_11_20_215471873762383.txt (100%) rename tool/{source_skeleton_compare => source_sync}/meta.py (100%) rename tool/{source_skeleton_compare => source_sync}/newer (100%) rename tool/{source_skeleton_compare => source_sync}/older (100%) rename tool/{source_skeleton_compare => source_sync}/skeleton.py (100%) create mode 120000 tool/sync create mode 100644 tool_2.tar diff --git a/developer/derived/.gitkeep b/developer/made/.gitkeep similarity index 100% rename from developer/derived/.gitkeep rename to developer/made/.gitkeep diff --git a/developer/tool/release b/developer/tool/promote similarity index 100% rename from developer/tool/release rename to developer/tool/promote diff --git a/document/Harmony/00_Project_Structure.org b/document/Harmony/00_Project_Structure.org index d55148c..8c08098 100644 --- a/document/Harmony/00_Project_Structure.org +++ b/document/Harmony/00_Project_Structure.org @@ -1,50 +1,162 @@ -#+TITLE: 00 - Project Structure and Prescriptive Ontology +#+TITLE: 00 - Project Structure and Ontology #+AUTHOR: Harmony Project Team #+DATE: 2025-11-21 #+OPTIONS: toc:2 num:nil +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: + +#+BEGIN_EXPORT html +
+#+END_EXPORT + * Purpose -The Harmony skeleton is cloned as a starting point for git based project development. Harmony was designed to serve as a central working point for a team. -* 1. Some nomenclature. +Harmony provides a language agnostic project directory structure and maintenance tools for long-lived, multi-person team software development. The structure exists to enforce: + +1. Clarity about where things live. +1.1. Role based work areas +1.2. Separation of skeleton, team member authored, machine-made, and third party installed software. +3. A safe, predictable build and release workflow. + +A newcomer should be able to clone Harmony and understand the entire +working model in minutes. + +To make a new project a toolsmith first clones Harmony, renames it to the project name, resets the history, and disconnects it from the Harmony project. The skeleton of the new project can be kept in sync with the Harmony skeleton by going to a Harmony skeleton clone and running the =Harmony/tool/sync= tool. + +Harmony is IDE agnostic. I typically use Emacs as an IDE and encourage its use. Because of this the documents standard format is emacs `.org` format. Files in this format can be exported to other formats, such as HTML. I have also used IntelliJ IDEA and Eclipse with Harmony, though the project skeleton has drifted some since then. I would like to update Harmony to work out of the box with these and other IDEs in the future. + +* 1. Key Concepts + +** Created vs. Made +Harmony divides the world into two categories: + +- *Created / Authored* + Human-written: source files, docs, design notes. + +- *Made* + Tool-produced: binaries, generated sources, intermediates. + +This separation protects authored material from accidental overwrite and +makes build artifacts fully disposable. + +** Semantic Paths +Directory names in Harmony are not decorative. +Each directory name is a *property* shared among files. Thus, a full path forms a semantic +sentence describing said files. + +Example: + +- =developer/authored/= + “Developer authored code” + +- =developer/scratchpad/made/= + “Developer → scratch workspace → tool-made binaries” + +Once you learn the ontology, you can infer the meaning of any path. + +* Top-Level Repository Layout + +The layout below is stable across all Harmony skeleton based projects: + +| Directory | Meaning | +|----------|---------| +| =developer/= | Primary workspace for developers | +| =tester/= | Regression and validation workspace for testers | +| =tool/= | Project-local tools | +| =tool_shared/= | Shared ecosystem tools | +| =document/= | Documentation (local to project) | +| =release/= | Central Working Point for promoted artifacts | +| =scratchpad/= | Global scratch (misc experiments) | +| =env_* = | Role activators | + +The `env_*` files prepare PATH, set environment variables, and cd into +the correct workspace. A team member will source one of the =env_*= files to take on a role in the project. As of this writing the supported roles are: toolsmith, developer, and tester. + +* The =release/= tree. + +The =release/= tree is where developers put work product that is to be shared with testers. Once the contents of the =release/= directory are blessed by the tester, the project will be given a release branch, and then the =release/= tree contains the files that are shared with users. Users should not be pulling files from anywhere else in the project tree. + +The =release/= tree is owned by the developer. No other role should write into this tree. + +Ideally, artifacts arrive in the =release/= tree *only* then the developer invokes the =promote= tool. And take note, The developer's =promote= script, as initially provided with the Harmony skeleton, has a command for erasing the contents of the release directory. + +** =release/made_tracked/= + Architecture-agnostic artifacts. Tracked by Git, comes when the project is cloned. Users update the release directory when on a release branch, by pulling the project. + +** =release/made_untracked/= + Architecture-specific artifacts. Directory tracked, contents are git ignored. The contents of this directory are created by running a build after the project is cloned/pulled. This was a compromise to avoid the problem of maintaining architecture and platform specific binaries. + +** =release/documnt/= + Documents for users of the code in the release directory. + +* The =developer/= tree + +This property is set, i.e. this director is entered, by first going to the top level directory of the project, then sourcing the =env_developer= environment file. The developer can hook additional items into the environment by putting them into the =developer/tool/env= file. + +** =authored/= + Human-written source. Tools should never delete files in this directory. =authored/= files are tracked. + +** =made/= + + Generated by tools, and the artifacts are tracked. These artifacts + are stable across machine architectures. A common item to find in + the =developer/made/= directory is a link to a Python program in + the =authored/= directory. When following RT conventions the entry + point of command line driven Python files is `CLI.py`, so the link + in =developer/made/= gives the program a name. + +** =experiment/= + Try-it-here code. Short-lived. Developers do spot testing here. If tests are to longer lived, they should be moved to the tester role. + +** =scratchpad/= + Contents of this directory are git ignored. It is intended to hold all intermediate build outputs, and anything else the developer might consider scratchpad work. + +** =scratchpad/made/= + By RT convention, architecture specific build artifacts are not tracked, but rather are built each time the project is cloned. Such build artifacts are placed in =developer/scratchpad/made= and if they are to be shared with the tester, the release script will release them to =release/made_untracted=. + +** =tool/= + Developer specific tools. Additional tools will be found under =tool_shared=. If the project is not self contained, then yet additional tools might come from the system environment. + +* Documents + +** =release/document/= + Documentation for users of released code. E.g.s a =man= page, user manual for an application, or a reference manually for a released library. + +** =document/= + Project wide documentation for project team members. + +** =developer/document/= + Documentation for developers. + +** =tester/document/= + Documentation for testers. + +** =tool_shared/document/= + Documentation on installing the shared tools. Note if a tool has a document directory that remains with the tool. + This will typically have a list of tools that need to be installed for the project, and notes to help make installs go more smoothly. + +* Tools -** The Foundational Principle: Create vs. Make -- Something **Created** came from God, Artists, or, apparently SQL interpreters. We will include developers in with Artists.;-) Created written material is **Authored**. -- Something **Made** is the result of assembling materials into a product. This is done by **Factories** and **Build Tools**. +** =tool/= -** Property Schema (The Semantic Path) -Directory names are properties bestowed upon their contents. The path is a descriptive sentence: -- =developer/authored/main.c= -> "The =main.c= file is **authored** by the developer." +We call the team members who administer the project and install tools the 'toolsmith'. The top level =tool/= directory holds the toolsmith's tools. -* 2. Directory Semantics +** =tool_shared/= -** =developer/authored/= -- **Invariant:** Primary Logic Source. -- **Contents:** All human-written source code (C, Python, etc.). +Shared tools are available to all team members. Those that have been written specifically for the Harmony skeleton or for this project go into the =tool_shared/bespoke= directory. Note the tool =scratchpad=, try =scratchpat help=. -** =developer/made/= -- **Invariant:** Architecture-specific Output. +Tools installed from third parties go into the git ignored directory =tool_shared/third_party=. -- **Contents:** Intended to hold compiled programs and links back into authored interpreted programs. As a general rule, if the contents of a "made" - directory are deleted, the contents can be remade from files already in the project, though perhaps with the use of third party tools and libraries. +** =developer/tool= -** =developer/scratchpad/= -- **Invariant:** Transient Workspace. -- **Contents:** Intermediate files, object files, dependency files. +Developer role specific tools. The =release= script and the RT project shared =make= scripts are found here. -** =developer/scratchpad/made/= -- **Invariant:** Machine-Made Binaries (Intermediate), generally OS loadable made things that are not to be tracked. -- **Contents:** Compiled binaries and libraries derived by the build system. The contents of =scratchpad/= are permanently Git-ignored. +** =tester/tool= -* 3. Release Structure (The Central Working Point) -The =$REPO_HOME/release= directory holds candidates for testing and promotion. +Tester role specific tools. -** =release/made_tracked/= -- **Invariant:** Shared, Agnostic Output. -- **Contents:** Architecture-agnostic final release candidates (TRACKED). -** =release/made_untracked/= -- **Invariant:** Local Action Required / Machine-Specific Output. -- **Rule:** This directory is empty but **TRACKED** (by a committed =.gitignore=) to signal that a **local build must be performed** post-clone to populate it with executables. -- **Contents:** Architecture-specific binaries (IGNORED). - +#+BEGIN_EXPORT html +
+#+END_EXPORT diff --git a/document/Harmony/01_Workflow_and_Build_Contract.org b/document/Harmony/01_Workflow_and_Build_Contract.org index 2fc8f23..6826ca6 100644 --- a/document/Harmony/01_Workflow_and_Build_Contract.org +++ b/document/Harmony/01_Workflow_and_Build_Contract.org @@ -1,33 +1,146 @@ #+TITLE: 01 - Workflow and Build Contract #+AUTHOR: RT +#+DATE: 2025-11-21 #+OPTIONS: toc:2 num:nil -* 1. Core Build Principles (The Contract) -This contract enforces read/write separation and predictable build orchestration. +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: -** 1.1 The Read-Only Contract -- **Authored Trees** (=developer/authored/=) are read-only to all scripts. -- **Write Area (SCRATCHPAD):** All synthesis, intermediates, binaries, and kbuild outputs must be directed to **=developer/scratchpad/=**. +#+BEGIN_EXPORT html +
+#+END_EXPORT -** 1.2 Orchestration and Discovery -- **Invocation:** Builds are invoked from the =$REPO_HOME/developer= directory. -- **Discovery:** Artifacts are discovered automatically by standardized file suffix (e.g., =*.lib.c=, =*.cli.c=, =*.mod.c=). Hard-coding file basenames is prohibited. +* Purpose +The workflow contract defines the steps from authorship through release of work product. -* 2. Project Roles and Workflow -The workflow minimizes friction by defining responsibilities and establishing a clear testing cycle. +There are three circular loops. -** 2.1 Roles -- **Developer:** Translates specs into code, evolving the =authored= tree. -- **Tester:** Runs regression suite and validates candidates. -- **Toolsmith:** Maintains the skeleton and shared tools. +In the development loop, developers author code and run experiments, eventually then promoting work product to the =release/= directory. -** 2.2 Release Promotion (The Explicit Step) -Promotion is an **explicit copy step** managed by the Python release script, not an automatic part of the build process. Build outputs remain in =developer/scratchpad/= until promotion. +In the developer tester loop, testers test the promoted release candidates and file issues against them, developers address these, and then promote new release candidates. Or in a tighter version of this loop, a developer with a local copy of this project plays both roles so as to speed the cycle. -** 2.3 New Release Targets -The release script must promote artifacts to these canonical locations: +In the third loop, the tester finds the release candidates to meet the goals for the release version, and to be of sufficient quality that they create a new release branch. Released code then has bug reports filed against it. Developers address these and the prior two loops are run until a new release candidate is stable, and a new release branch is made. -| Content Type | Developer Origin | Release Target | Invariant | -| :--- | :--- | :--- | :--- | -| **Binaries/Kmod** | scratchpad/made | **release/made_untracked/** | Architecture-Specific (IGNORED) | -| **Agnostic Scripts** | developer/made | **release/made_tracked/** | Shared, TRACKED | +Release branches have two integer numbers. The first number is the version of the software, as per the architectural specification. (That specification is placed into the project document directory.) The second number counts the number of times the tester has created a release branch for said version of the software. + +The workflow is designed for forward motion of through release numbers, so as to avoid having to maintain older releases separately. It is better to give a customer a new release if a bug must be fixed, even the customer will not pay for the new release, that it is to pay the cost of dealing with multi-release level bug fixes. However, as each release has its own branch, it is possible to perform multi-release level bug fixes if that is what is required or desired. + +* Roles and Process + +** Developer Role +Responsibilities: + +1. Write and modify authored source. Ensure code meets RT style (see =02_RT_Code_Format.org=). +2. Run builds. +3. Spot testing in =experiment/= +4. Promotes release candidates for more thorough testing using the customized =prommote= script. +5. Rinse, lather, repeat. + +** Tester Role +Responsibilities: + +1. Validate candidates under =release/=. +2. Run regression suites. +3. Approve for quality and completeness, and create release branches. + +** Toolsmith Role +Responsibilities: + +1. Setup the project directory, and keep the project in sync with the Harmony skeleton. +2. Maintain the role environments, apart from the =/tool/env= files which are owned by the respective ==. +3. Install and maintained shared tools, =tool/= and =tool_shared/=, and other tools upon request. +4. Address issues with project workflow. Propose updates to the Harmony skeleton. + + +* Entering the project + +What I do to enter a project is to first run an emacs shell. I cd to the project I want to work on, and then source the =env_toolsmith=, =env_developer=, or =env_tester= file, depending on which role I want to work in. Although sourcing these files affects the environment of the shell I am running, it does not effect the environment of emacs. Hence after sourcing the environment, I launch an IDE. This newly launched IDE will have a correct environment. For myself, these days, that new IDE will be emacs again. + +It is common that I will have two or three IDE's (emacs invocations) running side by side, each as different roles. Then I can write code, spot test it, promote it, then change to the other IDE and run regression tests. And if it is a phase of the project where tools are in flux, I will use the third IDE for modifying tools. Hence, as one person I will taken on three roles simultaneously, each in a different IDE. + +On a large project, chances are that all team members will be doing something similar to this on their local clones of the project. However, there will be team members concentrating on code development, and others on testing and release. Early on a toolsmith will setup the project, and then continue to maintain it. + +* Developer + +** Authoring and Building + +Developers write the build fodder files in the =authored/= directory. File name extensions are used to signal to the build tools how the build fodder is to be used. When the conventional single extension giving the main file type is not enough, two extensions are used. + +For example, with the default makefile for C, compiler fodder is found in the =authored/= directory, each file has one these file name extensions: + +- CLIs end in =.cli.c= +- Libary code source end in =.lib.c= +- Kernel module sources are =.mod.c= + +Fodder with the =.cli.c= extension is made into a stand alone executable. + +Fodder with =.lib.c= extension is compiled as an object file and added to the =lib.a= archive. The =.cli.c= files are linkedin against said archive. + +Build tools never write into the =developer/authored= directory. Build products that are not to be tracked go on the =scratchpad/=. Those that are tracked go into the =developer/made= directory. + +It is expected that developers customize and add to the build scripts that come with the Harmony skeleton in order to fit their specific build needs. Note the Ariadne project for complex builds. + +** Developer Testing + +Spot tests are run in the =experiment/= directory. If the tests grow complex or are to be kept for the long term, move them to the tester environment. + +Once the developer finds the edits to be stable he or she can promote them. The promoted code is referred to as release candidates. Promoted release candidates can then be read by the tester role. + +As I mentioned, it is not uncommon for a team member to have two IDEs open, with one being in the developer environment, and one being in the tester environment, and then to bounce back and fourth between them. + +Once the release candidate code is stable, the developer can pull the remote repo, address merge conflicts, then push the local repo back. Merge conflicts on tracked release candidates are common as it is a bottleneck point in the code development. + +** Promotion for release + +As mentioned, files are promoted from the developer environment to the top level =release/= directory by the developer. The developer effects promotion for release by running the customized =developer/tool/promote= script, and then pushing the repository. Only a tester can actually perform a release. + +Building and promotion are separate activities. + +- No tool may rebuild during promotion. +- Promotion is a copy-only operation. +- No builds are run in the =release/= directory. + +If architecture specific files are to be part of the release, the developer will develop a =build_untracked= script and promote it into the =release/tool= directory. Then when a user clones a released project, as a second step the user will invoke the =release/tool/build_untracked= script. That script will fill in the =release/made_untracked= directory with code built specifically for the user's platform. + +- =release/documnt/= (documents for those who intend to use the work product) +- =release/authored= (interpreter fodder - _none are run directly_) +- =release/made_tracked/= (pushed to remote, pulled from remote, links into authored scripts) +- =release/made_untracked/= (local-only) +- =release/tool/= (=build_untracked= and other tools for maintaining released code) + +We chose the 'build after clone' approach over the 'thousand architecture specific binary release directories' approach, because maintaining many architecture release files became a maintenance problem. Note this new approach requires that third party tools be installed so that the =release/tool/build_untracked= script can run. This is the trade off cost for nothing having the thousand architecture directories. + +A user of the Harmony skeleton is free to customize the promotion tool and go back to multiple architecture specific binary release directories if that is what they want. + +Clearly if work product is intended to be distributed to lay users, there must be a deployment step after the release step, but we do not address this in these documents, as it this is not part of Harmony. + + +* Tester + +The developer has promoted release candidates to the =release/= directory. He or she claims those represent a complete high quality product at the given release level. The testers are going to prove the developers to be wrong about that claim. If testers can't disprove this claim, the testers will make a release branch at the next minor release number for the given major release version. + +- The tester reads the spec, and writes a complete set of feature tests. + +- The tester uses the Mosaic test tool, and writes a set of tests, first for the individual functions that make up the program, then for functions in groups. + +- The tester accumulates tests for each bug that ever comes back on a release. + +- The tester collects tests from the developer when they are offered. + +- The tester writes other tests as he or she sees fit. + +- When the tests pass, one presumes, the tester will create a release branch. + +* Separation of roles. + +A tester never patches code in the =developer/= directory, instead the tester files issues. A tester could propose a code fix on another branch, and then point the developers at it in the issue report. + +A developer never writes into =tester/=, instead a developer adds to the =experiment/= and offers to share tests. A developer can propose tests on another branch, and then point testers at it. + +It is up the project manager how strict role assignments will be. + +As mentioned before, one person can play multiple roles. For example, it makes perfect sense for a developer with a local copy of the repo, to have an IDE open as a tester, so that he or she can run tests on release candidates before pushing them. However, in when doing this, the test code might be read only. The developer is merely running it and has no plans to push changes to it. + +#+BEGIN_EXPORT html +
+#+END_EXPORT diff --git a/document/Harmony/02_RT_Code_Format.org b/document/Harmony/02_RT_Code_Format.org index 7d6f554..0e9298e 100644 --- a/document/Harmony/02_RT_Code_Format.org +++ b/document/Harmony/02_RT_Code_Format.org @@ -3,59 +3,155 @@ #+DATE: 2025-11-21 #+OPTIONS: toc:2 num:nil +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: + +#+BEGIN_EXPORT html +
+#+END_EXPORT + * Purpose -The RT Code Format is **Prescriptive**; it defines the mandatory aesthetic and structural rules that override language defaults. The rules aim for a dense output and universal consistency. + +The goal is consistency, readability, and predictability across all +languages and tools. + +This document covers: + +1. Naming conventions +2. Vertical comma lists +3. Enclosure spacing +4. Line breaks and indentation +5. Cross-language guidance * 1. Naming Conventions ** 1.1 Identifier Naming -- **Namespaces/Types:** Use *PascalCase*. -- **Functions/Variables:** Use *snake_case*. -** 1.2 Variable Suffixes (File System and Interface) -Use suffixes to specify the interface or type for clarity: -- **File System:** =_fp= (file path), =_afp= (absolute file path), =_fn= (file name). -- **Interfaces:** =_list= (ordered collection), =_set= (set of items), =_f= (function). +- Types, modules: *PascalCase* +- Functions, variables: *snake_case* +- Globals: UPPER_SNAKE_CASE + +** 1.2 Suffix Semantics +Optionally suffixes are added to variable names to suggest type or interface. + +- =*_dp :: directory path, not specified if relative or absolute +- =*_dpr :: relative directory path +- =*_dpa :: absolute directory path + +- =*_fp :: file path, not specified if relative or absolute +- =*_fpr :: relative file path +- =*_fpa :: absolute file path + +- =*_list= :: generic ordered items +- =*_seq= :: ordered items accessed by index + +- =*_map= :: a keyed container +- =*_dict :: a keyed container + +- =*_count= :: number of elements +- =*_flag= :: boolean -* 2. Operator and Assignment -- **Multiplication/Division:** **No space** around `*` or `/`. -- **Other Binary Operators:** **One space** around all others (e.g., `+`, `-`). -- **Sampling Assignment:** **No space** around the assignment operator (`=`) when used inside a conditional (e.g., `if(result=condition())`). -- **Single Statement Assignment:** **One space** around the assignment operator (`=`). +- = *_Type :: names specific type, where the type name is capitalized. E.g.s =name_Array= or =name_Map= for the cases that name is an instance of a defined Array or Map type. -* 3. Commas (The Syntactic Append Operator) -This is the most distinctive rule: -- **Spacing:** **One space *before*** the comma, and **no space *after*** the comma (e.g., `item_a ,item_b`). -- **Line Breaks:** Break lines **before** the comma, not after. +Add a container type suffix instead of making variables names plural. For example, + +- =name_seq= :: a sequence of zero or more names, used in place of =names=. + + +* Comma separated list + +RT code format treats the comma in a list as belong to the item that caused the comma to be needed. Hence, this is an example of a horizontal comma separated list: + +#+BEGIN_SRC c + int x ,y ,z; +#+END_SRC + +Note the space before the comma, and the comma abuts the item that caused the comma to be needed. It does not matter if the last occurs in a language statement or in a data value. + +For a vertical comma list, the comma remains attached to the item that caused the comma to be needed: #+BEGIN_SRC c result = some_function( - first_argument - ,second_argument_with_longer_name + first_argument + ,second_argument + ,third_argument ); #+END_SRC -* 4. Enclosure Spacing (Parentheses, Braces, Brackets) +Example in Python: + +#+BEGIN_SRC python +items = [ + first_item + ,second_item + ,third_item +] +#+END_SRC + +- Two-space indent. +- Comma at column after indentation. +- All items aligned except the first, as it does not have a comma before it. +- Works identically across C, Python, Bash arrays, and JSON-like data. + +* 3. Enclosure Spacing + +This rule applies on a line by line basis. -- **Native Rule:** There is **no native space** before or after enclosure punctuation. -- **Adjacency:** When two enclosures appear side-by-side (like `)(` or `}{`), there is **no space** between them. -- **Nesting Exception:** For single-line enclosures that contain **at least one nested enclosure**, insert **one space** after the opening punctuation and **one space** before the closing punctuation to aid readability. +** For one level enclosures: + +- No space before =)=, =]=, =}=. +- No space before or after enclosure pairs. +- One-space exception: short single-line enclosures for readability. + +Conforming: -* 5. Short Stuff Rule -For simple `if`, `for`, and `while` statements that introduce a single-line clause: if the condition and clause together are simple, they should **remain on a single line without braces**. #+BEGIN_SRC c -if( x > 0 ) return x; -while( has_next() ) process_next(); +if(condition){ + do_something(); +} #+END_SRC + +Non conforming: -* 6. C-Specific Conventions +#+BEGIN_SRC c +if(condition) { + do_something(); +} +#+END_SRC -** 6.1 Integrated Headers and Namespaces -- **Integrated Header:** C projects adopt the practice of integrating the interface (header) directly into the source file, toggled by the **`FACE`** preprocessor macro, eliminating separate `.h` files. -- **Ad Hoc Namespace:** Exported C identifiers must be prefixed with a module-specific name followed by the **`·` (cdot) character** (e.g., `void Server·run();`) to avoid naming collisions. +Non conforming: -** 6.2 File Extensions -- **Library:** Files implementing library functions use the **`.lib.c`** extension. -- **CLI:** Files implementing command-line tools use the **`.cli.c`** extension. +#+BEGIN_SRC c +if ( condition ) { + do_something ( ); +} +#+END_SRC - +** For multi-level enclosures: + +One space around the level one (outermost) enclosure punctuation. Other levels are as for the one level enclosure. + +#+BEGIN_SRC c +if( f(g(x)) ){ + do_something(); +} +#+END_SRC + +In this example the =if= has a three level enclosure structure. (When measuring enclosure levels identifiers are ignored.) Hence level one gets one space of padding, while all other levels get no padding. + +** Unmatched enclosure punctuation. + +Format the enclosure punctuation that is present, as though it were matched. + + +* Indentation + +Harmony mandates: + +- Two spaces per indentation level. +- Never use tabs. +- Nest lines under the syntactic element that opened them. + +#+BEGIN_EXPORT html +
+#+END_EXPORT diff --git a/document/Harmony/03_Naming_and_Directory_Conventions.org b/document/Harmony/03_Naming_and_Directory_Conventions.org new file mode 100644 index 0000000..d719d5b --- /dev/null +++ b/document/Harmony/03_Naming_and_Directory_Conventions.org @@ -0,0 +1,33 @@ +#+TITLE: 03 - Naming and Directory Conventions +#+AUTHOR: RT +#+DATE: 2025-11-21 +#+OPTIONS: toc:2 num:nil +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: + +#+BEGIN_EXPORT html +
+#+END_EXPORT + +A directory name is taken a property for a set of files. Consequently, directory names are rarely plural. E.g. suppose we have a number of test files in a directory. The directory would be named =test=. As each file in the directory has the property of being a test. + +It would be nice if we could attach multiple properties to a file as part of the file system framework, but conventional file systems do not support this. Consequently, when needed, people add a second property to a file use dot extensions to the file's name. Hence, we get something like =sqrt.c= in a directory called =source=. So the first property is that the file is source code, and the second property is that it is C code. + +We could extent the dot suffix model of adding a property to file by using multiple dot suffixes. Our C makefile structure makes use of this. + +So what is a reasonable primary property for a set of files? Perhaps: + +- Who uses each file with this property. Home directories are named like this. +- The role of the people using the file. This is a more generic version of the prior rule. The =developer= and =tester= directories were named in this manner. +- What program are the files for. Thus we might name a directory a bunch of files for the cc compiler `cc`. +- The generic category of program said files are for. Thus we end up with directories called =src= or =executable=. + +As for the names =src= and =executable= those come from times when almost all programs were compiled. We prefer instead the names =authored= and =made=. =authored= files are those written by humans (or these days, perhaps AI), while =made= files are products of tools. For a Python program, we put packages in =authored= with a module called =CLI.py= for the command line interface. Then we link from =made= into =authored= so as to give the program a name. + +The RT C coding environment does not use separate source and header files. Instead a variable is set that gates off the implementation if the source code is to be used as a header. Hence, all of our C source fits fine within and =authored= directory. + + + +#+BEGIN_EXPORT html +
+#+END_EXPORT diff --git a/document/Harmony/04_Language_Addenda.org b/document/Harmony/04_Language_Addenda.org new file mode 100644 index 0000000..b9b4c77 --- /dev/null +++ b/document/Harmony/04_Language_Addenda.org @@ -0,0 +1,170 @@ +#+TITLE: 04 - Language Addenda (C, Python, Bash) +#+AUTHOR: RT +#+DATE: 2025-11-21 +#+OPTIONS: toc:2 num:nil +#+HTML_HEAD_EXTRA: +#+HTML_HEAD_EXTRA: + +#+BEGIN_EXPORT html +
+#+END_EXPORT + + +* Purpose +The RT code format is language-agnostic, but actual languages differ in +syntax and constraints. + +This document explains how the RT rules are applied in: + +1. C +2. Python +3. Bash + +For each language we answer: + +1. What carries over directly from =02_RT_Code_Format.org=. +2. What must be adapted. +3. What extra discipline is required. + +* 1. C Addendum + +** 1.1 Control Structure and File Layout + +The detailed RT C file structure is described in the dedicated = +RT_C_control_structure= document. The core ideas: + +1. Each module has an *Interface* section and an *Implementation* + section in the same file. +2. The sections are toggled using preprocessor macros (e.g. =FACE=). +3. Interface declarations are processed even when included multiple + times; the implementation is compiled only when used as an + implementation. + +This approach: + +1. Keeps the interface and implementation in sync. +2. Avoids maintaining parallel =.h= and =.c= files for each module. +3. Integrates smoothly with standardized makefiles. + +** 1.2 Indentation and Comma Lists + +C code follows the RT two-space indentation and vertical comma lists: + +#+BEGIN_SRC c +result = some_function( + first_argument + ,second_argument_with_longer_name + ,third_argument +); +#+END_SRC + +Rules: + +1. Two spaces per block indentation. +2. The comma starts the line in vertical lists. +3. Align continuation lines under the first symbol after the equals + sign or opening parenthesis when feasible. + +** 1.3 Error Handling and Ownership + +Guidelines: + +1. Functions should document ownership of pointers and lifetimes. +2. Prefer explicit =*_count= parameters over sentinel values when + passing arrays. +3. Return codes should be consistent (=0= success, non-zero failure) or + use clearly documented enums. + +* 2. Python Addendum + +** 2.1 Indentation and Layout + +Python enforces indentation syntactically, so the RT two-space rule +becomes: + +1. Use *two-space indentation* for all Python code, even though four is + common in the wider ecosystem. +2. Vertical comma lists still place the comma at the start of the line, + after the indentation. + +Example: + +#+BEGIN_SRC python +items = [ + first_item + ,second_item + ,third_item +] +#+END_SRC + +** 2.2 Modules and CLI Separation + +Python scripts distinguish between: + +1. *Work functions* (importable API). +2. *CLI entry points* (argument parsing, printing, exit codes). + +Pattern: + +1. Put reusable logic into functions and classes. +2. Put argument parsing and =if __name__ == "__main__":= in the CLI + section. +3. Keep side effects out of import time. + +** 2.3 Error Handling + +1. Raise exceptions for exceptional conditions. +2. Catch exceptions at the CLI boundary and convert them into user + messages and exit codes. +3. Avoid catching broad =Exception= unless it is immediately converted + into a controlled failure. + +* 3. Bash Addendum + +** 3.1 Shebang and Safety + +Bash scripts should start with: + +#+BEGIN_SRC sh +#!/usr/bin/env bash +set -euo pipefail +#+END_SRC + +Explanation: + +1. =-e= :: Exit on error. +2. =-u= :: Treat unset variables as errors. +3. =-o pipefail= :: Propagate errors across pipelines. + +** 3.2 Functions vs. Top-Level Code + +RT-style Bash separates: + +1. A small top-level CLI harness (argument parsing, usage, dispatch). +2. A set of functions that implement the work. + +Pattern: + +1. Parse arguments into variables. +2. Call a main function with explicit parameters. +3. Avoid relying on global mutable state where possible. + +** 3.3 Logging and Diagnostics + +1. Use =printf= or =echo= for user-facing messages. +2. Send debug or trace output to stderr (=>&2=). +3. Make it obvious when the script is changing system state (e.g. + mounting, creating users, modifying firewall rules). + +* 4. Using the Addenda + +When in doubt: + +1. Start with =02_RT_Code_Format.org= for the core rules. +2. Apply the relevant language section here. +3. If a language requires deviation from the generic rules, document + that deviation in this file instead of ad-hoc decisions. + +#+BEGIN_EXPORT html +
+#+END_EXPORT diff --git a/document/Harmony/style/rt_dark_doc.css b/document/Harmony/style/rt_dark_doc.css new file mode 100644 index 0000000..bac4fbf --- /dev/null +++ b/document/Harmony/style/rt_dark_doc.css @@ -0,0 +1,44 @@ + + body { + font-family: 'Noto Sans JP', Arial, sans-serif; + background-color: hsl(0, 0%, 0%); + color: hsl(42, 100%, 80%); + padding: 2rem; + } + .page { + padding: 3rem; + margin: 1.25rem auto; + max-width: 46.875rem; + background-color: hsl(0, 0%, 0%); + box-shadow: 0 0 0.625rem hsl(42, 100%, 50%); + } + h1 { + font-size: 1.5rem; + text-align: center; + color: hsl(42, 100%, 84%); + text-transform: uppercase; + margin-top: 1.5rem; + } + h2 { + font-size: 1.25rem; + color: hsl(42, 100%, 84%); + text-align: center; + margin-top: 2rem; + } + h3 { + font-size: 1.125rem; + color: hsl(42, 100%, 75%); + margin-top: 1.5rem; + } + p, li { + color: hsl(42, 100%, 90%); + text-align: justify; + margin-bottom: 1rem; + } + code { + font-family: 'Courier New', Courier, monospace; + background-color: hsl(0, 0%, 25%); + padding: 0.125rem 0.25rem; + color: hsl(42, 100%, 90%); + } + diff --git a/release/tool/.gitkeep b/release/tool/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tool/git-empty-dir b/tool/git-empty-dir new file mode 120000 index 0000000..51e7f2a --- /dev/null +++ b/tool/git-empty-dir @@ -0,0 +1 @@ +source_git-empty-dir/CLI.py \ No newline at end of file diff --git a/tool/git-tar b/tool/git-tar new file mode 100755 index 0000000..79d5a8c --- /dev/null +++ b/tool/git-tar @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- + +""" +git-tar — Create an archive of the current Git repo's ref into ./scratchpad + +Commands (order-insensitive): + git-tar # default: tar.gz (HEAD, ./scratchpad, Z-stamp if importable) + git-tar help # show help + git-tar version # show version + git-tar ref- # choose ref (tag/branch/commit), default HEAD + git-tar out- # choose output directory (default: /scratchpad) + git-tar no-stamp # force omit timestamp even if Z is importable + git-tar z-format- # override timestamp format used with Z (optional) + git-tar zip # write .zip instead of .tar.gz + git-tar tar # force .tar.gz explicitly + +Output names: + __[__].tar.gz + __[__].zip +""" + +from __future__ import annotations +import gzip, os, pathlib, subprocess, sys +from typing import Optional +import importlib, importlib.util +from importlib.machinery import SourceFileLoader + +VERSION = "1.5" + +# ---------------------------------------------------------------------- +# Editable timestamp format (used when calling Z) +# ---------------------------------------------------------------------- +Z_FORMAT = "%year-%month-%day_%hour%minute%secondZ" + +USAGE = f"""git-tar {VERSION} + +Usage: + git-tar [commands...] + +Commands (order-insensitive): + help + version + ref- + out- + no-stamp + z-format- + zip + tar + +Examples: + git-tar + git-tar zip + git-tar ref-main out-/tmp + git-tar z-format-%year-%month-%dayT%hour:%minute:%second.%scintillaZ +""".rstrip() + +# ---------------------------------------------------------------------- +# git helpers +# ---------------------------------------------------------------------- +def _run(*args: str, check: bool = True, cwd: Optional[pathlib.Path] = None) -> subprocess.CompletedProcess[str]: + return subprocess.run( + args + ,check=check + ,cwd=(str(cwd) if cwd else None) + ,text=True + ,stdout=subprocess.PIPE + ,stderr=subprocess.PIPE + ) + +def _in_git_repo() -> bool: + try: + return _run("git","rev-parse","--is-inside-work-tree").stdout.strip().lower() == "true" + except subprocess.CalledProcessError: + return False + +def _git_top() -> pathlib.Path: + return pathlib.Path(_run("git","rev-parse","--show-toplevel").stdout.strip()) + +def _git_ref_label(repo_top: pathlib.Path, ref: str) -> str: + try: + return _run("git","-C",str(repo_top),"describe","--tags","--always","--dirty",ref).stdout.strip() + except subprocess.CalledProcessError: + return _run("git","-C",str(repo_top),"rev-parse","--short",ref).stdout.strip() + +# ---------------------------------------------------------------------- +# Z module discovery (supports extension-less file named "Z") +# ---------------------------------------------------------------------- +def _import_Z_module(repo_top: pathlib.Path) -> Optional[object]: + try: + return importlib.import_module("Z") + except Exception: + pass + + candidates: list[pathlib.Path] = [] + here = pathlib.Path(__file__).resolve().parent + candidates += [here / "Z", here / "Z.py"] + candidates += [ + repo_top / "tool_shared" / "third_party" / "RT-project-share" / "release" / "python" / "Z", + repo_top / "tool_shared" / "third_party" / "RT-project-share" / "release" / "python" / "Z.py", + repo_top / "tool_shared" / "third_party" / "RT-project-share" / "release" / "bash" / "Z", + ] + for d in (pathlib.Path(p) for p in (os.getenv("PATH") or "").split(os.pathsep) if p): + p = d / "Z" + if p.exists() and p.is_file(): + candidates.append(p) + + for path in candidates: + try: + if not path.exists() or not path.is_file(): + continue + spec = importlib.util.spec_from_loader("Z", SourceFileLoader("Z", str(path))) + if not spec or not spec.loader: + continue + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) # type: ignore[attr-defined] + if hasattr(mod,"make_timestamp") or (hasattr(mod,"get_utc_dict") and hasattr(mod,"format_timestamp")): + return mod + except Exception: + continue + return None + +# ---------------------------------------------------------------------- +# Z stamp helper (format string visible & editable above) +# ---------------------------------------------------------------------- +def make_z_stamp(zmod: object, z_format: str) -> Optional[str]: + try: + if hasattr(zmod, "make_timestamp"): + s = zmod.make_timestamp(fmt=z_format) # type: ignore[attr-defined] + return (str(s).strip().replace("\n","") or None) + if hasattr(zmod, "get_utc_dict") and hasattr(zmod, "format_timestamp"): + td = zmod.get_utc_dict() # type: ignore[attr-defined] + s = zmod.format_timestamp(td, z_format) # type: ignore[attr-defined] + return (str(s).strip().replace("\n","") or None) + except Exception: + return None + return None + +# ---------------------------------------------------------------------- +# archiving +# ---------------------------------------------------------------------- +def _stream_git_archive_tar(repo_top: pathlib.Path, prefix: str, ref: str, out_gz_path: pathlib.Path) -> None: + proc = subprocess.Popen( + ["git","-C",str(repo_top),"archive","--format=tar",f"--prefix={prefix}/",ref] + ,stdout=subprocess.PIPE + ) + try: + with gzip.open(out_gz_path,"wb") as gz: + while True: + chunk = proc.stdout.read(1024 * 1024) # 1 MiB + if not chunk: + break + gz.write(chunk) + finally: + if proc.stdout: + proc.stdout.close() + rc = proc.wait() + if rc != 0: + try: + out_gz_path.unlink(missing_ok=True) + finally: + raise subprocess.CalledProcessError(rc, proc.args) + +def _stream_git_archive_zip(repo_top: pathlib.Path, prefix: str, ref: str, out_zip_path: pathlib.Path) -> None: + # Directly stream git's zip to file; no Python zip building needed. + proc = subprocess.Popen( + ["git","-C",str(repo_top),"archive","--format=zip",f"--prefix={prefix}/",ref] + ,stdout=subprocess.PIPE + ) + try: + with open(out_zip_path, "wb") as f: + while True: + chunk = proc.stdout.read(1024 * 1024) + if not chunk: + break + f.write(chunk) + finally: + if proc.stdout: + proc.stdout.close() + rc = proc.wait() + if rc != 0: + try: + out_zip_path.unlink(missing_ok=True) + finally: + raise subprocess.CalledProcessError(rc, proc.args) + +# ---------------------------------------------------------------------- +# work function +# ---------------------------------------------------------------------- +def work( + ref: str = "HEAD" + ,outdir: Optional[pathlib.Path] = None + ,force_no_stamp: bool = False + ,z_format: Optional[str] = None + ,archive_kind: str = "tar" # "tar" or "zip" +) -> pathlib.Path: + if archive_kind not in ("tar","zip"): + raise RuntimeError("archive_kind must be 'tar' or 'zip'") + + if not _in_git_repo(): + raise RuntimeError("not inside a git repository") + + repo_top = _git_top() + repo_name = repo_top.name + ref_label = _git_ref_label(repo_top, ref) + + stamp: Optional[str] = None + if not force_no_stamp: + zmod = _import_Z_module(repo_top) + if zmod is not None: + stamp = make_z_stamp(zmod, z_format or Z_FORMAT) + + target_dir = (outdir or (repo_top / "scratchpad")) + target_dir.mkdir(parents=True, exist_ok=True) + + suffix = ".zip" if archive_kind == "zip" else ".tar.gz" + out_name = f"{repo_name}__{ref_label}{('__' + stamp) if stamp else ''}{suffix}" + out_path = target_dir / out_name + + if archive_kind == "zip": + _stream_git_archive_zip(repo_top, repo_name, ref, out_path) + else: + _stream_git_archive_tar(repo_top, repo_name, ref, out_path) + + return out_path + +# ---------------------------------------------------------------------- +# CLI with command tokens +# ---------------------------------------------------------------------- +def CLI(argv: Optional[list[str]] = None) -> int: + if argv is None: + argv = sys.argv[1:] + + # defaults + ref = "HEAD" + outdir: Optional[pathlib.Path] = None + force_no_stamp = False + z_format: Optional[str] = None + archive_kind = "tar" + + # no args → do the default action + if not argv: + try: + print(f"Wrote {work(ref=ref, outdir=outdir, force_no_stamp=force_no_stamp, z_format=z_format, archive_kind=archive_kind)}") + return 0 + except Exception as e: + print(f"git-tar: {e}", file=sys.stderr); return 1 + + # consume tokens (order-insensitive) + for arg in argv: + if arg in ("help","-h","--help"): + print(USAGE); return 0 + if arg == "version": + print(f"git-tar {VERSION}"); return 0 + if arg == "no-stamp": + force_no_stamp = True; continue + if arg == "zip": + archive_kind = "zip"; continue + if arg == "tar": + archive_kind = "tar"; continue + if arg.startswith("ref-"): + ref = arg[4:] or ref; continue + if arg.startswith("out-"): + od = arg[4:]; outdir = pathlib.Path(od).resolve() if od else None; continue + if arg.startswith("z-format-"): + z_format = arg[len("z-format-"):] or None; continue + print(f"git-tar: unknown command '{arg}'", file=sys.stderr); return 1 + + # run + try: + out_path = work(ref=ref, outdir=outdir, force_no_stamp=force_no_stamp, z_format=z_format, archive_kind=archive_kind) + except Exception as e: + print(f"git-tar: {e}", file=sys.stderr); return 1 + + print(f"Wrote {out_path}") + return 0 + +# ---------------------------------------------------------------------- +if __name__ == "__main__": + raise SystemExit(CLI()) diff --git a/tool/skeleton_compare b/tool/skeleton_compare deleted file mode 120000 index 968c6c2..0000000 --- a/tool/skeleton_compare +++ /dev/null @@ -1 +0,0 @@ -source_skeleton_compare/CLI.py \ No newline at end of file diff --git a/tool/source_git-empty-dir/CLI.py b/tool/source_git-empty-dir/CLI.py new file mode 100755 index 0000000..2fb22e1 --- /dev/null +++ b/tool/source_git-empty-dir/CLI.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python3 +# ---------------------------------------------------------------------- +# git-empty-dir :: list/mark/clean empty directories, .gitignore aware +# ---------------------------------------------------------------------- + +import sys +import os +from pathlib import Path + +# The source_sync GitIgnore parser is inside the unpacked tool. +# We assume this directory structure: +# git-empty-dir/ +# CLI.py +# source_sync/ +# GitIgnore.py +# +# That mirrors how your harmony sync tool is structured. + +# Adjust import path so we can load source_sync.* +HERE = Path(__file__).resolve().parent +sys.path.insert(0, str(HERE)) + +from source_sync.GitIgnore import GitIgnore # type: ignore + + +# ---------------------------------------------------------------------- +# helpers +# ---------------------------------------------------------------------- + +def load_gitignore_tree(root: Path): + """ + Build a GitIgnore instance rooted at . + """ + return GitIgnore(str(root)) + +def is_empty_dir(path: Path) -> bool: + """ + A directory is empty if it contains no files or subdirectories. + (Hidden files count; .gitignored children are irrelevant because + behavior here should reflect real filesystem emptiness.) + """ + try: + for _ in path.iterdir(): + return False + return True + except PermissionError: + # treat as non-empty: safer than aborting + return False + + +def has_mark(path: Path, mark_file: str) -> bool: + return (path / mark_file).exists() + + +def sorted_dirs(root: Path): + """ + Produce a list of all directories under root, in parent-before-child order. + Sort rule: + 1. by path length + 2. then lexicographically + """ + all_dirs = [] + for p in root.rglob("*"): + if p.is_dir(): + all_dirs.append(p) + + return sorted( + all_dirs + ,key = lambda p: (len(p.parts), str(p)) + ) + + +# ---------------------------------------------------------------------- +# traversal +# ---------------------------------------------------------------------- + +def visible_dirs(root: Path, ignore_tree, mark_file: str): + """ + Yield all dirs under root, applying: + - skip .git + - apply .gitignore rules (if a dir is ignored, do not descend) + - parent-before-child ordering + """ + for d in sorted_dirs(root): + rel = d.relative_to(root) + + if rel == Path("."): + continue + + # skip .git explicitly + if d.name == ".git": + continue + + # .gitignore filtering + if ignore_tree.check(str(rel)) == "Ignore": + continue + + yield d + + +# ---------------------------------------------------------------------- +# actions +# ---------------------------------------------------------------------- + +def action_list(root, ignore_tree, mark_file, mode): + """ + mode ∈ {"empty","marked","all"} + """ + for d in visible_dirs(root, ignore_tree, mark_file): + if mode == "all": + print(d.relative_to(root)) + continue + + if mode == "marked": + if has_mark(d, mark_file): + print(d.relative_to(root)) + continue + + if mode == "empty": + if is_empty_dir(d): + print(d.relative_to(root)) + continue + + +def action_mark(root, ignore_tree, mark_file, mode): + """ + mode ∈ {"empty","all"} + """ + for d in visible_dirs(root, ignore_tree, mark_file): + if mode == "empty" and not is_empty_dir(d): + continue + try: + (d / mark_file).touch(exist_ok=True) + except Exception: + pass + + +def action_clean(root, ignore_tree, mark_file, mode): + """ + mode ∈ {"nonempty","all"} + """ + for d in visible_dirs(root, ignore_tree, mark_file): + m = d / mark_file + if not m.exists(): + continue + + if mode == "nonempty": + if is_empty_dir(d): + continue + + try: + m.unlink() + except Exception: + pass + + +# ---------------------------------------------------------------------- +# usage +# ---------------------------------------------------------------------- + +USAGE = """ +usage: + git-empty-dir (list|mark|clean) [all|marked|empty] [file-] + git-empty-dir help + git-empty-dir usage + +defaults: + mark-file = .gitkeep + ignores .git + follows .gitignore (no descent into ignored dirs) + +examples: + git-empty-dir list + git-empty-dir list marked file-.githolder + git-empty-dir mark + git-empty-dir clean all +""" + + +# ---------------------------------------------------------------------- +# CLI +# ---------------------------------------------------------------------- + +def CLI(argv): + if len(argv) == 0: + print(USAGE) + return 0 + + cmd = argv[0] + + if cmd in ("help","usage"): + print(USAGE) + return 0 + + # command + if cmd not in ("list","mark","clean"): + print(f"unknown command: {cmd}") + print(USAGE) + return 1 + + # submode + mode = None + mark_file = ".gitkeep" + + for a in argv[1:]: + if a.startswith("file-"): + mark_file = a[5:] + continue + + if a in ("all","empty","marked"): + mode = a + continue + + print(f"unknown argument: {a}") + print(USAGE) + return 1 + + # defaults + if cmd == "list": + if mode is None: + mode = "empty" + elif cmd == "mark": + if mode is None: + mode = "empty" + elif cmd == "clean": + if mode is None: + mode = "nonempty" + + root = Path(".").resolve() + ignore_tree = load_gitignore_tree(root) + + if cmd == "list": + action_list(root, ignore_tree, mark_file, mode) + + elif cmd == "mark": + if mode == "all": + action_mark(root, ignore_tree, mark_file, "all") + else: + action_mark(root, ignore_tree, mark_file, "empty") + + elif cmd == "clean": + if mode == "all": + action_clean(root, ignore_tree, mark_file, "all") + else: + action_clean(root, ignore_tree, mark_file, "nonempty") + + return 0 + + +if __name__ == "__main__": + sys.exit(CLI(sys.argv[1:])) diff --git a/tool/source_git-empty-dir/Harmony.py b/tool/source_git-empty-dir/Harmony.py new file mode 120000 index 0000000..112663e --- /dev/null +++ b/tool/source_git-empty-dir/Harmony.py @@ -0,0 +1 @@ +../source_sync/Harmony.py \ No newline at end of file diff --git a/tool/source_git-empty-dir/load_command_module.py b/tool/source_git-empty-dir/load_command_module.py new file mode 120000 index 0000000..87b98be --- /dev/null +++ b/tool/source_git-empty-dir/load_command_module.py @@ -0,0 +1 @@ +../source_sync/load_command_module.py \ No newline at end of file diff --git a/tool/source_git-empty-dir/meta.py b/tool/source_git-empty-dir/meta.py new file mode 100644 index 0000000..dee6439 --- /dev/null +++ b/tool/source_git-empty-dir/meta.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*- + +""" +meta.py - thin wrappers around command modules + +Current responsibilities: + 1. Load the incommon 'printenv' command module (no .py extension) + using load_command_module.load_command_module(). + 2. Expose printenv() here, calling the imported printenv() work + function with default arguments (equivalent to running without + any CLI arguments). + 3. Provide a simple version printer for this meta module. + 4. Provide a small debug tag API (set/clear/has). +""" + +from __future__ import annotations + +import datetime +from load_command_module import load_command_module + + +# Load the incommon printenv module once at import time +_PRINTENV_MODULE = load_command_module("printenv") +_Z_MODULE = load_command_module("Z") + + +# Meta module version +_major = 1 +_minor = 1 +def version_print() -> None: + """ + Print the meta module version as MAJOR.MINOR. + """ + print(f"{_major}.{_minor}") + + +# Debug tag set and helpers +_debug = set([ +]) + + +def debug_set(tag: str) -> None: + """ + Add a debug tag to the meta debug set. + """ + _debug.add(tag) + + +def debug_clear(tag: str) -> None: + """ + Remove a debug tag from the meta debug set, if present. + """ + _debug.discard(tag) + + +def debug_has(tag: str) -> bool: + """ + Return True if the given debug tag is present. + """ + return tag in _debug + + +# Touch the default tag once so static checkers do not complain about +# unused helpers when imported purely for side-effects. +debug_has("Command") + + +def printenv() -> int: + """ + Call the imported printenv() work function with default arguments: + - no null termination + - no newline quoting + - no specific names (print full environment) + - prog name 'printenv' + """ + return _PRINTENV_MODULE.printenv( + False # null_terminate + ,False # quote_newlines + ,[] # names + ,"printenv" + ) + + +def z_format_mtime( + mtime: float +) -> str: + """ + Format a POSIX mtime (seconds since epoch, UTC) using the Z module. + + Uses Z.ISO8601_FORMAT and Z.make_timestamp(dt=...). + """ + dt = datetime.datetime.fromtimestamp(mtime, datetime.timezone.utc) + return _Z_MODULE.make_timestamp( + fmt=_Z_MODULE.ISO8601_FORMAT + ,dt=dt + ) diff --git a/tool/source_git-empty-dir/source_sync b/tool/source_git-empty-dir/source_sync new file mode 120000 index 0000000..9fd1d51 --- /dev/null +++ b/tool/source_git-empty-dir/source_sync @@ -0,0 +1 @@ +../source_sync/ \ No newline at end of file diff --git a/tool/source_skeleton_compare/A_minus_B b/tool/source_sync/A_minus_B similarity index 100% rename from tool/source_skeleton_compare/A_minus_B rename to tool/source_sync/A_minus_B diff --git a/tool/source_skeleton_compare/CLI.py b/tool/source_sync/CLI.py similarity index 100% rename from tool/source_skeleton_compare/CLI.py rename to tool/source_sync/CLI.py diff --git a/tool/source_skeleton_compare/GitIgnore.py b/tool/source_sync/GitIgnore.py similarity index 100% rename from tool/source_skeleton_compare/GitIgnore.py rename to tool/source_sync/GitIgnore.py diff --git a/tool/source_skeleton_compare/Harmony.py b/tool/source_sync/Harmony.py similarity index 100% rename from tool/source_skeleton_compare/Harmony.py rename to tool/source_sync/Harmony.py diff --git a/tool/source_skeleton_compare/Harmony_where b/tool/source_sync/Harmony_where similarity index 100% rename from tool/source_skeleton_compare/Harmony_where rename to tool/source_sync/Harmony_where diff --git a/tool/source_skeleton_compare/README.org b/tool/source_sync/README.org similarity index 100% rename from tool/source_skeleton_compare/README.org rename to tool/source_sync/README.org diff --git a/tool/source_skeleton_compare/command.py b/tool/source_sync/command.py similarity index 100% rename from tool/source_skeleton_compare/command.py rename to tool/source_sync/command.py diff --git a/tool/source_skeleton_compare/doc.py b/tool/source_sync/doc.py similarity index 100% rename from tool/source_skeleton_compare/doc.py rename to tool/source_sync/doc.py diff --git a/tool/source_skeleton_compare/in_between_and_below b/tool/source_sync/in_between_and_below similarity index 100% rename from tool/source_skeleton_compare/in_between_and_below rename to tool/source_sync/in_between_and_below diff --git a/tool/source_skeleton_compare/load_command_module.py b/tool/source_sync/load_command_module.py similarity index 100% rename from tool/source_skeleton_compare/load_command_module.py rename to tool/source_sync/load_command_module.py diff --git a/tool/source_skeleton_compare/make_Harmony_tree_dict b/tool/source_sync/make_Harmony_tree_dict similarity index 100% rename from tool/source_skeleton_compare/make_Harmony_tree_dict rename to tool/source_sync/make_Harmony_tree_dict diff --git a/tool/source_skeleton_compare/manus_2025_11_20_215471873762383.txt b/tool/source_sync/manus_2025_11_20_215471873762383.txt similarity index 100% rename from tool/source_skeleton_compare/manus_2025_11_20_215471873762383.txt rename to tool/source_sync/manus_2025_11_20_215471873762383.txt diff --git a/tool/source_skeleton_compare/meta.py b/tool/source_sync/meta.py similarity index 100% rename from tool/source_skeleton_compare/meta.py rename to tool/source_sync/meta.py diff --git a/tool/source_skeleton_compare/newer b/tool/source_sync/newer similarity index 100% rename from tool/source_skeleton_compare/newer rename to tool/source_sync/newer diff --git a/tool/source_skeleton_compare/older b/tool/source_sync/older similarity index 100% rename from tool/source_skeleton_compare/older rename to tool/source_sync/older diff --git a/tool/source_skeleton_compare/skeleton.py b/tool/source_sync/skeleton.py similarity index 100% rename from tool/source_skeleton_compare/skeleton.py rename to tool/source_sync/skeleton.py diff --git a/tool/sync b/tool/sync new file mode 120000 index 0000000..fc351d9 --- /dev/null +++ b/tool/sync @@ -0,0 +1 @@ +source_sync/CLI.py \ No newline at end of file diff --git a/tool_2.tar b/tool_2.tar new file mode 100644 index 0000000000000000000000000000000000000000..e4449534ece82ad22bc9ebadcf555618132d83fa GIT binary patch literal 215040 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ℜ=aHhizg7isb+H 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ȘZ!5~bRcBx+ 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 literal 0 HcmV?d00001 -- 2.20.1