Generate flake.nix from module options. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ dendrix.oeiuwq.com/Dendritic.html
dendritic nix inputs

remove deps backend (#74)

* Revert "feat: add deps backend (#72)"

This reverts commit 1bf87eeb57ea517d4a6a96b4529f4f5d78a49e84.

* flake-parts.nixpkgs-lib follows nixpkgs

authored by oeiuwq.com and committed by

GitHub aa6077ff 1bf87eeb

+114 -1205
+33 -9
.github/workflows/flake-check.yaml
··· 21 21 runs-on: ubuntu-latest 22 22 strategy: 23 23 matrix: 24 - bootstrap: [inputs, flake, npins, unflake, deps] 24 + bootstrap: [inputs, flake, npins, unflake] 25 25 env: 26 26 NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" 27 27 steps: ··· 39 39 if: ${{ matrix.bootstrap == 'unflake' }} 40 40 - run: cat bootstrap/npins/sources.json 41 41 if: ${{ matrix.bootstrap == 'npins' }} 42 - - run: cat bootstrap/deps.nix 43 - if: ${{ matrix.bootstrap == 'deps' }} 44 - - name: Assert bootstrap deps has pinned nixpkgs 45 - if: ${{ matrix.bootstrap == 'deps' }} 46 - run: | 47 - nix-instantiate --parse bootstrap/deps.nix 48 - grep -E '^\s+nixpkgs\s*=' bootstrap/deps.nix 49 - grep -E '^\s+flake-parts\s*=' bootstrap/deps.nix 50 42 - name: Assert bootstrap npins transitive discovery (flake-parts -> nixpkgs-lib) 51 43 if: ${{ matrix.bootstrap == 'npins' }} 52 44 run: | ··· 97 89 sed -i 's/# flake-file = import/flake-file = import/' default.nix 98 90 echo "{ inputs, ... }: { npins.pkgs = import inputs.nixpkgs {}; }" | tee modules/pkgs.nix 99 91 nix-shell . -A npins.env --run write-npins 92 + npins-transitive: 93 + name: Check npins transitive discovery 94 + runs-on: ubuntu-latest 95 + env: 96 + NIX_PATH: "nixpkgs=https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz" 97 + steps: 98 + - uses: actions/checkout@v4 99 + - uses: wimpysworld/nothing-but-nix@main 100 + - uses: cachix/install-nix-action@v31 101 + - uses: DeterminateSystems/magic-nix-cache-action@main 102 + - name: Run write-npins with neomacs (has transitive deps) 103 + run: | 104 + mkdir test-out 105 + nix-shell ./default.nix -A flake-file.sh \ 106 + --run write-npins \ 107 + --arg modules ./modules/npins-transitive-test.nix \ 108 + --argstr outdir test-out 109 + - name: Assert declared inputs are pinned 110 + run: | 111 + jq -e '.pins | has("neomacs")' test-out/npins/sources.json 112 + jq -e '.pins | has("nixpkgs")' test-out/npins/sources.json 113 + - name: Assert transitive deps are auto-discovered 114 + run: | 115 + jq -e '.pins | has("crane")' test-out/npins/sources.json 116 + jq -e '.pins | has("rust-overlay")' test-out/npins/sources.json 117 + jq -e '.pins | has("nix-wpe-webkit")' test-out/npins/sources.json 118 + - name: Assert dedup-by-name (nixpkgs stays as Channel, not re-pinned from neomacs dep) 119 + run: | 120 + jq -e '.pins.nixpkgs.type == "Channel"' test-out/npins/sources.json 121 + - name: Show pinned sources 122 + if: always() 123 + run: cat test-out/npins/sources.json 100 124 unflake: 101 125 name: Check unflake 102 126 runs-on: ubuntu-latest
-1
default.nix
··· 39 39 ./modules 40 40 ./modules/options 41 41 ./modules/npins.nix 42 - ./modules/deps.nix 43 42 ./modules/unflake.nix 44 43 ./modules/write-inputs.nix 45 44 ./modules/write-flake.nix
-28
dev/modules/_lib/inputs-lib.nix
··· 1 - lib: esc: inputs: 2 - let 3 - pinnableInputs = lib.filterAttrs (_: v: v.url or "" != "") inputs; 4 - followsInputs = lib.filterAttrs (_: v: v.url or "" == "") inputs; 5 - 6 - seedBlock = 7 - entries: mkLine: 8 - let 9 - cmds = lib.mapAttrsToList mkLine entries; 10 - in 11 - if cmds == [ ] then ":" else "{\n" + lib.concatStringsSep "\n" cmds + "\n}"; 12 - 13 - followsSeed = 14 - seedBlock followsInputs (name: _: " printf '%s\\n' ${esc name}") + " >> \"$FOLLOWS_FILE\""; 15 - 16 - queueSeed = 17 - seedBlock pinnableInputs (name: input: " printf '%s\\t%s\\n' ${esc name} ${esc (input.url or "")}") 18 - + " >> \"$QUEUE_FILE\""; 19 - 20 - in 21 - { 22 - inherit 23 - pinnableInputs 24 - followsInputs 25 - followsSeed 26 - queueSeed 27 - ; 28 - }
-250
dev/modules/_lib/parse-url.nix
··· 1 - # Pure Nix flake URL parser. Returns a structured attrset for any flake URL. 2 - # Covers all types defined in the Nix flake reference spec. 3 - lib: 4 - let 5 - splitFirst = 6 - sep: s: 7 - let 8 - parts = lib.splitString sep s; 9 - in 10 - { 11 - head = lib.head parts; 12 - tail = lib.concatStringsSep sep (lib.tail parts); 13 - }; 14 - 15 - queryParam = 16 - key: queryStr: 17 - let 18 - pairs = if queryStr == "" then [ ] else lib.splitString "&" queryStr; 19 - m = lib.filter (lib.hasPrefix "${key}=") pairs; 20 - in 21 - if m == [ ] then "" else lib.removePrefix "${key}=" (lib.head m); 22 - 23 - parseUrl = 24 - rawUrl: 25 - let 26 - q = splitFirst "?" rawUrl; 27 - base = q.head; 28 - queryStr = q.tail; 29 - param = key: queryParam key queryStr; 30 - 31 - s = splitFirst ":" base; 32 - scheme = s.head; 33 - rest = s.tail; 34 - 35 - decodeSlash = lib.replaceStrings [ "%2F" "%2f" ] [ "/" "/" ]; 36 - 37 - parseOwnerRepo = 38 - path: 39 - let 40 - parts = lib.splitString "/" (decodeSlash path); 41 - owner = lib.elemAt parts 0; 42 - repo = if lib.length parts > 1 then lib.elemAt parts 1 else ""; 43 - pathRef = if lib.length parts > 2 then lib.concatStringsSep "/" (lib.drop 2 parts) else ""; 44 - in 45 - { 46 - inherit owner repo pathRef; 47 - }; 48 - 49 - inferType = 50 - if 51 - lib.elem scheme [ 52 - "github" 53 - "gitlab" 54 - "sourcehut" 55 - "indirect" 56 - "path" 57 - "tarball" 58 - "file" 59 - ] 60 - then 61 - scheme 62 - else if 63 - lib.elem scheme [ 64 - "git" 65 - "git+https" 66 - "git+http" 67 - "git+ssh" 68 - "git+git" 69 - "git+file" 70 - ] 71 - then 72 - "git" 73 - else if 74 - lib.elem scheme [ 75 - "hg" 76 - "hg+https" 77 - "hg+http" 78 - "hg+ssh" 79 - "hg+file" 80 - ] 81 - then 82 - "mercurial" 83 - else if 84 - lib.elem scheme [ 85 - "tarball+https" 86 - "tarball+http" 87 - "tarball+file" 88 - ] 89 - then 90 - "tarball" 91 - else if 92 - lib.elem scheme [ 93 - "file+https" 94 - "file+http" 95 - "file+file" 96 - ] 97 - then 98 - "file" 99 - else if 100 - lib.hasSuffix ".tar.gz" base 101 - || lib.hasSuffix ".tar.xz" base 102 - || lib.hasSuffix ".tgz" base 103 - || lib.hasSuffix ".tar.bz2" base 104 - || lib.hasSuffix ".tar.zst" base 105 - || lib.hasSuffix ".zip" base 106 - then 107 - "tarball" 108 - else 109 - "indirect"; 110 - 111 - type = inferType; 112 - 113 - ghgl = owner: repo: pathRef: defHost: { 114 - inherit type; 115 - owner = owner; 116 - repo = repo; 117 - ref = 118 - let 119 - r = param "ref"; 120 - in 121 - if r != "" then r else pathRef; 122 - rev = param "rev"; 123 - host = 124 - let 125 - h = param "host"; 126 - in 127 - if h != "" then h else defHost; 128 - dir = param "dir"; 129 - url = ""; 130 - }; 131 - 132 - p = parseOwnerRepo rest; 133 - 134 - in 135 - if type == "github" then 136 - ghgl p.owner p.repo p.pathRef "github.com" 137 - else if type == "gitlab" then 138 - ghgl p.owner p.repo p.pathRef "gitlab.com" 139 - else if type == "sourcehut" then 140 - let 141 - p2 = parseOwnerRepo rest; 142 - owner = lib.removePrefix "~" p2.owner; 143 - in 144 - { 145 - inherit type; 146 - owner = owner; 147 - repo = p2.repo; 148 - ref = 149 - let 150 - r = param "ref"; 151 - in 152 - if r != "" then r else p2.pathRef; 153 - rev = param "rev"; 154 - host = 155 - let 156 - h = param "host"; 157 - in 158 - if h != "" then h else "git.sr.ht"; 159 - dir = ""; 160 - url = ""; 161 - } 162 - else if type == "git" then 163 - { 164 - inherit type; 165 - owner = ""; 166 - repo = ""; 167 - ref = param "ref"; 168 - rev = param "rev"; 169 - host = ""; 170 - dir = param "dir"; 171 - url = "${scheme}:${rest}"; 172 - } 173 - else if type == "mercurial" then 174 - { 175 - inherit type; 176 - owner = ""; 177 - repo = ""; 178 - ref = param "ref"; 179 - rev = param "rev"; 180 - host = ""; 181 - dir = ""; 182 - url = "${scheme}:${rest}"; 183 - } 184 - else if type == "tarball" then 185 - { 186 - inherit type; 187 - owner = ""; 188 - repo = ""; 189 - ref = ""; 190 - rev = ""; 191 - host = ""; 192 - dir = ""; 193 - url = 194 - if 195 - lib.elem scheme [ 196 - "tarball+https" 197 - "tarball+http" 198 - "tarball+file" 199 - ] 200 - then 201 - lib.removePrefix "tarball+" rawUrl 202 - else 203 - rawUrl; 204 - } 205 - else if type == "file" then 206 - { 207 - inherit type; 208 - owner = ""; 209 - repo = ""; 210 - ref = ""; 211 - rev = ""; 212 - host = ""; 213 - dir = ""; 214 - url = 215 - if 216 - lib.elem scheme [ 217 - "file+https" 218 - "file+http" 219 - "file+file" 220 - ] 221 - then 222 - lib.removePrefix "file+" rawUrl 223 - else 224 - rawUrl; 225 - } 226 - else if type == "path" then 227 - { 228 - inherit type; 229 - owner = ""; 230 - repo = ""; 231 - ref = ""; 232 - rev = ""; 233 - host = ""; 234 - dir = ""; 235 - url = rawUrl; 236 - } 237 - else 238 - { 239 - type = "indirect"; 240 - owner = ""; 241 - repo = ""; 242 - ref = ""; 243 - rev = ""; 244 - host = ""; 245 - dir = ""; 246 - url = rawUrl; 247 - }; 248 - 249 - in 250 - parseUrl
-1
dev/modules/formatter.nix
··· 34 34 "**/unflake.nix" # generated by: nix-shell . -A unflake.env --run write-unflake 35 35 "**/inputs.nix" # generated by: nix-shell . -A unflake.env --run write-inputs 36 36 "**/npins/default.nix" # generated by write-npins 37 - "modules/deps/*.bash" # shell fragments included via builtins.readFile 38 37 "docs/*" 39 38 ]; 40 39 };
-73
dev/modules/unit-tests/inputs-lib.nix
··· 1 - { lib, ... }: 2 - let 3 - esc = lib.escapeShellArg; 4 - subject = inputs: import ./../_lib/inputs-lib.nix lib esc inputs; 5 - 6 - tests.inputs-lib."pinnableInputs excludes empty-url entries" = { 7 - expr = 8 - (subject { 9 - foo.url = "github:owner/foo"; 10 - bar.url = ""; 11 - baz = { }; 12 - }).pinnableInputs; 13 - expected = { 14 - foo.url = "github:owner/foo"; 15 - }; 16 - }; 17 - 18 - tests.inputs-lib."pinnableInputs keeps all non-empty urls" = { 19 - expr = 20 - lib.attrNames 21 - (subject { 22 - a.url = "github:a/a"; 23 - b.url = "github:b/b"; 24 - c.url = ""; 25 - }).pinnableInputs; 26 - expected = [ 27 - "a" 28 - "b" 29 - ]; 30 - }; 31 - 32 - tests.inputs-lib."followsInputs excludes inputs with urls" = { 33 - expr = 34 - (subject { 35 - nixpkgs.url = "github:NixOS/nixpkgs"; 36 - nixpkgs-lib.follows = "nixpkgs"; 37 - baz = { }; 38 - }).followsInputs; 39 - expected = { 40 - nixpkgs-lib.follows = "nixpkgs"; 41 - baz = { }; 42 - }; 43 - }; 44 - 45 - tests.inputs-lib."followsInputs is empty when all inputs have urls" = { 46 - expr = (subject { nixpkgs.url = "github:NixOS/nixpkgs"; }).followsInputs; 47 - expected = { }; 48 - }; 49 - 50 - tests.inputs-lib."queueSeed contains name and url for each pinnable input" = { 51 - expr = (subject { foo.url = "github:owner/foo"; }).queueSeed; 52 - expected = "{\n printf '%s\\t%s\\n' 'foo' 'github:owner/foo'\n} >> \"$QUEUE_FILE\""; 53 - }; 54 - 55 - tests.inputs-lib."queueSeed is empty block on no pinnable inputs" = { 56 - expr = (subject { foo.follows = "bar"; }).queueSeed; 57 - expected = ": >> \"$QUEUE_FILE\""; 58 - }; 59 - 60 - tests.inputs-lib."followsSeed emits printf for each follows-only input" = { 61 - expr = (subject { nixpkgs-lib.follows = "nixpkgs"; }).followsSeed; 62 - expected = "{\n printf '%s\\n' 'nixpkgs-lib'\n} >> \"$FOLLOWS_FILE\""; 63 - }; 64 - 65 - tests.inputs-lib."followsSeed is empty block when all inputs have urls" = { 66 - expr = (subject { nixpkgs.url = "github:NixOS/nixpkgs"; }).followsSeed; 67 - expected = ": >> \"$FOLLOWS_FILE\""; 68 - }; 69 - 70 - in 71 - { 72 - flake = { inherit tests; }; 73 - }
-81
dev/modules/unit-tests/normalize.nix
··· 1 - { inputs, ... }: 2 - let 3 - normalize = import "${inputs.flake-file}/modules/deps/normalize.nix"; 4 - 5 - mkFlake = content: builtins.toFile "flake.nix" content; 6 - 7 - norm = content: normalize (mkFlake content); 8 - 9 - tests.normalize."url form: github" = { 10 - expr = norm ''{ inputs.nixpkgs.url = "github:NixOS/nixpkgs"; outputs = _: {}; }''; 11 - expected = { 12 - nixpkgs = "github:NixOS/nixpkgs"; 13 - }; 14 - }; 15 - 16 - tests.normalize."attrset form: github basic" = { 17 - expr = norm ''{ inputs.nixpkgs = { type = "github"; owner = "NixOS"; repo = "nixpkgs"; }; outputs = _: {}; }''; 18 - expected = { 19 - nixpkgs = "github:NixOS/nixpkgs"; 20 - }; 21 - }; 22 - 23 - tests.normalize."attrset form: github with ref" = { 24 - expr = norm ''{ inputs.nixpkgs = { type = "github"; owner = "NixOS"; repo = "nixpkgs"; ref = "nixos-23.11"; }; outputs = _: {}; }''; 25 - expected = { 26 - nixpkgs = "github:NixOS/nixpkgs/nixos-23.11"; 27 - }; 28 - }; 29 - 30 - tests.normalize."attrset form: github with rev" = { 31 - expr = norm ''{ inputs.nixpkgs = { type = "github"; owner = "NixOS"; repo = "nixpkgs"; rev = "abc123"; }; outputs = _: {}; }''; 32 - expected = { 33 - nixpkgs = "github:NixOS/nixpkgs/abc123"; 34 - }; 35 - }; 36 - 37 - tests.normalize."attrset form: github with host" = { 38 - expr = norm ''{ inputs.foo = { type = "github"; owner = "org"; repo = "bar"; host = "ghe.example.com"; }; outputs = _: {}; }''; 39 - expected = { 40 - foo = "github:org/bar?host=ghe.example.com"; 41 - }; 42 - }; 43 - 44 - tests.normalize."attrset form: gitlab" = { 45 - expr = norm ''{ inputs.foo = { type = "gitlab"; owner = "veloren"; repo = "veloren"; }; outputs = _: {}; }''; 46 - expected = { 47 - foo = "gitlab:veloren/veloren"; 48 - }; 49 - }; 50 - 51 - tests.normalize."attrset form: sourcehut" = { 52 - expr = norm ''{ inputs.foo = { type = "sourcehut"; owner = "misterio"; repo = "nix-colors"; }; outputs = _: {}; }''; 53 - expected = { 54 - foo = "sourcehut:~misterio/nix-colors"; 55 - }; 56 - }; 57 - 58 - tests.normalize."attrset form: git" = { 59 - expr = norm ''{ inputs.foo = { type = "git"; url = "git+https://example.org/my/repo"; ref = "main"; }; outputs = _: {}; }''; 60 - expected = { 61 - foo = "git+https://example.org/my/repo?ref=main"; 62 - }; 63 - }; 64 - 65 - tests.normalize."follows: omitted from output" = { 66 - expr = norm ''{ inputs.nixpkgs-lib.follows = "nixpkgs"; inputs.nixpkgs.url = "github:NixOS/nixpkgs"; outputs = _: {}; }''; 67 - expected = { 68 - nixpkgs = "github:NixOS/nixpkgs"; 69 - nixpkgs-lib = ""; 70 - }; 71 - }; 72 - 73 - tests.normalize."no inputs: empty attrset" = { 74 - expr = norm "{ outputs = _: {}; }"; 75 - expected = { }; 76 - }; 77 - 78 - in 79 - { 80 - flake = { inherit tests; }; 81 - }
+54 -10
dev/modules/unit-tests/npins.nix
··· 1 1 { lib, ... }: 2 2 let 3 3 esc = lib.escapeShellArg; 4 - subject = inputs: import ./../_lib/inputs-lib.nix lib esc inputs; 5 4 6 - tests.npins."queueSeed wraps all entries in one redirect block" = { 5 + # Mirrors pinnableInputs from modules/npins.nix 6 + pinnableInputs = inputs: lib.filterAttrs (_: v: v.url or "" != "") inputs; 7 + 8 + # Mirrors queueSeed from modules/npins.nix 9 + queueSeed = 10 + pinnable: 11 + let 12 + lines = lib.mapAttrsToList ( 13 + name: input: " printf '%s\\t%s\\n' ${esc name} ${esc (input.url or "")}" 14 + ) pinnable; 15 + in 16 + "{\n" + lib.concatStringsSep "\n" lines + "\n} >> \"$QUEUE_FILE\""; 17 + 18 + tests.npins."pinnableInputs excludes empty-url entries" = { 19 + expr = pinnableInputs { 20 + foo.url = "github:owner/foo"; 21 + bar.url = ""; 22 + baz = { }; 23 + }; 24 + expected = { 25 + foo.url = "github:owner/foo"; 26 + }; 27 + }; 28 + 29 + tests.npins."pinnableInputs keeps all non-empty urls" = { 30 + expr = lib.attrNames (pinnableInputs { 31 + a.url = "github:a/a"; 32 + b.url = "github:b/b"; 33 + c.url = ""; 34 + }); 35 + expected = [ 36 + "a" 37 + "b" 38 + ]; 39 + }; 40 + 41 + tests.npins."pinnableInputs is empty on no-url inputs" = { 42 + expr = pinnableInputs { foo.follows = "bar"; }; 43 + expected = { }; 44 + }; 45 + 46 + tests.npins."queueSeed contains name and url for each pinnable input" = { 47 + expr = queueSeed { foo.url = "github:owner/foo"; }; 48 + expected = "{\n printf '%s\\t%s\\n' 'foo' 'github:owner/foo'\n} >> \"$QUEUE_FILE\""; 49 + }; 50 + 51 + tests.npins."queueSeed wraps all printfs in one redirect block" = { 7 52 expr = 8 53 let 9 - seed = 10 - (subject { 11 - a.url = "github:a/a"; 12 - b.url = "github:b/b"; 13 - }).queueSeed; 54 + seed = queueSeed { 55 + a.url = "github:a/a"; 56 + b.url = "github:b/b"; 57 + }; 14 58 in 15 59 lib.hasPrefix "{" seed && lib.hasSuffix ">> \"$QUEUE_FILE\"" seed; 16 60 expected = true; 17 61 }; 18 62 19 - tests.npins."pinnableInputs is empty on no-url inputs" = { 20 - expr = (subject { foo.follows = "bar"; }).pinnableInputs; 21 - expected = { }; 63 + tests.npins."queueSeed is empty block on no pinnable inputs" = { 64 + expr = queueSeed { }; 65 + expected = "{\n\n} >> \"$QUEUE_FILE\""; 22 66 }; 23 67 24 68 in
-380
dev/modules/unit-tests/parse-url.nix
··· 1 - { lib, ... }: 2 - let 3 - parse = import ./../_lib/parse-url.nix lib; 4 - p = url: parse url; 5 - 6 - # ── github ────────────────────────────────────────────────────────────────── 7 - tests.parse-url."github: basic" = { 8 - expr = p "github:NixOS/nixpkgs"; 9 - expected = { 10 - type = "github"; 11 - owner = "NixOS"; 12 - repo = "nixpkgs"; 13 - ref = ""; 14 - rev = ""; 15 - host = "github.com"; 16 - dir = ""; 17 - url = ""; 18 - }; 19 - }; 20 - 21 - tests.parse-url."github: branch ref" = { 22 - expr = p "github:NixOS/nixpkgs/nixos-23.11"; 23 - expected = { 24 - type = "github"; 25 - owner = "NixOS"; 26 - repo = "nixpkgs"; 27 - ref = "nixos-23.11"; 28 - rev = ""; 29 - host = "github.com"; 30 - dir = ""; 31 - url = ""; 32 - }; 33 - }; 34 - 35 - tests.parse-url."github: commit hash" = { 36 - expr = p "github:NixOS/nixpkgs/a3a3dda3bacf61e8a39258a0ed9c924eeca8e293"; 37 - expected = { 38 - type = "github"; 39 - owner = "NixOS"; 40 - repo = "nixpkgs"; 41 - ref = "a3a3dda3bacf61e8a39258a0ed9c924eeca8e293"; 42 - rev = ""; 43 - host = "github.com"; 44 - dir = ""; 45 - url = ""; 46 - }; 47 - }; 48 - 49 - tests.parse-url."github: pull request ref" = { 50 - expr = p "github:NixOS/nixpkgs/pull/357207/head"; 51 - expected = { 52 - type = "github"; 53 - owner = "NixOS"; 54 - repo = "nixpkgs"; 55 - ref = "pull/357207/head"; 56 - rev = ""; 57 - host = "github.com"; 58 - dir = ""; 59 - url = ""; 60 - }; 61 - }; 62 - 63 - tests.parse-url."github: custom host" = { 64 - expr = p "github:internal/project?host=company-github.example.org"; 65 - expected = { 66 - type = "github"; 67 - owner = "internal"; 68 - repo = "project"; 69 - ref = ""; 70 - rev = ""; 71 - host = "company-github.example.org"; 72 - dir = ""; 73 - url = ""; 74 - }; 75 - }; 76 - 77 - tests.parse-url."github: dir parameter" = { 78 - expr = p "github:edolstra/nix-warez?dir=blender"; 79 - expected = { 80 - type = "github"; 81 - owner = "edolstra"; 82 - repo = "nix-warez"; 83 - ref = ""; 84 - rev = ""; 85 - host = "github.com"; 86 - dir = "blender"; 87 - url = ""; 88 - }; 89 - }; 90 - 91 - tests.parse-url."github: rev query param" = { 92 - expr = p "github:NixOS/nixpkgs?rev=a3a3dda3bacf61e8a39258a0ed9c924eeca8e293"; 93 - expected = { 94 - type = "github"; 95 - owner = "NixOS"; 96 - repo = "nixpkgs"; 97 - ref = ""; 98 - rev = "a3a3dda3bacf61e8a39258a0ed9c924eeca8e293"; 99 - host = "github.com"; 100 - dir = ""; 101 - url = ""; 102 - }; 103 - }; 104 - 105 - # ── gitlab ────────────────────────────────────────────────────────────────── 106 - tests.parse-url."gitlab: basic" = { 107 - expr = p "gitlab:veloren/veloren"; 108 - expected = { 109 - type = "gitlab"; 110 - owner = "veloren"; 111 - repo = "veloren"; 112 - ref = ""; 113 - rev = ""; 114 - host = "gitlab.com"; 115 - dir = ""; 116 - url = ""; 117 - }; 118 - }; 119 - 120 - tests.parse-url."gitlab: branch ref" = { 121 - expr = p "gitlab:veloren/veloren/master"; 122 - expected = { 123 - type = "gitlab"; 124 - owner = "veloren"; 125 - repo = "veloren"; 126 - ref = "master"; 127 - rev = ""; 128 - host = "gitlab.com"; 129 - dir = ""; 130 - url = ""; 131 - }; 132 - }; 133 - 134 - tests.parse-url."gitlab: commit hash" = { 135 - expr = p "gitlab:veloren/veloren/80a4d7f13492d916e47d6195be23acae8001985a"; 136 - expected = { 137 - type = "gitlab"; 138 - owner = "veloren"; 139 - repo = "veloren"; 140 - ref = "80a4d7f13492d916e47d6195be23acae8001985a"; 141 - rev = ""; 142 - host = "gitlab.com"; 143 - dir = ""; 144 - url = ""; 145 - }; 146 - }; 147 - 148 - tests.parse-url."gitlab: custom host" = { 149 - expr = p "gitlab:openldap/openldap?host=git.openldap.org"; 150 - expected = { 151 - type = "gitlab"; 152 - owner = "openldap"; 153 - repo = "openldap"; 154 - ref = ""; 155 - rev = ""; 156 - host = "git.openldap.org"; 157 - dir = ""; 158 - url = ""; 159 - }; 160 - }; 161 - 162 - tests.parse-url."gitlab: percent-encoded subgroup" = { 163 - expr = p "gitlab:veloren%2Fdev/rfcs"; 164 - expected = { 165 - type = "gitlab"; 166 - owner = "veloren/dev"; 167 - repo = "rfcs"; 168 - ref = ""; 169 - rev = ""; 170 - host = "gitlab.com"; 171 - dir = ""; 172 - url = ""; 173 - }; 174 - }; 175 - 176 - # ── sourcehut ─────────────────────────────────────────────────────────────── 177 - tests.parse-url."sourcehut: basic with tilde" = { 178 - expr = p "sourcehut:~misterio/nix-colors"; 179 - expected = { 180 - type = "sourcehut"; 181 - owner = "misterio"; 182 - repo = "nix-colors"; 183 - ref = ""; 184 - rev = ""; 185 - host = "git.sr.ht"; 186 - dir = ""; 187 - url = ""; 188 - }; 189 - }; 190 - 191 - tests.parse-url."sourcehut: branch ref" = { 192 - expr = p "sourcehut:~misterio/nix-colors/main"; 193 - expected = { 194 - type = "sourcehut"; 195 - owner = "misterio"; 196 - repo = "nix-colors"; 197 - ref = "main"; 198 - rev = ""; 199 - host = "git.sr.ht"; 200 - dir = ""; 201 - url = ""; 202 - }; 203 - }; 204 - 205 - tests.parse-url."sourcehut: custom host" = { 206 - expr = p "sourcehut:~misterio/nix-colors?host=git.example.org"; 207 - expected = { 208 - type = "sourcehut"; 209 - owner = "misterio"; 210 - repo = "nix-colors"; 211 - ref = ""; 212 - rev = ""; 213 - host = "git.example.org"; 214 - dir = ""; 215 - url = ""; 216 - }; 217 - }; 218 - 219 - tests.parse-url."sourcehut: commit hash" = { 220 - expr = p "sourcehut:~misterio/nix-colors/182b4b8709b8ffe4e9774a4c5d6877bf6bb9a21c"; 221 - expected = { 222 - type = "sourcehut"; 223 - owner = "misterio"; 224 - repo = "nix-colors"; 225 - ref = "182b4b8709b8ffe4e9774a4c5d6877bf6bb9a21c"; 226 - rev = ""; 227 - host = "git.sr.ht"; 228 - dir = ""; 229 - url = ""; 230 - }; 231 - }; 232 - 233 - tests.parse-url."sourcehut: mercurial host" = { 234 - expr = p "sourcehut:~misterio/nix-colors/21c1a380?host=hg.sr.ht"; 235 - expected = { 236 - type = "sourcehut"; 237 - owner = "misterio"; 238 - repo = "nix-colors"; 239 - ref = "21c1a380"; 240 - rev = ""; 241 - host = "hg.sr.ht"; 242 - dir = ""; 243 - url = ""; 244 - }; 245 - }; 246 - 247 - # ── git ───────────────────────────────────────────────────────────────────── 248 - tests.parse-url."git+https: basic" = { 249 - expr = (p "git+https://example.org/my/repo").type; 250 - expected = "git"; 251 - }; 252 - 253 - tests.parse-url."git+https: with ref" = { 254 - expr = p "git+https://example.org/my/repo?ref=master"; 255 - expected = { 256 - type = "git"; 257 - owner = ""; 258 - repo = ""; 259 - ref = "master"; 260 - rev = ""; 261 - host = ""; 262 - dir = ""; 263 - url = "git+https://example.org/my/repo"; 264 - }; 265 - }; 266 - 267 - tests.parse-url."git+https: with ref and rev" = { 268 - expr = p "git+https://example.org/my/repo?ref=master&rev=f34751b88bd07d7f44f5cd3200fb4122bf916c7e"; 269 - expected = { 270 - type = "git"; 271 - owner = ""; 272 - repo = ""; 273 - ref = "master"; 274 - rev = "f34751b88bd07d7f44f5cd3200fb4122bf916c7e"; 275 - host = ""; 276 - dir = ""; 277 - url = "git+https://example.org/my/repo"; 278 - }; 279 - }; 280 - 281 - tests.parse-url."git: bare scheme with ref and rev" = { 282 - expr = p "git://github.com/edolstra/dwarffs?ref=unstable&rev=e486d8d40e626a20e06d792db8cc5ac5aba9a5b4"; 283 - expected = { 284 - type = "git"; 285 - owner = ""; 286 - repo = ""; 287 - ref = "unstable"; 288 - rev = "e486d8d40e626a20e06d792db8cc5ac5aba9a5b4"; 289 - host = ""; 290 - dir = ""; 291 - url = "git://github.com/edolstra/dwarffs"; 292 - }; 293 - }; 294 - 295 - tests.parse-url."git+ssh: with ref" = { 296 - expr = p "git+ssh://git@github.com/NixOS/nix?ref=v1.2.3"; 297 - expected = { 298 - type = "git"; 299 - owner = ""; 300 - repo = ""; 301 - ref = "v1.2.3"; 302 - rev = ""; 303 - host = ""; 304 - dir = ""; 305 - url = "git+ssh://git@github.com/NixOS/nix"; 306 - }; 307 - }; 308 - 309 - tests.parse-url."git+file: local" = { 310 - expr = (p "git+file:///home/my-user/some-repo").type; 311 - expected = "git"; 312 - }; 313 - 314 - # ── tarball ───────────────────────────────────────────────────────────────── 315 - tests.parse-url."tarball: https scheme" = { 316 - expr = p "https://github.com/NixOS/patchelf/archive/master.tar.gz"; 317 - expected = { 318 - type = "tarball"; 319 - owner = ""; 320 - repo = ""; 321 - ref = ""; 322 - rev = ""; 323 - host = ""; 324 - dir = ""; 325 - url = "https://github.com/NixOS/patchelf/archive/master.tar.gz"; 326 - }; 327 - }; 328 - 329 - tests.parse-url."tarball+https: explicit scheme" = { 330 - expr = (p "tarball+https://example.org/repo.tar.gz").type; 331 - expected = "tarball"; 332 - }; 333 - 334 - tests.parse-url."tarball+https: strips prefix from url" = { 335 - expr = (p "tarball+https://example.org/repo.tar.gz").url; 336 - expected = "https://example.org/repo.tar.gz"; 337 - }; 338 - 339 - tests.parse-url."tarball: nixos channel url" = { 340 - expr = (p "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz").type; 341 - expected = "tarball"; 342 - }; 343 - 344 - tests.parse-url."tarball: zip extension" = { 345 - expr = (p "https://example.org/archive.zip").type; 346 - expected = "tarball"; 347 - }; 348 - 349 - # ── file ──────────────────────────────────────────────────────────────────── 350 - tests.parse-url."file+http: type" = { 351 - expr = (p "file+http://example.org/foo").type; 352 - expected = "file"; 353 - }; 354 - 355 - tests.parse-url."file+https: strips prefix" = { 356 - expr = (p "file+https://example.org/foo").url; 357 - expected = "https://example.org/foo"; 358 - }; 359 - 360 - # ── mercurial ─────────────────────────────────────────────────────────────── 361 - tests.parse-url."hg+https: type" = { 362 - expr = (p "hg+https://example.org/my/repo").type; 363 - expected = "mercurial"; 364 - }; 365 - 366 - tests.parse-url."hg+https: with ref" = { 367 - expr = (p "hg+https://example.org/my/repo?ref=default").ref; 368 - expected = "default"; 369 - }; 370 - 371 - # ── path ──────────────────────────────────────────────────────────────────── 372 - tests.parse-url."path: absolute" = { 373 - expr = (p "path:/home/user/sub/dir").type; 374 - expected = "path"; 375 - }; 376 - 377 - in 378 - { 379 - flake = { inherit tests; }; 380 - }
+1
modules/bootstrap.nix
··· 4 4 import-tree.url = lib.mkDefault "github:vic/import-tree"; 5 5 flake-file.url = lib.mkDefault "github:vic/flake-file"; 6 6 flake-parts.url = lib.mkDefault "github:hercules-ci/flake-parts"; 7 + flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs"; 7 8 nixpkgs.url = lib.mkDefault "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 8 9 }; 9 10 }
-6
modules/default.nix
··· 7 7 dendritic 8 8 import-tree 9 9 npins 10 - deps 11 10 unflake 12 11 flake-options 13 12 ; ··· 23 22 npins.imports = [ 24 23 base 25 24 ./npins.nix 26 - ]; 27 - 28 - deps.imports = [ 29 - base 30 - ./deps.nix 31 25 ]; 32 26 33 27 unflake.imports = [
-52
modules/deps.nix
··· 1 - { lib, config, ... }: 2 - let 3 - inherit (config) flake-file; 4 - inherit (import ./../dev/modules/_lib lib) inputsExpr; 5 - 6 - inputs = inputsExpr flake-file.inputs; 7 - esc = lib.escapeShellArg; 8 - 9 - inherit (import ./inputs-lib.nix lib esc inputs) 10 - followsSeed 11 - queueSeed 12 - ; 13 - 14 - write-deps = 15 - pkgs: 16 - let 17 - normalizeNix = pkgs.writeText "normalize.nix" (builtins.readFile ./deps/normalize.nix); 18 - in 19 - pkgs.writeShellApplication { 20 - name = "write-deps"; 21 - runtimeInputs = [ 22 - pkgs.curl 23 - pkgs.jq 24 - pkgs.nix 25 - pkgs.git 26 - ]; 27 - text = '' 28 - cd ${flake-file.intoPath} 29 - 30 - ${builtins.readFile ./deps/url.bash} 31 - ${builtins.readFile ./deps/fetch-forge.bash} 32 - ${builtins.readFile ./deps/fetch.bash} 33 - ${builtins.readFile ./deps/bfs.bash} 34 - 35 - FOLLOWS_FILE=$(mktemp) 36 - SEEN_FILE=$(mktemp) 37 - QUEUE_FILE=$(mktemp) 38 - DEPS_FILE=$(mktemp) 39 - NORMALIZE_NIX=${normalizeNix} 40 - trap 'rm -f "$FOLLOWS_FILE" "$SEEN_FILE" "$QUEUE_FILE" "$DEPS_FILE"' EXIT 41 - 42 - ${followsSeed} 43 - ${queueSeed} 44 - 45 - bfs_main 46 - write_deps_nix 47 - ''; 48 - }; 49 - in 50 - { 51 - config.flake-file.apps = { inherit write-deps; }; 52 - }
-36
modules/deps/bfs.bash
··· 1 - # BFS: consume QUEUE_FILE, fetch each new item, discover transitive deps. 2 - bfs_main() { 3 - log_info "starting BFS..." 4 - local count=0 5 - while true; do 6 - local name="" url="" 7 - while IFS=$'\t' read -r qname qurl; do 8 - if ! grep -qxF "$qname" "$SEEN_FILE" 2>/dev/null \ 9 - && ! grep -qxF "$qname" "$FOLLOWS_FILE" 2>/dev/null; then 10 - name="$qname" url="$qurl" 11 - break 12 - fi 13 - done < "$QUEUE_FILE" 14 - [ -z "$name" ] && break 15 - printf '%s\n' "$name" >> "$SEEN_FILE" 16 - local entry 17 - entry=$(fetch_entry "$name" "$url") \ 18 - && { printf '%s\n' "$entry" >> "$DEPS_FILE"; count=$((count + 1)); } \ 19 - || true 20 - discover_transitive "$name" "$url" 21 - done 22 - log_info "done: $count inputs fetched" 23 - } 24 - 25 - # Write deps.nix from accumulated DEPS_FILE lines. 26 - write_deps_nix() { 27 - { 28 - printf '# DO-NOT-EDIT: Generated by github:vic/flake-file\n' 29 - printf '# To re-generate: nix-shell . -A flake-file.sh --run write-deps\n' 30 - printf '# Usage: let deps = import ./deps.nix; in deps.nixpkgs.outPath\n' 31 - printf '{\n' 32 - cat "$DEPS_FILE" 33 - printf '}\n' 34 - } > deps.nix 35 - log_info "wrote deps.nix" 36 - }
-74
modules/deps/fetch-forge.bash
··· 1 - fetch_github() { 2 - local name="$1" raw="$2" 3 - local body host dir rev ref owner repo sha256 outpath_nix 4 - body="$(url_base "${raw#github:}")" 5 - host="$(url_param host "$raw")"; host="${host:-github.com}" 6 - dir="$(url_param dir "$raw")" 7 - rev="$(url_param rev "$raw")" 8 - owner="${body%%/*}"; body="${body#*/}" 9 - repo="${body%%/*}"; ref="${body#"$repo"}"; ref="${ref#/}" 10 - [ -n "$rev" ] || rev=$(git_rev "https://${host}/${owner}/${repo}.git" "${ref:-HEAD}") 11 - local archive="https://${host}/${owner}/${repo}/archive/${rev}.tar.gz" 12 - log_info "fetching ${name} (github ${owner}/${repo} @ ${rev:0:12})" 13 - sha256=$(prefetch_tarball "$archive") || { log_info "warning: failed $name"; return 1; } 14 - if [ -n "$dir" ]; then 15 - outpath_nix="(builtins.fetchTarball { url = \"$archive\"; sha256 = \"$sha256\"; }) + \"/$dir\"" 16 - else 17 - outpath_nix="builtins.fetchTarball { url = \"$archive\"; sha256 = \"$sha256\"; }" 18 - fi 19 - emit_record "$name" "$outpath_nix" \ 20 - "type=github" "owner=$owner" "repo=$repo" "rev=$rev" "ref=$ref" "host=$host" "dir=$dir" 21 - } 22 - 23 - fetch_gitlab() { 24 - local name="$1" raw="$2" 25 - local body host dir rev ref owner repo sha256 archive 26 - body="$(url_base "${raw#gitlab:}")" 27 - host="$(url_param host "$raw")"; host="${host:-gitlab.com}" 28 - dir="$(url_param dir "$raw")" 29 - rev="$(url_param rev "$raw")" 30 - owner="$(url_decode "${body%%/*}")"; body="${body#*/}" 31 - repo="${body%%/*}"; ref="${body#"$repo"}"; ref="${ref#/}" 32 - [ -n "$rev" ] || rev=$(git_rev "https://${host}/${owner}/${repo}.git" "${ref:-HEAD}") 33 - archive="https://${host}/${owner}/${repo}/-/archive/${rev}/${repo}-${rev}.tar.gz" 34 - log_info "fetching ${name} (gitlab ${owner}/${repo} @ ${rev:0:12})" 35 - local sha256 36 - sha256=$(prefetch_tarball "$archive") || { log_info "warning: failed $name"; return 1; } 37 - emit_record "$name" "builtins.fetchTarball { url = \"$archive\"; sha256 = \"$sha256\"; }" \ 38 - "type=gitlab" "owner=$owner" "repo=$repo" "rev=$rev" "ref=$ref" "host=$host" 39 - } 40 - 41 - fetch_sourcehut_hg() { 42 - local name="$1" raw="$2" 43 - local body host rev owner repo ref remote sha256 archive 44 - host="$(url_param host "$raw")"; host="${host:-hg.sr.ht}" 45 - body="$(url_base "${raw#sourcehut:}")" 46 - rev="$(url_param rev "$raw")" 47 - owner="${body%%/*}"; owner="${owner#\~}" 48 - body="${body#*/}"; repo="${body%%/*}"; ref="${body#"$repo"}"; ref="${ref#/}" 49 - remote="https://${host}/~${owner}/${repo}" 50 - [ -n "$rev" ] || rev=$(curl -sfL "${remote}/log/${ref:-tip}/rss" \ 51 - | grep -m1 '<guid>' | sed 's|.*<guid>.*rev=\([^<]*\).*|\1|') 52 - archive="${remote}/archive/${rev}.tar.gz" 53 - log_info "fetching ${name} (sourcehut-hg ${owner}/${repo} @ ${rev:0:12})" 54 - sha256=$(prefetch_tarball "$archive") || { log_info "warning: failed $name"; return 1; } 55 - emit_record "$name" "builtins.fetchTarball { url = \"$archive\"; sha256 = \"$sha256\"; }" \ 56 - "type=sourcehut" "owner=$owner" "repo=$repo" "rev=$rev" "ref=$ref" "host=$host" 57 - } 58 - 59 - fetch_sourcehut() { 60 - local name="$1" raw="$2" 61 - local body host ref rev owner repo remote sha256 archive 62 - host="$(url_param host "$raw")"; host="${host:-git.sr.ht}" 63 - body="$(url_base "${raw#sourcehut:}")" 64 - rev="$(url_param rev "$raw")" 65 - owner="${body%%/*}"; owner="${owner#\~}" 66 - body="${body#*/}"; repo="${body%%/*}"; ref="${body#"$repo"}"; ref="${ref#/}" 67 - remote="https://${host}/~${owner}/${repo}" 68 - [ -n "$rev" ] || rev=$(git_rev "${remote}" "${ref:-HEAD}") 69 - archive="${remote}/archive/${rev}.tar.gz" 70 - log_info "fetching ${name} (sourcehut ${owner}/${repo} @ ${rev:0:12})" 71 - sha256=$(prefetch_tarball "$archive") || { log_info "warning: failed $name"; return 1; } 72 - emit_record "$name" "builtins.fetchTarball { url = \"$archive\"; sha256 = \"$sha256\"; }" \ 73 - "type=sourcehut" "owner=$owner" "repo=$repo" "rev=$rev" "ref=$ref" "host=$host" 74 - }
-81
modules/deps/fetch.bash
··· 1 - fetch_git_url() { 2 - local name="$1" raw="$2" 3 - local url ref rev 4 - url="$(url_base "$raw")"; url="${url#git+}" 5 - ref="$(url_param ref "$raw")" 6 - rev="$(url_param rev "$raw")" 7 - [ -n "$rev" ] || rev=$(git_rev "$url" "${ref:-HEAD}") 8 - log_info "fetching ${name} (git ${url} @ ${rev:0:12})" 9 - emit_record "$name" "builtins.fetchGit { url = \"$url\"; rev = \"$rev\"; }" \ 10 - "type=git" "url=$url" "rev=$rev" "ref=$ref" 11 - } 12 - 13 - fetch_tarball_url() { 14 - local name="$1" raw="$2" url sha256 15 - url="$(url_base "$raw")"; url="${url#tarball+}" 16 - log_info "fetching ${name} (tarball)" 17 - sha256=$(prefetch_tarball "$url") || { log_info "warning: failed $name"; return 1; } 18 - emit_record "$name" "builtins.fetchTarball { url = \"$url\"; sha256 = \"$sha256\"; }" \ 19 - "type=tarball" "url=$url" 20 - } 21 - 22 - fetch_file_url() { 23 - local name="$1" raw="$2" url sha256 24 - url="$(url_base "$raw")"; url="${url#file+}" 25 - log_info "fetching ${name} (file)" 26 - sha256=$(nix-prefetch-url "$url" 2>/dev/null) || { log_info "warning: failed $name"; return 1; } 27 - emit_record "$name" "builtins.fetchurl { url = \"$url\"; sha256 = \"$sha256\"; }" \ 28 - "type=file" "url=$url" 29 - } 30 - 31 - fetch_mercurial() { 32 - local name="$1" raw="$2" url ref rev sha256 archive 33 - url="$(url_base "$raw")"; url="${url#hg+}" 34 - ref="$(url_param ref "$raw")" 35 - rev="$(url_param rev "$raw")" 36 - [ -n "$rev" ] || rev=$(curl -sfL "${url}/log/${ref:-tip}/rss" \ 37 - | grep -m1 '<guid>' | sed 's|.*<guid>.*rev=\([^<]*\).*|\1|') 38 - archive="${url}/archive/${rev}.tar.gz" 39 - log_info "fetching ${name} (mercurial @ ${rev:0:12})" 40 - sha256=$(prefetch_tarball "$archive") || { log_info "warning: failed $name"; return 1; } 41 - emit_record "$name" "builtins.fetchTarball { url = \"$archive\"; sha256 = \"$sha256\"; }" \ 42 - "type=mercurial" "url=$url" "rev=$rev" "ref=$ref" 43 - } 44 - 45 - fetch_entry() { 46 - local name="$1" url="$2" 47 - case "$url" in 48 - github:*) fetch_github "$name" "$url" ;; 49 - gitlab:*) fetch_gitlab "$name" "$url" ;; 50 - sourcehut:*hg.sr.ht*) fetch_sourcehut_hg "$name" "$url" ;; 51 - sourcehut:*) fetch_sourcehut "$name" "$url" ;; 52 - git+http://*|git+https://*|git+ssh://*|git+git://*|git+file://*) 53 - fetch_git_url "$name" "$url" ;; 54 - git://*) fetch_git_url "$name" "git+${url}" ;; 55 - hg+*) fetch_mercurial "$name" "$url" ;; 56 - tarball+*) fetch_tarball_url "$name" "$url" ;; 57 - file+*) fetch_file_url "$name" "$url" ;; 58 - *.tar.gz|*.tar.bz2|*.tar.xz|*.tar.zst|*.zip|http://*|https://*) 59 - fetch_tarball_url "$name" "$url" ;; 60 - path:*) log_info "skipping ${name} (local path)" ;; 61 - *) log_info "skipping ${name} (indirect/unknown: $url)" ;; 62 - esac 63 - } 64 - 65 - discover_transitive() { 66 - local name="$1" url="$2" 67 - [[ "$url" != github:* ]] && return 0 68 - local spec owner repo ref flake_tmp expr_tmp 69 - spec="${url#github:}" owner="${spec%%/*}" spec="${spec#*/}" 70 - repo="${spec%%/*}" ref="${spec#*/}" 71 - [ "$ref" = "$repo" ] && ref="HEAD" 72 - flake_tmp=$(mktemp --suffix=.nix) 73 - expr_tmp=$(mktemp --suffix=.nix) 74 - curl -sf "https://raw.githubusercontent.com/${owner}/${repo}/${ref}/flake.nix" \ 75 - > "$flake_tmp" || { rm -f "$flake_tmp" "$expr_tmp"; return 0; } 76 - printf '(import %s) %s\n' "$NORMALIZE_NIX" "$flake_tmp" > "$expr_tmp" 77 - nix-instantiate --eval --strict --json "$expr_tmp" 2>/dev/null \ 78 - | jq -r 'to_entries[] | select(.value | . != "" and test("^[a-z]")) | [.key, .value] | @tsv' \ 79 - >> "$QUEUE_FILE" || true 80 - rm -f "$flake_tmp" "$expr_tmp" 81 - }
-66
modules/deps/normalize.nix
··· 1 - flakeFile: 2 - let 3 - f = import flakeFile; 4 - 5 - withRef = 6 - owner: repo: ref: 7 - "${owner}/${repo}${if ref != "" then "/" + ref else ""}"; 8 - withHost = host: def: if host != "" && host != def then "?host=${host}" else ""; 9 - 10 - refOf = v: if v ? rev then v.rev else (v.ref or ""); 11 - 12 - github = v: "github:${withRef v.owner v.repo (refOf v)}${withHost (v.host or "") "github.com"}"; 13 - gitlab = v: "gitlab:${withRef v.owner v.repo (refOf v)}${withHost (v.host or "") "gitlab.com"}"; 14 - sourcehut = 15 - v: "sourcehut:~${withRef v.owner v.repo (refOf v)}${withHost (v.host or "") "git.sr.ht"}"; 16 - 17 - gitParams = 18 - v: 19 - let 20 - ref = if v ? ref then "ref=${v.ref}" else ""; 21 - rev = if v ? rev then "rev=${v.rev}" else ""; 22 - params = builtins.filter (s: s != "") [ 23 - ref 24 - rev 25 - ]; 26 - in 27 - if params == [ ] then "" else "?" + builtins.concatStringsSep "&" params; 28 - 29 - fromAttrs = 30 - v: 31 - if !(v ? type) then 32 - (v.url or "") 33 - else if v.type == "github" then 34 - github v 35 - else if v.type == "gitlab" then 36 - gitlab v 37 - else if v.type == "sourcehut" then 38 - sourcehut v 39 - else if v.type == "git" then 40 - "${v.url or ""}${gitParams v}" 41 - else if v.type == "tarball" then 42 - v.url or "" 43 - else if v.type == "file" then 44 - v.url or "" 45 - else if v.type == "path" then 46 - "path:${v.path or ""}" 47 - else if v.type == "indirect" then 48 - v.id or "" 49 - else if v.type == "mercurial" then 50 - v.url or "" 51 - else 52 - ""; 53 - 54 - norm = 55 - v: 56 - if builtins.isString v then 57 - v 58 - else if v ? url then 59 - v.url 60 - else if v ? follows then 61 - "" 62 - else 63 - fromAttrs v; 64 - 65 - in 66 - builtins.mapAttrs (_: norm) (f.inputs or { })
-40
modules/deps/url.bash
··· 1 - # Extract a query parameter value from a URL: url_param KEY URL 2 - url_param() { 3 - local key="$1" url="$2" qs 4 - qs="${url#*\?}" 5 - [ "$qs" = "$url" ] && { printf ''; return; } 6 - printf '%s' "$qs" | tr '&' '\n' | grep "^${key}=" | cut -d= -f2- | head -1 7 - } 8 - 9 - url_base() { printf '%s' "${1%%\?*}"; } 10 - url_decode() { printf '%s' "$1" | sed 's/%2[Ff]/\//g'; } 11 - 12 - # Resolve a git ref to exact commit SHA (deref tags, fallback to ref as-is). 13 - git_rev() { 14 - local remote="$1" ref="$2" resolved deref 15 - resolved=$(git ls-remote "$remote" \ 16 - "refs/heads/$ref" "refs/tags/$ref" "HEAD" 2>/dev/null \ 17 - | grep -v '\^{}' | awk 'NR==1{print $1; exit}') 18 - deref=$(git ls-remote "$remote" "refs/tags/$ref^{}" 2>/dev/null | awk '{print $1; exit}') 19 - printf '%s' "${deref:-${resolved:-$ref}}" 20 - } 21 - 22 - # Fetch sha256 for a tarball URL (nix-prefetch-url --unpack). 23 - prefetch_tarball() { nix-prefetch-url --unpack "$1" 2>/dev/null; } 24 - 25 - # Progress output to stderr. 26 - log_info() { printf '[deps] %s\n' "$*" >&2; } 27 - 28 - # Emit a rich Nix attrset record. 29 - # Usage: emit_record NAME OUTPATH_NIX_EXPR [key=value ...] 30 - emit_record() { 31 - local name="$1" outpath="$2" 32 - shift 2 33 - printf ' %s = {\n outPath = %s;\n' "$name" "$outpath" 34 - local kv k v 35 - for kv in "$@"; do 36 - k="${kv%%=*}" v="${kv#*=}" 37 - [ -n "$v" ] && printf ' %s = "%s";\n' "$k" "$v" 38 - done 39 - printf ' };\n' 40 - }
-1
modules/inputs-lib.nix
··· 1 - import ./../dev/modules/_lib/inputs-lib.nix
+13
modules/npins-transitive-test.nix
··· 1 + { lib, ... }: 2 + { 3 + # Declares neomacs with nixpkgs-follows so nixpkgs is not re-pinned separately. 4 + # Transitive discovery must find crane, rust-overlay, nix-wpe-webkit 5 + # from neomacs's own flake.nix at runtime. 6 + flake-file.inputs = { 7 + nixpkgs.url = lib.mkDefault "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"; 8 + neomacs = { 9 + url = "github:eval-exec/neomacs"; 10 + inputs.nixpkgs.follows = "nixpkgs"; 11 + }; 12 + }; 13 + }
+13 -16
modules/npins.nix
··· 6 6 inputs = inputsExpr flake-file.inputs; 7 7 esc = lib.escapeShellArg; 8 8 9 - inherit (import ./inputs-lib.nix lib esc inputs) 10 - followsSeed 11 - queueSeed 12 - ; 9 + pinnableInputs = lib.filterAttrs (_: v: v.url or "" != "") inputs; 10 + 11 + # Seed the runtime queue with one tab-separated "name\turl" line per declared input. 12 + queueSeed = 13 + let 14 + lines = lib.mapAttrsToList ( 15 + name: input: " printf '%s\\t%s\\n' ${esc name} ${esc (input.url or "")}" 16 + ) pinnableInputs; 17 + in 18 + "{\n" + lib.concatStringsSep "\n" lines + "\n} >> \"$QUEUE_FILE\""; 13 19 14 20 write-npins = 15 21 pkgs: ··· 25 31 cd ${flake-file.intoPath} 26 32 npins init --bare 2>/dev/null || true 27 33 28 - FOLLOWS_FILE=$(mktemp) 29 34 SEEN_FILE=$(mktemp) 30 35 QUEUE_FILE=$(mktemp) 31 - trap 'rm -f "$FOLLOWS_FILE" "$SEEN_FILE" "$QUEUE_FILE"' EXIT 36 + trap 'rm -f "$SEEN_FILE" "$QUEUE_FILE"' EXIT 32 37 33 38 # Add a pin by its flake-style URL (github:o/r, gitlab:o/r, channel URL, etc.) 34 39 npins_add_url() { ··· 38 43 spec="''${url#github:}" owner="''${spec%%/*}" spec="''${spec#*/}" 39 44 repo="''${spec%%/*}" ref="''${spec#*/}" 40 45 if [ "$ref" != "$repo" ]; then 41 - # Explicit ref: try as branch, then as release tag, then common branches. 42 - npins add github --name "$name" -b "$ref" "$owner" "$repo" 2>/dev/null \ 43 - || npins add github --name "$name" "$owner" "$repo" 2>/dev/null \ 44 - || npins add github --name "$name" -b main "$owner" "$repo" 2>/dev/null \ 45 - || npins add github --name "$name" -b master "$owner" "$repo" 46 + npins add github --name "$name" -b "$ref" "$owner" "$repo" 46 47 else 47 48 # No explicit ref: prefer a release tag, fall back to common branches. 48 49 npins add github --name "$name" "$owner" "$repo" 2>/dev/null \ ··· 95 96 rm -f "$flake_tmp" "$nix_tmp" 96 97 } 97 98 98 - # Pre-mark follows-only inputs so BFS never enqueues them. 99 - ${followsSeed} 100 - 101 99 # Seed the BFS queue with all declared inputs. 102 100 ${queueSeed} 103 101 ··· 105 103 while true; do 106 104 name="" url="" 107 105 while IFS=$'\t' read -r qname qurl; do 108 - if ! grep -qxF "$qname" "$SEEN_FILE" 2>/dev/null && \ 109 - ! grep -qxF "$qname" "$FOLLOWS_FILE" 2>/dev/null; then 106 + if ! grep -qxF "$qname" "$SEEN_FILE" 2>/dev/null; then 110 107 name="$qname" url="$qurl" 111 108 break 112 109 fi