├── tests ├── grow │ ├── format.nix │ ├── __fixture │ │ ├── bar-cell │ │ │ └── test-block │ │ │ │ └── default.nix │ │ └── foo-cell │ │ │ └── test-block.nix │ └── expr.nix ├── soil │ ├── format.nix │ ├── __fixture │ │ ├── bar-cell │ │ │ ├── templates │ │ │ │ └── default.nix │ │ │ └── foo-block.nix │ │ └── foo-cell │ │ │ └── foo-block.nix │ └── expr.nix └── _snapshots │ ├── soil │ └── grow ├── .gitignore ├── .envrc ├── namaka.toml ├── soil ├── default.nix ├── harvest.nix ├── pick.nix └── winnow.nix ├── cog.toml ├── treefmt.toml ├── .github └── workflows │ └── ci.yaml ├── flake.nix ├── paths.nix ├── grow ├── newProcessCfg.nix ├── newHelpers.nix ├── newImportSignatureFor.nix ├── grow-on.nix ├── newExtractFor.nix └── default.nix ├── types ├── default.nix └── cell.nix ├── local ├── flake.nix └── flake.lock ├── flake.lock ├── CHANGELOG.md ├── registry.schema.json └── README.md /tests/grow/format.nix: -------------------------------------------------------------------------------- 1 | "pretty" 2 | -------------------------------------------------------------------------------- /tests/soil/format.nix: -------------------------------------------------------------------------------- 1 | "pretty" 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.direnv 2 | /.data 3 | result 4 | 5 | -------------------------------------------------------------------------------- /tests/soil/__fixture/bar-cell/templates/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | tmpl = "tmpl (no system)"; 3 | } 4 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | watch_file local/flake.nix 4 | watch_file local/flake.lock 5 | use_flake ./local 6 | -------------------------------------------------------------------------------- /namaka.toml: -------------------------------------------------------------------------------- 1 | [check] 2 | cmd = ["nix", "flake", "check", "./local"] 3 | 4 | [eval] 5 | cmd = ["nix", "eval", "./local#checks"] 6 | -------------------------------------------------------------------------------- /tests/soil/__fixture/foo-cell/foo-block.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | cell, 4 | }: { 5 | foo = "foo"; 6 | fox = "fox"; 7 | fan = "fan"; 8 | } 9 | -------------------------------------------------------------------------------- /tests/soil/__fixture/bar-cell/foo-block.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | cell, 4 | }: { 5 | fxr = "fxr"; 6 | fxa = "fxa"; 7 | fxn = "farri"; 8 | } 9 | -------------------------------------------------------------------------------- /tests/grow/__fixture/bar-cell/test-block/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | cell, 4 | }: { 5 | inherit (inputs.cells.foo-cell.test-block) self; 6 | } 7 | -------------------------------------------------------------------------------- /soil/default.nix: -------------------------------------------------------------------------------- 1 | {l}: let 2 | winnow = import ./winnow.nix {inherit l;}; 3 | harvest = import ./harvest.nix {inherit winnow;}; 4 | pick = import ./pick.nix {inherit harvest;}; 5 | in {inherit winnow harvest pick;} 6 | -------------------------------------------------------------------------------- /tests/grow/__fixture/foo-cell/test-block.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs, 3 | cell, 4 | }: { 5 | self = "via foo-cell ${inputs.self}"; 6 | cellsNamesAndSystemsCrossCompilationEscapeHatch = builtins.attrNames inputs.cells; 7 | barCellBlockNames = builtins.attrNames inputs.cells.bar-cell; 8 | } 9 | -------------------------------------------------------------------------------- /cog.toml: -------------------------------------------------------------------------------- 1 | post_bump_hooks = [ 2 | "git push", 3 | "git push origin {{version}}", 4 | "cog -q changelog --at {{version}}", 5 | ] 6 | 7 | [changelog] 8 | path = "CHANGELOG.md" 9 | template = "remote" 10 | remote = "github.com" 11 | repository = "core" 12 | owner = "paisano-nix" 13 | authors = [{ username = "blaggacao", signature = "David Arnold" }] 14 | -------------------------------------------------------------------------------- /soil/harvest.nix: -------------------------------------------------------------------------------- 1 | {winnow}: 2 | /* 3 | A function that "up-lifts" your `std` targets. 4 | 5 | The transformation is: system.cell.block.target -> system.target 6 | 7 | Semantically equivalent to winnow without a filter 8 | 9 | You can typically use this function in a compatibility layer of soil. 10 | 11 | Example: 12 | 13 | ```nix 14 | # Soil ... 15 | # nix-cli compat 16 | { 17 | devShell = inputs.std.harvest inputs.self ["tullia" "devshell" "default"]; 18 | defaultPackage = inputs.std.harvest inputs.self ["tullia" "apps" "tullia"]; 19 | } 20 | ``` 21 | */ 22 | winnow true 23 | -------------------------------------------------------------------------------- /treefmt.toml: -------------------------------------------------------------------------------- 1 | # One CLI to format the code tree - https://github.com/numtide/treefmt 2 | [formatter.nix] 3 | command = "alejandra" 4 | includes = ["*.nix"] 5 | excludes = ["./cells/cardano/packages/materialized/*"] 6 | 7 | [formatter.prettier] 8 | command = "prettier" 9 | options = ["--plugin", "prettier-plugin-toml", "--write"] 10 | includes = ["*.md", "*.yaml", "*.toml"] 11 | 12 | [formatter.shell] 13 | command = "shfmt" 14 | options = [ 15 | "-i", 16 | "2", # indent 2 17 | "-s", # simplify the code 18 | "-w", # write back to the file 19 | 20 | ] 21 | includes = ["*.sh"] 22 | -------------------------------------------------------------------------------- /soil/pick.nix: -------------------------------------------------------------------------------- 1 | {harvest}: 2 | /* 3 | A function that "up-lifts" your `std` targets and devoids it of its system 4 | scoping by simply picking the first system. 5 | 6 | The transformation is: system.cell.block.target -> target 7 | 8 | Use this if the system scopeing is not only irrelevant but also must go away. 9 | 10 | Example: 11 | 12 | ```nix 13 | # Soil ... 14 | # nix-cli compat 15 | { 16 | templates = inputs.std.pick inputs.self ["presets" "templates"]; 17 | } 18 | ``` 19 | */ 20 | let 21 | pick = t: p: let 22 | r = harvest t p; 23 | s = builtins.head (builtins.attrNames r); 24 | in 25 | r.${s}; 26 | in 27 | pick 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | check: 11 | name: check 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v3 16 | 17 | - name: Install nix 18 | uses: nixbuild/nix-quick-install-action@v22 19 | with: 20 | nix_conf: experimental-features = nix-command flakes 21 | 22 | - name: Run checks 23 | run: nix flake check 24 | 25 | - name: Check formatting 26 | run: nix develop --no-update-lock-file ./local#check --command treefmt -- . --fail-on-change --no-cache 27 | -------------------------------------------------------------------------------- /tests/grow/expr.nix: -------------------------------------------------------------------------------- 1 | { 2 | grow, 3 | inputs, 4 | }: 5 | grow { 6 | inherit inputs; 7 | cellsFrom = ./__fixture; 8 | cellBlocks = [ 9 | { 10 | name = "test-block"; 11 | type = "test-block"; 12 | actions = { 13 | currentSystem, 14 | fragment, # sometimes needed when direct invocation on drv is not possible 15 | fragmentRelPath, 16 | target, 17 | }: 18 | with inputs.nixpkgs.legacyPackages.${currentSystem}; [ 19 | { 20 | name = "foo-action"; 21 | description = "paisano foo"; 22 | command = pkgs.writeShellScript "foo-action" '' 23 | echo "I'm Paisano and 42!" 24 | ''; 25 | } 26 | ]; 27 | } 28 | ]; 29 | } 30 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 The Standard Authors 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | { 5 | inputs.nosys.url = "github:divnix/nosys"; 6 | inputs.call-flake.url = "github:divnix/call-flake"; 7 | inputs.yants = { 8 | url = "github:divnix/yants"; 9 | inputs.nixpkgs.follows = "nixpkgs"; 10 | }; 11 | 12 | inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 13 | 14 | outputs = { 15 | nixpkgs, 16 | call-flake, 17 | nosys, 18 | yants, 19 | self, 20 | }: let 21 | l = nixpkgs.lib // builtins; 22 | deSystemize = nosys.lib.deSys; 23 | paths = import ./paths.nix; 24 | types = import ./types {inherit l yants paths;}; 25 | in { 26 | inherit (import ./soil {inherit l;}) pick harvest winnow; 27 | inherit (import ./grow {inherit l deSystemize paths types call-flake;}) grow growOn; 28 | isDirty = rev: rev == "not-a-commit"; 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /paths.nix: -------------------------------------------------------------------------------- 1 | rec { 2 | cellPath = cellsFrom: cellName: { 3 | __toString = _: "${cellsFrom}/${cellName}"; 4 | flake = "${cellsFrom}/${cellName}/flake.nix"; 5 | readme = "${cellsFrom}/${cellName}/Readme.md"; 6 | rel = "${builtins.baseNameOf cellsFrom}/${cellName}"; 7 | }; 8 | cellBlockPath = cellPath': cellBlock: { 9 | __toString = _: "${cellPath'}/${cellBlock.name}"; 10 | file = "${cellPath'}/${cellBlock.name}.nix"; 11 | file' = "${cellPath'.rel}/${cellBlock.name}.nix"; 12 | dir = "${cellPath'}/${cellBlock.name}/default.nix"; 13 | dir' = "${cellPath'.rel}/${cellBlock.name}/default.nix"; 14 | readme = "${cellPath'}/${cellBlock.name}.md"; 15 | readmeDir = "${cellPath'}/${cellBlock.name}/Readme.md"; 16 | }; 17 | targetPath = cellsFrom: cellName: cellBlock: let 18 | cellBlockPath' = cellBlockPath (cellPath cellsFrom cellName) cellBlock; 19 | in 20 | name: { 21 | readme = "${cellBlockPath'}/${name}.md"; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /tests/soil/expr.nix: -------------------------------------------------------------------------------- 1 | { 2 | growOn, 3 | harvest, 4 | winnow, 5 | pick, 6 | inputs, 7 | }: let 8 | self = growOn { 9 | inherit inputs; 10 | cellsFrom = ./__fixture; 11 | cellBlocks = [ 12 | { 13 | name = "foo-block"; 14 | type = "another type"; 15 | } 16 | { 17 | name = "templates"; 18 | type = "a type"; 19 | } 20 | ]; 21 | }; 22 | in 23 | # Soil 24 | { 25 | foo = harvest self ["foo-cell" "foo-block"]; 26 | fooAndBar = harvest self [ 27 | ["foo-cell" "foo-block"] 28 | ["bar-cell" "foo-block"] 29 | ]; 30 | fooAndBar' = winnow (n: v: n == v) self [ 31 | ["foo-cell" "foo-block"] 32 | ["bar-cell" "foo-block"] 33 | ]; 34 | libToplevel = harvest self ["foo-cell"]; 35 | libToplevelAndHoistedChildren = harvest self [ 36 | ["foo-cell"] 37 | ["foo-cell" "foo-block"] 38 | ]; 39 | templates = pick self ["bar-cell" "templates"]; 40 | } 41 | -------------------------------------------------------------------------------- /grow/newProcessCfg.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file validates and prorpocesses the grow function arguments. 3 | */ 4 | { 5 | l, 6 | types, 7 | }: cfg: 8 | # for showing the flake that has the problem 9 | sourceInfo: let 10 | inherit (types) BlockTypes Systems Cell; 11 | inherit (cfg) cellBlocks systems cellsFrom; 12 | originFlake = "${sourceInfo}/flake.nix"; 13 | origin = key: (builtins.unsafeGetAttrPos key cfg).file or originFlake; 14 | in rec { 15 | cellBlocks' = let 16 | unique = 17 | l.foldl' ( 18 | acc: e: 19 | if l.elem e.name acc.visited 20 | then acc 21 | else { 22 | visited = acc.visited ++ [e.name]; 23 | result = acc.result ++ [e]; 24 | } 25 | ) { 26 | visited = []; 27 | result = []; 28 | }; 29 | in 30 | (unique 31 | (BlockTypes "${origin "cellBlocks"} - grow[On]:cellBlocks" cellBlocks)) 32 | .result; 33 | systems' = Systems "${origin "systems"} - grow[On]:systems" systems; 34 | cells' = l.mapAttrsToList (Cell originFlake cellsFrom cellBlocks') (l.readDir cellsFrom); 35 | } 36 | -------------------------------------------------------------------------------- /soil/winnow.nix: -------------------------------------------------------------------------------- 1 | {l}: let 2 | /* 3 | A function that "up-lifts" your `std` targets. 4 | 5 | The transformation is: system.cell.block.target -> system.target 6 | 7 | The results are filtered based on the `pred` function 8 | 9 | You can typically use this function in a compatibility layer of soil. 10 | 11 | Example: 12 | 13 | ```nix 14 | # Soil ... 15 | # nix-cli compat 16 | { 17 | devShell = inputs.std.winnow (_: v: v != null) inputs.self ["tullia" "devshell" "default"]; 18 | defaultPackage = inputs.std.winnow (n: _: n != "cli") inputs.self ["tullia" "apps" "tullia"]; 19 | } 20 | ``` 21 | */ 22 | winnow = pred: t: p: let 23 | multiplePaths = l.isList (l.elemAt p 0); 24 | hoist = path: 25 | l.mapAttrs ( 26 | _: v: let 27 | attr = l.getAttrFromPath path v; 28 | in 29 | # skip overhead if filtering is not needed 30 | if pred == true 31 | then attr 32 | else l.filterAttrs pred attr 33 | ) 34 | ( 35 | l.filterAttrs ( 36 | n: v: 37 | (l.elem n l.systems.doubles.all) # avoids infinit recursion 38 | && (l.hasAttrByPath path v) 39 | ) 40 | t 41 | ); 42 | in 43 | if multiplePaths 44 | then l.foldl' l.recursiveUpdate {} (map (path: hoist path) p) 45 | else hoist p; 46 | in 47 | winnow 48 | -------------------------------------------------------------------------------- /grow/newHelpers.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file implements aggregation helper for collecting blocks. 3 | */ 4 | {l}: { 5 | accumulate = 6 | l.foldl' 7 | ( 8 | acc: new: let 9 | first = l.head new; 10 | second = l.head cdr; 11 | third = l.head cdr'; 12 | tail = l.tail cdr'; 13 | 14 | cdr = l.tail new; 15 | cdr' = l.tail cdr; 16 | in 17 | ( 18 | if first == null 19 | then {inherit (acc) output;} 20 | else {output = acc.output // first;} 21 | ) 22 | // ( 23 | if second == null 24 | then {inherit (acc) actions;} 25 | else {actions = acc.actions // second;} 26 | ) 27 | // ( 28 | if third == null 29 | then {inherit (acc) init;} 30 | else {init = acc.init ++ [third];} 31 | ) 32 | // ( 33 | if tail == [null] 34 | then {inherit (acc) ci;} 35 | else {ci = acc.ci ++ (l.concatMap (t: l.flatten t.ci) tail);} 36 | ) 37 | ) 38 | { 39 | output = {}; 40 | actions = {}; 41 | init = []; 42 | ci = []; 43 | }; 44 | 45 | optionalLoad = cond: elem: 46 | if cond 47 | then elem 48 | else [ 49 | null # empty output 50 | null # empty action 51 | null # empty init 52 | null # empty ci 53 | ]; 54 | } 55 | -------------------------------------------------------------------------------- /grow/newImportSignatureFor.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file implements the unique import signature of each block. 3 | */ 4 | { 5 | l, 6 | deSystemize, 7 | }: cfg: let 8 | self = cfg.inputs.self.sourceInfo // {rev = cfg.inputs.self.sourceInfo.rev or "not-a-commit";}; 9 | instantiateNixpkgsWith = system: nixpkgs: 10 | ( 11 | if cfg.nixpkgsConfig != {} 12 | then 13 | (import nixpkgs { 14 | inherit system; 15 | config = cfg.nixpkgsConfig; 16 | }) 17 | # numtide/nixpkgs-unfree blocks re-import 18 | else nixpkgs.legacyPackages.${system} 19 | ) 20 | // {inherit (nixpkgs) outPath sourceInfo;}; 21 | in 22 | system: cells: additionalInputs: let 23 | currentNixpkgs = 24 | if additionalInputs ? nixpkgs 25 | then additionalInputs.nixpkgs 26 | else if cfg.inputs ? nixpkgs 27 | then cfg.inputs.nixpkgs 28 | else null; 29 | in ( 30 | (deSystemize system (cfg.inputs // additionalInputs)) 31 | // { 32 | inherit self; 33 | cells = deSystemize system cells; # recursion on cells 34 | } 35 | // l.optionalAttrs (currentNixpkgs != null) { 36 | nixpkgs = 37 | (instantiateNixpkgsWith system currentNixpkgs) 38 | // 39 | # mimick deSystemize behaviour 40 | (builtins.mapAttrs 41 | (system: _: instantiateNixpkgsWith system currentNixpkgs) 42 | currentNixpkgs.legacyPackages); 43 | } 44 | ) 45 | -------------------------------------------------------------------------------- /types/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | l, 3 | yants, 4 | paths, 5 | }: { 6 | Cell = import ./cell.nix { 7 | inherit l; 8 | inherit (paths) cellPath cellBlockPath; 9 | }; 10 | Target = log: 11 | with yants log; 12 | # unfortunately eval during check can cause infinite recursions 13 | # if blockType == "runnables" || blockType == "installables" 14 | # then attrs drv 15 | # else if blockType == "functions" 16 | # then attrs function 17 | # else throw "unreachable"; 18 | attrs any; 19 | Systems = log: with yants log; list (enum "System" l.systems.doubles.all); 20 | BlockTypes = log: 21 | with yants log; 22 | list (struct "Cell Block" { 23 | name = string; 24 | type = string; 25 | __functor = option function; 26 | ci = option (attrs bool); 27 | cli = option bool; 28 | actions = option (functionWithArgs { 29 | inputs = false; 30 | target = false; 31 | fragment = false; 32 | fragmentRelPath = false; 33 | currentSystem = false; 34 | }); 35 | }); 36 | Block = log: 37 | with yants log; 38 | block: ( 39 | if l.typeOf block == "set" 40 | then attrs any block 41 | else 42 | functionWithArgs { 43 | inputs = false; 44 | cell = false; 45 | } 46 | block 47 | ); 48 | ActionCommand = log: with yants log; drv; 49 | } 50 | -------------------------------------------------------------------------------- /local/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Paisano Core development shell"; 3 | inputs.nosys.url = "github:divnix/nosys"; 4 | inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; 5 | inputs.devshell.url = "github:numtide/devshell"; 6 | inputs.namaka.url = "github:nix-community/namaka/v0.2.0"; 7 | inputs.call-flake.url = "github:divnix/call-flake"; 8 | outputs = inputs @ { 9 | nosys, 10 | call-flake, 11 | ... 12 | }: 13 | nosys ((call-flake ../.).inputs // inputs) ( 14 | { 15 | self, 16 | namaka, 17 | nixpkgs, 18 | devshell, 19 | ... 20 | }: 21 | with nixpkgs.legacyPackages; 22 | with nixpkgs.legacyPackages.nodePackages; 23 | with devshell.legacyPackages; let 24 | inherit (lib.stringsWithDeps) noDepEntry; 25 | checkMod = { 26 | commands = [{package = treefmt;}]; 27 | packages = [alejandra shfmt prettier prettier-plugin-toml]; 28 | devshell.startup.nodejs-setuphook = noDepEntry '' 29 | export NODE_PATH=${prettier-plugin-toml}/lib/node_modules:$NODE_PATH 30 | ''; 31 | }; 32 | in { 33 | devShells = { 34 | check = mkShell { 35 | name = "Paisano Core (Check)"; 36 | imports = [checkMod]; 37 | }; 38 | default = mkShell { 39 | name = "Paisano Core"; 40 | imports = [checkMod]; 41 | commands = [ 42 | {package = namaka.packages.default;} 43 | { 44 | package = cocogitto; 45 | name = "cog"; 46 | } 47 | ]; 48 | }; 49 | }; 50 | checks = namaka.lib.load { 51 | src = ../tests; 52 | inputs = 53 | (call-flake ../.) 54 | // { 55 | # simulate 'inputs' 56 | inputs = { 57 | inherit nixpkgs; 58 | self.sourceInfo = { 59 | outPath = "constant-self"; 60 | rev = "constant-rev"; 61 | }; 62 | }; 63 | }; 64 | }; 65 | } 66 | ); 67 | } 68 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "call-flake": { 4 | "locked": { 5 | "lastModified": 1687380775, 6 | "narHash": "sha256-bmhE1TmrJG4ba93l9WQTLuYM53kwGQAjYHRvHOeuxWU=", 7 | "owner": "divnix", 8 | "repo": "call-flake", 9 | "rev": "74061f6c241227cd05e79b702db9a300a2e4131a", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "divnix", 14 | "repo": "call-flake", 15 | "type": "github" 16 | } 17 | }, 18 | "nixpkgs": { 19 | "locked": { 20 | "lastModified": 1681571934, 21 | "narHash": "sha256-Q3B3HTqhTahhPCT53ahK1FPktOXlEWmudSttd9CWGbE=", 22 | "owner": "nixos", 23 | "repo": "nixpkgs", 24 | "rev": "29176972b4be60f7d3eb3101f696c99f2e6ada57", 25 | "type": "github" 26 | }, 27 | "original": { 28 | "owner": "nixos", 29 | "ref": "nixpkgs-unstable", 30 | "repo": "nixpkgs", 31 | "type": "github" 32 | } 33 | }, 34 | "nosys": { 35 | "locked": { 36 | "lastModified": 1668010795, 37 | "narHash": "sha256-JBDVBnos8g0toU7EhIIqQ1If5m/nyBqtHhL3sicdPwI=", 38 | "owner": "divnix", 39 | "repo": "nosys", 40 | "rev": "feade0141487801c71ff55623b421ed535dbdefa", 41 | "type": "github" 42 | }, 43 | "original": { 44 | "owner": "divnix", 45 | "repo": "nosys", 46 | "type": "github" 47 | } 48 | }, 49 | "root": { 50 | "inputs": { 51 | "call-flake": "call-flake", 52 | "nixpkgs": "nixpkgs", 53 | "nosys": "nosys", 54 | "yants": "yants" 55 | } 56 | }, 57 | "yants": { 58 | "inputs": { 59 | "nixpkgs": [ 60 | "nixpkgs" 61 | ] 62 | }, 63 | "locked": { 64 | "lastModified": 1677285314, 65 | "narHash": "sha256-hlAcg2514zKrPu8jn24BUsIjjvXvCLdw1jvKgBTpqko=", 66 | "owner": "divnix", 67 | "repo": "yants", 68 | "rev": "9eab24b273ce021406c852166c216b86e2bb4ec4", 69 | "type": "github" 70 | }, 71 | "original": { 72 | "owner": "divnix", 73 | "repo": "yants", 74 | "type": "github" 75 | } 76 | } 77 | }, 78 | "root": "root", 79 | "version": 7 80 | } 81 | -------------------------------------------------------------------------------- /grow/grow-on.nix: -------------------------------------------------------------------------------- 1 | { 2 | l, 3 | grow, 4 | }: 5 | /* 6 | A variant of `paisano.grow` that let's you pass an arbitraty 7 | (variadic) amount of arguments after "growing" the flake. 8 | 9 | These arguments are conied "layers of soil" for convenience 10 | and are recursively merged -- in order from top to bottom -- 11 | onto the "grown flake output". 12 | 13 | Use this facility to implement compatibility layers with 14 | other tooling that expect a certain flake schema. 15 | 16 | See `paisano.harvest` for how to level-up outputs conveniently. 17 | 18 | Example use: 19 | 20 | ```nix 21 | { 22 | inputs = { 23 | # ... 24 | std.url = "github:divnix/std"; 25 | }; 26 | 27 | outputs = inputs: let 28 | tasks = import ./nix/std.nix inputs; 29 | lib = import ./nix/lib.nix inputs; 30 | in 31 | inputs.std.growOn { 32 | inherit inputs; 33 | cellsFrom = ./cells; 34 | cellBlocks = [ 35 | # ... 36 | ]; 37 | } 38 | # Soil ... 39 | # nix-cli compat 40 | { 41 | devShell = inputs.std.harvest inputs.self ["tullia" "devshell" "default"]; 42 | defaultPackage = inputs.std.harvest inputs.self ["tullia" "apps" "tullia"]; 43 | } 44 | # dog food 45 | (lib.fromStd { 46 | actions = inputs.std.harvest inputs.self ["tullia" "action"]; 47 | tasks = inputs.std.harvest inputs.self ["tullia" "task"]; 48 | }) 49 | # top level tullia outputs 50 | (lib // {inherit tasks;}); 51 | } 52 | ``` 53 | */ 54 | let 55 | inherit (builtins) head; 56 | inherit (builtins) isAttrs; 57 | inherit (builtins) length; 58 | inherit (l.lists) elemAt; 59 | inherit (l.lists) flatten; 60 | inherit (l.lists) take; 61 | 62 | g = p: l: r: v: let 63 | attrPath = take 2 p; 64 | v1 = !(isAttrs l && isAttrs r); 65 | v2 = if attrPath == ["__std" "ci"] || attrPath == ["__std" "init"] then flatten v else head v; 66 | in [v1 v2]; 67 | 68 | recursiveUpdateUntil = 69 | g: 70 | lhs: 71 | rhs: 72 | let f = attrPath: 73 | l.zipAttrsWith (n: values: 74 | let 75 | a = g here (elemAt values 1) (head values) values; 76 | here = attrPath ++ [n]; 77 | in 78 | if length values == 1 || head a then 79 | elemAt a 1 80 | else 81 | f here values 82 | ); 83 | in f [] [rhs lhs]; 84 | recursiveUpdate = 85 | lhs: 86 | rhs: 87 | recursiveUpdateUntil g lhs rhs; 88 | in 89 | args: 90 | grow args 91 | // { 92 | __functor = l.flip recursiveUpdate; 93 | } 94 | -------------------------------------------------------------------------------- /types/cell.nix: -------------------------------------------------------------------------------- 1 | { 2 | l, 3 | cellPath, 4 | cellBlockPath, 5 | }: originFlake: cellsFrom: cellBlocks: cell: type: let 6 | path = cellBlockPath (cellPath cellsFrom cell); 7 | atLeastOneCellBlock = l.any (x: x) ( 8 | l.map ( 9 | o: l.pathExists (path o).file || l.pathExists (path o).dir 10 | ) 11 | cellBlocks 12 | ); 13 | cellsFrom' = "${l.baseNameOf cellsFrom}"; 14 | 15 | maxLength = list: 16 | builtins.foldl' (max: v: 17 | if v > max 18 | then v 19 | else max) 20 | 0 21 | list; 22 | 23 | cellBlockNameLength = map ({name, ...}: builtins.stringLength name) cellBlocks; 24 | maxCellBlockNameLength = maxLength cellBlockNameLength; 25 | 26 | cellBlockTypeLength = map ({type, ...}: builtins.stringLength type) cellBlocks; 27 | maxCellBlockTypeLength = maxLength cellBlockTypeLength; 28 | 29 | pad = str: num: 30 | if num > 0 31 | then pad "${str} " (num - 1) 32 | else str; 33 | padl = str: num: 34 | if num > 0 35 | then padl " ${str}" (num - 1) 36 | else str; 37 | in 38 | if type != "directory" 39 | then 40 | abort '' 41 | 42 | Not a Cell: ${cellsFrom}/${cell} 43 | Containing Flake: ${originFlake} 44 | 45 | Everything at the first level under ${cellsFrom'}/* is a Cell. 46 | Cells are directories by convention. 47 | Hence, only directories are allowed at ${cellsFrom'}/* 48 | 49 | Please remove: `rm ${cellsFrom'}/${cell}' 50 | Important: `git add ${cellsFrom'}/${cell}' 51 | '' 52 | else if !atLeastOneCellBlock 53 | then 54 | abort '' 55 | 56 | Missing Cell Block: ${cellsFrom}/${cell} 57 | Containing Flake: ${originFlake} 58 | 59 | This Cell must provide at least one Cell Block. 60 | In this project, the Cell Blocks may be: 61 | - ${l.concatStringsSep "\n - " (l.map (o: "${o.name}") cellBlocks)} 62 | 63 | 64 | ${ 65 | l.concatStringsSep "\n" ( 66 | l.map ( 67 | cellBlock: let 68 | padName = maxCellBlockNameLength - (builtins.stringLength cellBlock.name); 69 | padType = maxCellBlockTypeLength - (builtins.stringLength cellBlock.type); 70 | title = "For Block ${padl cellBlock.name padName} of type ${pad cellBlock.type padType} create: "; 71 | paths = "${pad (path cellBlock).file' padName} or ${(path cellBlock).dir'}"; 72 | in 73 | title + paths 74 | ) 75 | cellBlocks 76 | ) 77 | } 78 | 79 | When done, don't forget: 80 | `git add ${cellsFrom'}/${cell}' 81 | '' 82 | else cell 83 | -------------------------------------------------------------------------------- /grow/newExtractFor.nix: -------------------------------------------------------------------------------- 1 | /* 2 | This file implements an extractor that feeds the registry. 3 | */ 4 | { 5 | l, 6 | paths, 7 | types, 8 | }: cellsFrom: system: cellName: cellBlock: targetTracer: inputs: name: target: let 9 | tPath = paths.targetPath cellsFrom cellName cellBlock name; 10 | fragment = ''"${system}"."${cellName}"."${cellBlock.name}"."${name}"''; 11 | actions' = 12 | if cellBlock ? actions 13 | then 14 | l.listToAttrs ( 15 | map 16 | (a: l.nameValuePair a.name a) (cellBlock.actions { 17 | inherit target fragment inputs; 18 | fragmentRelPath = "${cellName}/${cellBlock.name}/${name}"; 19 | # in impure mode, detect the current system to run 20 | # the action's executables themselves with correct arch 21 | currentSystem = builtins.currentSystem or system; 22 | }) 23 | ) 24 | else {}; 25 | ci = 26 | if cellBlock ? ci 27 | then 28 | l.mapAttrsToList ( 29 | action: _: let 30 | action' = actions'.${action}; 31 | command = types.ActionCommand "Action \"${action'.name}\" of Cell Block \"${cellBlock.name}\" (Cell Block Type: \"${cellBlock.type}\")" action'.command; 32 | in ( 33 | if ! l.hasAttr action actions' 34 | then 35 | throw '' 36 | divnix/std(ci-integration): Block Type '${cellBlock.type}' has no '${action}' Action defined. 37 | --- 38 | ${l.generators.toPretty {} (l.removeAttrs cellBlock ["__functor"])} 39 | '' 40 | else { 41 | inherit name; 42 | cell = cellName; 43 | block = cellBlock.name; 44 | blockType = cellBlock.type; 45 | inherit action; 46 | targetDrv = command.targetDrv or target.drvPath or null; # can be null: nomad mainfests only hold data 47 | actionDrv = command.drvPath; 48 | proviso = action'.proviso or null; 49 | meta = action'.meta or null; 50 | } 51 | ) 52 | ) 53 | cellBlock.ci 54 | else []; 55 | in { 56 | inherit ci; 57 | actions = l.mapAttrs (_: a: a.command) actions'; 58 | init = 59 | targetTracer name 60 | { 61 | inherit name; 62 | # for speed only extract name & description, the bare minimum for display 63 | actions = 64 | l.mapAttrsToList (name: a: { 65 | inherit name; 66 | inherit (a) description; 67 | requiresArgs = 68 | if (target ? meta && target.meta ? requiresArgs) 69 | then (builtins.elem name target.meta.requiresArgs) 70 | else false; 71 | }) 72 | actions'; 73 | } 74 | // l.optionalAttrs (l.pathExists tPath.readme) {inherit (tPath) readme;} 75 | // l.optionalAttrs (target ? meta && target.meta ? description) {inherit (target.meta) description;}; 76 | } 77 | -------------------------------------------------------------------------------- /tests/_snapshots/soil: -------------------------------------------------------------------------------- 1 | #pretty 2 | { 3 | foo = { 4 | aarch64-darwin = { 5 | fan = "fan"; 6 | foo = "foo"; 7 | fox = "fox"; 8 | }; 9 | aarch64-linux = { 10 | fan = "fan"; 11 | foo = "foo"; 12 | fox = "fox"; 13 | }; 14 | x86_64-darwin = { 15 | fan = "fan"; 16 | foo = "foo"; 17 | fox = "fox"; 18 | }; 19 | x86_64-linux = { 20 | fan = "fan"; 21 | foo = "foo"; 22 | fox = "fox"; 23 | }; 24 | }; 25 | fooAndBar = { 26 | aarch64-darwin = { 27 | fan = "fan"; 28 | foo = "foo"; 29 | fox = "fox"; 30 | fxa = "fxa"; 31 | fxn = "farri"; 32 | fxr = "fxr"; 33 | }; 34 | aarch64-linux = { 35 | fan = "fan"; 36 | foo = "foo"; 37 | fox = "fox"; 38 | fxa = "fxa"; 39 | fxn = "farri"; 40 | fxr = "fxr"; 41 | }; 42 | x86_64-darwin = { 43 | fan = "fan"; 44 | foo = "foo"; 45 | fox = "fox"; 46 | fxa = "fxa"; 47 | fxn = "farri"; 48 | fxr = "fxr"; 49 | }; 50 | x86_64-linux = { 51 | fan = "fan"; 52 | foo = "foo"; 53 | fox = "fox"; 54 | fxa = "fxa"; 55 | fxn = "farri"; 56 | fxr = "fxr"; 57 | }; 58 | }; 59 | fooAndBar' = { 60 | aarch64-darwin = { 61 | fan = "fan"; 62 | foo = "foo"; 63 | fox = "fox"; 64 | fxa = "fxa"; 65 | fxr = "fxr"; 66 | }; 67 | aarch64-linux = { 68 | fan = "fan"; 69 | foo = "foo"; 70 | fox = "fox"; 71 | fxa = "fxa"; 72 | fxr = "fxr"; 73 | }; 74 | x86_64-darwin = { 75 | fan = "fan"; 76 | foo = "foo"; 77 | fox = "fox"; 78 | fxa = "fxa"; 79 | fxr = "fxr"; 80 | }; 81 | x86_64-linux = { 82 | fan = "fan"; 83 | foo = "foo"; 84 | fox = "fox"; 85 | fxa = "fxa"; 86 | fxr = "fxr"; 87 | }; 88 | }; 89 | libToplevel = { 90 | aarch64-darwin = { 91 | foo-block = { 92 | fan = "fan"; 93 | foo = "foo"; 94 | fox = "fox"; 95 | }; 96 | }; 97 | aarch64-linux = { 98 | foo-block = { 99 | fan = "fan"; 100 | foo = "foo"; 101 | fox = "fox"; 102 | }; 103 | }; 104 | x86_64-darwin = { 105 | foo-block = { 106 | fan = "fan"; 107 | foo = "foo"; 108 | fox = "fox"; 109 | }; 110 | }; 111 | x86_64-linux = { 112 | foo-block = { 113 | fan = "fan"; 114 | foo = "foo"; 115 | fox = "fox"; 116 | }; 117 | }; 118 | }; 119 | libToplevelAndHoistedChildren = { 120 | aarch64-darwin = { 121 | fan = "fan"; 122 | foo = "foo"; 123 | foo-block = { 124 | fan = "fan"; 125 | foo = "foo"; 126 | fox = "fox"; 127 | }; 128 | fox = "fox"; 129 | }; 130 | aarch64-linux = { 131 | fan = "fan"; 132 | foo = "foo"; 133 | foo-block = { 134 | fan = "fan"; 135 | foo = "foo"; 136 | fox = "fox"; 137 | }; 138 | fox = "fox"; 139 | }; 140 | x86_64-darwin = { 141 | fan = "fan"; 142 | foo = "foo"; 143 | foo-block = { 144 | fan = "fan"; 145 | foo = "foo"; 146 | fox = "fox"; 147 | }; 148 | fox = "fox"; 149 | }; 150 | x86_64-linux = { 151 | fan = "fan"; 152 | foo = "foo"; 153 | foo-block = { 154 | fan = "fan"; 155 | foo = "foo"; 156 | fox = "fox"; 157 | }; 158 | fox = "fox"; 159 | }; 160 | }; 161 | templates = { 162 | tmpl = "tmpl (no system)"; 163 | }; 164 | } -------------------------------------------------------------------------------- /local/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "call-flake": { 4 | "locked": { 5 | "lastModified": 1686448809, 6 | "narHash": "sha256-Cc+Krf2Ar5NjFMxUWaJFOAQkj8s40r6iEJwIfbxa0Vc=", 7 | "owner": "divnix", 8 | "repo": "call-flake", 9 | "rev": "a0b97f9c6d21997fe5f1ff9a5eedc05a7935a917", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "divnix", 14 | "repo": "call-flake", 15 | "type": "github" 16 | } 17 | }, 18 | "devshell": { 19 | "inputs": { 20 | "flake-utils": "flake-utils", 21 | "nixpkgs": "nixpkgs" 22 | }, 23 | "locked": { 24 | "lastModified": 1678957337, 25 | "narHash": "sha256-Gw4nVbuKRdTwPngeOZQOzH/IFowmz4LryMPDiJN/ah4=", 26 | "owner": "numtide", 27 | "repo": "devshell", 28 | "rev": "3e0e60ab37cd0bf7ab59888f5c32499d851edb47", 29 | "type": "github" 30 | }, 31 | "original": { 32 | "owner": "numtide", 33 | "repo": "devshell", 34 | "type": "github" 35 | } 36 | }, 37 | "flake-utils": { 38 | "locked": { 39 | "lastModified": 1642700792, 40 | "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=", 41 | "owner": "numtide", 42 | "repo": "flake-utils", 43 | "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba", 44 | "type": "github" 45 | }, 46 | "original": { 47 | "owner": "numtide", 48 | "repo": "flake-utils", 49 | "type": "github" 50 | } 51 | }, 52 | "haumea": { 53 | "inputs": { 54 | "nixpkgs": [ 55 | "namaka", 56 | "nixpkgs" 57 | ] 58 | }, 59 | "locked": { 60 | "lastModified": 1685133229, 61 | "narHash": "sha256-FePm/Gi9PBSNwiDFq3N+DWdfxFq0UKsVVTJS3cQPn94=", 62 | "owner": "nix-community", 63 | "repo": "haumea", 64 | "rev": "34dd58385092a23018748b50f9b23de6266dffc2", 65 | "type": "github" 66 | }, 67 | "original": { 68 | "owner": "nix-community", 69 | "ref": "v0.2.2", 70 | "repo": "haumea", 71 | "type": "github" 72 | } 73 | }, 74 | "namaka": { 75 | "inputs": { 76 | "haumea": "haumea", 77 | "nixpkgs": "nixpkgs_2" 78 | }, 79 | "locked": { 80 | "lastModified": 1685739139, 81 | "narHash": "sha256-CLGEW11Fo1v4vj0XSqiyW1EbhRZFO7dkgM43eKwItrk=", 82 | "owner": "nix-community", 83 | "repo": "namaka", 84 | "rev": "d9a2cc83c1d0f68bd613f1fc909d0ef2cfffcf2e", 85 | "type": "github" 86 | }, 87 | "original": { 88 | "owner": "nix-community", 89 | "ref": "v0.2.0", 90 | "repo": "namaka", 91 | "type": "github" 92 | } 93 | }, 94 | "nixpkgs": { 95 | "locked": { 96 | "lastModified": 1677383253, 97 | "narHash": "sha256-UfpzWfSxkfXHnb4boXZNaKsAcUrZT9Hw+tao1oZxd08=", 98 | "owner": "NixOS", 99 | "repo": "nixpkgs", 100 | "rev": "9952d6bc395f5841262b006fbace8dd7e143b634", 101 | "type": "github" 102 | }, 103 | "original": { 104 | "owner": "NixOS", 105 | "ref": "nixpkgs-unstable", 106 | "repo": "nixpkgs", 107 | "type": "github" 108 | } 109 | }, 110 | "nixpkgs_2": { 111 | "locked": { 112 | "lastModified": 1685655444, 113 | "narHash": "sha256-6EujQNAeaUkWvpEZZcVF8qSfQrNVWFNNGbUJxv/A5a8=", 114 | "owner": "nixos", 115 | "repo": "nixpkgs", 116 | "rev": "e635192892f5abbc2289eaac3a73cdb249abaefd", 117 | "type": "github" 118 | }, 119 | "original": { 120 | "owner": "nixos", 121 | "ref": "nixos-unstable", 122 | "repo": "nixpkgs", 123 | "type": "github" 124 | } 125 | }, 126 | "nixpkgs_3": { 127 | "locked": { 128 | "lastModified": 1708564076, 129 | "narHash": "sha256-KKkqoxlgx9n3nwST7O2kM8tliDOijiSSNaWuSkiozdQ=", 130 | "owner": "nixos", 131 | "repo": "nixpkgs", 132 | "rev": "98b00b6947a9214381112bdb6f89c25498db4959", 133 | "type": "github" 134 | }, 135 | "original": { 136 | "owner": "nixos", 137 | "ref": "nixpkgs-unstable", 138 | "repo": "nixpkgs", 139 | "type": "github" 140 | } 141 | }, 142 | "nosys": { 143 | "locked": { 144 | "lastModified": 1668010795, 145 | "narHash": "sha256-JBDVBnos8g0toU7EhIIqQ1If5m/nyBqtHhL3sicdPwI=", 146 | "owner": "divnix", 147 | "repo": "nosys", 148 | "rev": "feade0141487801c71ff55623b421ed535dbdefa", 149 | "type": "github" 150 | }, 151 | "original": { 152 | "owner": "divnix", 153 | "repo": "nosys", 154 | "type": "github" 155 | } 156 | }, 157 | "root": { 158 | "inputs": { 159 | "call-flake": "call-flake", 160 | "devshell": "devshell", 161 | "namaka": "namaka", 162 | "nixpkgs": "nixpkgs_3", 163 | "nosys": "nosys" 164 | } 165 | } 166 | }, 167 | "root": "root", 168 | "version": 7 169 | } 170 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines. 3 | 4 | - - - 5 | ## [0.2.0](https://github.com/paisano-nix/core/compare/0.1.1..0.2.0) - 2024-02-22 6 | #### Bug Fixes 7 | - also do special nix instantiation for supflake nixpkgs - ([10270dc](https://github.com/paisano-nix/core/commit/10270dc46532c947de473ee88c8f5a3346a396fb)) - [@blaggacao](https://github.com/blaggacao) 8 | - add is dirty predicate that consumes this repo's constant - ([9683ecf](https://github.com/paisano-nix/core/commit/9683ecfbc05f8c86396f0284d7125fe1567cd8d0)) - [@blaggacao](https://github.com/blaggacao) 9 | - add outPath to nixpks to align with any other input - ([9954e48](https://github.com/paisano-nix/core/commit/9954e48e1ebc74a698b9d4ac02aee85514fc0237)) - [@blaggacao](https://github.com/blaggacao) 10 | #### Features 11 | - add support for require args - ([3200ca9](https://github.com/paisano-nix/core/commit/3200ca90ada493ba1b1f190d8c06336162e2d812)) - [@blaggacao](https://github.com/blaggacao) 12 | - implement cell block introspection - ([8025cff](https://github.com/paisano-nix/core/commit/8025cffab28f5ce3ebed74d79a2006f4865afaa2)) - Alex Zero 13 | - add inputs argument to actions - ([f0f5525](https://github.com/paisano-nix/core/commit/f0f5525a4e9713b775fffc592c476df2c857fec0)) - [@blaggacao](https://github.com/blaggacao) 14 | - take cell-level outputs for nix inputs preprocessing - ([13d1901](https://github.com/paisano-nix/core/commit/13d19011d0a327eb514d7493c8696055a6018ca1)) - [@blaggacao](https://github.com/blaggacao) 15 | - add cell-level flake to inject inputs - ([8143561](https://github.com/paisano-nix/core/commit/8143561bf0c4329a94c5bc464cdc15e194575206)) - [@blaggacao](https://github.com/blaggacao) 16 | #### Miscellaneous Chores 17 | - bump devshell nixpkgs - ([9e793f7](https://github.com/paisano-nix/core/commit/9e793f7ea438e1a502d317a90cf172e047f7627b)) - [@blaggacao](https://github.com/blaggacao) 18 | #### Refactoring 19 | - use cursor syntax - ([218a7f5](https://github.com/paisano-nix/core/commit/218a7f50451cbc5c981fc8dfe6f962044041f9aa)) - Alex Zero 20 | 21 | - - - 22 | 23 | ## [0.1.1](https://github.com/paisano-nix/core/compare/0.1.0..0.1.1) - 2023-06-15 24 | #### Bug Fixes 25 | - use new namaka in local flake only - ([694ed3f](https://github.com/paisano-nix/core/commit/694ed3f59f3edf9e2755e560ba1bc34e77979ed5)) - [@blaggacao](https://github.com/blaggacao) 26 | 27 | - - - 28 | 29 | ## [0.1.0](https://github.com/paisano-nix/core/compare/9b95b00f7b4ea1af1d4eb5e09b33cdf8fdc1db44..0.1.0) - 2023-06-03 30 | #### Bug Fixes 31 | - **(README)** typo - ([8bc3f43](https://github.com/paisano-nix/core/commit/8bc3f4328628df114d75974982d2440c0ef11ad1)) - Timothy DeHerrera 32 | - **(README)** standard -> paisano - ([dce0354](https://github.com/paisano-nix/core/commit/dce0354aed9697515f31a00e7dae71faf3b47209)) - Timothy DeHerrera 33 | - the sourceInfo to merge into nixpkgs - ([88f2aff](https://github.com/paisano-nix/core/commit/88f2aff10a5064551d1d4cb86800d17084489ce3)) - guangtao 34 | - make compatible with numtide/nixpkgs-unfree - ([f71a2db](https://github.com/paisano-nix/core/commit/f71a2db9414d66663c03a65ade97a9f353fb6d55)) - [@blaggacao](https://github.com/blaggacao) 35 | - regression where cells wheren't system-spaced anymore - ([63b36b5](https://github.com/paisano-nix/core/commit/63b36b54d5368722e386e16f8e0827dc75165f06)) - [@blaggacao](https://github.com/blaggacao) 36 | - regression over 'nixpkgs'-special-input destystemization - ([2cb985f](https://github.com/paisano-nix/core/commit/2cb985f2df81ad39c2fbfe100e0dfc827964b90e)) - [@blaggacao](https://github.com/blaggacao) 37 | - ci' registry eval error itroduced by refactoring - ([3a37147](https://github.com/paisano-nix/core/commit/3a3714790a58d4f43b74f1756234eb9ca6428836)) - [@blaggacao](https://github.com/blaggacao) 38 | - bad naming and oversights - ([6690cf0](https://github.com/paisano-nix/core/commit/6690cf076a47db643222529c53f41066d6c32e9d)) - [@blaggacao](https://github.com/blaggacao) 39 | #### Continuous Integration 40 | - fix snapshot to pretty print; pretty & avoids flaky reformats - ([0505078](https://github.com/paisano-nix/core/commit/0505078a74819052aa262313e7c0c1cf1ecfecfb)) - [@blaggacao](https://github.com/blaggacao) 41 | - enable GH Action - ([f858648](https://github.com/paisano-nix/core/commit/f858648f18e3a360159e12b75ed0b158e3d5d15f)) - [@blaggacao](https://github.com/blaggacao) 42 | #### Documentation 43 | - reflect schema changes in json schema - ([a73add7](https://github.com/paisano-nix/core/commit/a73add780aa9bd0d61a9b7c3f505c5d45acf7574)) - [@blaggacao](https://github.com/blaggacao) 44 | #### Features 45 | - allow setting metadata in the CI registry - ([5f2fc05](https://github.com/paisano-nix/core/commit/5f2fc05e98e001cb1cf9535ded09e05d90cec131)) - Timothy DeHerrera 46 | - add blockname.md as readme - ([687683a](https://github.com/paisano-nix/core/commit/687683ae1d9028135a43ed1f9cc3954cf55fc689)) - [@blaggacao](https://github.com/blaggacao) 47 | - improve error reporting - ([64026ed](https://github.com/paisano-nix/core/commit/64026ed84100940ecbfbe4056b2f072138155d00)) - [@blaggacao](https://github.com/blaggacao) 48 | - provide actions with the current system - ([8fdf9b1](https://github.com/paisano-nix/core/commit/8fdf9b1e6b21005c0ef4280dbdf3f48cb599a149)) - [@blaggacao](https://github.com/blaggacao) 49 | - add trace verbose on imports - ([143afa3](https://github.com/paisano-nix/core/commit/143afa3083274af3be808687ab23fddbbc9d22ed)) - [@blaggacao](https://github.com/blaggacao) 50 | #### Miscellaneous Chores 51 | - fix typo (thanks for reporting) - ([0ec387f](https://github.com/paisano-nix/core/commit/0ec387f2c2551622b8580b98bea919a395a8c77e)) - [@blaggacao](https://github.com/blaggacao) 52 | - update lock files - ([b83335b](https://github.com/paisano-nix/core/commit/b83335b8018d609903ae4166436f4aa83c275efb)) - [@blaggacao](https://github.com/blaggacao) 53 | - enable cog for real - ([de0a77d](https://github.com/paisano-nix/core/commit/de0a77db4f047ca5cda1fabfcc30b7116fcabdd6)) - [@blaggacao](https://github.com/blaggacao) 54 | - add dev shell and formatters - ([48498b7](https://github.com/paisano-nix/core/commit/48498b74ba33e8ba7e52cbaab68cffbf745333a9)) - [@blaggacao](https://github.com/blaggacao) 55 | - clarify and expand the README - ([c84fa73](https://github.com/paisano-nix/core/commit/c84fa73748b4c2f971bd6ea55e3a26d22eb0d32e)) - Timothy DeHerrera 56 | #### Refactoring 57 | - **(grow)** make ci action's proviso and meta nullable values - ([065db49](https://github.com/paisano-nix/core/commit/065db495e4c131090c4958ca15c7b0d352874aeb)) - [@blaggacao](https://github.com/blaggacao) 58 | - **(grow)** merge ci' into ci as the distinction remained unused so far - ([4b6973d](https://github.com/paisano-nix/core/commit/4b6973d5202aa8b14ea1a35fb45a5f3deb0556f0)) - [@blaggacao](https://github.com/blaggacao) 59 | - simplify local env - ([5475a1e](https://github.com/paisano-nix/core/commit/5475a1ed67ea33ec5cca18a10322aac212d9bf76)) - [@blaggacao](https://github.com/blaggacao) 60 | - remove the debug traced; std check is a better tool - ([81014d0](https://github.com/paisano-nix/core/commit/81014d0a3534de0019d845e07d1e4debf7b7d23f)) - [@blaggacao](https://github.com/blaggacao) 61 | #### Style 62 | - format & lock file - ([7b72870](https://github.com/paisano-nix/core/commit/7b72870291043978a7a5bd2c4912eed8b3a987c7)) - [@blaggacao](https://github.com/blaggacao) 63 | - treefmt - ([bbfe02b](https://github.com/paisano-nix/core/commit/bbfe02b7d2e3b0793973607539fec019086228ae)) - [@blaggacao](https://github.com/blaggacao) 64 | #### Tests 65 | - add snapshot tests for soil function familiy - ([a6b7742](https://github.com/paisano-nix/core/commit/a6b7742bb1e57c910bd76f60f413f04816a0d285)) - [@blaggacao](https://github.com/blaggacao) 66 | - add test instrumentation based on haumea & namaka - ([bd66369](https://github.com/paisano-nix/core/commit/bd66369086d85563a85c61edd99fa74e29aae4ab)) - [@blaggacao](https://github.com/blaggacao) 67 | 68 | - - - 69 | 70 | Changelog generated by [cocogitto](https://github.com/cocogitto/cocogitto). -------------------------------------------------------------------------------- /registry.schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json-schema.org/draft/2020-12/schema", 3 | "$id": "https://raw.githubusercontent.com/divnix/std/main/registry.schema.json", 4 | "title": "Standard Registry", 5 | "description": "The json schema to be found when serializing .#__std of a Standardized repository with Nix to json.", 6 | "type": "object", 7 | "additionalProperties": true, 8 | "properties": { 9 | "__schema": { 10 | "title": "Schema Version", 11 | "description": "The Standard Registry schema version.", 12 | "const": "v0" 13 | }, 14 | "cellsFrom": { 15 | "title": "Cell Root Path", 16 | "description": "Relative path to the repository root from which cells are discovered.", 17 | "type": "string" 18 | }, 19 | "ci": { 20 | "$ref": "#/definitions/ci" 21 | }, 22 | "init": { 23 | "$ref": "#/definitions/init" 24 | }, 25 | "actions": { 26 | "$ref": "#/definitions/actions" 27 | } 28 | }, 29 | "required": [ 30 | "__schema", 31 | "ci", 32 | "init", 33 | "actions", 34 | "cellsFrom" 35 | ], 36 | "definitions": { 37 | "actions": { 38 | "title": "Actions", 39 | "description": "The Actions collection's runnable derivations. They house derivations. Since building these derivations may be expensive, they are housed in a separate namespace that can be accessed on demand by a caller.", 40 | "type": "object", 41 | "additionalProperties": { 42 | "title": "System", 43 | "description": "Actions are namespaced per system as a derviation is only valid for its specified system.", 44 | "type": "object", 45 | "additionalProperties": { 46 | "title": "Cell", 47 | "description": "The cell namespace for actions.", 48 | "type": "object", 49 | "additionalProperties": { 50 | "title": "Block", 51 | "description": "The block namespace for actions.", 52 | "type": "object", 53 | "additionalProperties": { 54 | "title": "Target", 55 | "description": "The target namespace for actions.", 56 | "type": "object", 57 | "additionalProperties": { 58 | "title": "Action", 59 | "description": "The string reperesentation of a realized store path that points to a runnable which implements the action.", 60 | "type": "string" 61 | } 62 | } 63 | } 64 | } 65 | } 66 | }, 67 | "init": { 68 | "title": "Init", 69 | "description": "The representational metadata about the Standardized repository.", 70 | "type": "object", 71 | "additionalProperties": { 72 | "title": "System", 73 | "description": "For evaluation economy, init is namespaced by system.", 74 | "type": "array", 75 | "items": { 76 | "title": "Cell", 77 | "description": "The representational data of a cell.", 78 | "type": "object", 79 | "required": [ 80 | "cell", 81 | "cellBlocks" 82 | ], 83 | "properties": { 84 | "cell": { 85 | "type": "string" 86 | }, 87 | "cellBlocks": { 88 | "type": "array", 89 | "items": { 90 | "title": "Block", 91 | "description": "The representational data of a block.", 92 | "type": "object", 93 | "required": [ 94 | "blockType", 95 | "cellBlock", 96 | "targets" 97 | ], 98 | "properties": { 99 | "blockType": { 100 | "type": "string" 101 | }, 102 | "cellBlock": { 103 | "type": "string" 104 | }, 105 | "targets": { 106 | "type": "array", 107 | "items": { 108 | "title": "Target", 109 | "description": "The representational data of a target.", 110 | "type": "object", 111 | "required": [ 112 | "name", 113 | "actions" 114 | ], 115 | "properties": { 116 | "name": { 117 | "type": "string" 118 | }, 119 | "actions": { 120 | "type": "array", 121 | "items": { 122 | "title": "Action", 123 | "description": "The representational data of an action (w/o derivation).", 124 | "type": "object", 125 | "properties": { 126 | "name": { 127 | "type": "string" 128 | }, 129 | "description": { 130 | "type": "string" 131 | } 132 | } 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | }, 145 | "ci": { 146 | "title": "CI", 147 | "description": "An evaluation that provides all necessary metadata and evaluated derivations.", 148 | "type": "object", 149 | "additionalProperties": { 150 | "title": "System", 151 | "description": "Actions are namespaced per system as a derviation is only valid for its specified system.", 152 | "type": "array", 153 | "items": { 154 | "title": "CI Discovery Candidate", 155 | "description": "A CI discovery candidate.", 156 | "type": "object", 157 | "required": [ 158 | "action", 159 | "block", 160 | "blockType", 161 | "cell", 162 | "name", 163 | "actionDrv" 164 | ], 165 | "properties": { 166 | "action": { 167 | "type": "string", 168 | "description": "The name of the action." 169 | }, 170 | "block": { 171 | "type": "string", 172 | "description": "The block name." 173 | }, 174 | "blockType": { 175 | "type": "string", 176 | "description": "The block type." 177 | }, 178 | "cell": { 179 | "type": "string", 180 | "description": "The cell name." 181 | }, 182 | "name": { 183 | "type": "string", 184 | "description": "The target name." 185 | }, 186 | "actionDrv": { 187 | "type": "string", 188 | "description": "The evaluated derivation for the action runnable." 189 | }, 190 | "targetDrv": { 191 | "type": [ 192 | "string", 193 | "null" 194 | ], 195 | "description": "The evaluated derivation for the target (if target is a derivation)." 196 | }, 197 | "proviso": { 198 | "type": [ 199 | "string", 200 | "null" 201 | ], 202 | "description": "A provisio which lets a CI cheaply decide whether running an action can be skipped." 203 | }, 204 | "meta": { 205 | "type": [ 206 | "string", 207 | "null" 208 | ], 209 | "description": "Arbitrary metadata needed during the priviso or discovery." 210 | } 211 | } 212 | } 213 | } 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /grow/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | l, 3 | deSystemize, 4 | call-flake, 5 | paths, 6 | types, 7 | }: let 8 | inherit (types) Block Target; 9 | ImportSignatureFor = import ./newImportSignatureFor.nix {inherit l deSystemize;}; 10 | ExtractFor = import ./newExtractFor.nix {inherit l types paths;}; 11 | ProcessCfg = import ./newProcessCfg.nix {inherit l types;}; 12 | Helpers = import ./newHelpers.nix {inherit l;}; 13 | /* 14 | A function that 'grows' Cell Blocks from Cells found in 'cellsFrom'. 15 | 16 | This figurative glossary is so non-descriptive, yet fitting, that 17 | it will be easy to reason about this nomenclature even in a casual 18 | conversation when not having convenient access to the actual code. 19 | 20 | Essentially, it is a special type of importer, that detects nix & 21 | some companion files placed in a specific folder structure inside 22 | your repository. 23 | 24 | The root of that special folder hierarchy is declared via 'cellsFrom'. 25 | This is a good opportunity to isolate your actual build-relevant source 26 | code from other repo boilerplate or documentation as a first line measure 27 | to improve build caching. 28 | 29 | Cell Blocks are the actual typed flake outputs, for convenience, Cell Blocks 30 | are grouped into Block Types which usually augment a Cell Block with action 31 | definitions that the std TUI will be able to understand and execute. 32 | 33 | The usual dealings with 'system' are greatly reduced in std. Inspired by 34 | the ideas known partly as "Super Simple Flakes" in the community, contrary 35 | to clasical nix, _all_ outputs are simply scoped by system as the first-level 36 | output key. That's it. Never deal with it again. The 'deSystemize' function 37 | automatically folds any particular system scope of inputs automatically one 38 | level up. So, when dealing with inputs, no dealing with 'system' either. 39 | 40 | If you need to crosscompile and know your current system, `inputs.nixpkgs.system` 41 | always has it. And all other inputs still expose `inputs.foo.system` as a 42 | fall back. But use your escape hatch wisely. If you feel that you need it and 43 | you aren't doing cross-compilation, search for the upstream bug. 44 | It's there! Guaranteed! 45 | 46 | Finally, there are a couple of special inputs: 47 | 48 | - `inputs.cells` - all other cells, deSystemized 49 | - `inputs.nixpkgs` - an _instatiated_ nixpkgs, configurabe via `nixpkgsConfig` 50 | - `inputs.self` - the `sourceInfo` (and only that) of the current flake 51 | 52 | Overlays? Go home or file an upstream bug. They are possible, but so heavily 53 | discouraged that you gotta find out for yourself if you really need to use 54 | them in a Cell Block. Hint: `.extend`. 55 | 56 | Yes, std is opinionated. Make sure to also meet `alejandra`. 😎 57 | 58 | */ 59 | grow = { 60 | inputs, 61 | cellsFrom, 62 | cellBlocks, 63 | systems ? [ 64 | "x86_64-linux" 65 | "aarch64-linux" 66 | "x86_64-darwin" 67 | "aarch64-darwin" 68 | ], 69 | nixpkgsConfig ? {}, 70 | } @ cfg: let 71 | # preserve pos of `systems` if not using the default 72 | cfg' = 73 | cfg 74 | // ( 75 | if cfg ? systems 76 | then {} 77 | else {inherit systems;} 78 | ); 79 | inherit (ProcessCfg cfg' inputs.self.sourceInfo) systems' cells' cellBlocks'; 80 | inherit (Helpers) accumulate optionalLoad; 81 | 82 | __ImportSignatureFor = ImportSignatureFor {inherit inputs nixpkgsConfig;}; 83 | ___extract = ExtractFor cellsFrom; 84 | 85 | cells = res.output; # recursion on cells (with system) 86 | 87 | # List of all flake outputs injected by std in the outputs and inputs.cells format 88 | loadOutputFor = system: let 89 | __extract = ___extract system; 90 | # Load a cell, return the flake outputs injected by std 91 | _ImportSignatureFor = cell: maybeWithFlake: let 92 | additionalInputs = ( 93 | if l.pathExists maybeWithFlake 94 | then (call-flake (dirOf maybeWithFlake)).outputs 95 | else {} 96 | ); 97 | in { 98 | inputs = __ImportSignatureFor system cells additionalInputs; 99 | inherit cell; 100 | }; 101 | loadCellFor = cellName: let 102 | _extract = __extract cellName; 103 | cellP = paths.cellPath cellsFrom cellName; 104 | loadCellBlock = cellBlock: let 105 | blockP = paths.cellBlockPath cellP cellBlock; 106 | isFile = l.pathExists blockP.file; 107 | isDir = l.pathExists blockP.dir; 108 | signature = let 109 | # pass through the current cell and cell block names for introspection 110 | outputMeta = 111 | res.output 112 | // { 113 | __cr = [cellName cellBlock.name]; 114 | }; 115 | in 116 | _ImportSignatureFor outputMeta cellP.flake; # recursion on cell 117 | import' = { 118 | displayPath, 119 | importPath, 120 | }: let 121 | # since we're not really importing files within the framework 122 | # the non-memoization of scopedImport doesn't have practical penalty 123 | block = 124 | Block "paisano/import: ${displayPath}" 125 | (l.scopedImport signature importPath); 126 | in 127 | if l.typeOf block == "set" 128 | then block 129 | else block signature; 130 | importPaths = 131 | if isFile 132 | then { 133 | displayPath = blockP.file'; 134 | importPath = blockP.file; 135 | } 136 | else if isDir 137 | then { 138 | displayPath = blockP.dir'; 139 | importPath = blockP.dir; 140 | } 141 | else throw "unreachable!"; 142 | Target' = {displayPath, ...}: Target "paisano/import: ${displayPath}"; 143 | imported = Target' importPaths (import' importPaths); 144 | # extract instatiates actions and extracts metadata for the __std registry 145 | targetTracer = name: l.traceVerbose "Paisano loading for ${system} ${importPaths.importPath}:${name}"; 146 | extracted = l.optionalAttrs (cellBlock.cli or true) (l.mapAttrs (_extract cellBlock targetTracer signature.inputs) imported); 147 | in 148 | optionalLoad (isFile || isDir) 149 | [ 150 | # top level output 151 | {${cellBlock.name} = imported;} 152 | # __std.actions (slow) 153 | {${cellBlock.name} = l.mapAttrs (_: set: set.actions) extracted;} 154 | # __std.init (fast) 155 | ( 156 | { 157 | cellBlock = cellBlock.name; 158 | blockType = cellBlock.type; 159 | targets = l.mapAttrsToList (_: set: set.init) extracted; 160 | } 161 | // (l.optionalAttrs (l.pathExists blockP.readmeDir) {readme = blockP.readmeDir;}) 162 | // (l.optionalAttrs (l.pathExists blockP.readme) {inherit (blockP) readme;}) 163 | ) 164 | # __std.ci 165 | { 166 | ci = l.mapAttrsToList (_: set: set.ci) extracted; 167 | } 168 | ]; 169 | res = accumulate (l.map loadCellBlock cellBlocks'); 170 | in [ 171 | # top level output 172 | {${cellName} = res.output;} 173 | # __std.actions (slow) 174 | {${cellName} = res.actions;} 175 | # __std.init (fast) 176 | ( 177 | { 178 | cell = cellName; 179 | cellBlocks = res.init; # [] 180 | } 181 | // (l.optionalAttrs (l.pathExists cellP.readme) {inherit (cellP) readme;}) 182 | ) 183 | # __std.ci 184 | { 185 | inherit (res) ci; 186 | } 187 | ]; # }; 188 | res = accumulate (l.map loadCellFor cells'); 189 | in [ 190 | # top level output 191 | {${system} = res.output;} 192 | # __std.actions (slow) 193 | {${system} = res.actions;} 194 | # __std.init (fast) 195 | { 196 | name = system; 197 | value = res.init; 198 | } 199 | # __std.ci 200 | { 201 | ci = [ 202 | { 203 | name = system; 204 | value = res.ci; 205 | } 206 | ]; 207 | } 208 | ]; 209 | res = accumulate (l.map loadOutputFor systems'); 210 | in 211 | assert l.assertMsg ((l.compareVersions l.nixVersion "2.10.3") >= 0) "The truth is: you'll need a newer nix version (minimum: v2.10.3)."; 212 | res.output 213 | // { 214 | __std.__schema = "v0"; 215 | __std.ci = l.listToAttrs res.ci; 216 | __std.init = l.listToAttrs res.init; 217 | __std.actions = res.actions; 218 | __std.cellsFrom = l.baseNameOf cellsFrom; 219 | }; 220 | 221 | growOn = import ./grow-on.nix {inherit l grow;}; 222 | in {inherit grow growOn;} 223 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Paisano Core 8 | 9 | _Organize your Flakes-based projects_ 10 | 11 | Paisano implements an API for organizing Nix code into folders. 12 | 13 | It then maps that folder structure into Flake outputs, once per system. 14 | 15 | To type outputs, an output type system is provided and traits (i.e. "abstract behaviour") may be implemented on them. 16 | 17 | ## Motivation 18 | 19 | Nix flakes make it easy to create self-contained projects with a common top-level interface that has been standardized througout the Nix Community. 20 | However, as an upstream standard it was built (mostly) for the packaging use case of Nix in the context of small package-centric repositories. 21 | It is, therefore, less suited for a DevOps centric usage pattern. 22 | 23 | With Paisano, we attempt to solve the following problems: 24 | 25 | - **Internal code boundaries**: 26 | Nix isn't typed and doesn't itself impose any opinion on how to organize code. 27 | It also doesn't define a module system in the same sense as a typical programming language, in which modules are often folder-based encapsulation of functionality. 28 | 29 | Therefore, Nix forces its users to make a significant upfront investment in designing their code layout. 30 | Unfortunately, due to the planning overhead that this entails, many users may just skip out on Nix for this reason alone. 31 | Over longer time horizons, Nix code seen in the wild tends, in our experience, to lose clarity and organization. 32 | 33 | Paisano addresses this problem by simple, clear, and extensible calling conventions on its module importer interface. 34 | 35 | - **Ease of refactoring**: 36 | In many a Nix codebase, a multiplicity of interaces, coupled with needlessly bespoke calling conventions make semantic code refactoring unnecessarily difficult. 37 | 38 | In contrast, Paisano enforces a single, but powerful, calling convention for its importer. As a result, Paisano makes semantic refactoring straightforward as your project naturally grows. 39 | 40 | - **Shared mental structure**: 41 | A custom code structure often comes with a hefty price tag in terms of context switching between projects. 42 | Yet, in a typical DevOps workflow, it is not uncommon to deal with multiple, diverse code bases. 43 | 44 | By encouraging basic organizational principles (at least) in your (Nix) code, a future "self" or present "other" will be able to significantly lower their cognitive load, 45 | leaving more time to get useful work done. 46 | 47 | - **Take out the guesswork**: 48 | The costs of the upfront design work required to effectively structure your project, along with the above mentioned hurdles in code refactoring are simply too high. 49 | And if that's not bad enough, the cost of making a mistake during this process is _even higher_, leading to more tedious work simply to make sense out of your existing code. 50 | 51 | As a consequence, many (Nix) projects evolve unguided, with the heavy price of refactoring postponed. 52 | This can quickly become a vicious cycle of ever growing spaghetti code, which is then more and more difficult to refactor as time goes on. 53 | 54 | Paisano's meta-structure alleviates the guesswork considerably, enabling the user to spend their time creating a meaningful project type system. 55 | It is this very system which allows time to focus on effectively solving your problem; the solution of which can then be mapped effortlessly over any related outputs, again and again. 56 | 57 | In short, considerable effort is expended to take the previously destructive feedback loop described above, and turn it into a highly productive one; allowing for quick _and_ correct (i.e. well-typed) iteration. 58 | 59 | - **Avoid level-creep**: 60 | There is often a tension between depth and breadth when organizing the folder structure of your project. 61 | A deeply nested scheme may sometimes map the problem domain more efficiently, but it isn't necessarily optimized for human consumption. 62 | 63 | Paisano tries to find a nice balance, which readily accomodates every problem domain without compromising readability. 64 | 65 | We do this by offering an unambiguous model for structuring your code, which breaks down fairly simply as follows. 66 | 67 | ### When you want: 68 | 69 | - Breath → add a code block 70 | - Depth → compose flakes 71 | 72 | This creates a natural depth boundary at the repository level, since it is generally considered good practive to use one flake per project repository. 73 | 74 | ## Terminology 75 | 76 | - **Cells** — they are the first level in the folder structure and group related functionality together. 77 | An example from the microserivce use case would be a backend cell or a frontend cell. 78 | - **Block** — the next level in the folder structure are (typed) blocks that implement a collection of similar functionality, i.e. code modules (in other languages). 79 | One could be labeled "tasks", another "packages", another "images", etc. 80 | 81 | - **Targets** — each block type can have one or more targets. 82 | These are your concrete packages, container images, scripts, etc. 83 | 84 | - **Block Types & Actions** — 85 | These are the types attached to the blocks mentioned above. They allow you to define arbitary actions which can be run over the specific targets contained in the associated block. 86 | This allows a platform or framework provider to implement shared functionality for their particular use case, such as a single action which describes how to "push" container images to their registry. 87 | 88 | This is really where Paisano breaks away from the simple packaging pattern of Nix and allows you to define what you actually want to _do_ with those packages, artifacts, scripts, or images in a well-defined, boilerplate free way. 89 | 90 | - **Registry** — the registry extracts structured, yet json-serializable, data from our output type system and code structure. 91 | Consumers such as CI, a CLI/TUI, or even a UI can access and extract that data for a tight integration with the respective target use cases. For a concrete example of a consumer, see [std-action](https://github.com/divnix/std-action). 92 | 93 | ## Regsitry Schema Spec 94 | 95 | The current schema version is `v0` (unstable). 96 | 97 | The Jsonschema specification of the registry can be found inside [`./registry.schema.json`](./registry.schema.json). 98 | It can be explored interactively with this [link][explore-registry-schema]. 99 | 100 | [explore-registry-schema]: https://json-schema-viewer.vercel.app/view?url=https%3A%2F%2Fraw.githubusercontent.com%2Fdivnix%2Fpaisano%2Fmain%2Fregistry.schema.json&description_is_markdown=on&expand_buttons=on&show_breadcrumbs=on&with_footer=on&template_name=js 101 | 102 | ## Usage 103 | 104 | ```nix 105 | # flake.nix 106 | { 107 | inputs.paisano.url = "github:divnix/paisano"; 108 | inputs.paisano.inputs.nixpkgs.follows = "nixpkgs"; 109 | 110 | outputs = { paisano, self }@inputs: 111 | paisano.growOn { 112 | /* 113 | the grow function needs `inputs` to desystemize 114 | them and make them available to your cell blocks 115 | */ 116 | inherit inputs; 117 | /* 118 | sepcify from where to grow the cells 119 | `./nix` is a typical choice that signals 120 | to everyone where the nix code lies 121 | */ 122 | cellsFrom = ./nix; 123 | /* 124 | These blocks may or may not be found in a particular cell. 125 | But blocks that aren't defined here, cannot exist in any cell. 126 | */ 127 | cellBlocks = [ 128 | { 129 | /* 130 | Because the name is `mycellblock`, paisano's importer 131 | will be hooking into any file `/mycellblock.nix` 132 | or `/mycellblock/default.nix`. 133 | Block tragets are exposed under: 134 | #... 135 | */ 136 | name = "mycellblock"; 137 | type = "mytype"; 138 | 139 | /* 140 | Optional 141 | 142 | Actions are exposed in paisano's "registry" under 143 | #__std.actions..... 144 | */ 145 | actions = { 146 | system, 147 | flake, 148 | fragment, 149 | fragmentRelPath, 150 | }: [ 151 | { 152 | name = "build"; 153 | description = "build this target"; 154 | command = '' 155 | nix build ${flake}#${fragment} 156 | ''; 157 | } 158 | ]; 159 | /* 160 | Optional 161 | 162 | The CI registry flattens the targets and 163 | the actions to run for each target into a list 164 | so that downstream tooling can discover what to 165 | do in the CI. The invokable action is determined 166 | by the attribute name: ci. = true 167 | 168 | #__std.ci. = [ {...} ... ]; 169 | */ 170 | ci.build = true; 171 | } 172 | ]; 173 | } 174 | { 175 | /* Soil */ 176 | # Here, we make our domain layout compatible with the Nix CLI, among others 177 | devShells = paisano.harvest self [ "" ""]; 178 | packages = paisano.winnow (n: v: n == "" && v != null ) self [ "" ""]; 179 | templates = paisano.pick self [ "" ""]; 180 | }; 181 | } 182 | ``` 183 | -------------------------------------------------------------------------------- /tests/_snapshots/grow: -------------------------------------------------------------------------------- 1 | #pretty 2 | { 3 | __std = { 4 | __schema = "v0"; 5 | actions = { 6 | aarch64-darwin = { 7 | bar-cell = { 8 | test-block = { 9 | self = { 10 | foo-action = ; 11 | }; 12 | }; 13 | }; 14 | foo-cell = { 15 | test-block = { 16 | barCellBlockNames = { 17 | foo-action = ; 18 | }; 19 | cellsNamesAndSystemsCrossCompilationEscapeHatch = { 20 | foo-action = ; 21 | }; 22 | self = { 23 | foo-action = ; 24 | }; 25 | }; 26 | }; 27 | }; 28 | aarch64-linux = { 29 | bar-cell = { 30 | test-block = { 31 | self = { 32 | foo-action = ; 33 | }; 34 | }; 35 | }; 36 | foo-cell = { 37 | test-block = { 38 | barCellBlockNames = { 39 | foo-action = ; 40 | }; 41 | cellsNamesAndSystemsCrossCompilationEscapeHatch = { 42 | foo-action = ; 43 | }; 44 | self = { 45 | foo-action = ; 46 | }; 47 | }; 48 | }; 49 | }; 50 | x86_64-darwin = { 51 | bar-cell = { 52 | test-block = { 53 | self = { 54 | foo-action = ; 55 | }; 56 | }; 57 | }; 58 | foo-cell = { 59 | test-block = { 60 | barCellBlockNames = { 61 | foo-action = ; 62 | }; 63 | cellsNamesAndSystemsCrossCompilationEscapeHatch = { 64 | foo-action = ; 65 | }; 66 | self = { 67 | foo-action = ; 68 | }; 69 | }; 70 | }; 71 | }; 72 | x86_64-linux = { 73 | bar-cell = { 74 | test-block = { 75 | self = { 76 | foo-action = ; 77 | }; 78 | }; 79 | }; 80 | foo-cell = { 81 | test-block = { 82 | barCellBlockNames = { 83 | foo-action = ; 84 | }; 85 | cellsNamesAndSystemsCrossCompilationEscapeHatch = { 86 | foo-action = ; 87 | }; 88 | self = { 89 | foo-action = ; 90 | }; 91 | }; 92 | }; 93 | }; 94 | }; 95 | cellsFrom = "__fixture"; 96 | ci = { 97 | aarch64-darwin = [ ]; 98 | aarch64-linux = [ ]; 99 | x86_64-darwin = [ ]; 100 | x86_64-linux = [ ]; 101 | }; 102 | init = { 103 | aarch64-darwin = [ 104 | { 105 | cell = "bar-cell"; 106 | cellBlocks = [ 107 | { 108 | blockType = "test-block"; 109 | cellBlock = "test-block"; 110 | targets = [ 111 | { 112 | actions = [ 113 | { 114 | description = "paisano foo"; 115 | name = "foo-action"; 116 | } 117 | ]; 118 | name = "self"; 119 | } 120 | ]; 121 | } 122 | ]; 123 | } 124 | { 125 | cell = "foo-cell"; 126 | cellBlocks = [ 127 | { 128 | blockType = "test-block"; 129 | cellBlock = "test-block"; 130 | targets = [ 131 | { 132 | actions = [ 133 | { 134 | description = "paisano foo"; 135 | name = "foo-action"; 136 | } 137 | ]; 138 | name = "barCellBlockNames"; 139 | } 140 | { 141 | actions = [ 142 | { 143 | description = "paisano foo"; 144 | name = "foo-action"; 145 | } 146 | ]; 147 | name = "cellsNamesAndSystemsCrossCompilationEscapeHatch"; 148 | } 149 | { 150 | actions = [ 151 | { 152 | description = "paisano foo"; 153 | name = "foo-action"; 154 | } 155 | ]; 156 | name = "self"; 157 | } 158 | ]; 159 | } 160 | ]; 161 | } 162 | ]; 163 | aarch64-linux = [ 164 | { 165 | cell = "bar-cell"; 166 | cellBlocks = [ 167 | { 168 | blockType = "test-block"; 169 | cellBlock = "test-block"; 170 | targets = [ 171 | { 172 | actions = [ 173 | { 174 | description = "paisano foo"; 175 | name = "foo-action"; 176 | } 177 | ]; 178 | name = "self"; 179 | } 180 | ]; 181 | } 182 | ]; 183 | } 184 | { 185 | cell = "foo-cell"; 186 | cellBlocks = [ 187 | { 188 | blockType = "test-block"; 189 | cellBlock = "test-block"; 190 | targets = [ 191 | { 192 | actions = [ 193 | { 194 | description = "paisano foo"; 195 | name = "foo-action"; 196 | } 197 | ]; 198 | name = "barCellBlockNames"; 199 | } 200 | { 201 | actions = [ 202 | { 203 | description = "paisano foo"; 204 | name = "foo-action"; 205 | } 206 | ]; 207 | name = "cellsNamesAndSystemsCrossCompilationEscapeHatch"; 208 | } 209 | { 210 | actions = [ 211 | { 212 | description = "paisano foo"; 213 | name = "foo-action"; 214 | } 215 | ]; 216 | name = "self"; 217 | } 218 | ]; 219 | } 220 | ]; 221 | } 222 | ]; 223 | x86_64-darwin = [ 224 | { 225 | cell = "bar-cell"; 226 | cellBlocks = [ 227 | { 228 | blockType = "test-block"; 229 | cellBlock = "test-block"; 230 | targets = [ 231 | { 232 | actions = [ 233 | { 234 | description = "paisano foo"; 235 | name = "foo-action"; 236 | } 237 | ]; 238 | name = "self"; 239 | } 240 | ]; 241 | } 242 | ]; 243 | } 244 | { 245 | cell = "foo-cell"; 246 | cellBlocks = [ 247 | { 248 | blockType = "test-block"; 249 | cellBlock = "test-block"; 250 | targets = [ 251 | { 252 | actions = [ 253 | { 254 | description = "paisano foo"; 255 | name = "foo-action"; 256 | } 257 | ]; 258 | name = "barCellBlockNames"; 259 | } 260 | { 261 | actions = [ 262 | { 263 | description = "paisano foo"; 264 | name = "foo-action"; 265 | } 266 | ]; 267 | name = "cellsNamesAndSystemsCrossCompilationEscapeHatch"; 268 | } 269 | { 270 | actions = [ 271 | { 272 | description = "paisano foo"; 273 | name = "foo-action"; 274 | } 275 | ]; 276 | name = "self"; 277 | } 278 | ]; 279 | } 280 | ]; 281 | } 282 | ]; 283 | x86_64-linux = [ 284 | { 285 | cell = "bar-cell"; 286 | cellBlocks = [ 287 | { 288 | blockType = "test-block"; 289 | cellBlock = "test-block"; 290 | targets = [ 291 | { 292 | actions = [ 293 | { 294 | description = "paisano foo"; 295 | name = "foo-action"; 296 | } 297 | ]; 298 | name = "self"; 299 | } 300 | ]; 301 | } 302 | ]; 303 | } 304 | { 305 | cell = "foo-cell"; 306 | cellBlocks = [ 307 | { 308 | blockType = "test-block"; 309 | cellBlock = "test-block"; 310 | targets = [ 311 | { 312 | actions = [ 313 | { 314 | description = "paisano foo"; 315 | name = "foo-action"; 316 | } 317 | ]; 318 | name = "barCellBlockNames"; 319 | } 320 | { 321 | actions = [ 322 | { 323 | description = "paisano foo"; 324 | name = "foo-action"; 325 | } 326 | ]; 327 | name = "cellsNamesAndSystemsCrossCompilationEscapeHatch"; 328 | } 329 | { 330 | actions = [ 331 | { 332 | description = "paisano foo"; 333 | name = "foo-action"; 334 | } 335 | ]; 336 | name = "self"; 337 | } 338 | ]; 339 | } 340 | ]; 341 | } 342 | ]; 343 | }; 344 | }; 345 | aarch64-darwin = { 346 | bar-cell = { 347 | test-block = { 348 | self = "via foo-cell constant-self"; 349 | }; 350 | }; 351 | foo-cell = { 352 | test-block = { 353 | barCellBlockNames = [ 354 | "test-block" 355 | ]; 356 | cellsNamesAndSystemsCrossCompilationEscapeHatch = [ 357 | "aarch64-darwin" 358 | "aarch64-linux" 359 | "bar-cell" 360 | "foo-cell" 361 | "x86_64-darwin" 362 | "x86_64-linux" 363 | ]; 364 | self = "via foo-cell constant-self"; 365 | }; 366 | }; 367 | }; 368 | aarch64-linux = { 369 | bar-cell = { 370 | test-block = { 371 | self = "via foo-cell constant-self"; 372 | }; 373 | }; 374 | foo-cell = { 375 | test-block = { 376 | barCellBlockNames = [ 377 | "test-block" 378 | ]; 379 | cellsNamesAndSystemsCrossCompilationEscapeHatch = [ 380 | "aarch64-darwin" 381 | "aarch64-linux" 382 | "bar-cell" 383 | "foo-cell" 384 | "x86_64-darwin" 385 | "x86_64-linux" 386 | ]; 387 | self = "via foo-cell constant-self"; 388 | }; 389 | }; 390 | }; 391 | x86_64-darwin = { 392 | bar-cell = { 393 | test-block = { 394 | self = "via foo-cell constant-self"; 395 | }; 396 | }; 397 | foo-cell = { 398 | test-block = { 399 | barCellBlockNames = [ 400 | "test-block" 401 | ]; 402 | cellsNamesAndSystemsCrossCompilationEscapeHatch = [ 403 | "aarch64-darwin" 404 | "aarch64-linux" 405 | "bar-cell" 406 | "foo-cell" 407 | "x86_64-darwin" 408 | "x86_64-linux" 409 | ]; 410 | self = "via foo-cell constant-self"; 411 | }; 412 | }; 413 | }; 414 | x86_64-linux = { 415 | bar-cell = { 416 | test-block = { 417 | self = "via foo-cell constant-self"; 418 | }; 419 | }; 420 | foo-cell = { 421 | test-block = { 422 | barCellBlockNames = [ 423 | "test-block" 424 | ]; 425 | cellsNamesAndSystemsCrossCompilationEscapeHatch = [ 426 | "aarch64-darwin" 427 | "aarch64-linux" 428 | "bar-cell" 429 | "foo-cell" 430 | "x86_64-darwin" 431 | "x86_64-linux" 432 | ]; 433 | self = "via foo-cell constant-self"; 434 | }; 435 | }; 436 | }; 437 | } --------------------------------------------------------------------------------