diff --git a/build.sh b/build.sh index 6086886de..a4a8ce85f 100755 --- a/build.sh +++ b/build.sh @@ -27,6 +27,8 @@ BOOTSTRAP_CACHES=false ACTION="switch" # default action after build: switch | boot BUILD_FLAGS=() NH_CMD=() +LOG_DIR="${XDG_STATE_HOME:-${HOME}/.local/state}/nixos-build" +LOG_FILE="" # Colors for output (readonly constants) readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' @@ -56,9 +58,12 @@ Options: --bootstrap Use extra substituters for first build (e.g., Determinate Nix) -h, --help Show this help message +Logs: + Each run is recorded to %s/build--.log + Usage Example: ${0} --offline -" "${0##*/}" "${PWD}" "$(hostname)" +" "${0##*/}" "${PWD}" "$(hostname)" "${LOG_DIR}" } # Status messages with printf @@ -89,7 +94,21 @@ trap_error() { } trap trap_error ERR -trap 'true' EXIT # Cleanup hook (no-op; extend as needed) +# Close redirected fds so tee subprocesses see EOF, then wait for them to flush. +trap 'exec >&- 2>&-; wait' EXIT + +setup_logging() { + LOG_FILE="${LOG_DIR}/build-$(date +%Y%m%d-%H%M%S)-$$.log" + mkdir -p "${LOG_DIR}" + # Merge stderr into stdout before the tee so a single sed process + # appends to the log. POSIX guarantees atomic O_APPEND only up to + # PIPE_BUF (4096 bytes on Linux); separate stdout/stderr appenders + # would interleave at byte boundaries when verbose nix output emits + # long single lines (store-path arrays, dumped derivations). The + # outer tee preserves ANSI on the terminal; sed strips the file copy. + exec > >(tee >(sed -u 's/\x1b\[[0-9;]*m//g' >>"${LOG_FILE}")) 2>&1 + status_msg "${GREEN}" "Logging to: ${LOG_FILE}" +} # Parse command-line arguments while [[ $# -gt 0 ]]; do @@ -201,8 +220,8 @@ fi # Used for initial Determinate Nix setup or similar migrations BOOTSTRAP_SUBSTITUTERS=( "https://mirrors.tuna.tsinghua.edu.cn/nix-channels/store" - "https://mirror.sjtu.edu.cn/nix-channels/store" - #"https://mirrors.ustc.edu.cn/nix-channels/store" + #"https://mirror.sjtu.edu.cn/nix-channels/store" + "https://mirrors.ustc.edu.cn/nix-channels/store" "https://cache.nixos.org" "https://cache.garnix.io?priority=38" "https://cache.numtide.com" @@ -423,6 +442,7 @@ run_firmware_updates() { } main() { + setup_logging configure_nix_config configure_build_flags diff --git a/docs/guides/custom-packages-style-guide.md b/docs/guides/custom-packages-style-guide.md index 253be15e6..84163b143 100644 --- a/docs/guides/custom-packages-style-guide.md +++ b/docs/guides/custom-packages-style-guide.md @@ -259,22 +259,23 @@ Optional but recommended: ## Registering in the Overlay -After creating the package, register it in `modules/system76/custom-packages-overlay.nix`: +In-tree custom packages are exposed through the shared `customPackages` overlay at `modules/base/custom-packages-overlay.nix`. Add a single entry there for each new package: ```nix _: { - configurations.nixos.system76.module = { - nixpkgs.overlays = [ - (final: _prev: { - # Existing packages... - my-new-package = final.callPackage ../../packages/my-new-package { }; - }) - ]; + flake.lib.overlays.customPackages = final: prev: { + # Existing packages... + my-new-package = final.callPackage ../../packages/my-new-package { }; }; } ``` -This makes the package available as `pkgs.my-new-package` throughout the configuration. +Hosts opt in by composing the shared overlay into `nixpkgs.overlays`. The wiring already exists for both managed hosts: + +- `modules/system76/custom-packages-overlay.nix` composes the shared overlay and layers host-specific patches on top (e.g., the `system76-power` patch). +- `modules/tpnix/custom-packages-overlay.nix` composes the shared overlay alone. + +Use the per-host files only for host-only patches, version overrides, or hardware-specific tweaks; new in-tree packages belong in the shared overlay so every host that opts in sees them. After registration the package is available as `pkgs.my-new-package` on every host whose `custom-packages-overlay` module is loaded. ## Hash Fetching Workflow @@ -286,12 +287,14 @@ This makes the package available as `pkgs.my-new-package` throughout the configu hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; ``` -2. Attempt to build: +2. Attempt to build the package through the overlay-aware host `pkgs`: ```bash - nix build .#my-package + nix build .#nixosConfigurations.system76.pkgs.my-package ``` + Overlay-backed packages are not exposed as top-level flake outputs, so `nix build .#my-package` will fail with `does not provide attribute packages.x86_64-linux.my-package`. Always go through `nixosConfigurations..pkgs.` to apply the overlay. + 3. Copy the `got:` hash from the error message into your file. Alternatively, use `nix-prefetch-github`: @@ -352,13 +355,15 @@ Create a corresponding app module in `modules/apps/.nix` when: - The package is a user-facing application - Users should be able to enable/disable it declaratively - The package needs unfree allowlisting or extra configuration +- The package is host-visible tooling such as a shell helper or system-management script (e.g., `modules/apps/sss-pass-gpg-bootstrap.nix`, `modules/apps/sss-nix-repair.nix`) Skip the app module when: -- The package is host-specific tooling - The package is only used in devshells - The package is a library or build tool +The `apps-catalog-sync` pre-commit hook (`modules/meta/hooks/apps-catalog-sync.nix`) enforces that every app module under `modules/apps/` has a matching entry in each host's `apps-enable.nix`. After adding the app module, register it in `modules/system76/apps-enable.nix` and `modules/tpnix/apps-enable.nix`. Use `lib.mkOverride 1100 false` as the default and flip individual host catalogs to `true` only where the tool should be installed. + See [Apps Module Style Guide](apps-module-style-guide.md) for the app module format. ## Validation Checklist @@ -367,10 +372,10 @@ Before committing a new package: - [ ] File exists at `packages//default.nix` - [ ] All required meta fields are present -- [ ] Package is registered in `custom-packages-overlay.nix` -- [ ] `nix build .#` succeeds (or via overlay: test in config) +- [ ] Package is registered in `modules/base/custom-packages-overlay.nix` (shared `customPackages` overlay) +- [ ] `nix build .#nixosConfigurations..pkgs.` succeeds (overlay-backed packages are not exposed as top-level flake outputs) - [ ] `nix flake check --accept-flake-config` passes -- [ ] App module created if user-facing (see [Apps Module Style Guide](apps-module-style-guide.md)) +- [ ] App module created if user-facing or host-visible (see [Apps Module Style Guide](apps-module-style-guide.md)); `apps-catalog-sync` will fail the push if `modules/apps/.nix` lacks a matching entry in every host's `apps-enable.nix` ## Reference Implementations diff --git a/flake.lock b/flake.lock index 4dbbcdae4..95ce688d1 100644 --- a/flake.lock +++ b/flake.lock @@ -298,11 +298,11 @@ ] }, "locked": { - "lastModified": 1778008851, - "narHash": "sha256-gn/SN/Kd5f61kBTuObyqdJuGGE+BniurD9UQKsujO2o=", + "lastModified": 1778048802, + "narHash": "sha256-KgXGfVxnUGyIjirpqnc49wK/0Sb3TZ3cPujV3h2eAJk=", "owner": "nix-community", "repo": "NUR", - "rev": "2d9e1961a61896c0672664c39fc7a323362ea175", + "rev": "452c5cea023572b2fe400a512d25b9035f4f15ae", "type": "github" }, "original": { @@ -350,11 +350,11 @@ "nixpkgs-stable": "nixpkgs-stable" }, "locked": { - "lastModified": 1778004708, - "narHash": "sha256-dZeTLaf9TpkZ1oRT9xQFBPrCAEIDiMRub+RbQAFRqn4=", + "lastModified": 1778035564, + "narHash": "sha256-XJr1aD7alVflwcyqKhl91KbgxeUGCqiWI5cVJ2gb5Jo=", "owner": "nix-community", "repo": "emacs-overlay", - "rev": "a4dca412694e9d1c2b19218ac0e722baecd6103a", + "rev": "522f0c1535cf260f26485ee96b512ba2df057542", "type": "github" }, "original": { @@ -810,11 +810,11 @@ ] }, "locked": { - "lastModified": 1778007384, - "narHash": "sha256-Z+SBVn8dditLJtxi9GoQ5dhyi0dtUf3lgRNhvhhXzU0=", + "lastModified": 1778044692, + "narHash": "sha256-feJrvdnT9SGuhSG7tYWqPf77L3TxmPtk2Xza6HyEIMc=", "owner": "numtide", "repo": "llm-agents.nix", - "rev": "3a926e3686d75aa9d9e3ff52d5e05b0d11cd8b59", + "rev": "6159b9a1a78a736cea2977543e74787c5c382dfa", "type": "github" }, "original": { @@ -868,11 +868,11 @@ ] }, "locked": { - "lastModified": 1777555748, - "narHash": "sha256-RvKwvF868YY6HCfVC3K1kVrlUOnn4ynWxAi5PujhFXo=", + "lastModified": 1778042286, + "narHash": "sha256-FEY/HcDmLa3gFu8eag+hB4kxmZENGHatM/2gG/c/P2Y=", "owner": "natsukium", "repo": "mcp-servers-nix", - "rev": "39253ce656ff86527a060148c40901bbbde6a4c2", + "rev": "59b5a95c2e65abb7821e915c65e3e99607d522f2", "type": "github" }, "original": { @@ -956,11 +956,11 @@ ] }, "locked": { - "lastModified": 1777952747, - "narHash": "sha256-Q7XCl60/tzL9Ki0z1GtgwtyrQiol3xmlD82CndMZKfo=", + "lastModified": 1778040108, + "narHash": "sha256-1BNcfm6jQOoCSm4+xKrQ3HR3z9bOXuzaup30tW4xNq8=", "owner": "Bad3r", "repo": "nix-logseq-git-flake", - "rev": "1eb4086a36c028e0fd8a0c82a50b1c8bb443b227", + "rev": "d6760a143c820673e393e4ac492c6675bc0ef0ef", "type": "github" }, "original": { @@ -1033,11 +1033,11 @@ }, "nixpkgs-stable": { "locked": { - "lastModified": 1777673416, - "narHash": "sha256-5c2POKPOjU40Kh0MirOdScBLG0bu9TAuPYAtPRNZMBs=", + "lastModified": 1778003029, + "narHash": "sha256-q/nkKLDtHIyLjZpKhWk3cSK5IYsFqtMd6UtXF3ddjgA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "26ef669cffa904b6f6832ab57b77892a37c1a671", + "rev": "0c88e1f2bdb93d5999019e99cb0e61e1fe2af4c5", "type": "github" }, "original": { @@ -1049,11 +1049,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1777918403, - "narHash": "sha256-7QiZv0LcW1yIOLo2LNuCQjWon1Z1r99FwK24hbtBOF4=", + "lastModified": 1777946660, + "narHash": "sha256-iw3XDIG6xxk+AZTcawCLHf6i9i4tXRzLZEoV9xhRToQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "afc5551119aae6eab73a95c1960891cfe63204f6", + "rev": "bc57abace07689cfd34203aa5fb4027514895987", "type": "github" }, "original": { diff --git a/modules/apps/rip.nix b/modules/apps/rip.nix index a8019e6c2..7f2b3840f 100644 --- a/modules/apps/rip.nix +++ b/modules/apps/rip.nix @@ -245,6 +245,61 @@ let trash-put "''${TRASH_PUT_ARGS[@]}" "''${TRASH_DIR_ARGS[@]}" -- "''${FILES[@]}" ''; }; + + ripCompletion = pkgs.writeTextFile { + name = "rip-zsh-completion"; + destination = "/share/zsh/site-functions/_rip"; + text = '' + #compdef rip + + # Hand-written completion for the rip wrapper. Source of truth lives + # alongside the wrapper in this same module; the flag list must stay + # in sync with the case-statements in ripWrapper above. + + _rip_files() { + # `(#m)` and `$MATCH` require extendedglob; ensure it is set even + # when the caller's shell disables it. `localoptions` confines the + # change to this function. + setopt localoptions extendedglob + # Mirror the escaping shim trash-cli uses in _trash_files (see + # _trash-put / _trash-restore on the same fpath). Operate on a + # copy of `words` because `line` only holds positional args while + # `CURRENT` indexes `words`; mixing the two leaves the in-progress + # word in the exclusion set and silently breaks completion when a + # half-typed path contains a metachar. + local -a tmp_words + tmp_words=( "''${words[@]}" ) + tmp_words[CURRENT]=() + tmp_words=( ''${tmp_words//(#m)[\[\]()\\*?#<>~\^\|]/\\$MATCH} ) + _files -F tmp_words + } + + _rip() { + local context state line curcontext="$curcontext" + typeset -A opt_args + + # Exclusion lists mirror the wrapper's mode_count check: the four + # mode flags (--empty-trash, -s/--seance, -u/--unbury, positional + # FILES) are mutually exclusive. -i/--inspect is a trash-mode + # modifier and is rejected by the wrapper alongside the mode + # flags, so list it symmetrically. -u/--unbury also excludes the + # global positional spec (`*`) so files-to-trash completion stops + # firing once the operator has committed to a restore. + _arguments -C -s -S \ + '(- *)'{-h,--help}'[print help and exit]' \ + '(--empty-trash --seance -s --unbury -u -i --inspect *)--empty-trash[permanently empty the trash]' \ + '(--empty-trash --seance -s --unbury -u -i --inspect *)'{-s,--seance}'[list files trashed from cwd]' \ + '(--empty-trash --seance -s --unbury -u -i --inspect *)'{-u,--unbury}'[restore trashed files (interactive picker if no PATH)]:*::path to restore:_rip_files' \ + '(--empty-trash --seance -s --unbury -u)'{-i,--inspect}'[inspect (ls -la) and prompt before trashing]' \ + {-f,--force}'[skip all confirmation prompts]' \ + '--graveyard=[override trash directory for this invocation]:trash dir:_files -/' \ + {-r,-R,-d}'[rm compat, no-op]' \ + '*:files to trash:_rip_files' + } + + _rip "$@" + ''; + }; in { options.programs.rip.extended = { @@ -290,6 +345,7 @@ let environment.systemPackages = [ cfg.package ripWrapper + ripCompletion ]; systemd.tmpfiles.rules = [ diff --git a/notes.md b/notes.md deleted file mode 100644 index af1077e77..000000000 --- a/notes.md +++ /dev/null @@ -1,11 +0,0 @@ -## TODO - -1. High: the overlay registration section is stale and host-specific. custom-packages-style-guide.md:262 and custom-packages-style-guide.md:277 still tell authors to register custom packages only in modules/system76/custom-packages-overlay.nix and - imply that makes them globally available. Current repo practice is per-host overlay wiring, as shown in custom-packages-overlay.nix:19 and custom-packages-overlay.nix:18. -2. High: the validation command is wrong for overlay-backed custom packages. custom-packages-style-guide.md:292 and custom-packages-style-guide.md:371 recommend nix build .#, but this repo does not expose these packages as top-level flake - package outputs. I verified that nix develop -c nix build .#sss-pass-gpg-bootstrap fails with “does not provide attribute packages.x86_64-linux.sss-pass-gpg-bootstrap”. The working validation path is via host configs or overlay consumers. -3. Medium: the app-module guidance under-specifies the host catalog contract. custom-packages-style-guide.md:358 says to skip app modules for host-specific tooling, and custom-packages-style-guide.md:373 stops at “App module created”. In practice, - host-visible tooling is still modeled as app modules plus explicit host catalog entries, which the push hook enforces. Current evidence: sss-pass-gpg-bootstrap.nix:1, apps-enable.nix:303, apps-enable.nix:280, and the existing host-scoped tooling - pattern in sss-nix-repair.nix:21. - -- burpsuitepro.desktop> /nix/store/a14ldmhl5wsmz4mh9ybbvkvjjbxmkigx-burpsuitepro.desktop/share/applications/burpsuitepro.desktop: hint: value "Development;Security;System" for key "Categories" in group "Desktop Entry" contains more than one main category; application might appear more than once in the application menu