├── .github └── workflows │ └── all-tests.yml ├── .gitignore ├── README.md ├── check.sh ├── ci └── actions │ └── set-system │ └── action.yml ├── flake.lock ├── flake.nix ├── lib ├── attrsets.nix ├── call-flake-w.nix ├── debug.nix ├── default.nix ├── encode.nix ├── filesystem.nix ├── filt.nix ├── flake-registry.nix ├── flake-utils.nix ├── flake.lock ├── flake.nix ├── funk.nix ├── json.nix ├── lists.nix ├── overlay.lib.nix ├── paths.nix ├── repl.nix ├── safe-reads.nix ├── semver.nix ├── stdenv.nix ├── strings.nix ├── tags.nix ├── thunk.nix ├── trivial.nix ├── types.nix └── yants.nix ├── pkgs ├── build-support │ ├── setup-hooks │ │ ├── default.nix │ │ └── isAR.sh │ └── trivial │ │ ├── copy.nix │ │ ├── link.nix │ │ ├── tar.nix │ │ └── tests │ │ ├── default.nix │ │ └── tests.nix ├── development │ └── tools │ │ └── jo │ │ ├── .gitignore │ │ ├── checks.nix │ │ ├── default.nix │ │ ├── flake.lock │ │ └── flake.nix ├── docgen │ ├── default.nix │ ├── makeinfo │ │ └── default.nix │ ├── module-options.nix │ └── pandoc │ │ └── default.nix └── scripts │ └── nix │ └── nix-outputs ├── plugs ├── conf │ └── template │ │ ├── default.nix │ │ └── plugin.nix └── hello │ ├── default.nix │ └── hello.cc ├── profiles └── development │ ├── default.nix │ └── shall.nix ├── templates ├── autotools │ ├── .gitignore │ ├── Makefile.am │ ├── README │ ├── README.org │ ├── bootstrap │ ├── build-aux │ │ ├── config.guess │ │ ├── config.sub │ │ └── install-sh │ ├── configure.ac │ ├── default.nix │ ├── flake.nix │ └── m4 │ │ └── utils.m4 ├── basic-pkg │ └── flake.nix ├── basic-with-lib │ ├── flake.lock │ └── flake.nix ├── basic │ ├── flake.lock │ └── flake.nix ├── lib-sub │ └── sub.nix ├── meaty │ ├── flake.lock │ └── flake.nix ├── nix-bin │ ├── default.nix │ ├── main.cc │ └── pkg-fun.nix ├── nix-plugin │ ├── default.nix │ ├── pkg-fun.nix │ └── plugin.cc ├── tests-sub │ ├── default.nix │ └── tests.nix └── tests │ ├── README.org │ ├── bootstrap.sh │ ├── check.sh │ ├── default.nix │ └── sub │ ├── default.nix │ └── tests.nix ├── tests ├── attrsets.nix ├── data │ ├── file0.json │ ├── file1.json │ └── sha512s.txt ├── debug.nix ├── default.nix ├── encode.nix ├── libfunk.nix ├── libjson.nix ├── liblist.nix ├── libsemver.nix ├── libtag.nix ├── paths.nix ├── strings.nix ├── tar.nix └── trivial.nix ├── types ├── fs.nix └── overlay.yt.nix └── update.sh /.github/workflows/all-tests.yml: -------------------------------------------------------------------------------- 1 | name: All Tests 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - .github/workflows/all-tests.yml 8 | - flake.nix 9 | - flake.lock 10 | - tests/** 11 | - types/** 12 | - lib/** 13 | - '!**/README*' 14 | 15 | pull_request: 16 | types: [opened, synchronize, reopened] 17 | paths: 18 | - .github/workflows/all-tests.yml 19 | - flake.nix 20 | - flake.lock 21 | - tests/** 22 | - types/** 23 | - lib/** 24 | - '!**/README*' 25 | 26 | concurrency: 27 | group: ${{ github.workflow }}-${{ github.ref }} 28 | cancel-in-progress: true 29 | jobs: 30 | all-tests: 31 | runs-on: ubuntu-latest 32 | env: 33 | SYSTEM: x86_64-linux 34 | steps: 35 | - uses: cachix/install-nix-action@11f4ad19be46fd34c005a2864996d8f197fb51c6 36 | with: 37 | extra_nix_config: | 38 | experimental-features = nix-command flakes 39 | substituters = https://cache.nixos.org 40 | trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= 41 | max-jobs = auto 42 | cores = 0 43 | 44 | - name: Setup 45 | run: | 46 | echo "# ============================================================================ #" >&2; 47 | { printf ' bash version: '; bash --version|head -n1; } >&2; 48 | { printf ' nix version: '; nix --version; } >&2; 49 | echo "# ---------------------------------------------------------------------------- #" >&2; 50 | nix registry add head "github:${{ github.repository }}/$GITHUB_REF"; 51 | 52 | - name: All Checks 53 | run: | 54 | nix flake check head --show-trace; 55 | nix flake check head --show-trace --impure; 56 | 57 | - name: All Tests 58 | run: | 59 | nix build head#tests --show-trace; 60 | nix build head#tests --show-trace --impure; 61 | 62 | - name: DeepSeq Lib 63 | run: | 64 | nix eval head#lib --apply "lib: builtins.deepSeq lib true" --show-trace; 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | result 2 | result* 3 | tags 4 | .ccls-cache 5 | .*.swp 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ak-nix 2 | Various `nix` and NixOS extensions 3 | 4 | # Outputs 5 | ## REPL Extensions 6 | The output `ak-nix#repl` holds convenience functions for use in a Nix REPL. 7 | The highlights are `ls` which behaves like your shell's `ls` command, `pwd` 8 | which does exactly what you think, and `show` which uses `builtins.trace` to 9 | print values or lists of values to the console. 10 | 11 | ```nix 12 | nix-repl> :a ( builtins.getFlake "ak-nix" ).repl 13 | nix-repl> pwd 14 | /home/sally/src/ak-nix 15 | nix-repl> ls "./*" 16 | trace: 17 | ./attrsets.nix 18 | ./debug.nix 19 | ./default.nix 20 | ./filesystem.nix 21 | ./json.nix 22 | ./lists.nix 23 | ./paths.nix 24 | ./repl.nix 25 | ./stdenv.nix 26 | ./strings.nix 27 | true 28 | nix-repl> show ["oh" "dip" ( it: "is" ) 420] 29 | trace: 30 | oh 31 | dip 32 | 33 | 420 34 | true 35 | ``` 36 | 37 | # Lib 38 | A set of extensions to `nixpkgs.lib`. 39 | This is constructed using `nixpkgs.lib.extend`, so it can be used as an 40 | alternate in existing expressions which already take `lib` as an argument. 41 | 42 | The lib attribute contains `librepl` and is available as at the top-level, or 43 | as a subdir flake: 44 | ```nix 45 | nix-repl> lib = builtins.getFlake "github:aakropotkin/ak-nix?dir=lib" 46 | nix-repl> :a lib.librepl 47 | nix-repl> pwd 48 | /home/sally/src/ak-nix 49 | nix-repl> add = curryDefaultSystems' ( system: 50 | { x, y }: builtins.trace system ( x + y ) ) 51 | nix-repl> add { x = 1; y = 2; } 52 | { __functor = ; 53 | aarch64-darwin = 3; trace: aarch64-darwin 54 | aarch64-linux = 3; trace: aarch64-linux 55 | i686-linux = 3; trace: i686-linux 56 | x86_64-darwin = 3; trace: x86_64-darwin 57 | x86_64-linux = 3; trace: x86_64-linux 58 | } 59 | nix-repl> ( add { x = 2; y = 2; } ).x86_64-linux 60 | 3 61 | nix-repl> ( add { x = 3; y = 2; } ) "x86_64-linux" 62 | trace: x86_64-linux 63 | 5 64 | nix-repl> add "x86_64-linux" { x = 4; y = 20; } 65 | trace: x86_64-linux 66 | 24 67 | ``` 68 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -eu; 3 | set -o pipefail; 4 | 5 | : "${REALPATH:=realpath}"; 6 | : "${NIX:=nix}"; 7 | : "${NIX_FLAGS:=--no-warn-dirty}"; 8 | : "${NIX_CMD_FLAGS:=-L --show-trace}"; 9 | : "${SYSTEM:=$( $NIX eval --raw --impure --expr builtins.currentSystem; )}"; 10 | : "${GREP:=grep}" 11 | : "${JQ:=jq}"; 12 | 13 | SDIR="$( $REALPATH "${BASH_SOURCE[0]}" )"; 14 | SDIR="${SDIR%/*}"; 15 | : "${FLAKE_REF:=$SDIR}"; 16 | 17 | trap '_es="$?"; exit "$_es";' HUP EXIT INT QUIT ABRT; 18 | 19 | nix_w() { 20 | { 21 | { 22 | $NIX $NIX_FLAGS "$@" 3>&2 2>&1 1>&3||exit 1; 23 | }|$GREP -v 'warning: unknown flake output'; 24 | } 3>&2 2>&1 1>&3; 25 | } 26 | 27 | nix_w flake check "$FLAKE_REF" $NIX_CMD_FLAGS --system "$SYSTEM"; 28 | nix_w flake check "$FLAKE_REF" $NIX_CMD_FLAGS --system "$SYSTEM" --impure; 29 | 30 | # Swallow traces, but show them on failure. 31 | check_lib() { 32 | nix_w eval "$FLAKE_REF#lib" --apply 'lib: builtins.deepSeq lib true'; 33 | } 34 | check_lib 2>/dev/null||check_lib; 35 | -------------------------------------------------------------------------------- /ci/actions/set-system/action.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Set SYSTEM 3 | description: Sets the env var SYSTEM to the Nix platform double for the active runner. 4 | 5 | runs: 6 | using: "composite" 7 | steps: 8 | - name: Define System 9 | shell: bash 10 | run: | 11 | { 12 | printf 'SYSTEM='; 13 | case "${{ runner.arch }}" in 14 | X64) printf 'x86_64-'; ;; 15 | ARM64) printf 'aarch64-'; ;; 16 | *) exit 1; ;; 17 | esac 18 | case "${{ runner.os }}" in 19 | Linux) echo "linux"; ;; 20 | maxOS) echo "darwin"; ;; 21 | *) exit 1; ;; 22 | esac 23 | } >> $GITHUB_ENV 24 | - run: echo "SYSTEM=$SYSTEM" 25 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 0, 6 | "narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=", 7 | "path": "/nix/store/lwyjz70qh12nq6cb7fixl85vryzxqm3c-source", 8 | "type": "path" 9 | }, 10 | "original": { 11 | "id": "nixpkgs", 12 | "type": "indirect" 13 | } 14 | }, 15 | "root": { 16 | "inputs": { 17 | "nixpkgs": "nixpkgs" 18 | } 19 | } 20 | }, 21 | "root": "root", 22 | "version": 7 23 | } 24 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { 8 | 9 | description = "Misc Nix derivations and expressions"; 10 | 11 | # ---------------------------------------------------------------------------- # 12 | 13 | outputs = { nixpkgs, ... }: let 14 | 15 | # ---------------------------------------------------------------------------- # 16 | 17 | # A standalone lib overlay, useful if you are creating other pure libs. 18 | libOverlays.default = import ./lib/overlay.lib.nix; 19 | 20 | # Extends Nixpkgs with new builders as well as our lib and type extensions. 21 | # Types are stashed under `lib.ytypes'. 22 | overlays.default = final: prev: let 23 | tarutils = import ./pkgs/build-support/trivial/tar.nix { 24 | inherit (prev) gzip gnutar coreutils bash findutils system; 25 | inherit (final) lib; 26 | }; 27 | linkutils = import ./pkgs/build-support/trivial/link.nix { 28 | inherit (prev) coreutils bash system; 29 | inherit (final) lib; 30 | }; 31 | copyutils = import ./pkgs/build-support/trivial/copy.nix { 32 | inherit (prev) coreutils bash system; 33 | inherit (final) lib; 34 | }; 35 | trivial = tarutils // linkutils // copyutils; 36 | in { 37 | lib = prev.lib.extend libOverlays.default; 38 | } // trivial; 39 | 40 | # These are already included in our lib overlay. 41 | # We splice them out here to help simplify the use of overrides in other 42 | # flakes with complex compositions. 43 | # Users should ignore this overlay - you shouldn't ever need to this overlay 44 | # unless you're trying to stub the type checkers with dummy functions. 45 | ytOverlays.default = final: prev: 46 | ( nixpkgs.lib.extend libOverlays.default ).ytypes; 47 | 48 | # ---------------------------------------------------------------------------- # 49 | 50 | nixosModules.default = { config, ... }: { overlays = [overlays.ak-nix]; }; 51 | 52 | # ---------------------------------------------------------------------------- # 53 | 54 | inherit (nixpkgs.lib.extend libOverlays.default) eachDefaultSystemMap; 55 | 56 | lib = nixpkgs.lib.extend libOverlays.default; 57 | 58 | # ---------------------------------------------------------------------------- # 59 | 60 | packages = eachDefaultSystemMap ( system: let 61 | pkgsFor = nixpkgs.legacyPackages.${system}.extend overlays.default; 62 | in { 63 | tests = ( pkgsFor.callPackage ./tests { 64 | inherit pkgsFor nixpkgs system; 65 | inherit (pkgsFor) lib; 66 | } ).checkDrv; 67 | } ); 68 | 69 | 70 | # ---------------------------------------------------------------------------- # 71 | 72 | in { 73 | 74 | # ---------------------------------------------------------------------------- # 75 | 76 | # Inheriting these allows us to avoid referring to a "global self". 77 | # This is important in order to avoid quirks in lockfiles, and to simplify 78 | # the use of `callFlake'. 79 | inherit overlays libOverlays ytOverlays nixosModules lib packages; 80 | 81 | # ---------------------------------------------------------------------------- # 82 | 83 | # `nix-repl> :a ( builtins.getFlake "ak-core" ).repl' 84 | repl = let 85 | pkgsFor = nixpkgs.legacyPackages.${builtins.currentSystem}.extend 86 | overlays.default; 87 | lib = let 88 | pureLib = nixpkgs.lib.extend libOverlays.default; 89 | in pureLib.extend ( _: _: { inNixRepl = true; } ); 90 | in lib.joinAttrs [ 91 | lib 92 | lib.librepl 93 | builtins 94 | { inherit pkgsFor lib; } 95 | ]; 96 | 97 | # Wrappers for Pandoc, Makeinfo, and NixOS module options' generators. 98 | docgen = ( eachDefaultSystemMap ( system: import ./pkgs/docgen { 99 | inherit (nixpkgs.legacyPackages.${system}) pandoc texinfo; 100 | } ) ) // { __functor = _self: system: _self.${system}; }; 101 | 102 | 103 | # ---------------------------------------------------------------------------- # 104 | 105 | checks = lib.eachDefaultSystemMap ( system: let 106 | pkgsFor = nixpkgs.legacyPackages.${system}.extend overlays.default; 107 | in { 108 | inherit (packages.${system}) tests; 109 | untarSanPerms = ( pkgsFor.callPackage ./tests/tar.nix { 110 | inherit pkgsFor; 111 | } ).drvs.testUntarSanPerms_0; 112 | } ); 113 | 114 | 115 | # ---------------------------------------------------------------------------- # 116 | 117 | legacyPackages = eachDefaultSystemMap ( system: 118 | nixpkgs.legacyPackages.${system}.extend overlays.default 119 | ); 120 | 121 | 122 | # ---------------------------------------------------------------------------- # 123 | 124 | templates = let 125 | basic.path = ./templates/basic; 126 | basic.description = "a dank starter flake"; 127 | in { 128 | inherit basic; 129 | default = basic; 130 | 131 | basic-with-lib.path = ./templates/basic-with-lib; 132 | basic-with-lib.description = "a dank starter flake with lib extensions"; 133 | 134 | meaty.path = ./templates/meaty; 135 | meaty.description = "a meaty starter flake"; 136 | 137 | basic-pkg.path = ./templates/basic-pkg; 138 | basic-pkg.description = "a basic GNU build system package"; 139 | 140 | autotools.path = ./templates/autotools; 141 | autotools.description = "a basic autotools project"; 142 | 143 | lib-sub.path = ./templates/lib-sub; 144 | lib-sub.description = "a sub library file"; 145 | 146 | tests.path = ./templates/tests; 147 | tests.description = "a test harness for Nix expressions and drvs"; 148 | 149 | tests-sub.path = ./templates/tests-sub; 150 | tests-sub.description = "a subset of tests for the `ak-nix' Test harness"; 151 | 152 | nix-plugin.path = ./templates/nix-plugin; 153 | nix-plugin.description = "a nix plugin with wrapper executable"; 154 | 155 | nix-bin.path = ./templates/nix-bin; 156 | nix-bin.description = "an executable which uses nix libraries"; 157 | }; 158 | 159 | 160 | # ---------------------------------------------------------------------------- # 161 | 162 | }; # End Outputs 163 | 164 | # ---------------------------------------------------------------------------- # 165 | 166 | } 167 | 168 | # ---------------------------------------------------------------------------- # 169 | # 170 | # 171 | # 172 | # ============================================================================ # 173 | -------------------------------------------------------------------------------- /lib/attrsets.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Example Usage: 4 | # nix-repl> add = curryDefaultSystems' ( system: 5 | # { x, y }: builtins.trace system ( x + y ) ) 6 | # 7 | # nix-repl> add { x = 1; y = 2; } 8 | # { __functor = ; 9 | # aarch64-darwin = 3; trace: aarch64-darwin 10 | # aarch64-linux = 3; trace: aarch64-linux 11 | # i686-linux = 3; trace: i686-linux 12 | # x86_64-darwin = 3; trace: x86_64-darwin 13 | # x86_64-linux = 3; trace: x86_64-linux 14 | # } 15 | # 16 | # nix-repl> ( add { x = 1; y = 2; } ) "x86_64-linux" 17 | # trace: x86_64-linux 18 | # 3 19 | # 20 | # 21 | # ---------------------------------------------------------------------------- # 22 | 23 | { lib }: let 24 | 25 | yt = lib.ytypes // lib.ytypes.Core // lib.ytypes.Prim; 26 | 27 | # ---------------------------------------------------------------------------- # 28 | 29 | # Apply `fn' to each `system', forming an attrset keyed by system names. 30 | eachSystemMap = systems: fn: 31 | builtins.foldl' ( acc: sys: acc // { ${sys} = fn sys; } ) {} systems; 32 | 33 | eachDefaultSystemMap = eachSystemMap lib.defaultSystems; 34 | 35 | 36 | # ---------------------------------------------------------------------------- # 37 | 38 | pushDownNames = builtins.mapAttrs ( name: val: val // { inherit name; } ); 39 | 40 | 41 | # ---------------------------------------------------------------------------- # 42 | 43 | # Convert an attrset to a list of `{ name : string, value }' pairs. 44 | attrsToList = as: let 45 | inherit (builtins) attrValues mapAttrs; 46 | in attrValues ( mapAttrs ( name: value: { inherit name value; } ) as ); 47 | 48 | 49 | # ---------------------------------------------------------------------------- # 50 | 51 | # Merges an attrset or list of sub-attrsets to a single attrset 52 | joinAttrs = { 53 | __funcitonMeta = { 54 | name = "joinAttrs"; 55 | doc = "Merges an attrset or list of sub-attrsets to a single attrset."; 56 | argc = 1; 57 | argsType = yt.either ( ( yt.list yt.any ) ( yt.attrs yt.any ) ); 58 | returnType = yt.attrs yt.any; 59 | }; 60 | __processArgs = x: if builtins.isList x then x else builtins.attrValues x; 61 | __innerFunction = builtins.foldl' ( a: b: a // b ) {}; 62 | __functor = self: x: self.__innerFunction ( self.__processArgs x ); 63 | }; 64 | 65 | 66 | # ---------------------------------------------------------------------------- # 67 | 68 | # Rename keys in `attrs' using mapping in `kmap : { oldName = newName; ... }'. 69 | # Unmapped keys are not modified. 70 | remapKeys = kmap: attrs: let 71 | proc = acc: key: 72 | acc // { ${kmap.${key} or key} = attrs.${key}; }; 73 | in builtins.foldl' proc ( builtins.attrNames attrs ); 74 | 75 | # Remap keys using function `remap : string -> (string|null)'. 76 | # If remap returns `null' key will not be modified. 77 | remapKeysWith = remap: attrs: let 78 | proc = acc: key: let 79 | r = remap key; 80 | new = if r == null then key else r; 81 | in acc // { ${r} = attrs.${key}; }; 82 | in builtins.foldl' proc {} ( builtins.attrNames attrs ); 83 | 84 | 85 | # ---------------------------------------------------------------------------- # 86 | 87 | # Convert a list of attrs to and attrset keyed using `field'. 88 | listToAttrsBy = field: list: let 89 | proc = acc: value: acc // { ${value.${field}} = value; }; 90 | in builtins.foldl' proc {} list; 91 | 92 | 93 | # ---------------------------------------------------------------------------- # 94 | 95 | # Reduce an attrset using function `op' with prototype where `R' and `T' are 96 | # typenames of "Return" and "From". 97 | # foldAttrs :: ( op : lambda ) -> ( nul : R ) -> ( attrs : { F } ) -> R 98 | # op :: ( acc : R ) -> ( key : string ) -> ( value : F ) -> R 99 | foldAttrsl = op: nul: attrs: let 100 | proc = acc: name: op acc name attrs.${name}; 101 | in builtins.foldl' proc nul ( builtins.attrNames attrs ); 102 | 103 | 104 | # ---------------------------------------------------------------------------- # 105 | 106 | # Parse a string like `foo.bar."baz.quux".fizz."buzz"' to an attrpath, 107 | # ["foo" "bar" "baz.quux" "fizz" "buzz"] 108 | parseAttrPath = str: let 109 | dropEmpty = builtins.filter ( x: x != "" ); 110 | esc = dropEmpty ( builtins.split "\"([^\"]*)\"" str ); 111 | proc = acc: x: 112 | if builtins.isList x then acc ++ x else 113 | acc ++ ( dropEmpty ( lib.splitString "." x ) ); 114 | in builtins.foldl' proc [] esc; 115 | 116 | 117 | # getAttrByStr "foo.\"bar.baz\".quux" { foo."bar.baz".quux = 420; } => 420 118 | getAttrByStr = s: builtins.getAttr ( parseAttrPath s ); 119 | 120 | 121 | # ---------------------------------------------------------------------------- # 122 | 123 | # Filter out equal attrs recursively. 124 | # Returns two top level attrs { _A = { ... }; _B = { ... }; }' containing the 125 | # differing fields found in each attrset. 126 | # 127 | # diffAttrs { x = 1; y = 2; } { x = 1; y = 3; z = 4; } 128 | # => 129 | # { 130 | # _A.y = 2; 131 | # _B = { 132 | # y = 3; 133 | # z = 4; 134 | # }; 135 | # } 136 | diffAttrs = a: b: let 137 | comm = builtins.intersectAttrs a b; 138 | different = lib.filterAttrs ( k: bv: a.${k} != bv ) comm; 139 | proc = acc: k: let 140 | sub = diffAttrs a.${k} b.${k}; 141 | add = if ( builtins.isAttrs b.${k} ) && ( builtins.isAttrs a.${k} ) 142 | then diffAttrs a.${k} b.${k} 143 | else { _A.${k} = a.${k}; _B.${k} = b.${k}; }; 144 | in { _A = ( acc._A or {} ) // add._A; _B = ( acc._B or {} ) // add._B; }; 145 | diff = builtins.foldl' proc {} ( builtins.attrNames different ); 146 | in { 147 | _A = ( removeAttrs a ( builtins.attrNames comm ) ) // ( diff._A or {} ); 148 | _B = ( removeAttrs b ( builtins.attrNames comm ) ) // ( diff._B or {} ); 149 | }; 150 | 151 | 152 | # ---------------------------------------------------------------------------- # 153 | 154 | # Apply functions held in fields of first arg to values of matching fields in 155 | # second arg. 156 | # Unmatched fields in second arg are unmodified. 157 | # 158 | # applyAttrs { x = prev: prev * 2; y = prev: prev / 2; } { x = 1; y = 3; } 159 | # => 160 | # { x = 2; y = 1; } 161 | applyAttrs = fns: set: let 162 | comm = builtins.intersectAttrs fns set; 163 | applied = builtins.mapAttrs ( k: v: fns.${k} v ) comm; 164 | in set // applied; 165 | 166 | 167 | # ---------------------------------------------------------------------------- # 168 | 169 | in { 170 | inherit 171 | pushDownNames 172 | eachSystemMap eachDefaultSystemMap 173 | attrsToList 174 | joinAttrs 175 | remapKeys remapKeysWith 176 | listToAttrsBy 177 | foldAttrsl 178 | parseAttrPath 179 | getAttrByStr 180 | diffAttrs 181 | applyAttrs 182 | ; 183 | } 184 | 185 | 186 | /* ========================================================================== */ 187 | -------------------------------------------------------------------------------- /lib/call-flake-w.nix: -------------------------------------------------------------------------------- 1 | # XXX: This basically overlaps with `./attrs.nix:callFlake' except this uses 2 | # the upstream implementation in Nix. 3 | # It may not actually make sense to expose both but I'm doing it for now to 4 | # experiment with them. 5 | { nix ? builtins.getFlake "github:NixOS/nix/master" }: 6 | let 7 | 8 | /** 9 | * This is the "raw" form of `builtins.getFlake'. 10 | * This can be useful if you are creating a fake lockfile. 11 | * Notice that the "inner" `_raw' function accepts the lockfile as a JSON 12 | * string rather than a path. 13 | * 14 | * callFlake { lock = ./flake.lock; root = ./.; } 15 | */ 16 | callSubFlake = let subDir = s: if s == "" || s == null then "" else "${s}/"; 17 | in { 18 | lock ? "${root}/${subDir subdir}flake.lock" 19 | , root ? ( toString ./. ) 20 | , subdir ? "" 21 | } @ args: let 22 | inherit (builtins) substring readFile pathExists; 23 | lockFileStr = 24 | if isPath lock then readFile lock else 25 | if isString lock && pathExists lock then readFile lock else 26 | if isAttrs lock && lock ? outPath then readFile ( toString lock ) else 27 | lock; 28 | 29 | rootSrc = if isAttrs root && root ? narHash then root else 30 | builtins.fetchTree { type = "path"; path = toString root; }; 31 | 32 | _raw = import "${nix}/src/libexpr/flake/call-flake.nix"; 33 | in _raw lockFileStr rootSrc subdir; 34 | 35 | in callSubFlake 36 | 37 | /** 38 | * Included for reference, this is obviously subject to change, which is 39 | * why I'm importing from `nix' upstream above. 40 | * Presumably if/when they change `call-flake.nix' there this should break. 41 | 42 | # nix/src/libexpr/flake/call-flake.nix 43 | lockFileStr: rootSrc: rootSubdir: 44 | 45 | let 46 | 47 | lockFile = builtins.fromJSON lockFileStr; 48 | 49 | allNodes = 50 | builtins.mapAttrs 51 | (key: node: 52 | let 53 | 54 | sourceInfo = 55 | if key == lockFile.root 56 | then rootSrc 57 | else fetchTree (node.info or {} // removeAttrs node.locked ["dir"]); 58 | 59 | subdir = if key == lockFile.root then rootSubdir else node.locked.dir or ""; 60 | 61 | flake = import (sourceInfo + (if subdir != "" then "/" else "") + subdir + "/flake.nix"); 62 | 63 | inputs = builtins.mapAttrs 64 | (inputName: inputSpec: allNodes.${resolveInput inputSpec}) 65 | (node.inputs or {}); 66 | 67 | # Resolve a input spec into a node name. An input spec is 68 | # either a node name, or a 'follows' path from the root 69 | # node. 70 | resolveInput = inputSpec: 71 | if builtins.isList inputSpec 72 | then getInputByPath lockFile.root inputSpec 73 | else inputSpec; 74 | 75 | # Follow an input path (e.g. ["dwarffs" "nixpkgs"]) from the 76 | # root node, returning the final node. 77 | getInputByPath = nodeName: path: 78 | if path == [] 79 | then nodeName 80 | else 81 | getInputByPath 82 | # Since this could be a 'follows' input, call resolveInput. 83 | (resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path}) 84 | (builtins.tail path); 85 | 86 | outputs = flake.outputs (inputs // { self = result; }); 87 | 88 | result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; }; 89 | in 90 | if node.flake or true then 91 | assert builtins.isFunction flake.outputs; 92 | result 93 | else 94 | sourceInfo 95 | ) 96 | lockFile.nodes; 97 | 98 | in allNodes.${lockFile.root} 99 | 100 | */ 101 | -------------------------------------------------------------------------------- /lib/debug.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | 3 | let 4 | 5 | inherit (lib) runTests; # From Nixpkgs 6 | 7 | # ---------------------------------------------------------------------------- # 8 | 9 | # Given output from `nixpkgs.lib.runTests', use `trace' to print information 10 | # about failed test cases. 11 | report' = trace: { name, expected, result } @ test: let 12 | msg = '' 13 | Test ${name} Failure: Expectation did not match result. 14 | expected: ${lib.generators.toPretty {} expected} 15 | result: ${lib.generators.toPretty {} result} 16 | ''; 17 | in trace msg test; 18 | 19 | report = report' builtins.trace; 20 | 21 | 22 | # ---------------------------------------------------------------------------- # 23 | 24 | # Tests are considered "passed" if `runner' returns an empty list, and I 25 | # recommend using `nixpkgs.lib.runTests' here. 26 | # I have left `runner' as an argument to allow users to provide a customized 27 | # test runtime.` 28 | # NOTE: `run' is a list of "evaluated" test cases which failed. 29 | # They have the fields `{ name, expected, result }'. 30 | 31 | # Returns true/false 32 | checkerDefault = name: run: 33 | ( map ( t: ( t.result == t.expected ) || ( report t ) ) run ) == []; 34 | 35 | # Returns PASS/FAIL with test-suite name. 36 | checkerMsg = name: run: 37 | if run == [] then "PASS: ${name}" else "FAIL: ${name}"; 38 | 39 | # Runs tests with tracing, ends in an assertion, return `true' if it survives. 40 | # This is the only checker where `doTrace' makes sense, because without it 41 | # the assertion can kill you before the user sees output. 42 | checkerEvalAssert' = doTrace: name: run: let 43 | rsl = checkerDefault name run; 44 | msg = checkerMsg name run; 45 | rsl' = if doTrace then builtins.deepSeq ( builtins.trace msg ) rsl else rsl; 46 | in assert rsl'; rsl'; 47 | 48 | checkerEvalAssert = checkerEvalAssert' true; 49 | 50 | checkerReport = name: run: let 51 | # A phony runner used to capture report messages. 52 | msgs = [( checkerMsg name run )] ++ ( map ( report' ( x: _: x ) ) run ); 53 | msg = " " + ( builtins.concatStringsSep "\n " msgs ); 54 | # The real runner. 55 | rsl = checkerDefault name run; 56 | in if rsl then "PASS: ${name}" else "FAIL: ${name}" + msg; 57 | 58 | # Produce a dummy output if `check' succeeds. 59 | # I recommend passing the output of `checker' as the argument `check'.` 60 | # NOTE: This is largely here for reference, and as a nice starter. 61 | # You'll notice below in `mkTestHarness' I call `writeText' directly so that 62 | # I can change the name of the output file; but for the convenience of users 63 | # I've offered up this dinky wrapper. 64 | mkCheckerDrv = { 65 | name ? "test" 66 | , keepFailed ? false 67 | , check 68 | , writeText 69 | }: ( writeText "${name}.log" check ).overrideAttrs ( _: _: { 70 | checkPhase = '' 71 | if grep -q "^FAIL: " "$out"; then 72 | cat "$out"; 73 | cat "$out" >&2; 74 | ${lib.optionalString ( ! keepFailed ) "exit 1;"} 75 | fi 76 | ''; 77 | } ); 78 | 79 | 80 | # ---------------------------------------------------------------------------- # 81 | 82 | /** 83 | * `mkTestHarness' extends original arguments with `run', `check', and 84 | * ( maybe ) `checkDrv' with a `__functor' alias ( for `nix build' 85 | * to auto-call ). 86 | * The use case for this is in a `flake.nix' or `default.nix' where you want 87 | * to handle batches of `tests.nix' style files with attrsets of tests with 88 | * a general purpose harness. 89 | * A preferable approach is to use the template `ak-nix.templates.nix-tests' 90 | * which provides more purpose built files for specific use cases such as 91 | * `nix repl', `nix eval', and `nix build'; but `mkTestHarness' is nice for 92 | * when you're feeling lazy. 93 | * 94 | * `run' simply evaluates `test' case pairs using `lib.runTests' 95 | * returning a list of test cases where `expr' did not match `expected'. 96 | * This is "really" the function you'll want to use for interactive 97 | * development, and notably it does NOT require any Nixpkgs references. 98 | * If you really just want `run' you can pass in `withDrv = false' and/or 99 | * remove `writeText' from your test file entirely. 100 | * Later on if you want to add the `checkDrv' you can use 101 | * `harness' = harness.addCheckDrv pkgs.writeText;' to make it 102 | * available lazily ( I recommend this approach for tests which are 103 | * purely Nix expressions with no dependencies outside of `lib' ). 104 | * 105 | * `check' invokes `run' and forces deep-evaluation, printing `trace' 106 | * output and uses `assert' to enforce that all tests MUST pass. 107 | * This is intended for use with a CI system or `nix flake check', where 108 | * you really just want an exit status of 0/1 for a set of tests. 109 | * This is not a particularly useful function for iterative development, 110 | * for which I recommend using `run' directly. 111 | * 112 | * Finally you've got `checkDrv' which simply runs `check' and writes a 113 | * dummy derivation output when they succeed. 114 | * This just exists so you can call `nix build -f ./tests.nix' or add 115 | * Nix expressions checks to CI/Hydra jobs. 116 | * Again, not particularly useful for interactive dev. 117 | */ 118 | mkTestHarness = { 119 | name ? "tests" 120 | , tests 121 | , runner ? lib.runTests 122 | , run ? runner tests 123 | , checker ? checkerReport 124 | , check ? checker name run 125 | , keepFailed ? false 126 | , mkCheckerDrv ? lib.libdbg.mkCheckerDrv 127 | , writeText ? throw "(mkTestHarnedd:${name}): You much provide writeText" 128 | , ... 129 | } @ args: 130 | assert builtins.isAttrs tests; let 131 | # Additional args get passed through to be members of output attrset. 132 | extraArgs = let 133 | needArgs = lib.functionArgs mkTestHarness; 134 | in removeAttrs args ( builtins.attrNames needArgs ); 135 | # Minimum args needed by `mkCheckerDrv' 136 | args' = { inherit name check; } // args; 137 | mkCheckerDrv' = lib.callPackageWith args' mkCheckerDrv; 138 | # A functor that overrides itself, adding `writeText' to the callWith. 139 | # This allows you to inject it later in a call pipeline which can be 140 | # convenient for flakes. 141 | # If `writeText' was already given it's just the `checkDrv' call.` 142 | funk = if args ? writeText then { 143 | checkDrv = mkCheckerDrv' {}; 144 | __functor = self: mkCheckerDrv'; 145 | } else { 146 | __functor = self: x: if builtins.isFunction x then self // { 147 | checkDrv = mkCheckerDrv' { writeText = x; }; 148 | __functor = self: let 149 | nuargs = args' // { writeText = x; }; 150 | in lib.makeCallPackagesWith nuargs mkCheckerDrv; 151 | } else mkCheckerDrv' x; 152 | }; 153 | in extraArgs // { inherit name run check tests; } // funk; 154 | 155 | 156 | # ---------------------------------------------------------------------------- # 157 | 158 | in { 159 | inherit 160 | report' 161 | report 162 | checkerDefault 163 | checkerMsg 164 | checkerReport 165 | checkerEvalAssert' 166 | checkerEvalAssert 167 | mkCheckerDrv 168 | mkTestHarness 169 | ; 170 | } // lib.debug 171 | -------------------------------------------------------------------------------- /lib/default.nix: -------------------------------------------------------------------------------- 1 | { lib ? ( builtins.getFlake "github:NixOS/nixpkgs?dir=lib" ).lib }: 2 | lib.extend ( import ./overlay.lib.nix ) 3 | -------------------------------------------------------------------------------- /lib/filesystem.nix: -------------------------------------------------------------------------------- 1 | _: let 2 | 3 | inherit (builtins) head split readDir substring stringLength filter; 4 | 5 | # ---------------------------------------------------------------------------- # 6 | 7 | baseName = p: let 8 | isBaseName = mb: ( baseNameOf mb ) == mb; 9 | isNixStorePath = nsp: let 10 | prefix = "/nix/store/"; 11 | plen = stringLength prefix; 12 | in prefix == ( substring 0 plen ( toString nsp ) ); 13 | removeNixStorePrefix = nsp: let 14 | m = builtins.match "/nix/store/[^-]+-(.*)" ( toString nsp ); 15 | in if m == null then nsp else ( head m ); 16 | in baseNameOf ( removeNixStorePrefix p ); 17 | 18 | baseName' = p: builtins.unsafeDiscardStringContext ( baseName p ); 19 | 20 | baseNameOfDropExt = p: head ( split "\\." ( baseName p ) ); 21 | baseNameOfDropExt' = p: head ( split "\\." ( baseName' p ) ); 22 | 23 | 24 | # ---------------------------------------------------------------------------- # 25 | 26 | listSubdirs = dir: let 27 | proc = name: type: 28 | if type == "directory" then toString ( dir + "/${name}" ) else null; 29 | inodes = builtins.readDir dir; 30 | ents = builtins.attrValues ( builtins.mapAttrs proc inodes ); 31 | in builtins.filter ( x: x != null ) ents; 32 | 33 | listFiles = dir: let 34 | proc = name: type: 35 | if type == "directory" then null else toString ( dir + "/${name}" ); 36 | inodes = builtins.readDir dir; 37 | ents = builtins.attrValues ( builtins.mapAttrs proc inodes ); 38 | in builtins.filter ( x: x != null ) ents; 39 | 40 | listDir = dir: let 41 | inodes = builtins.readDir dir; 42 | in map ( name: toString ( dir + "/${name}" ) ) ( builtins.attrNames inodes ); 43 | 44 | 45 | # ---------------------------------------------------------------------------- # 46 | 47 | mapSubdirs = fn: dir: map fn ( listSubdirs dir ); 48 | 49 | listDirsRecursive = dir: let 50 | dirs = listSubdirs dir; 51 | in builtins.foldl' ( acc: d: acc ++ ( listDirsRecursive d ) ) dirs dirs; 52 | 53 | 54 | # ---------------------------------------------------------------------------- # 55 | 56 | findFileWithSuffix = dir: sfx: let 57 | slen = stringLength sfx; 58 | suffstring = l: str: let 59 | sl = stringLength str; 60 | in substring ( sl - l ) sl str; 61 | hasSfx = s: 62 | ( slen <= ( stringLength s ) ) && ( suffstring slen s ) == sfx; 63 | matches = filter hasSfx ( builtins.attrNames ( readDir dir ) ); 64 | in "${toString dir}/${head matches}"; 65 | 66 | 67 | # ---------------------------------------------------------------------------- # 68 | in { 69 | inherit 70 | baseName 71 | baseName' 72 | baseNameOfDropExt 73 | baseNameOfDropExt' 74 | listSubdirs 75 | listFiles 76 | listDir 77 | mapSubdirs 78 | listDirsRecursive 79 | findFileWithSuffix 80 | ; 81 | } 82 | -------------------------------------------------------------------------------- /lib/filt.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | genericFilt = name: type: let 12 | bname = baseNameOf name; 13 | ignoreDirs = [".Trashes" ".direnv" ".git"]; 14 | ignoreDirsP = []; 15 | dirPred = let 16 | exact = builtins.elem bname ignoreDirs; 17 | match = builtins.any ( patt: lib.test patt bname ) ignoreDirsP; 18 | in assert type == "directory"; ! ( exact || match ); 19 | ignoreFiles = [ 20 | "result" ".DS_Store" ".envrc" ".eslintcache" ".gitconfig" ".gitignore" 21 | ]; 22 | ignoreFilesP = [".*~" "\\._.*" ".*\\.(tgz|tar(\\.gz)?)" "result-.*"]; 23 | filePred = let 24 | exact = builtins.elem bname ignoreFiles; 25 | match = builtins.any ( patt: lib.test patt bname ) ignoreFilesP; 26 | in assert type != "directory"; ! ( exact || match ); 27 | in if ( type == "directory" ) then dirPred else filePred; 28 | 29 | 30 | # ---------------------------------------------------------------------------- # 31 | 32 | nixFilt' = name: type: let 33 | bname = baseNameOf name; 34 | in ( bname != "flake.lock" ) && 35 | ( ! ( lib.test ".*\\.nix" name ) ); 36 | 37 | nixFilt = name: type: ( genericFilt name type ) && ( nixFilt' name type ); 38 | 39 | 40 | # ---------------------------------------------------------------------------- # 41 | 42 | in { 43 | inherit 44 | genericFilt 45 | nixFilt' 46 | nixFilt 47 | ; 48 | } 49 | 50 | 51 | # ---------------------------------------------------------------------------- # 52 | # 53 | # 54 | # 55 | # ============================================================================ # 56 | -------------------------------------------------------------------------------- /lib/flake-registry.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Reference Flake Registry in Nix expressions ( Impure ). 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | registries' = { ... } @ lazy: let 12 | paths = { 13 | # NOTE: The global registry may be different if the user provided CLI args 14 | # or settings in `nix.conf'. 15 | # This is the default registry. 16 | global = let 17 | repo = builtins.fetchTree { 18 | type = "git"; 19 | url = "https://github.com/NixOS/flake-registry"; 20 | }; 21 | in "${repo}/flake-registry.json"; 22 | system = "${lib.nixEnvVars.NIX_CONF_DIR}/registry.json"; 23 | user = "${lib.nixEnvVars._NIX_USER_CONF_DIR}/registry.json"; 24 | }; 25 | fileExists = path: 26 | ( ! lib.inPureEvalMode ) && ( builtins.pathExists path ); 27 | getReg = path: if ! fileExists path then {} else 28 | builtins.fromJSON ( builtins.readFile path ); 29 | in builtins.mapAttrs ( _: getReg ) paths; 30 | 31 | 32 | # ---------------------------------------------------------------------------- # 33 | 34 | lookupFlakeIn = { flakes ? [], ... } @ reg: id: let 35 | flt = builtins.filter ( { from, ... }: from.id == id ) flakes; 36 | in if ( builtins.length flt ) < 1 then null else builtins.head flt; 37 | 38 | lookupFlake = id: let 39 | registries = registries' {}; 40 | u = lookupFlakeIn registries.user id; 41 | s = lookupFlakeIn registries.system id; 42 | g = lookupFlakeIn registries.global id; 43 | in if u != null then u else if s != null then s else g; 44 | 45 | 46 | # ---------------------------------------------------------------------------- # 47 | 48 | registryFlakeRefs' = { ... } @ lazy: let 49 | registries = registries' {}; 50 | flakes = ( registries.global.flakes or [] ) ++ 51 | ( registries.system.flakes or [] ) ++ 52 | ( registries.user.flakes or [] ); 53 | asAttrs = { from, to }: { 54 | name = if from ? ref then "${from.id}/${from.ref}" else from.id; 55 | value = to; 56 | }; 57 | in builtins.listToAttrs ( map asAttrs flakes ); 58 | 59 | # The real trees produced by flakes have no indication of `dir' in 60 | # their fields. 61 | # The only way you can tell is literally to poke around with `readDir'. 62 | # Here we just take our original args addin `outPath' and `sourceInfo'. 63 | # 64 | # FIXME: follow indirect -> indirect -> ... -> real 65 | registryFlakeTrees' = { ... } @ lazy: let 66 | # XXX: this preserves `dir' at top level. 67 | ftf = _: fra: let 68 | sourceInfo = builtins.fetchTree ( removeAttrs fra ["dir"] ); 69 | in fra // { inherit sourceInfo; inherit (sourceInfo) outPath; }; 70 | in builtins.mapAttrs ftf ( registryFlakeRefs' {} ); 71 | 72 | 73 | # ---------------------------------------------------------------------------- # 74 | 75 | toValue = x: let 76 | members = let 77 | fallback = if x ? val then {} else 78 | lib.filterAttrs ( k: v: ! ( lib.hasPrefix "__" k ) ) x; 79 | in x.members or fallback; 80 | val = x.val or ( lib.mapAttrs ( _: toValue ) members ); 81 | in if ! ( builtins.isAttrs x ) then x else 82 | if x ? __toValue then x.__toValue x else 83 | val; 84 | 85 | 86 | # ---------------------------------------------------------------------------- # 87 | 88 | inherit (lib.generators) toPretty; 89 | 90 | # ---------------------------------------------------------------------------- # 91 | 92 | # NOTE: Options have subtypes that can be inferred from their `name' field. 93 | typeOf = x: let 94 | fromBuiltin = builtins.typeOf x; 95 | fromString = 96 | if lib.isStorePath then "store-path" else 97 | if builtins.hasContext then "string-with-context" else 98 | fromBuiltin; 99 | fromAttrs = x._type or ( 100 | if lib.isDerivation x then "derivation" else 101 | if lib.isFunction x then "function" else # Distinct from "lambda" 102 | fromBuiltin 103 | ); 104 | in if fromBuiltin == "string" then fromString else 105 | if fromBuiltin == "set" then fromAttrs else 106 | fromBuiltin; 107 | 108 | 109 | # ---------------------------------------------------------------------------- # 110 | 111 | defToPretty' = { 112 | _type ? lib.typeOf attrs 113 | , __toPretty ? self: { 114 | val = toValue self; 115 | __pretty = toPretty { allowPrettyValues = true; }; 116 | } 117 | , ... 118 | } @ attrs: attrs // { inherit __toPretty _type; }; 119 | 120 | defToPretty = { 121 | # FIXME: fill rest of `__functionMeta'. 122 | __functionMeta.argTypes = ["anything"]; 123 | __functionArgs = lib.functionArgs defToPretty'; 124 | __functor = self: x: 125 | if builtins.isAttrs x then defToPretty' x else defToPretty' { 126 | _type = typeOf x; 127 | val = x; 128 | }; 129 | }; 130 | 131 | 132 | # ---------------------------------------------------------------------------- # 133 | 134 | # FIXME: For options you can use their `show' member function. 135 | toPrettyV = x: 136 | if ( x ? __pretty ) && ( x ? val ) then { inherit (x) __pretty val; } else 137 | if x ? __toPretty then x.__toPretty x else 138 | toPrettyV ( defToPretty x ); 139 | 140 | # ---------------------------------------------------------------------------- # 141 | 142 | mkIndirectFlakeRef = x: let 143 | fromAttrs = { id, ref ? null, ... } @ ent: defToPretty' { 144 | _type = "flake-ref"; 145 | __toString = self: let 146 | v = toValue self; 147 | in if self ? val.ref then "${v.id}/${v.ref}" else v.id; 148 | __toValue = self: self.val; 149 | val = { 150 | type = "indirect"; 151 | inherit id; 152 | } // ( lib.optionalAttrs ( ref != null ) { inherit ref; } ); 153 | }; 154 | parse = str: let 155 | m = builtins.match "([^/]+)(/([^/]+))?" str; 156 | ref = builtins.elemAt m 2; 157 | in fromAttrs { id = builtins.head m; inherit ref; }; 158 | in assert ( builtins.isAttrs x ) || ( builtins.isString x ); 159 | if builtins.isString x then parse x else 160 | if lib.isType "flake-ref" x then x else 161 | fromAttrs x; 162 | 163 | 164 | mkFlakeRegistryAlias = { from, to }: 165 | defToPretty' { 166 | _type = "flake-registry-entry"; 167 | __toString = self: let 168 | v = self.members; 169 | in "${toString v.from} -> ${toString v.to}"; 170 | __toValue = self: builtins.mapAttrs toValue self.members; 171 | members.from = mkIndirectFlakeRef from; 172 | members.to = mkIndirectFlakeRef to; 173 | }; 174 | 175 | 176 | 177 | # ---------------------------------------------------------------------------- # 178 | 179 | in { 180 | 181 | inherit 182 | toValue 183 | toPrettyV 184 | typeOf 185 | defToPretty 186 | 187 | mkIndirectFlakeRef 188 | mkFlakeRegistryAlias 189 | lookupFlakeIn 190 | ; 191 | 192 | } // ( lib.optionalAttrs ( ! lib.inPureEvalMode ) { 193 | 194 | inherit 195 | lookupFlake 196 | registries' 197 | registryFlakeRefs' 198 | registryFlakeTrees' 199 | ; 200 | 201 | } ) 202 | 203 | 204 | # ---------------------------------------------------------------------------- # 205 | # 206 | # 207 | # 208 | # ============================================================================ # 209 | -------------------------------------------------------------------------------- /lib/flake-utils.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | # Like `callPackageWith' but for flakes. 12 | # This allows you to stash a "thunk" of auto-called args, and pass overrides 13 | # at the end. 14 | # 15 | # An example of re-calling `ak-nix' flake from some other flake 16 | # using the inputs of the caller "self" as a base, then overriding `nixpkgs' 17 | # to make `ak-nix' follow one of our inputs' instance. 18 | # ak-nix-custom = callFlakeWith self.inputs self { 19 | # nixpkgs = self.inputs.bar.inputs.nixpkgs; 20 | # }; 21 | # 22 | # Also try calling with your registries ( see [[file:./flake-registry.nix]] ): 23 | # let 24 | # reg = builtins.mapAttrs ( _: builtins.fetchTree ) 25 | # lib.libflake.registryFlakeRefs; 26 | # foo = lib.callFlakeWith reg reg.foo { 27 | # bar = builtins.getFlake "/some/dir/bar"; 28 | # }; 29 | # in foo.packages.default 30 | callFlakeWith = auto: refOrDir: extraArgs: let 31 | ftSrc = builtins.fetchTree ( removeAttrs refOrDir ["dir"] ); 32 | fromFt = if refOrDir ? dir then ftSrc + "/${refOrDir.dir}" else ftSrc; 33 | flakeDir = 34 | if lib.isStorePath refOrDir then refOrDir else 35 | if lib.isCoercibleToPath refOrDir then refOrDir else 36 | if builtins.isAttrs refOrDir then fromFt else 37 | throw "This doesn't look like a path"; 38 | flake = import ( flakeDir + "/flake.nix" ); 39 | inputs = let 40 | lock = lib.importJSONOr { nodes = {}; } ( flakeDir + "/flake.lock" ); 41 | locked = builtins.mapAttrs ( id: fetchInput ) lock.nodes; 42 | stdArgs = locked // auto // { inherit self; }; 43 | fetchInput = { locked, ... }: builtins.fetchTree locked; 44 | in lib.canPassStrict flake.outputs stdArgs; 45 | self = flake // ( flake.outputs ( inputs // extraArgs ) ); 46 | in self; 47 | 48 | 49 | # ---------------------------------------------------------------------------- # 50 | 51 | # Non-flake inputs don't contain a `sourceInfo' field, because they are the 52 | # `sourceInfo' record itself. 53 | # This allows us to detect which inputs are flakes and which arent. 54 | # The alternative approach is importing your own lock and scraping for the 55 | # field `flake = ' in the nodes which is a pain in the ass. 56 | inputIsFlake = input: assert input ? narHash; 57 | input ? sourceInfo; 58 | 59 | 60 | # ---------------------------------------------------------------------------- # 61 | 62 | in { 63 | inherit 64 | callFlakeWith 65 | inputIsFlake 66 | ; 67 | 68 | callFlake = callFlakeWith {}; 69 | 70 | } # End `attrsets.nix' 71 | 72 | 73 | /* ========================================================================== */ 74 | -------------------------------------------------------------------------------- /lib/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 0, 6 | "narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=", 7 | "path": "/nix/store/lwyjz70qh12nq6cb7fixl85vryzxqm3c-source", 8 | "type": "path" 9 | }, 10 | "original": { 11 | "id": "nixpkgs", 12 | "type": "indirect" 13 | } 14 | }, 15 | "root": { 16 | "inputs": { 17 | "nixpkgs": "nixpkgs" 18 | } 19 | } 20 | }, 21 | "root": "root", 22 | "version": 7 23 | } 24 | -------------------------------------------------------------------------------- /lib/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Nixpkgs lib extension"; 3 | outputs = { nixpkgs, ... }: { 4 | lib = nixpkgs.lib.extend ( import ./overlay.lib.nix ); 5 | }; 6 | } 7 | -------------------------------------------------------------------------------- /lib/json.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | # This wipes out any C style comments in JSON files that were written by 12 | # sub-humans that cannot abide by simple file format specifications. 13 | # Later this function will be revised to schedule chron jobs which send 14 | # daily emails to offending projects' authors - recommending various 15 | # re-education programs they may enroll in. 16 | importJSON' = file: let 17 | f = lib.libstr.removeSlashSlashComments ( builtins.readFile file ); 18 | in builtins.fromJSON f; 19 | 20 | 21 | # ---------------------------------------------------------------------------- # 22 | 23 | importJSONOr = fallback: file: 24 | if lib.inPureEvalMode then fallback else 25 | if builtins.pathExists file then lib.importJSON file else fallback; 26 | 27 | importJSONOr' = fallback: file: 28 | if lib.inPureEvalMode then fallback else 29 | if builtins.pathExists file then lib.importJSON' file else fallback; 30 | 31 | 32 | # ---------------------------------------------------------------------------- # 33 | 34 | in { 35 | inherit 36 | importJSON' 37 | importJSONOr 38 | importJSONOr' 39 | ; 40 | } 41 | 42 | # ---------------------------------------------------------------------------- # 43 | # 44 | # 45 | # 46 | # ============================================================================ # 47 | -------------------------------------------------------------------------------- /lib/lists.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | # This could also be done with a functor: 12 | # let adder = { x = 0; __functor = self: x: self // { x = self.x + x; }; }; 13 | # in ( builtins.foldl' ( acc: acc ) adder [1 2 3] ).rsl 14 | takeUntil = cond: lst: let 15 | proc = { rsl, done } @ acc: x: 16 | if acc.done then acc else 17 | if cond x then acc // { done = true; } else 18 | acc // { rsl = rsl ++ [x]; }; 19 | in ( builtins.foldl' proc { done = false; rsl = []; } lst ).rsl; 20 | 21 | 22 | dropAfter = cond: lst: let 23 | proc = { rsl, done } @ acc: x: 24 | if done then acc else 25 | if cond x then { rsl = rsl ++ [x]; done = true; } else 26 | { rsl = rsl ++ [x]; done = false; }; 27 | in ( builtins.foldl' proc { rsl = []; done = false; } lst ).rsl; 28 | 29 | 30 | # ---------------------------------------------------------------------------- # 31 | 32 | dropUntil = cond: lst: let 33 | proc = { rsl, start } @ acc: x: 34 | if start then acc // { rsl = rsl ++ [x]; } else 35 | if cond x then { start = true; rsl = [x]; } else 36 | acc; 37 | in ( builtins.foldl' proc { start = false; rsl = []; } lst ).rsl; 38 | 39 | 40 | takeAfter = cond: lst: let 41 | rsl = dropUntil cond lst; 42 | in if rsl == [] then [] else builtins.tail rsl; 43 | 44 | 45 | # ---------------------------------------------------------------------------- # 46 | 47 | commonPrefix = a: b: let 48 | alen = builtins.length a; 49 | blen = builtins.length b; 50 | maxLen = if alen < blen then alen else blen; 51 | a' = lib.take maxLen a; 52 | b' = lib.take maxLen b; 53 | idxList = builtins.genList ( x: x ) maxLen; 54 | proc = i: ( builtins.elemAt a' i ) != ( builtins.elemAt b' i ); 55 | commons = takeUntil proc idxList; 56 | in lib.take ( builtins.length commons ) a'; 57 | 58 | 59 | commonSuffix = a: b: 60 | lib.reverseList ( commonPrefix ( lib.reverseList a ) 61 | ( lib.reverseList b ) ); 62 | 63 | 64 | # ---------------------------------------------------------------------------- # 65 | 66 | # Map Non-Nulls 67 | mapNoNulls = f: xs: 68 | map f ( builtins.filter ( x: x != null ) xs ); 69 | 70 | # Sieve Non-Nulls from Mapped 71 | mapDropNulls = f: xs: 72 | builtins.filter ( x: x != null ) ( map f xs ); 73 | 74 | 75 | # ---------------------------------------------------------------------------- # 76 | 77 | in { 78 | inherit 79 | takeUntil 80 | dropAfter 81 | dropUntil 82 | takeAfter 83 | commonPrefix 84 | commonSuffix 85 | mapNoNulls 86 | mapDropNulls 87 | ; 88 | } 89 | 90 | 91 | # ---------------------------------------------------------------------------- # 92 | # 93 | # 94 | # 95 | # ============================================================================ # 96 | -------------------------------------------------------------------------------- /lib/overlay.lib.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Overlays Nixpkgs' `lib' adding new sublibs. 4 | # Additionally this initializes a "core" set of YANTS types: `ytypes'. 5 | # 6 | # ---------------------------------------------------------------------------- # 7 | 8 | final: prev: let 9 | 10 | # ---------------------------------------------------------------------------- # 11 | 12 | # Partitions libraries into `{ fns, doc }' fields separating any `__doc__*' 13 | # members from real functions. 14 | processDocs = sublib: let 15 | isDocKey = k: ( builtins.match "__docs?__" k ) != null; 16 | isDocAttr = k: _: isDocKey k; 17 | part = { doc, fns } @ acc: name: let 18 | isDoc = isDocAttr name sublib.${name}; 19 | # Detect typos 20 | in assert ! ( isDocKey name ); { 21 | doc = if isDoc then doc // { ${name} = sublib.${name}; } else doc; 22 | fns = if ! isDoc then fns // { ${name} = sublib.${name}; } else fns; 23 | }; 24 | in builtins.foldl' part { doc = {}; fns = {}; } 25 | ( builtins.attrNames sublib ); 26 | 27 | # Full post-processing for sublibs 28 | scrubLib = sublib: let 29 | noDocs = ( processDocs sublib ).fns; 30 | in noDocs; 31 | 32 | # NOTE: previously an argument `exportDocs' would add an attribute 33 | # `__docs' which stashed the content produced by `processDocs.docs'. 34 | # When migrating to an overlay this was removed since I lacked a clear way 35 | # to indicate this argument without having it appear in the overlay itself. 36 | 37 | 38 | # ---------------------------------------------------------------------------- # 39 | 40 | callLibWith = { lib ? final, ... } @ auto: x: let 41 | f = if lib.isFunction x then x else import x; 42 | args = builtins.intersectAttrs ( builtins.functionArgs f ) 43 | ( { inherit lib; } // auto ); 44 | in scrubLib ( f args ); 45 | 46 | callLib = callLibWith {}; 47 | callLibsWith = auto: 48 | builtins.foldl' ( acc: x: acc // ( callLibWith auto x ) ) {}; 49 | callLibs = callLibsWith {}; 50 | 51 | 52 | # ---------------------------------------------------------------------------- # 53 | 54 | # Backport missing `lib.inPureEvalMode' 55 | # NOTE: only injected if missing so `pos' isn't disturbed. 56 | backport.inPureEvalMode = ! ( builtins ? currentSystem ); 57 | 58 | backportFns = let 59 | proc = acc: fname: 60 | if prev ? ${fname} then acc else acc // { ${fname} = backport.${fname}; }; 61 | in builtins.foldl' proc {} ( builtins.attrNames backport ); 62 | 63 | 64 | # ---------------------------------------------------------------------------- # 65 | 66 | in backportFns // { 67 | 68 | # Cribbed from `flake-utils', vendored to skip a redundant fetch. 69 | defaultSystems = [ 70 | "x86_64-linux" "x86_64-darwin" 71 | "aarch64-linux" "aarch64-darwin" 72 | "i686-linux" 73 | ]; 74 | 75 | 76 | # ---------------------------------------------------------------------------- # 77 | 78 | # Import sub-libs 79 | libattrs = callLib ./attrsets.nix; 80 | libpath = callLib ./paths.nix; 81 | libjson = callLib ./json.nix; 82 | libstr = callLib ./strings.nix; 83 | libfs = callLib ./filesystem.nix; 84 | librepl = callLib ./repl.nix; 85 | liblist = callLib ./lists.nix; 86 | libdbg = callLib ./debug.nix; 87 | libtriv = callLib ./trivial.nix; 88 | libenc = callLib ./encode.nix; 89 | libsemver = callLib ./semver.nix; 90 | libfunk = callLibs [./funk.nix ./thunk.nix]; 91 | libflake = callLibs [./flake-registry.nix ./flake-utils.nix]; 92 | libtag = callLib ./tags.nix; 93 | libtypes = callLib ./types.nix; 94 | libfilt = callLib ./filt.nix; 95 | libread = callLib ./safe-reads.nix; 96 | 97 | inherit (final.libread) 98 | readNeedsIFD 99 | readNeedsImpure 100 | readAllowed 101 | runReadOp 102 | ; 103 | 104 | inherit (final.libfilt) 105 | genericFilt 106 | nixFilt 107 | ; 108 | 109 | inherit (final.libattrs) 110 | eachSystemMap 111 | eachDefaultSystemMap 112 | attrsToList 113 | remapKeys 114 | remapKeysWith 115 | listToAttrsBy 116 | foldAttrsl 117 | joinAttrs 118 | diffAttrs 119 | applyAttrs 120 | ; 121 | 122 | inherit (final.libjson) 123 | importJSON' 124 | importJSONOr' 125 | importJSONOr 126 | ; 127 | 128 | inherit (final.libpath) 129 | isAbspath 130 | asAbspath 131 | extSuffix 132 | expandGlob 133 | realpathRel 134 | categorizePath 135 | isCoercibleToPath 136 | coercePath 137 | asDrvRelPath 138 | ; 139 | 140 | inherit (final.libstr) 141 | matchingLines 142 | readLines 143 | charN 144 | coerceString 145 | lines 146 | trim 147 | yank 148 | yankN 149 | test 150 | isTarballUrl 151 | nameFromTarballUrl 152 | ; 153 | 154 | inherit (final.libfs) 155 | baseName' 156 | baseNameOfDropExt' 157 | listSubdirs 158 | listFiles 159 | listDir 160 | findFileWithSuffix 161 | ; 162 | 163 | inherit (final.librepl) 164 | pp ls pwd 165 | show 166 | showPretty 167 | showPrettyArgs 168 | showPrettyAttrNames 169 | showPrettyAttrTypes 170 | showDoc 171 | spp 172 | spa 173 | ; 174 | 175 | inherit (final.liblist) 176 | takeUntil 177 | dropUntil 178 | mapNoNulls 179 | mapDropNulls 180 | ; 181 | 182 | inherit (final.libdbg) 183 | report 184 | checkerReport 185 | mkCheckerDrv 186 | mkTestHarness 187 | ; 188 | 189 | # Other version members are already at `lib' top level from `nixpkgs'. 190 | inherit (final.libtriv) 191 | sortVersions' 192 | sortVersions 193 | latestVersion 194 | withHooks 195 | getEnvOr 196 | nixEnvVars 197 | ; 198 | 199 | inherit (final.libenc) 200 | toHex fromHex 201 | toBase16 fromBase16 202 | toBase32 fromBase32 203 | toBase64 fromBase64 204 | hexToSri 205 | sriFile sri256File sri512File 206 | ; 207 | 208 | inherit (final.libfunk) 209 | currySystems 210 | funkSystems 211 | canPassStrict 212 | canCallStrict 213 | callWith 214 | apply 215 | callWithOvStrict 216 | callWithOvStash 217 | callWithOv 218 | setFunctionArgProcessor setFunkArgProcessor 219 | setFunkMetaField 220 | setFunkProp 221 | setFunkDoc 222 | processArgs 223 | defunk 224 | funkName 225 | ; 226 | 227 | inherit (final.libtag) 228 | discr 229 | discrDef 230 | matchLam 231 | matchTag 232 | tagName 233 | tagValue 234 | ; 235 | 236 | 237 | # ---------------------------------------------------------------------------- # 238 | 239 | ytypes = let 240 | libyants = callLib ./yants.nix; 241 | core = prev.makeExtensible ( ytFinal: { 242 | inherit (libyants) __internal; 243 | inherit (final.libtypes.ytypes) Typeclasses Attrsets; 244 | inherit (final.libfunk.ytypes) Funk; 245 | Strings = final.libstr.ytypes.Strings // ytFinal.Hash.Strings; 246 | Prim = libyants.Prim // final.libtypes.ytypes.Prim; 247 | Hash = final.libenc.ytypes; 248 | Core = libyants.Core // final.libtypes.ytypes.Core; 249 | } ); 250 | in core.extend ( import ../types/overlay.yt.nix ); 251 | 252 | 253 | # ---------------------------------------------------------------------------- # 254 | 255 | } # End Overlay 256 | 257 | 258 | # ---------------------------------------------------------------------------- # 259 | # 260 | # 261 | # 262 | # ============================================================================ # 263 | -------------------------------------------------------------------------------- /lib/repl.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | pp = lib.generators.toPretty { allowPrettyValues = true; }; 12 | 13 | # ---------------------------------------------------------------------------- # 14 | 15 | showList' = printer: xs: let 16 | lines = builtins.concatStringsSep "\n" ( map printer xs ); 17 | in builtins.trace ( "\n" + lines ) ""; 18 | showList = showList' lib.libstr.coerceString; 19 | showListP = showList' ( lst: pp lst ); 20 | 21 | # Uses trace to print arbitrary values to the console. 22 | # If passed a list, each element will be printed on a line. 23 | show = x: showList ( if ( builtins.isList x ) then x else [x] ); 24 | 25 | showPretty = x: showListP ( if ( builtins.isList x ) then x else [x] ); 26 | showPrettyCurried = { 27 | __curr = x: x; 28 | __functor = self: x: let 29 | y = self.__curr x; 30 | in if builtins.isFunction y then self // { __curr = y; } 31 | else showPretty y; 32 | }; 33 | 34 | showPrettyAttrNames = a: showPretty ( builtins.attrNames a ); 35 | showPrettyAttrTypes = a: 36 | showPretty ( builtins.mapAttrs ( _: builtins.typeOf ) a ); 37 | 38 | 39 | # ---------------------------------------------------------------------------- # 40 | 41 | showPrettyArgs = fn: let 42 | args = lib.functionArgs fn; 43 | allBools = builtins.all builtins.isBool ( builtins.attrValues args ); 44 | showOpt = builtins.mapAttrs ( _: v: if v then "Optional" else "Mandatory" ) 45 | args; 46 | in showPretty ( if allBools then showOpt else args ); 47 | 48 | 49 | # ---------------------------------------------------------------------------- # 50 | 51 | pwd' = if lib.inPureEvalMode then null else builtins.getEnv "PWD"; 52 | pwd = if lib.inPureEvalMode then null else ( _: toString ./. ) null; 53 | 54 | 55 | # ---------------------------------------------------------------------------- # 56 | 57 | unGlob = path: 58 | builtins.head ( builtins.split "\\*" ( toString path ) ); 59 | 60 | lsDir' = dir: let 61 | files = lib.listFiles dir; 62 | dirs = lib.listSubdirs dir; 63 | in files ++ ( map ( d: d + "/" ) dirs ); 64 | 65 | # Only handles globs at the end of paths. 66 | lsDirGlob' = path': let 67 | inherit (builtins) substring stringLength split head replaceStrings; 68 | inherit (builtins) concatLists; 69 | path = toString path'; 70 | wasAbs = lib.libpath.isAbspath path; 71 | ng = unGlob path; 72 | dir = if ng == "" then toString ./. else lib.libpath.asAbspath ./. ng; 73 | plen = builtins.stringLength path; 74 | isSGlob = ( 2 <= plen ) && ( substring ( plen - 2 ) plen path ) == "/*"; 75 | isDGlob = ( 3 <= plen ) && ( substring ( plen - 3 ) plen path ) == "/**"; 76 | files = lib.listFiles dir; 77 | subs = concatLists ( lib.libfs.mapSubdirs lib.libfs.listDir dir ); 78 | lines = if isSGlob then ( files ++ subs ) else 79 | if isDGlob then ( lib.filesystem.listFilesRecursive dir ) else 80 | ( lsDir' dir ); 81 | makeRel = lib.libpath.realpathRel' dir; # dir -> path -> rel-path 82 | relLines = if wasAbs then lines else ( map makeRel lines ); 83 | in show relLines; 84 | 85 | 86 | # ---------------------------------------------------------------------------- # 87 | 88 | showDoc = fn: let 89 | loc = "ak-nix#lib.librepl.showDoc"; 90 | in if ! ( fn ? __functionMeta.doc ) 91 | then throw "(${loc}): No doc string defined in `__functionMeta.doc'." 92 | else show "\n${fn.__functionMeta.doc}"; 93 | 94 | 95 | # ---------------------------------------------------------------------------- # 96 | 97 | in { 98 | inherit 99 | pp 100 | 101 | show 102 | showPretty 103 | showPrettyCurried 104 | showPrettyArgs 105 | showPrettyAttrNames 106 | showPrettyAttrTypes 107 | showDoc 108 | 109 | pwd' 110 | pwd 111 | ; 112 | showp = showPretty; 113 | spp = showPrettyCurried; 114 | spa = showPrettyArgs; 115 | saa = showPrettyAttrNames; 116 | sat = showPrettyAttrTypes; 117 | 118 | # FIXME: Handle globs in the middle of paths, and names. 119 | ls = lsDirGlob'; 120 | 121 | } 122 | 123 | 124 | # ---------------------------------------------------------------------------- # 125 | # 126 | # 127 | # 128 | # ============================================================================ # 129 | -------------------------------------------------------------------------------- /lib/safe-reads.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Eval time hints indicating if reading a path might get you killed. 4 | # Look before you leap. 5 | # 6 | # I use it to split "build plan eval" ( instantiation ) operations that need 7 | # impure, from execution of the build plan ( realization ) in a single run. 8 | # This allows you to dynamically declare reproducible derivations using 9 | # inference without writing anything to disk or spinning up a second 10 | # "pure pass" after an impure run. 11 | # This isn't anything new, flakes in particular have to deal with this a lot. 12 | # These routines are just guard rails to help you develop without shooting 13 | # yourself in the foot and accidentally poisoning a generation of builds. 14 | # 15 | # 16 | # ---------------------------------------------------------------------------- # 17 | 18 | { lib }: let 19 | 20 | # ---------------------------------------------------------------------------- # 21 | 22 | # Mimics the `allowedPaths' in `libexpr'. 23 | # We lack any type of introspection to know what the list is with a query, 24 | # but the user can populate this list themselves. 25 | # In practice you aren't going to emulate the real construct, 26 | # but it's useful for path crawling in pure mode and artificial limiting in 27 | # impure mode. 28 | isAllowedPath = { allowedPaths }: path: 29 | ( builtins.any ( allow: lib.hasPrefix allow path ) allowedPaths ); 30 | 31 | 32 | # ---------------------------------------------------------------------------- # 33 | 34 | # `getContext' returns `{ = { allOutputs = ; }; }' for `*.drv', 35 | # `{ = { outputs = ["out" ...]; }; }' for derivation outputs, 36 | # and `{ = { path = ; }; }` for builtin outputs. 37 | # We care about the second form of path. 38 | readNeedsIFD = pathlike: let 39 | str = if builtins.isString pathlike then pathlike else 40 | pathlike.outPath or ( toString pathlike ); 41 | ctx = builtins.attrValues ( builtins.getContext str ); 42 | hasOP = builtins.any ( x: x ? outputs ) ctx; 43 | forAttrs = ( pathlike ? drvPath ) || 44 | ( ( ( pathlike ? outPath ) || ( pathlike ? __toString ) ) && 45 | hasOP ); 46 | in if builtins.isAttrs pathlike then forAttrs else hasOP; 47 | 48 | 49 | # ---------------------------------------------------------------------------- # 50 | 51 | readNeedsImpureStrict = pathlike: let 52 | str = if builtins.isString pathlike then pathlike else 53 | pathlike.outPath or ( toString pathlike ); 54 | ctx = builtins.getContext str; 55 | forAttrs = ( ( pathlike.drvPath or pathlike.outPath or null ) == null ) || 56 | ( ctx == {} ); 57 | in if builtins.isPath pathlike then ! ( lib.isStorePath pathlike ) else 58 | if builtins.isAttrs pathlike then forAttrs else 59 | ( ctx == {} ); 60 | 61 | 62 | # ---------------------------------------------------------------------------- # 63 | 64 | readNeedsImpureExcept = { allowedPaths }: pathlike: 65 | ( readNeedsImpureStrict pathlike ) && 66 | ( ! ( isAllowedPath { inherit allowedPaths; } ( toString pathlike ) ) ); 67 | 68 | readNeedsImpure = { allowedPaths ? [] }: pathlike: 69 | readNeedsImpureExcept { inherit allowedPaths; } pathlike; 70 | 71 | 72 | # ---------------------------------------------------------------------------- # 73 | 74 | readAllowed' = { pure, ifd, allowedPaths }: pathlike: let 75 | isImpure = readNeedsImpureExcept { inherit allowedPaths; } pathlike; 76 | inAllowedPaths = isAllowedPath { inherit allowedPaths; } pathlike; 77 | needsIFD = readNeedsIFD pathlike; 78 | pureOk = ( ! pure ) || inAllowedPaths || ( ! isImpure ); 79 | ifdOk = ifd || ( ! needsIFD ); 80 | ifdMsg = "Cannot read path '${toString pathlike}' without IFD."; 81 | pureMsg = "Cannot read unlocked path '${toString pathlike}' in pure mode."; 82 | err' = if ifdOk && pureOk then {} else { 83 | err = if ifdOk then pureMsg else ifdMsg; 84 | }; 85 | in { 86 | ok = pureOk && ifdOk; 87 | inherit isImpure inAllowedPaths needsIFD; 88 | rules = { inherit pure ifd allowedPaths; }; 89 | } // err'; 90 | 91 | readAllowed = { pure, ifd, allowedPaths ? [] }: pathlike: 92 | ( readAllowed' { inherit pure ifd allowedPaths; } pathlike ).ok; 93 | 94 | 95 | # ---------------------------------------------------------------------------- # 96 | 97 | runReadOp = { pure, ifd, allowedPaths } @ renv: op: pathlike: let 98 | check = readAllowed' renv pathlike; 99 | msg = if ! ( op ? __functionMeta.name ) then check.err else 100 | "${op.__functionMeta.name}): ${check.err}"; 101 | in if check.ok then op pathlike else throw msg; 102 | 103 | 104 | defSafeReaders = { pure, ifd, allowedPaths } @ renv: let 105 | ops = { 106 | inherit (builtins) readFile readDir pathExists path; 107 | inherit (lib) importJSON; 108 | }; 109 | in builtins.mapAttrs ( _: runReadOp renv ) ops; 110 | 111 | 112 | # ---------------------------------------------------------------------------- # 113 | 114 | runtimeEnvReaders = defSafeReaders { 115 | pure = lib.inPureEvalMode; 116 | allowedPaths = []; 117 | ifd = true; # For cross eval: `builtins.currentSystem == system' 118 | }; 119 | 120 | 121 | # ---------------------------------------------------------------------------- # 122 | 123 | in { 124 | inherit 125 | isAllowedPath 126 | readNeedsIFD 127 | readNeedsImpureStrict readNeedsImpureExcept readNeedsImpure 128 | readAllowed' readAllowed 129 | runReadOp 130 | defSafeReaders 131 | runtimeEnvReaders 132 | ; 133 | } 134 | 135 | 136 | # ---------------------------------------------------------------------------- # 137 | # 138 | # 139 | # 140 | # ============================================================================ # 141 | -------------------------------------------------------------------------------- /lib/stdenv.nix: -------------------------------------------------------------------------------- 1 | { libfs ? import ./filesystem.nix }: 2 | let 3 | # nix build nixpkgs#legacyPackages.x86_64-{linux,darwin}.pkgs{,Static}.stdenv.cc{.bintools.bintools_bin,} 4 | # NOTE: Musl binaries are named `${stdenv.hostPlatform.config}-${name}' 5 | stdenvTools = stdenv: 6 | let 7 | inherit (stdenv.hostPlatform) isMusl isLinux isDarwin config; 8 | getTool' = dir: name: 9 | if isMusl then "${dir}/${config}-${name}" else "${dir}/${name}"; 10 | getTool = dir: name: let t = getTool' dir name; in 11 | assert ( libfs.exists t ); 12 | t; 13 | ccp = stdenv.cc; 14 | btp = stdenv.cc.bintools.bintools_bin; 15 | getCcTool = getTool "${ccp}/bin"; 16 | getBtTool = getTool "${btp}/bin"; 17 | in { 18 | # Compiler Collection (stdenv.cc) 19 | cc = getCcTool "cc"; 20 | cxx = getCcTool "c++"; 21 | # # Optionals 22 | # cpp = null; # Non-Musl 23 | # gcc = null; # Linux 24 | # gxx = null; # Linux 25 | # clang = null; # Darwin 26 | # clangxx = null; # Darwin 27 | 28 | # Bintools Collection (stenv.cc.bintools.bintools_bin) 29 | ar = getBtTool "ar"; 30 | as = getBtTool "as"; 31 | cxxfilt = getBtTool "c++filt"; 32 | ld = getBtTool "ld"; 33 | nm = getBtTool "nm"; 34 | ranlib = getBtTool "ranlib"; 35 | size = getBtTool "size"; 36 | strings = getBtTool "strings"; 37 | strip = getBtTool "strip"; 38 | # # Optionals 39 | # addr2line = null; # Linux Only 40 | # dwp = null; # Linux Only 41 | # elfedit = null; # Linux Only 42 | # gprof = null; # Linux Only 43 | # ldBfd = null; # Linux Only. Usually the same as `ld' 44 | # ldGold = null; # Linux Only 45 | # objcopy = null; # Linux Only 46 | # objdump = null; # Linux Only 47 | # readelf = null; # Linux Only 48 | # codesign_allocate = null; # Darwin Only 49 | # dsymutil = null; # Darwin Only 50 | # install_name_tool = null; # Darwin Only 51 | # lipo = null; # Darwin Only 52 | # otool = null; # Darwin Only 53 | }; 54 | in { 55 | inherit stdenvTools; 56 | } 57 | -------------------------------------------------------------------------------- /lib/tags.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # These helpers were graciously expropriated from 4 | # The Virus Lounge: https://code.tvl.fyi/tree 5 | # 6 | # ---------------------------------------------------------------------------- # 7 | # 8 | # The MIT License (MIT) 9 | # 10 | # Copyright (c) 2019 Vincent Ambo 11 | # Copyright (c) 2020-2021 The TVL Authors 12 | # 13 | # Permission is hereby granted, free of charge, to any person obtaining a copy 14 | # of this software and associated documentation files (the "Software"), to deal 15 | # in the Software without restriction, including without limitation the rights 16 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | # copies of the Software, and to permit persons to whom the Software is 18 | # furnished to do so, subject to the following conditions: 19 | # 20 | # The above copyright notice and this permission notice shall be included in all 21 | # copies or substantial portions of the Software. 22 | # 23 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | # SOFTWARE. 30 | # 31 | # 32 | # ---------------------------------------------------------------------------- # 33 | 34 | { lib }: let 35 | 36 | # ---------------------------------------------------------------------------- # 37 | 38 | # Takes a tag, checks whether it is an attrset with one element, 39 | # if so sets `isTag` to `true` and sets the name and value. 40 | # If not, sets `isTag` to `false` and sets `errmsg`. 41 | verifyTag = tag: let 42 | cases = builtins.attrNames tag; 43 | len = builtins.length cases; 44 | name = builtins.head cases; 45 | in if builtins.length cases == 1 then { 46 | inherit name; 47 | isTag = true; 48 | val = tag.${name}; 49 | errmsg = null; 50 | } else { 51 | isTag = false; 52 | errmsg = "match: an instance of a sum is an attrset " 53 | + "with exactly one element, yours had ${toString len}" 54 | + ", namely: ${lib.generators.toPretty {} cases}"; 55 | name = null; 56 | val = null; 57 | }; 58 | 59 | # Returns the tag name of a given tag attribute set. 60 | # Throws if the tag is invalid. 61 | # 62 | # Type: tag -> string 63 | tagName = tag: (assertIsTag tag).name; 64 | 65 | # Returns the tagged value of a given tag attribute set. 66 | # Throws if the tag is invalid. 67 | # 68 | # Type: tag -> any 69 | tagValue = tag: (assertIsTag tag).val; 70 | 71 | # like `verifyTag`, but throws the error message if it is not a tag. 72 | assertIsTag = tag: let 73 | res = verifyTag tag; 74 | in if res.isTag then { inherit (res) name val; } else throw res.errmsg; 75 | 76 | 77 | # ---------------------------------------------------------------------------- # 78 | 79 | # Discriminator for values. 80 | # Goes through a list of tagged predicates `{ = ; }` 81 | # and returns the value inside the tag 82 | # for which the first predicate applies, `{ = v; }`. 83 | # They can then later be matched on with `match`. 84 | # 85 | # `defTag` is the tag that is assigned if there is no match. 86 | # 87 | # Examples: 88 | # discrDef "smol" [ 89 | # { biggerFive = i: i > 5; } 90 | # { negative = i: i < 0; } 91 | # ] (-100) 92 | # => { negative = -100; } 93 | # discrDef "smol" [ 94 | # { biggerFive = i: i > 5; } 95 | # { negative = i: i < 0; } 96 | # ] 1 97 | # => { smol = 1; } 98 | discrDef = defTag: fs: v: let 99 | res = lib.findFirst ( t: t.val v ) null ( map assertIsTag fs ); 100 | in if res == null then { ${defTag} = v; } else { ${res.name} = v; }; 101 | 102 | # Like `discrDef', but fail if there is no match. 103 | # NOTE: the original routine used `res != null', however this is a bug. 104 | # Because `null' is used as a key as `let k = null; in { ${k} = 1; }' you 105 | # get back an empty set `{}'. 106 | # I was surprised that this didn't throw an error honestly. 107 | # XXX: if this ever misbehaves the default should just be swapped for a magic 108 | # reserved keyword like `"_%FAIL%_"' to avoid undefined behavior. 109 | discr = fs: v: let 110 | res = discrDef null fs v; 111 | msg = "tag.discr: No predicate found that matches " + 112 | ( lib.generators.toPretty {} v ); 113 | in if res != {} then res else throw msg; 114 | 115 | 116 | # ---------------------------------------------------------------------------- # 117 | 118 | # The canonical pattern matching primitive. 119 | # A sum value is an attribute set with one element, 120 | # whose key is the name of the variant and 121 | # whose value is the content of the variant. 122 | # `matcher` is an attribute set which enumerates 123 | # all possible variants as keys and provides a function 124 | # which handles each variant’s content. 125 | # You should make an effort to return values of the same 126 | # type in your matcher, or new sums. 127 | # 128 | # Example: 129 | # let 130 | # success = { res = 42; }; 131 | # failure = { err = "no answer"; }; 132 | # matcher = { 133 | # res = i: i + 1; 134 | # err = _: 0; 135 | # }; 136 | # in 137 | # match success matcher == 43 138 | # && match failure matcher == 0; 139 | # 140 | match = sum: matcher: 141 | let cases = builtins.attrNames sum; 142 | in assert 143 | let len = builtins.length cases; in 144 | lib.assertMsg (len == 1) 145 | ("match: an instance of a sum in an attrset " 146 | + "with exactly one element, yours had ${toString len}" 147 | + ", namely: ${lib.generators.toPretty {} cases}"); 148 | let case = builtins.head cases; 149 | in assert 150 | lib.assertMsg (matcher ? ${case}) 151 | ("match: \"${case}\" is not a valid case of this sum, " 152 | + "the matcher accepts: ${lib.generators.toPretty {} 153 | (builtins.attrNames matcher)}"); 154 | matcher.${case} sum.${case}; 155 | 156 | 157 | # ---------------------------------------------------------------------------- # 158 | 159 | # A `match` with the arguments flipped. 160 | # “Lam” stands for “lambda”, because it can be used like the 161 | # `\case` LambdaCase statement in Haskell, to create a curried 162 | # “matcher” function ready to take a value. 163 | # 164 | # Example: 165 | # lib.pipe { foo = 42; } [ 166 | # (matchLam { 167 | # foo = i: if i < 23 then { small = i; } else { big = i; }; 168 | # bar = _: { small = 5; }; 169 | # }) 170 | # (matchLam { 171 | # small = i: "yay it was small"; 172 | # big = i: "whoo it was big!"; 173 | # }) 174 | # ] 175 | # => "whoo it was big!"; 176 | matchLam = matcher: sum: match sum matcher; 177 | 178 | 179 | # ---------------------------------------------------------------------------- # 180 | 181 | in 182 | { 183 | inherit 184 | verifyTag 185 | tagName 186 | tagValue 187 | discr 188 | discrDef 189 | match 190 | matchLam 191 | ; 192 | matchTag = match; 193 | } 194 | 195 | 196 | # ---------------------------------------------------------------------------- # 197 | # 198 | # 199 | # 200 | # ============================================================================ # 201 | -------------------------------------------------------------------------------- /lib/thunk.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Essentially extensions and renames of Nixpkgs' `lib/customization.nix'. 4 | # Largely this aims to use more "user friendly" names to make the use of 5 | # things like `callPackageWith' and `` 6 | # 7 | # ---------------------------------------------------------------------------- # 8 | 9 | { lib }: let 10 | 11 | # ---------------------------------------------------------------------------- # 12 | 13 | defFnMeta = { 14 | __functionMeta = { 15 | name = "defFnMeta"; 16 | argc = 1; 17 | vargs = true; 18 | argTypes = ["set"]; 19 | returnTypes = ["function"]; 20 | }; 21 | __functionArgs = { 22 | name = true; 23 | argc = true; 24 | vargs = true; 25 | argTypes = true; 26 | returnTypes = true; 27 | keywords = true; 28 | terminalArgs = true; 29 | }; 30 | __functor = self: self.__innerFunction; 31 | __innerFunction = meta: { 32 | keywords = let 33 | infers = { 34 | #functor = ( meta ? functor ) || ( meta ? __processArgs ); 35 | #wrapper = meta ? __processArgs; 36 | #polymorphic = 1 < ( builtins.length meta.argTypes ); 37 | thunk = meta ? thunkMembers; 38 | vargs = ( meta ? vargs ) && meta.vargs; 39 | curried = ( meta ? argc ) && ( 1 < meta.argc ); 40 | #strict = ( meta.__functionArgs != {} ) && 41 | # ( builtins.all builtins.isBool 42 | # ( builtins.attrValues meta.__functionArgs ) ); 43 | }; 44 | fallback = builtins.attrNames ( lib.filterAttrs ( _: c: c ) infers ); 45 | in meta.keywords or fallback; 46 | } // meta; 47 | }; 48 | 49 | 50 | # ---------------------------------------------------------------------------- # 51 | 52 | defFunkCore = { 53 | __functionMeta = { 54 | name = "defFunkCore"; 55 | argc = 1; 56 | vargs = false; 57 | argTypes = ["set"]; 58 | returnTypes = ["function"]; 59 | }; 60 | __functionArgs = { 61 | __innerFunction = true; 62 | __functor = true; 63 | __functionArgs = true; 64 | __functionMeta = true; 65 | __processArgs = true; 66 | }; 67 | __functor = self: args: let 68 | margs = builtins.intersectAttrs { 69 | __function = true; 70 | __functor = true; 71 | __functionArgs = true; 72 | __processArgs = true; 73 | } args; 74 | targs = if ! ( self ? __processArgs ) then args else 75 | self.__processArgs self args; 76 | in self.__innerFunction ( targs // { 77 | __functionMeta = defFnMeta margs; 78 | } ); 79 | }; 80 | 81 | 82 | # ---------------------------------------------------------------------------- # 83 | 84 | defThunkedFunk = { 85 | __functionMeta = { 86 | name = "defThunkedFunk"; 87 | argc = 1; 88 | vargs = false; 89 | argTypes = ["set"]; 90 | returnTypes = ["function"]; 91 | }; 92 | __functionArgs = { 93 | __thunk = true; # ? {} 94 | __innerFunction = true; # ? functor ; NO `processArgs' 95 | __processArgs = true; # ? Merge thunk with args 96 | __functor = true; # ? pargs -> makeOverridable 97 | __functionMeta = true; # ? {} 98 | override = true; # ? `makeOverrideable' field 99 | overrideDerivation = true; # ? `makeOverrideable' field 100 | }; 101 | __functor = self: self.__innerFunction self; 102 | __innerFunction = args: let 103 | core = defFunkCore args; 104 | in lib.recursiveUpdate core { 105 | __functionMeta.thunkMembers = 106 | args.__functionMeta or 107 | ( builtins.attrNames ( args.__thunk or {} ) ); 108 | __thunk = args.__thunk or {}; 109 | }; 110 | }; 111 | 112 | 113 | # ---------------------------------------------------------------------------- # 114 | 115 | in { 116 | 117 | inherit 118 | defFnMeta 119 | defFunkCore 120 | defThunkedFunk 121 | ; 122 | 123 | } 124 | 125 | 126 | # ---------------------------------------------------------------------------- # 127 | # 128 | # 129 | # ============================================================================ # 130 | -------------------------------------------------------------------------------- /lib/trivial.nix: -------------------------------------------------------------------------------- 1 | { lib }: let 2 | 3 | inherit (lib) 4 | versionOlder 5 | versionAtLeast 6 | getVersion 7 | ; 8 | 9 | inherit (builtins) 10 | compareVersions 11 | foldl' 12 | ; 13 | 14 | 15 | # ---------------------------------------------------------------------------- # 16 | 17 | # If you pass in an attrset you'll receive a list of pairs sorted. 18 | # Converting back to an attrset would "undo" the sorting because fields are 19 | # "unsorted" and printed alphabetically. 20 | sortVersions' = { 21 | ascending ? false 22 | , accessor ? ( x: if builtins.isString x then x else getVersion x ) 23 | }: xs: let 24 | gvp = if builtins.isList xs then accessor 25 | else ( { name, value }: accessor value ); 26 | versionList = if builtins.isList xs then xs else lib.attrsToList xs; 27 | cmpDesc = a: b: 0 < ( compareVersions ( gvp a ) ( gvp b ) ); 28 | cmpAsc = a: b: ( compareVersions ( gvp a ) ( gvp b ) ) < 0; 29 | cmp = if ascending then cmpAsc else cmpDesc; 30 | sorted = builtins.sort cmp versionList; 31 | in sorted; 32 | 33 | sortVersions = sortVersions' {}; 34 | 35 | # FIXME: `foldl' can optimize this but you need to redeclare the comparitors. 36 | latestVersion' = xs: builtins.head ( sortVersions xs ); 37 | latestVersion = xs: let 38 | latest = latestVersion' xs; 39 | in if builtins.isList xs then latest else { ${latest.name} = latest.value; }; 40 | 41 | 42 | # ---------------------------------------------------------------------------- # 43 | 44 | # Be careful with this, it's easy to exceed 2^64 without realizing it. 45 | pow' = x: pow: let 46 | counter = builtins.genList ( _: null ) pow; 47 | in builtins.foldl' ( acc: _: acc * x ) 1 counter; 48 | 49 | pow = x: pow: let 50 | _mulSafe = a: b: let c = a * b; in assert ( c != 0 ); c; 51 | counter = builtins.genList ( _: null ) pow; 52 | rsl = builtins.foldl' ( acc: _: _mulSafe acc x ) 1 counter; 53 | in if x == 0 then 0 else rsl; 54 | 55 | mulSafe = a: b: let 56 | c = a * b; 57 | in assert ( ( a == 0 ) || ( b == 0 ) ) || ( c != 0 ); c; 58 | 59 | 60 | # ---------------------------------------------------------------------------- # 61 | 62 | baseListToDec' = base: foldl' ( acc: x: acc * base + x ) 0; 63 | baseListToDec = base: foldl' ( acc: x: ( mulSafe acc base ) + x ) 0; 64 | 65 | 66 | # ---------------------------------------------------------------------------- # 67 | 68 | # Wrap a routine with `runHook (pre|post)' 69 | withHooks = type: body: let 70 | up = let 71 | u = lib.toUpper ( builtins.substring 0 1 type ); 72 | in u + ( builtins.substring 1 ( builtins.stringLength type ) type ); 73 | in "runHook pre${up}\n${body}\nrunHook post${up}"; 74 | 75 | 76 | # ---------------------------------------------------------------------------- # 77 | 78 | getEnvOr = fallback: var: let 79 | val = builtins.getEnv var; 80 | in if lib.inPureEvalMode then fallback else 81 | if val == "" then fallback else val; 82 | 83 | 84 | nixEnvVars = let 85 | lookup = var: fb: lib.getEnvOr fb var; 86 | localstatedir = "/nix/var"; 87 | vars = self: 88 | builtins.mapAttrs lookup { 89 | HOME = "/home-shelter"; 90 | XDG_CONFIG_DIRS = "/etc/xdg"; 91 | XDG_CONFIG_HOME = "${self.HOME}/.config"; 92 | XDG_CACHE_HOME = "${self.HOME}/.cache"; 93 | NIX_STORE_DIR = self.NIX_STORE; 94 | NIX_STORE = "/nix/store"; 95 | NIX_CONF_DIR = "/etc/nix"; 96 | # NOTE: searched in reverse order 97 | NIX_USER_CONF_FILES = builtins.concatStringsSep ":" [ 98 | "${self.XDG_CONFIG_DIRS}/nix" 99 | "${self.XDG_CONFIG_HOME}/nix" 100 | ]; 101 | NIX_CONFIG = ""; 102 | # Legacy `nix-env' CLI uses this 103 | NIX_PROFILE = "${localstatedir}/nix/profiles/default"; 104 | # Set by Daemon 105 | NIX_PROFILES = [ 106 | "${localstatedir}/nix/profiles/default" 107 | "${self.HOME}/.nix-profile" 108 | ]; 109 | IN_NIX_SHELL = ""; 110 | IN_NIX_REPL = ""; 111 | }; 112 | vals = ( lib.fix vars ) // { 113 | # This is made up, I use it for convenience. 114 | _NIX_USER_CONF_DIR = let 115 | m = builtins.match "(.*:)?([^:]+)" vals.NIX_USER_CONF_FILES; 116 | in if m == null then vals.XDG_CONFIG_HOME else builtins.elemAt m 1; 117 | }; 118 | in if lib.inPureEvalMode then {} else vals; 119 | 120 | 121 | # ---------------------------------------------------------------------------- # 122 | 123 | in { 124 | inherit 125 | sortVersions' 126 | sortVersions 127 | latestVersion' 128 | latestVersion 129 | versionOlder 130 | versionAtLeast 131 | getVersion 132 | pow' 133 | pow 134 | mulSafe 135 | baseListToDec' 136 | baseListToDec 137 | withHooks 138 | getEnvOr 139 | nixEnvVars 140 | ; 141 | } 142 | -------------------------------------------------------------------------------- /pkgs/build-support/setup-hooks/default.nix: -------------------------------------------------------------------------------- 1 | { makeSetupHook, writeShellScriptBin }: 2 | { 3 | isAR = makeSetupHook { name = "isAR"; } ./isAR.sh; 4 | isAR_sh = let isARContents = builtins.readFile ./isAR.sh; in 5 | writeShellScriptBin "isAR.sh" ( isARContents + '' 6 | isAR "$1" 7 | '' ); 8 | } 9 | -------------------------------------------------------------------------------- /pkgs/build-support/setup-hooks/isAR.sh: -------------------------------------------------------------------------------- 1 | # Test if a file is an AR archive. 2 | function isAR() { 3 | local fn="$1" 4 | local fd 5 | local magic 6 | exec {fd}<"$fn" 7 | ### In Zsh `read -k NUM' behaves like Bash's `read -n NUM'. 8 | ##if test "${ZSH_VERSION+set}" = set; then 9 | ## read -r -k 7 -u "$fd" magic 10 | ##else 11 | ## read -r -n 7 -u "$fd" magic 12 | ##fi 13 | read -r -n 7 -u "$fd" magic 14 | exec {fd}<&- 15 | # First seven characters should be "!" 16 | if test "$magic" = $'\041\074arch\076'; then return 0; else return 1; fi 17 | } 18 | -------------------------------------------------------------------------------- /pkgs/build-support/trivial/copy.nix: -------------------------------------------------------------------------------- 1 | { lib, system, coreutils, bash }: let 2 | 3 | inherit (lib.libfs) baseName'; 4 | 5 | /* -------------------------------------------------------------------------- */ 6 | 7 | # Use "$out" normally in `cpFlags', we'll replace it. 8 | # NOTE: No other shell expansions are supported. 9 | runcp = { 10 | name ? "source" 11 | , src ? null 12 | , srcs ? [src] 13 | , cpFlags ? ["-pr" "--reflink=auto" "--"] ++ ( map toString srcs ) ++ 14 | [( builtins.placeholder "out" )] 15 | , extraAttrs ? {} 16 | } @ args: 17 | # Make sure the user really provided SOME way for `cp' to run successfully. 18 | assert ! ( ( srcs == [] ) && ( src == null ) && ( ! ( args ? cpFlags ) ) ); 19 | ( derivation { 20 | inherit name system; 21 | builder = "${coreutils}/bin/cp"; 22 | args = let 23 | so = builtins.replaceStrings ["$out"] [( builtins.placeholder "out" )]; 24 | in if ( args ? cpFlags ) then ( map so cpFlags ) else cpFlags; 25 | } ) // extraAttrs; 26 | 27 | 28 | /* -------------------------------------------------------------------------- */ 29 | 30 | copyOut = { src, name ? baseName' src, extraAttrs ? {} }: 31 | runcp { inherit name src extraAttrs; }; 32 | 33 | 34 | /* -------------------------------------------------------------------------- */ 35 | 36 | copyToPath = { 37 | name ? "source" 38 | , src, to 39 | , extraCpFlags ? ["-pr" "--reflink=auto"] 40 | , extraAttrs ? {} 41 | }: assert builtins.isString to; 42 | ( derivation { 43 | inherit name system extraCpFlags src to; 44 | builder = "${bash}/bin/bash"; 45 | PATH = "${coreutils}/bin"; 46 | passAsFile = ["buildPhase"]; 47 | buildPhase = '' 48 | mkdir -p $out/${dirOf to} 49 | eval "cp $extraCpFlags -- $src $out/$to" 50 | ''; 51 | args = ["-c" ". $buildPhasePath"]; 52 | } ) // extraAttrs; 53 | 54 | 55 | /* -------------------------------------------------------------------------- */ 56 | 57 | # We'll replace "$out" for you, but not "$src". 58 | # We use `lib.toGnuCommandLine' to convert our args. 59 | # Because that function takes attrsets, we accept a list of attrsets to allow 60 | # the user to use flags repeatedly. 61 | # This isn't ideal but whatever. 62 | # 63 | # If a member of `argsList' is not an attrset, we will recurse over lists, 64 | # and call `toString' on anything else. 65 | # 66 | # FIXME: you can avoid `runcp' by extending replacement rules in 67 | # `toGNUCommandLine' to handle "$out". 68 | # The trick is leaving `( builtins.placeholder "out" )' as a thunk until 69 | # inside of `derivation { ... }'. 70 | cpcli = { name, argsList, extraAttrs ? {} }: let 71 | mkCpFlags = builtins.foldl' process []; 72 | process = acc: a: 73 | if builtins.isAttrs a then acc ++ ( lib.cli.toGNUCommandLine {} a ) else 74 | if builtins.isList a then acc ++ ( mkCpFlags a ) else 75 | ( acc ++ [( toString a )] ); 76 | cpFlags = mkCpFlags argsList; 77 | in runcp { inherit name cpFlags extraAttrs; src = []; }; 78 | 79 | 80 | /* -------------------------------------------------------------------------- */ 81 | 82 | in { inherit runcp copyOut copyToPath cpcli; } 83 | 84 | 85 | /* -------------------------------------------------------------------------- */ 86 | -------------------------------------------------------------------------------- /pkgs/build-support/trivial/link.nix: -------------------------------------------------------------------------------- 1 | 2 | # lndir is available under `nixpkgs.legacyPackages.${system}.xorg.lndir' 3 | { lib, system, coreutils, bash /* , lndir */ }: let 4 | 5 | inherit (lib.libfs) baseName'; 6 | 7 | /* -------------------------------------------------------------------------- */ 8 | 9 | # Use "$out" normally in `lnFlags', we'll replace it. 10 | # NOTE: No other shell expansions are supported. 11 | runLn = { 12 | name ? "source" 13 | , src ? null 14 | , srcs ? [src] 15 | , lnFlags ? ["-s" "--"] ++ ( map toString srcs ) ++ 16 | [( builtins.placeholder "out" )] 17 | , extraAttrs ? {} 18 | } @ args: 19 | # Make sure the user really provided SOME way for `ln' to run successfully. 20 | assert ! ( ( srcs == [] ) && ( src == null ) && ( ! ( args ? lnFlags ) ) ); 21 | ( derivation { 22 | inherit name system; 23 | builder = "${coreutils}/bin/ln"; 24 | args = let 25 | so = builtins.replaceStrings ["$out"] [( builtins.placeholder "out" )]; 26 | in if ( args ? lnFlags ) then ( map so lnFlags ) else lnFlags; 27 | } ) // extraAttrs; 28 | 29 | 30 | /* -------------------------------------------------------------------------- */ 31 | 32 | # Create a symlink from a file ( presumably from a larger `drv' ) to `$out'. 33 | # On its own this isn't particularly useful; but when viewed as analogous to 34 | # "copying" a single file ( which is effectively how the Nix Store will see 35 | # treat it when performing `--optimize' or binary cache fetches ) it's 36 | # becomes a powerful tool for creating "fine grained" Derivation contexts. 37 | linkOut = { src, name ? baseName' src, extraAttrs ? {} }: 38 | runLn { inherit name src extraAttrs; }; 39 | 40 | 41 | /* -------------------------------------------------------------------------- */ 42 | 43 | linkToPath = { 44 | name ? "source" 45 | , src, to 46 | , extraLnFlags ? ["-s"] 47 | , extraAttrs ? {} 48 | }: assert builtins.isString to; 49 | ( derivation { 50 | inherit name system extraLnFlags src to; 51 | builder = "${bash}/bin/bash"; 52 | PATH = "${coreutils}/bin"; 53 | passAsFile = ["buildPhase"]; 54 | buildPhase = '' 55 | mkdir -p $out/${dirOf to} 56 | eval "ln $extraLnFlags -- $src $out/$to" 57 | ''; 58 | args = ["-c" ". $buildPhasePath"]; 59 | } ) // extraAttrs; 60 | 61 | 62 | /* -------------------------------------------------------------------------- */ 63 | 64 | #runLndir = 65 | 66 | 67 | /* -------------------------------------------------------------------------- */ 68 | 69 | in { inherit runLn linkOut linkToPath; } 70 | -------------------------------------------------------------------------------- /pkgs/build-support/trivial/tests/default.nix: -------------------------------------------------------------------------------- 1 | { lib ? builtins.getFlake ( toString ../../../../lib ) 2 | , writeText ? pkgs.writeText 3 | , runCommandNoCC ? pkgs.runCommandNoCC 4 | , tarutils ? import ../tar.nix { inherit lib system coreutils gnutar gzip bash findutils; } 5 | , linkutils ? import ../link.nix { inherit lib system coreutils bash; } 6 | 7 | # Optional: Only required if attrs aboves attempt to fallback. 8 | , nixpkgs ? builtins.getFlake "nixpkgs" 9 | , system ? builtins.currentSystem 10 | , pkgs ? nixpkgs.legacyPackages.${system} 11 | , gnutar ? pkgs.gnutar 12 | , gzip ? pkgs.gzip 13 | , coreutils ? pkgs.coreutils 14 | , findutils ? pkgs.findutils 15 | , bash ? pkgs.bash 16 | 17 | # Configurables: 18 | # -------------- 19 | # When using `writeRunReport', Print the report to `stderr' as well. 20 | # This has no effect on other outputs. 21 | , enableTraces ? true 22 | 23 | # Applied to the output out `printTestReport' for traced output. 24 | # If you change this just be sure you match the original function prototype. 25 | , traceFn ? builtins.trace 26 | 27 | # Change the output. This is most useful for importing `tests.nix' into the REPL 28 | # or a `nix eval --expr' call to avoid pulling inputs explicitly. 29 | # The following two examples are equivalent, but they illustrate the utility: 30 | # 31 | # nix-repl> tests = ( import ./default.nix { outputAttr = "tests"; } ) 32 | # nix-repl> :lf nixpkgs 33 | # nix-repl> :p lib.runTests tests 34 | # 35 | # nix-repl> :p import ./default.nix { outputAttr = "run"; } 36 | # 37 | # You can also export `outputs' in its entirety using `outputAttrs = "all";'. 38 | # NOTE: Yes, I implemented a lock-less flake from scratch - I'm aware. 39 | , outputAttr ? "writeRunReport" 40 | 41 | # You can set this to a list of test names to limit what gets run. 42 | , testsToRun ? null 43 | 44 | # You can pass in whatever else you want, it'll be added to `inputs', which 45 | # is really only useful for the REPL. 46 | , ... 47 | } @ args: let 48 | 49 | 50 | /* -------------------------------------------------------------------------- */ 51 | 52 | inputs = args // { 53 | inherit lib nixpkgs system pkgs; 54 | inherit tarutils linkutils; 55 | inherit runCommandNoCC writeText gzip coreutils bash; 56 | inherit testsToRun; 57 | }; 58 | 59 | tests = ( import ./tests.nix { 60 | inherit lib runCommandNoCC linkutils tarutils; 61 | } ) // ( if testsToRun == null then {} else { tests = testsToRun; } ); 62 | 63 | run = lib.runTests tests; 64 | 65 | 66 | /* -------------------------------------------------------------------------- */ 67 | 68 | printTestReport = test @ { name, expected, result }: let 69 | pass = expected == result; 70 | indentStr = " "; 71 | indentBlock = lns: 72 | builtins.concatStringsSep "\n${indentStr}" 73 | ( lib.splitString "\n" lns ); 74 | msgFail = '' 75 | Test ${name} Failure: Expectation did not match result. 76 | expected: 77 | --- 78 | ${indentBlock ( lib.libstr.coerceString expected )} 79 | --- 80 | 81 | result: 82 | --- 83 | ${indentBlock ( lib.libstr.coerceString result )} 84 | --- 85 | ''; 86 | in if pass then "Test ${name} Passes." else msgFail; 87 | 88 | printRunReport = builtins.concatStringsSep "\n" ( map printTestReport run ); 89 | 90 | # Print the report to `stderr', and return the outputs of `runTests'. 91 | traceRunReport = traceFn printRunReport run; 92 | 93 | # Create a derivation from the report. 94 | writeRunReport = let 95 | reporter = if enableTraces then printRunReport 96 | else traceFn printRunReport printRunReport; 97 | in writeText "trivial-tests" printRunReport; 98 | 99 | 100 | /* -------------------------------------------------------------------------- */ 101 | 102 | outputs = { 103 | inherit inputs tests run traceFn; 104 | inherit printTestReport printRunReport writeRunReport traceRunReport; 105 | }; 106 | 107 | output = if outputAttr == "all" then outputs else outputs.${outputAttr}; 108 | 109 | 110 | /* -------------------------------------------------------------------------- */ 111 | 112 | in output 113 | -------------------------------------------------------------------------------- /pkgs/build-support/trivial/tests/tests.nix: -------------------------------------------------------------------------------- 1 | { lib, runCommandNoCC, linkutils, tarutils, ... } @ args: let 2 | 3 | inherit (builtins) typeOf tryEval mapAttrs toJSON readFile toFile; 4 | inherit (tarutils) runTar tar untar tarcli; 5 | inherit (linkutils) runLn linkOut linkToPath; 6 | 7 | source = runCommandNoCC "source" {} '' 8 | mkdir -p $out/sub 9 | echo "Howdy" > "$out/a" 10 | echo "Partner" > "$out/b" 11 | echo "Nest" > "$out/sub/c" 12 | ''; 13 | 14 | # Recycled for various calls. 15 | tarSourceCommonArgs = { 16 | src = ["a" "b" "sub/c"]; 17 | tarFlagsLate = ["-C" "${source}"]; 18 | }; 19 | 20 | # Simplest form, just give relative paths from drv root. 21 | tarSourceExplicit = tar tarSourceCommonArgs; 22 | 23 | # Overridable form of `tarSourceExplicit' 24 | tarSourceO = lib.makeOverridable tar tarSourceCommonArgs; 25 | 26 | # This produces an identical list of paths as `tarSourceExplicit'; but shows 27 | # the processes required to get a "regular" tarball with enties that aren't 28 | # a complete mess. 29 | # The point of the case is really to illustrate how much of a pain in the 30 | # ass it is to use `tar { ... }' programmatically. 31 | tarSourceTreeWalk = tar { 32 | src = 33 | # FIXME: The effort required here to remove directories bad. 34 | # This needs to be reworked, unforunately `tar' doesn't provide 35 | # useful flags for handling directory structures. 36 | # Note that getting pathnames to be written without `./' is 37 | # also an issue that needs attention. 38 | map ( p: lib.libstr.yank "\\./(.*)" 39 | ( lib.libpath.realpathRel' "${source}" p ) ) 40 | ( lib.filesystem.listFilesRecursive "${source}" ); 41 | tarFlagsLate = ["-C" "${source}"]; 42 | }; 43 | 44 | tarballDrvs = { 45 | inherit tarSourceTreeWalk; 46 | inherit tarSourceExplicit; 47 | inherit tarSourceO; 48 | }; 49 | 50 | ttFileLists = tarballs: let 51 | inherit (builtins) concatStringsSep; 52 | listMembers = t: '' 53 | tar -tf ${t} >> "$out" 54 | ''; 55 | sep = '' 56 | echo "***" >> "$out" 57 | ''; 58 | drv = runCommandNoCC "tarball-files.log" { 59 | preferLocalBuild = true; 60 | allowSubstitutes = false; 61 | } ( concatStringsSep sep ( map listMembers tarballs ) ); 62 | in drv // { meta = { inherit tarballs; }; }; 63 | 64 | # We need `rec' because some test piggy back off of others' expressions. 65 | in { 66 | 67 | # Stash our inputs in case we'd like to refer to them later. 68 | # Think of these as "read-only", since overriding this attribute won't have 69 | # any effect on the tests themselves. 70 | inputs = args // { 71 | inherit lib; 72 | inherit source ; 73 | inherit tarSourceCommonArgs; 74 | inherit ttFileLists; 75 | inherit tarballDrvs; 76 | }; 77 | 78 | /* -------------------------------------------------------------------------- */ 79 | 80 | testTrivial = { 81 | expr = let x = 0; in x; 82 | expected = 0; 83 | }; 84 | 85 | 86 | /* -------------------------------------------------------------------------- */ 87 | 88 | # Assert that `extraAttrs' do not appear in Derivations. 89 | # This is important because if they do, a change to meta-data will wrongly 90 | # trigger rebuilds. 91 | testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 92 | expr = let pkg = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 93 | in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 94 | expected = { pkg.meta.boy = "howdy"; drv = {}; }; 95 | }; 96 | 97 | # TODO: runTar 98 | #testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 99 | # expr = let pkgTar = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 100 | # in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 101 | # expected = { pkg.meta.boy = "howdy"; drv = {}; }; 102 | #}; 103 | 104 | # TODO: tarcli 105 | #testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 106 | # expr = let pkgTar = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 107 | # in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 108 | # expected = { pkg.meta.boy = "howdy"; drv = {}; }; 109 | #}; 110 | 111 | # TODO: untar 112 | #testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 113 | # expr = let pkgTar = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 114 | # in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 115 | # expected = { pkg.meta.boy = "howdy"; drv = {}; }; 116 | #}; 117 | 118 | # TODO: linkOut 119 | #testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 120 | # expr = let pkgTar = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 121 | # in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 122 | # expected = { pkg.meta.boy = "howdy"; drv = {}; }; 123 | #}; 124 | 125 | # TODO: linkToPath 126 | #testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 127 | # expr = let pkgTar = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 128 | # in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 129 | # expected = { pkg.meta.boy = "howdy"; drv = {}; }; 130 | #}; 131 | 132 | # TODO: runLn 133 | #testExtraAttrs_tar = let extraAttrs = { meta.boy = "howdy"; }; in { 134 | # expr = let pkgTar = tar ( tarSourceCommonArgs // { inherit extraAttrs; } ); 135 | # in { pkg = pkg.meta or {}; drv = pkg.drvAttrs.meta or {}; }; 136 | # expected = { pkg.meta.boy = "howdy"; drv = {}; }; 137 | #}; 138 | 139 | /* -------------------------------------------------------------------------- */ 140 | 141 | testTar = { 142 | # We are recycling the work done by global `tarSource*` calls. 143 | expr = 144 | readFile ( ttFileLists [tarSourceTreeWalk tarSourceExplicit] ).outPath; 145 | expected = '' 146 | a 147 | b 148 | sub/c 149 | *** 150 | a 151 | b 152 | sub/c 153 | ''; 154 | }; 155 | 156 | 157 | /* -------------------------------------------------------------------------- */ 158 | 159 | testTarCli = { 160 | expr = let 161 | file = toFile "welcome" "Hello, World!"; 162 | foo = tarcli { 163 | name = "foo.tar.gz"; 164 | argsList = [{ 165 | c = true; # Create Archive 166 | f = "$out"; # Name Archive "$out" ( replaced later ) 167 | } { # We split to make sure the `foldl' works 168 | C = dirOf file; # Change to directory before archiving 169 | xform = "s,^[^-]*-,,"; # Strip store path 170 | } 171 | ( baseNameOf file ) # Input file, relative to `C' working dir 172 | ]; 173 | }; 174 | # Now unpack it to make sure it did what we wanted. 175 | unpacked = untar { tarball = foo.outPath; }; 176 | # Confirm the file name was preserved 177 | # Also, we obviously expect the message to be the same. 178 | in readFile "${unpacked}/welcome"; 179 | expected = "Hello, World!"; 180 | }; 181 | 182 | 183 | /* -------------------------------------------------------------------------- */ 184 | 185 | } 186 | -------------------------------------------------------------------------------- /pkgs/development/tools/jo/.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | -------------------------------------------------------------------------------- /pkgs/development/tools/jo/checks.nix: -------------------------------------------------------------------------------- 1 | { jo, diffutils, runCommandNoCC }: 2 | { 3 | 4 | object = runCommandNoCC "checks-object-${jo.name}" { 5 | expected = '' 6 | { 7 | "name": "jo", 8 | "n": 17, 9 | "parser": false 10 | } 11 | ''; 12 | passAsFile = ["expected"]; 13 | } '' 14 | PATH="''${PATH+$PATH:}${jo}/bin:${diffutils}/bin"; 15 | jo -p name=jo n=17 parser=false 2>&1|tee "$out" 16 | diff -q "$out" "$expectedPath" 2>&1 17 | ''; 18 | 19 | list = runCommandNoCC "checks-object-${jo.name}" { 20 | expected = '' 21 | [1,2,3,4,5,6,7,8,9,10] 22 | ''; 23 | passAsFile = ["expected"]; 24 | } '' 25 | PATH="''${PATH+$PATH:}${jo}/bin:${diffutils}/bin"; 26 | seq 1 10|jo -a 2>&1|tee "$out" 27 | diff -q "$out" "$expectedPath" 2>&1 28 | ''; 29 | 30 | } 31 | -------------------------------------------------------------------------------- /pkgs/development/tools/jo/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , autoreconfHook 3 | , pkg-config 4 | , pandoc 5 | , jo-src ? builtins.fetchGit { 6 | url = "https://github.com/jpmens/jo.git"; 7 | ref = "refs/tags/1.6"; 8 | rev = "6962bca178a6778328d1126ff762120305bb4327"; 9 | } 10 | }: 11 | stdenv.mkDerivation { 12 | pname = "jo"; 13 | version = "1.6"; 14 | src = jo-src; 15 | nativeBuildInputs = [ 16 | pkg-config 17 | pandoc 18 | autoreconfHook 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /pkgs/development/tools/jo/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "jo-src": { 4 | "flake": false, 5 | "locked": { 6 | "lastModified": 1641398377, 7 | "narHash": "sha256-aATCeJV0x+XHOQbwulutxivPzGVQ0mJj90vA+6IM124=", 8 | "owner": "jpmens", 9 | "repo": "jo", 10 | "rev": "6962bca178a6778328d1126ff762120305bb4327", 11 | "type": "github" 12 | }, 13 | "original": { 14 | "owner": "jpmens", 15 | "ref": "1.6", 16 | "repo": "jo", 17 | "type": "github" 18 | } 19 | }, 20 | "nixpkgs": { 21 | "locked": { 22 | "lastModified": 0, 23 | "narHash": "sha256-cy6ArO4k5qTx+l5o+0mL9f5fa86tYUX3ozE1S+Txlds=", 24 | "path": "/nix/store/lwyjz70qh12nq6cb7fixl85vryzxqm3c-source", 25 | "type": "path" 26 | }, 27 | "original": { 28 | "id": "nixpkgs", 29 | "type": "indirect" 30 | } 31 | }, 32 | "root": { 33 | "inputs": { 34 | "jo-src": "jo-src", 35 | "nixpkgs": "nixpkgs", 36 | "utils": "utils" 37 | } 38 | }, 39 | "utils": { 40 | "locked": { 41 | "lastModified": 1653893745, 42 | "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", 43 | "owner": "numtide", 44 | "repo": "flake-utils", 45 | "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", 46 | "type": "github" 47 | }, 48 | "original": { 49 | "id": "utils", 50 | "type": "indirect" 51 | } 52 | } 53 | }, 54 | "root": "root", 55 | "version": 7 56 | } 57 | -------------------------------------------------------------------------------- /pkgs/development/tools/jo/flake.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # ---------------------------------------------------------------------------- # 5 | 6 | { 7 | 8 | # ---------------------------------------------------------------------------- # 9 | 10 | description = "a small utility to create JSON objects"; 11 | 12 | # ---------------------------------------------------------------------------- # 13 | 14 | inputs.jo-src.url = "github:jpmens/jo/1.6"; 15 | inputs.jo-src.flake = false; 16 | 17 | # ---------------------------------------------------------------------------- # 18 | 19 | outputs = { self, nixpkgs, utils, jo-src, ... }: let 20 | 21 | # ---------------------------------------------------------------------------- # 22 | 23 | eachDefaultSystemMap = fn: let 24 | defaultSystems = [ 25 | "x86_64-linux" "aarch64-linux" "i686-linux" 26 | "x86_64-darwin" "aarch64-darwin" 27 | ]; 28 | proc = system: { name = system; value = fn system; }; 29 | in builtins.listToAttrs ( map proc defaultSystems ); 30 | 31 | 32 | # ---------------------------------------------------------------------------- # 33 | 34 | overlays.jo = final: prev: { 35 | jo = prev.callPackage ./. { inherit jo-src; }; 36 | }; 37 | overlays.default = overlays.jo; 38 | 39 | 40 | # ---------------------------------------------------------------------------- # 41 | 42 | packages = eachDefaultSystemMap ( system: let 43 | jo = nixpkgs.legacyPackages.${system}.callPackage ./. { inherit jo-src; }; 44 | in { inherit jo; default = jo; } ); 45 | 46 | 47 | # ---------------------------------------------------------------------------- # 48 | 49 | in { 50 | 51 | # ---------------------------------------------------------------------------- # 52 | 53 | inherit overlays packages; 54 | 55 | # ---------------------------------------------------------------------------- # 56 | 57 | nixosModules.jo = { config, ... }: { overlays = [overlays.jo]; }; 58 | nixosModules.default = self.nixosModules.jo; 59 | 60 | checks = utils.lib.eachDefaultSystemMap ( system: import ./checks.nix { 61 | inherit (packages.${system}) jo; 62 | inherit (nixpkgs.legacyPackages.${system}) runCommandNoCC diffutils; 63 | } ); 64 | 65 | # ---------------------------------------------------------------------------- # 66 | 67 | }; # End `outputs' 68 | 69 | 70 | # ---------------------------------------------------------------------------- # 71 | 72 | } 73 | 74 | 75 | # ---------------------------------------------------------------------------- # 76 | # 77 | # 78 | # 79 | # ============================================================================ # 80 | -------------------------------------------------------------------------------- /pkgs/docgen/default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? builtins.getFlake "nixpkgs" 2 | , system ? builtins.currentSystem 3 | , pkgs ? nixpkgs.legacyPackages.${system} 4 | , pandoc ? pkgs.pandoc 5 | , texinfo ? pkgs.texinfo 6 | , ... 7 | }: 8 | let 9 | pandocGen = import ./pandoc { inherit pandoc; }; 10 | infoGen = import ./makeinfo { inherit texinfo; }; 11 | moduleOptions = import ./module-options.nix { 12 | inherit pandocGen infoGen pkgs nixpkgs; 13 | inherit (pkgs) linkFarmFromDrvs; 14 | }; 15 | # NOTE: This is only "okay" because these imports do not clash on any 16 | # fields that are attribute (sub)sets. 17 | # If you ever add `meta' to `makeinfo/default.nix' you need to fix this. 18 | in pandocGen // infoGen // moduleOptions 19 | -------------------------------------------------------------------------------- /pkgs/docgen/makeinfo/default.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Convert `texi' ( TexInfo ) files to `info' pages. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { nixpkgs ? builtins.getFlake "nixpkgs" 8 | , system ? builtins.currentSystem 9 | , pkgs ? import nixpkgs.legacyPackages.${system} 10 | , texinfo ? pkgs.texinfo 11 | }: { 12 | texiToInfo = { name, ... } @ file: derivation { 13 | inherit system; 14 | name = builtins.replaceStrings ["texinfo" "texi"] ["info" "info"] name; 15 | args = ["-o" ( builtins.placeholder "out" ) file]; 16 | builder = "${texinfo}/bin/makeinfo"; 17 | }; 18 | } 19 | 20 | 21 | # ---------------------------------------------------------------------------- # 22 | # 23 | # 24 | # 25 | # ============================================================================ # 26 | -------------------------------------------------------------------------------- /pkgs/docgen/module-options.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? builtins.getFlake "nixpkgs" 2 | , system ? builtins.currentSystem 3 | , pkgsFor ? nixpkgs.legacyPackages.${system} 4 | , lib ? nixpkgs.lib 5 | , genDoc ? import "${nixpkgs}/nixos/lib/make-options-doc" 6 | , pandocGen ? import ./pandoc { inherit (pkgsFor) pandoc; } 7 | , infoGen ? import ./makeinfo { inherit (pkgsFor) texinfo; } 8 | , linkFarmFromDrvs ? pkgsFor.linkFarmFromDrvs 9 | }: 10 | let 11 | inherit (pandocGen) docbookToManN docbookToTexi docbookToHtml docbookToOrg; 12 | 13 | docbookToMan5 = docbookToManN 5; 14 | 15 | generateDocsForOptions = options: 16 | let 17 | docs' = genDoc { inherit lib options; pkgs = pkgsFor; }; 18 | texi = docbookToTexi docs'.optionsDocBook; 19 | singles = { 20 | asciidoc = docs'.optionsAsciiDoc // { name = "options.asciidoc"; }; 21 | markdown = docs'.optionsCommonMark // { name = "options.md"; }; 22 | docbook = docs'.optionsDocBook // { name = "options-docbook.xml"; }; 23 | json = docs'.optionsJSON // { name = "options.json"; }; 24 | xml = docs'.optionsXML // { name = "options.xml"; }; 25 | html = docbookToHtml docs'.optionsDocBook; 26 | man = docbookToMan5 docs'.optionsDocBook; 27 | org = docbookToOrg docs'.optionsDocBook; 28 | info = infoGen.texiToInfo texi; 29 | inherit texi; 30 | }; 31 | in singles // { 32 | all = linkFarmFromDrvs "docs-full" 33 | ( builtins.attrValues ( builtins.removeAttrs docs' ["optionsNix"] ) ); 34 | }; 35 | 36 | in { 37 | inherit generateDocsForOptions; 38 | } 39 | -------------------------------------------------------------------------------- /pkgs/docgen/pandoc/default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? builtins.getFlake "nixpkgs" 2 | , system ? builtins.currentSystem 3 | , pkgs ? import nixpkgs.legacyPackages.${system} 4 | , pandoc ? pkgs.pandoc 5 | }: 6 | let 7 | 8 | pandocInputFormats = [ 9 | "biblatex" "bibtex" "commonmark" "commonmark_x" "creole" "csljson" "csv" 10 | "docbook" "docx" "dokuwiki" "epub" "fb2" "gfm" "haddock" "html" "ipynb" 11 | "jats" "jira" "json" "latex" "man" "markdown" "markdown_github" 12 | "markdown_mmd" "markdown_phpextra" "markdown_strict" "mediawiki" "muse" 13 | "native" "odt" "opml" "org" "rst" "rtf" "t2t" "textile" "tikiwiki" "twiki" 14 | "vimwiki" 15 | ]; 16 | 17 | pandocOutputFormats = [ 18 | "asciidoc" "asciidoctor" "beamer" "biblatex" "bibtex" "commonmark" 19 | "commonmark_x" "context" "csljson" "docbook" "docbook4" "docbook5" "docx" 20 | "dokuwiki" "dzslides" "epub" "epub2" "epub3" "fb2" "gfm" "haddock" "html" 21 | "html4" "html5" "icml" "ipynb" "jats" "jats_archiving" 22 | "jats_articleauthoring" "jats_publishing" "jira" "json" "latex" "man" 23 | "markdown" "markdown_github" "markdown_mmd" "markdown_phpextra" 24 | "markdown_strict" "markua" "mediawiki" "ms" "muse" "native" "odt" 25 | "opendocument" "opml" "org" "pdf" "plain" "pptx" "revealjs" "rst" "rtf" "s5" 26 | "slideous" "slidy" "tei" "texinfo" "textile" "xwiki" "zimwiki" 27 | ]; 28 | 29 | pandocOutputExts = { 30 | commonmark = "md"; 31 | markdown = "md"; 32 | markdown_github = "md"; 33 | markdown_strict = "md"; 34 | markdown_phpextra = "md"; 35 | markdown_mmd = "mmd"; 36 | docbook = "xml"; 37 | docbook4 = "xml"; 38 | docbook5 = "xml"; 39 | opendocument = "odt"; 40 | texinfo = "texi"; 41 | }; 42 | 43 | 44 | /* -------------------------------------------------------------------------- */ 45 | 46 | runPandoc = { from, to, toExt ? pandocOutputExts.${to} or to }: 47 | file: 48 | let 49 | iname = file.name or file.drvAttrs.name or "document"; 50 | # Darwin's broken greedy matching is such bullshit... 51 | m = builtins.match "(.*)-docbook\\.[^.]*" iname; 52 | m' = builtins.match "(.*)\\.[^.]*" iname; 53 | bname = if ( m != null ) then ( builtins.head m ) else 54 | if ( m' != null ) then ( builtins.head m' ) else iname; 55 | in derivation { 56 | name = bname + "." + toExt; 57 | inherit system; 58 | builder = "${pandoc}/bin/pandoc"; 59 | args = [ 60 | "-o" ( builtins.placeholder "out" ) 61 | "-f" from 62 | "-t" to 63 | file 64 | ]; 65 | }; 66 | 67 | docbookToHtml = runPandoc { from = "docbook"; to = "html5"; }; 68 | docbookToPdf = runPandoc { from = "docbook"; to = "pdf"; }; 69 | docbookToJira = runPandoc { from = "docbook"; to = "jira"; }; 70 | docbookToTexi = runPandoc { from = "docbook"; to = "texinfo"; }; 71 | docbookToOrg = runPandoc { from = "docbook"; to = "org"; }; 72 | docbookToMan = runPandoc { from = "docbook"; to = "man"; }; 73 | docbookToManN = n: runPandoc { 74 | from = "docbook"; 75 | to = "man"; 76 | toExt = toString n; 77 | }; 78 | 79 | 80 | /* -------------------------------------------------------------------------- */ 81 | 82 | in { 83 | inherit runPandoc; 84 | inherit docbookToHtml docbookToPdf docbookToJira docbookToTexi docbookToOrg; 85 | inherit docbookToMan docbookToManN; 86 | meta.pandoc = { 87 | inputFormats = pandocInputFormats; 88 | outputFormats = pandocOutputFormats; 89 | defaultOutputExtensions = pandocOutputExts; 90 | }; 91 | } 92 | -------------------------------------------------------------------------------- /pkgs/scripts/nix/nix-outputs: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env nix-shell 2 | #! nix-shell -i bash -p bash 3 | 4 | flakeref='nixpkgs'; 5 | attr=''; 6 | nixflags=''; 7 | declare -A regrefs; 8 | eval "regrefs=( $( 9 | nix registry list|sed 's/^[^:]\{1,\}:\([^ ]\{1,\}\) \(.*\)$/[\1]=\"\2\"/'; 10 | ) );"; 11 | 12 | is_regref() { 13 | test -n "${regrefs[$1]}"; 14 | } 15 | 16 | parse_flag() { 17 | case "$1" in 18 | --write-to|--file|-f|--apply) 19 | nixflags="${nixflags+$nixflags }$1 '$2'"; 20 | return 2; 21 | ;; 22 | --raw) 23 | unlines='o: ( builtins.concatStringsSep "\n" o ) + "\n"'; 24 | nixflags="${nixflags+$nixflags }--raw --apply '$unlines'"; 25 | return 1; 26 | ;; 27 | --json) 28 | nixflags="${nixflags+$nixflags }$1"; 29 | return 1; 30 | ;; 31 | *) 32 | echo "Unrecognized flag: $1" >&2; 33 | exit 1; 34 | ;; 35 | esac 36 | } 37 | 38 | parse_arg() { 39 | case "$1" in 40 | -*) 41 | parse_flag "$@"; 42 | return "$?"; 43 | ;; 44 | *#*) 45 | flakeref="${1/\#*}"; 46 | attr="${1/*\#}"; 47 | return 1; 48 | ;; 49 | *) 50 | if { is_regref "$1"||test -e "${1/\/}/flake.nix"; } && test "$#" -gt 1; 51 | then 52 | flakeref="${1%%/}"; 53 | attr="$2"; 54 | return 2; 55 | else 56 | attr="$1"; 57 | return 1; 58 | fi 59 | ;; 60 | esac 61 | } 62 | 63 | while test "$#" -gt 0; do 64 | parse_arg "$@"; 65 | shift "$?"; 66 | done 67 | 68 | eval "nix eval --impure --derivation $nixflags '$flakeref#$attr.outputs';" 69 | -------------------------------------------------------------------------------- /plugs/conf/template/default.nix: -------------------------------------------------------------------------------- 1 | # See instructions in the `instruct' text below. 2 | { nixpkgs ? builtins.getFlake "nixpkgs" 3 | , system ? builtins.currentSystem 4 | , pkgs ? nixpkgs.legacyPackages.${system} 5 | , writeText ? pkgs.writeText 6 | , myPlugin ? pkgs.myPlugin # FIXME 7 | }: let 8 | instruct = "\n\n" + '' 9 | Build this config file using: 10 | nix build -f ./default.nix --out-link ~/.config/nix/plugin.conf 11 | 12 | Include this in `~/.config/nix/nix.conf' or a similar config file as: 13 | !include ./plugin.conf 14 | 15 | If you would like to add this to a different config, such as 16 | `/etc/nix/nix.conf', just be sure change `--out-link' appropriately. 17 | 18 | If you would like to refer directly to the Nix Store, you can register 19 | this derivation as a GC root, and modify your include line to be: 20 | include /nix/store/XXXXXXXXX...-plugin.conf 21 | ''; 22 | # FIXME 23 | nixConf = import ./plugin.nix { inherit system writeText myPlugin; }; 24 | in builtins.trace instruct nixConf 25 | -------------------------------------------------------------------------------- /plugs/conf/template/plugin.nix: -------------------------------------------------------------------------------- 1 | # See instructions in `./default.nix' 2 | { system, writeText, myPlugin }: let 3 | platform = builtins.elemAt ( builtins.split "-" system ) 2; 4 | isDarwin = platform == "darwin"; 5 | isLinux = platform == "linux"; 6 | libExt = if isDarwin then "dylib" else if isLinux then "so" else 7 | throw "Unknown platform: ${platform}. Unsure of which lib extension to use"; 8 | in writeText "myPlugin.conf" '' 9 | extra-plugin-files = ${myPlugin}/lib/libnix_doc_plugin.${libExt} 10 | '' 11 | -------------------------------------------------------------------------------- /plugs/hello/default.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Produces a Nix Plugin with a `builtins.hello' extensions. 4 | # 5 | # Example plugin invocation ( for a trivial hello world plugin ) 6 | # NOTE: use `libhello.dylib' on Darwin. 7 | # $ nix --option plugin-files './result/libexec/libhello.so' eval \ 8 | # --expr 'builtins.hello' 9 | # "Hello, World!" 10 | # 11 | # 12 | # ---------------------------------------------------------------------------- # 13 | 14 | { nixpkgs ? ( import ../../inputs ).nixpkgs.flake 15 | , system ? builtins.currentSystem 16 | , pkgsFor ? nixpkgs.legacyPackages.${system} 17 | , stdenv ? pkgsFor.stdenv 18 | , nix ? 19 | builtins.getFlake "github:NixOS/nix/${builtins.nixVersion or "2.12.0"}" 20 | , boost ? pkgsFor.boost 21 | }: stdenv.mkDerivation { 22 | pname = "nix-hello-plugin"; 23 | version = "0.1.0"; 24 | src = builtins.path { 25 | name = "source"; 26 | path = ./.; 27 | filter = name: type: 28 | ( type == "regular" ) && ( ( builtins.match ".*\\.nix" name ) == null ); 29 | }; 30 | libExt = stdenv.hostPlatform.extensions.sharedLibrary; 31 | buildInputs = [nix.packages.${system}.nix.dev boost.dev]; 32 | buildPhase = '' 33 | runHook preBuild; 34 | $CXX -shared -o libhello$libExt -std=c++17 ./*.cc \ 35 | ${if stdenv.isDarwin then "-undefined suppress -flat_namespace" else ""}; 36 | runHook postBuild; 37 | ''; 38 | installPhase = '' 39 | runHook preInstall; 40 | mkdir -p $out/libexec; 41 | mv -- ./libhello$libExt $out/libexec/libhello$libExt; 42 | runHook postInstall; 43 | ''; 44 | } 45 | 46 | 47 | # ---------------------------------------------------------------------------- # 48 | # 49 | # 50 | # 51 | # ============================================================================ # 52 | -------------------------------------------------------------------------------- /plugs/hello/hello.cc: -------------------------------------------------------------------------------- 1 | /* ========================================================================== * 2 | * 3 | * 4 | * 5 | * -------------------------------------------------------------------------- */ 6 | 7 | #include "nix/primops.hh" 8 | 9 | using namespace nix; 10 | 11 | /* -------------------------------------------------------------------------- */ 12 | 13 | static void prim_hello( 14 | EvalState & state, const PosIdx pos, Value ** args, Value & v 15 | ) 16 | { 17 | v.mkString( "Hello, World!" ); 18 | } 19 | 20 | 21 | static RegisterPrimOp primop_hello({ 22 | .name = "__hello", 23 | .args = {}, 24 | .doc = R"( 25 | Return the string "Hello, World!" 26 | )", 27 | .fun = prim_hello, 28 | }); 29 | 30 | 31 | /* -------------------------------------------------------------------------- * 32 | * 33 | * 34 | * 35 | * ========================================================================== */ 36 | -------------------------------------------------------------------------------- /profiles/development/default.nix: -------------------------------------------------------------------------------- 1 | { callPackage }: 2 | { 3 | shall = callPackage ./shall.nix {}; 4 | } 5 | -------------------------------------------------------------------------------- /profiles/development/shall.nix: -------------------------------------------------------------------------------- 1 | { buildEnv 2 | , bash 3 | , tcsh 4 | , zsh 5 | , ksh 6 | , dash 7 | }: 8 | # You would need to create a profile script to get MANPATH 9 | buildEnv { 10 | name = "shall"; 11 | paths = [ 12 | bash 13 | tcsh 14 | zsh 15 | ksh 16 | dash 17 | ]; 18 | extraOutputsToInstall = ["man" "doc"]; 19 | } 20 | -------------------------------------------------------------------------------- /templates/autotools/.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.la 3 | *.lo 4 | *.o 5 | *.so 6 | *.swp 7 | *.trs 8 | *~ 9 | .cache 10 | .deps/ 11 | .libs/ 12 | Makefile 13 | Makefile.in 14 | autom4te.cache/ 15 | build/ 16 | config.h.in 17 | configure 18 | gmon.out 19 | output/ 20 | result 21 | stamp-h1 22 | -------------------------------------------------------------------------------- /templates/autotools/Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | -------------------------------------------------------------------------------- /templates/autotools/README: -------------------------------------------------------------------------------- 1 | README.org -------------------------------------------------------------------------------- /templates/autotools/README.org: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex-ameen/ak-nix/ddf10c609d5c434a2d01c6a327ee5a74c481eb15/templates/autotools/README.org -------------------------------------------------------------------------------- /templates/autotools/bootstrap: -------------------------------------------------------------------------------- 1 | aclocal && autoreconf -if 2 | -------------------------------------------------------------------------------- /templates/autotools/configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.71]) 5 | AC_INIT([@PROJECT@], [@VERSION@], [BUG-REPORT-ADDRESS]) 6 | 7 | # Checks for programs. 8 | 9 | # Checks for libraries. 10 | 11 | # Checks for header files. 12 | 13 | # Checks for typedefs, structures, and compiler characteristics. 14 | 15 | # Checks for library functions. 16 | 17 | AC_CONFIG_FILES([Makefile]) 18 | AC_OUTPUT 19 | -------------------------------------------------------------------------------- /templates/autotools/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv 2 | , autoreconfHook 3 | }: 4 | stdenv.mkDerivation { 5 | pname = "@PROJECT@"; 6 | version = "@VERSION@"; 7 | src = ./.; 8 | nativeBuildInputs = [ 9 | autoreconfHook 10 | ]; 11 | } 12 | -------------------------------------------------------------------------------- /templates/autotools/flake.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # ---------------------------------------------------------------------------- # 5 | 6 | { 7 | 8 | # ---------------------------------------------------------------------------- # 9 | 10 | # FIXME: Replace "PROJECT" with your project name. 11 | description = "a basic autotools package"; 12 | 13 | # ---------------------------------------------------------------------------- # 14 | 15 | outputs = { self, nixpkgs, utils, PROJECT-src }: let 16 | 17 | # ---------------------------------------------------------------------------- # 18 | 19 | eachDefaultSystemMap = fn: let 20 | defaultSystems = [ 21 | "x86_64-linux" "aarch64-linux" "i686-linux" 22 | "x86_64-darwin" "aarch64-darwin" 23 | ]; 24 | proc = system: { name = system; value = fn system; }; 25 | in builtins.listToAttrs ( map proc defaultSystems ); 26 | 27 | # ---------------------------------------------------------------------------- # 28 | 29 | in { 30 | 31 | packages = eachDefaultSystemMap ( system: let 32 | pkgsFor = import nixpkgs { inherit system; }; 33 | PROJECT = pkgsFor.callPackage ./default.nix {}; 34 | in { 35 | inherit PROJECT; 36 | default = PROJECT; 37 | } ); 38 | 39 | 40 | # ---------------------------------------------------------------------------- # 41 | 42 | }; # End `outputs' 43 | 44 | 45 | # ---------------------------------------------------------------------------- # 46 | 47 | } 48 | 49 | 50 | # ---------------------------------------------------------------------------- # 51 | # 52 | # 53 | # 54 | # ============================================================================ # 55 | -------------------------------------------------------------------------------- /templates/autotools/m4/utils.m4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alex-ameen/ak-nix/ddf10c609d5c434a2d01c6a327ee5a74c481eb15/templates/autotools/m4/utils.m4 -------------------------------------------------------------------------------- /templates/basic-pkg/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | # FIXME: replace BASIC and OWNER with real info 3 | description = "a basic package"; 4 | 5 | inputs.utils.url = "github:numtide/flake-utils"; 6 | inputs.utils.inputs.nixpkgs.follows = "/nixpkgs"; 7 | 8 | inputs.BASIC-src.url = "github:OWNER/BASIC"; 9 | inputs.BASIC-src.flake = false; 10 | 11 | outputs = { self, nixpkgs, utils, BASIC-src }: let 12 | inherit (utils.lib) eachDefaultSystemMap; 13 | in { 14 | 15 | packages = eachDefaultSystemMap ( system: let 16 | pkgsFor = nixpkgs.legacyPackages.${system}; 17 | in { 18 | BASIC = pkgsFor.stdenv.mkDerivation { 19 | pname = "BASIC"; 20 | version = "0.0.0"; 21 | src = BASIC-src; 22 | nativeBuildInputs = with pkgsFor; [ 23 | # pkg-config 24 | # help2man 25 | # texinfoInteractive 26 | autoreconfHook 27 | ]; 28 | buildInputs = with pkgsFor; [ 29 | # zlib.dev 30 | ]; 31 | }; 32 | 33 | default = self.packages.${system}.BASIC; 34 | } ); # End Packages 35 | 36 | }; 37 | } 38 | # NOTE: This approach to building is not compatible with overlays. 39 | # This is fine for the vast majority of use cases, but if you need to add 40 | # your package to the `nixpkgs.legacyPackages' set you'll need to write 41 | # an overlay which references `nixpkgs' by `final' and `prev'. 42 | # Cases where the overlay is useful are: 43 | # 1. I want `stdenv' modifiers such as `pkgsCross' and `pkgsStatic' to work 44 | # on my package. 45 | # 2. My package is a module for an interpreter, and I want it to be 46 | # available globally for functions like `mkPackage'. 47 | # This largely effects Python and Haskell. 48 | -------------------------------------------------------------------------------- /templates/basic-with-lib/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "ak-nix": { 4 | "inputs": { 5 | "nixpkgs": [ 6 | "nixpkgs" 7 | ] 8 | }, 9 | "locked": { 10 | "lastModified": 1702675111, 11 | "narHash": "sha256-/Bm4A06DmCveuGGCDlt5TzaKaI53CqVvro9BnKo6SNI=", 12 | "owner": "aakropotkin", 13 | "repo": "ak-nix", 14 | "rev": "af3b6e2a1341fa593bce68c6045e6330875b4f66", 15 | "type": "github" 16 | }, 17 | "original": { 18 | "owner": "aakropotkin", 19 | "ref": "main", 20 | "repo": "ak-nix", 21 | "type": "github" 22 | } 23 | }, 24 | "nixpkgs": { 25 | "locked": { 26 | "lastModified": 1710088261, 27 | "narHash": "sha256-cpFX80KeluWb6zmeo+jRIlhRCfeSwMcIzGItHhMO+jM=", 28 | "owner": "NixOS", 29 | "repo": "nixpkgs", 30 | "rev": "3f61120136fcd9410fc5b829c583325193623909", 31 | "type": "github" 32 | }, 33 | "original": { 34 | "owner": "NixOS", 35 | "ref": "master", 36 | "repo": "nixpkgs", 37 | "type": "github" 38 | } 39 | }, 40 | "root": { 41 | "inputs": { 42 | "ak-nix": "ak-nix", 43 | "nixpkgs": "nixpkgs" 44 | } 45 | } 46 | }, 47 | "root": "root", 48 | "version": 7 49 | } 50 | -------------------------------------------------------------------------------- /templates/basic-with-lib/flake.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # A dank flake starter kit. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | description = "A dank starter flake"; 12 | 13 | # ---------------------------------------------------------------------------- # 14 | 15 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/master"; 16 | inputs.ak-nix.url = "github:aakropotkin/ak-nix/main"; 17 | inputs.ak-nix.inputs.nixpkgs.follows = "/nixpkgs"; 18 | 19 | # ---------------------------------------------------------------------------- # 20 | 21 | outputs = { self, nixpkgs, ak-nix, ... }: let 22 | 23 | # ---------------------------------------------------------------------------- # 24 | 25 | eachDefaultSystemMap = fn: let 26 | defaultSystems = [ 27 | "x86_64-linux" "aarch64-linux" "i686-linux" 28 | "x86_64-darwin" "aarch64-darwin" 29 | ]; 30 | proc = system: { name = system; value = fn system; }; 31 | in builtins.listToAttrs ( map proc defaultSystems ); 32 | 33 | 34 | # ---------------------------------------------------------------------------- # 35 | 36 | lib = ak-nix.lib.extend self.overlays.lib; 37 | pkgsForSys = system: nixpkgs.legacyPackages.${system}; 38 | 39 | # ---------------------------------------------------------------------------- # 40 | 41 | in { 42 | 43 | # ---------------------------------------------------------------------------- # 44 | 45 | # Pure `lib' extensions. 46 | overlays.lib = final: prev: {}; 47 | # Nixpkgs overlay: Builders, Packages, Overrides, etc. 48 | overlays.pkgs = final: prev: let 49 | callPackagesWith = auto: prev.lib.callPackagesWith ( final // auto ); 50 | callPackageWith = auto: prev.lib.callPackageWith ( final // auto ); 51 | callPackages = callPackagesWith {}; 52 | callPackage = callPackageWith {}; 53 | in { 54 | lib = prev.lib.extend self.overlays.lib; 55 | }; 56 | # Recommended: Compose with deps into a single overlay. 57 | overlays.default = self.overlays.pkgs; 58 | 59 | 60 | # ---------------------------------------------------------------------------- # 61 | 62 | # Installable Packages for Flake CLI. 63 | packages = eachDefaultSystemMap ( system: let 64 | pkgsFor = pkgsForSys system; 65 | in {} ); 66 | 67 | 68 | # ---------------------------------------------------------------------------- # 69 | 70 | }; # End `outputs' 71 | } 72 | 73 | 74 | # ---------------------------------------------------------------------------- # 75 | # 76 | # 77 | # 78 | # ============================================================================ # 79 | -------------------------------------------------------------------------------- /templates/basic/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1694961060, 6 | "narHash": "sha256-3CJ/6H/JmVRDc8QdFVjFlhpTfeRFzb6nWf48X9IuZO0=", 7 | "owner": "NixOS", 8 | "repo": "nixpkgs", 9 | "rev": "9466d15361b37413d51d4057f427dd7adba958cf", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "NixOS", 14 | "repo": "nixpkgs", 15 | "type": "github" 16 | } 17 | }, 18 | "root": { 19 | "inputs": { 20 | "nixpkgs": "nixpkgs" 21 | } 22 | } 23 | }, 24 | "root": "root", 25 | "version": 7 26 | } 27 | -------------------------------------------------------------------------------- /templates/basic/flake.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # CHANGE: Look for any `CHANGEME' blocks and replace things like `NAME' with 4 | # your flake's name. 5 | # 6 | # ---------------------------------------------------------------------------- # 7 | 8 | { 9 | 10 | # ---------------------------------------------------------------------------- # 11 | 12 | description = "A dank starter flake"; 13 | 14 | 15 | # ---------------------------------------------------------------------------- # 16 | 17 | inputs.nixpkgs.url = "github:NixOS/nixpkgs"; 18 | 19 | 20 | # ---------------------------------------------------------------------------- # 21 | 22 | outputs = { nixpkgs, ... }: let 23 | 24 | # ---------------------------------------------------------------------------- # 25 | 26 | eachDefaultSystemMap = fn: let 27 | defaultSystems = [ 28 | "x86_64-linux" "aarch64-linux" "i686-linux" 29 | "x86_64-darwin" "aarch64-darwin" 30 | ]; 31 | proc = system: { name = system; value = fn system; }; 32 | in builtins.listToAttrs ( map proc defaultSystems ); 33 | 34 | 35 | # ---------------------------------------------------------------------------- # 36 | 37 | inherit (nixpkgs) lib; 38 | 39 | 40 | # ---------------------------------------------------------------------------- # 41 | 42 | # Aggregate dependency overlays here. 43 | 44 | ## CHANGEME 45 | 46 | # If you only need `nixpkgs.legacyPackages', use this 47 | overlays.deps = final: prev: {}; 48 | 49 | ## If you only need a single extension, use this and change `INPUT' 50 | ##overlays.deps = INPUT.overlays.default; 51 | 52 | ## If you need two, use this and change `INPUT#'s. 53 | ##overlays.deps = lib.composeExtensions INPUT0.overlays.default 54 | ## INPUT1.overlays.default; 55 | 56 | ## If you need many, use this and change `INPUT#s's 57 | ##overlays.deps = lib.composeManyExtensions [ 58 | ## INPUT0.overlays.default 59 | ## INPUT1.overlays.default 60 | ## INPUT2.overlays.default 61 | ##]; 62 | 63 | 64 | # ---------------------------------------------------------------------------- # 65 | 66 | # Define our overlay 67 | 68 | # CHANGEME 69 | 70 | overlays.NAME = final: prev: { 71 | ## NAME = final.callPackage ./default.nix {}; 72 | }; 73 | 74 | 75 | # Make our default overlay as `deps + NAME'. 76 | overlays.default = lib.composeExtensions overlays.deps overlays.NAME; 77 | 78 | 79 | # ---------------------------------------------------------------------------- # 80 | 81 | in { 82 | 83 | inherit lib overlays; 84 | 85 | # Installable Packages for Flake CLI. 86 | packages = eachDefaultSystemMap ( system: let 87 | pkgsFor = nixpkgs.legacyPackages.${system}.extend overlays.default; 88 | in { 89 | # CHANGEME 90 | inherit (pkgsFor) NAME; 91 | } ); 92 | 93 | 94 | 95 | }; # End `outputs' 96 | 97 | 98 | # ---------------------------------------------------------------------------- # 99 | 100 | } 101 | 102 | 103 | # ---------------------------------------------------------------------------- # 104 | # 105 | # 106 | # 107 | # ============================================================================ # 108 | -------------------------------------------------------------------------------- /templates/lib-sub/sub.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | inc = x: x + 1; 12 | 13 | 14 | # ---------------------------------------------------------------------------- # 15 | 16 | in { 17 | inherit 18 | inc 19 | ; 20 | } 21 | 22 | # ---------------------------------------------------------------------------- # 23 | # 24 | # 25 | # 26 | # ============================================================================ # 27 | -------------------------------------------------------------------------------- /templates/meaty/flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "ak-nix": { 4 | "inputs": { 5 | "nixpkgs": [ 6 | "nixpkgs" 7 | ] 8 | }, 9 | "locked": { 10 | "lastModified": 1702675111, 11 | "narHash": "sha256-/Bm4A06DmCveuGGCDlt5TzaKaI53CqVvro9BnKo6SNI=", 12 | "owner": "aakropotkin", 13 | "repo": "ak-nix", 14 | "rev": "af3b6e2a1341fa593bce68c6045e6330875b4f66", 15 | "type": "github" 16 | }, 17 | "original": { 18 | "owner": "aakropotkin", 19 | "ref": "main", 20 | "repo": "ak-nix", 21 | "type": "github" 22 | } 23 | }, 24 | "nixpkgs": { 25 | "locked": { 26 | "lastModified": 1710088261, 27 | "narHash": "sha256-cpFX80KeluWb6zmeo+jRIlhRCfeSwMcIzGItHhMO+jM=", 28 | "owner": "NixOS", 29 | "repo": "nixpkgs", 30 | "rev": "3f61120136fcd9410fc5b829c583325193623909", 31 | "type": "github" 32 | }, 33 | "original": { 34 | "owner": "NixOS", 35 | "ref": "master", 36 | "repo": "nixpkgs", 37 | "type": "github" 38 | } 39 | }, 40 | "root": { 41 | "inputs": { 42 | "ak-nix": "ak-nix", 43 | "nixpkgs": "nixpkgs" 44 | } 45 | } 46 | }, 47 | "root": "root", 48 | "version": 7 49 | } 50 | -------------------------------------------------------------------------------- /templates/meaty/flake.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # A meaty flake starter flake. 4 | # 5 | # FIXME: You need to edit "NAME" stubs in this file, and delete the time-bomb 6 | # `ASSERT_SETUP' once you've set up this flake. 7 | # Search around for any "FIXME" messages. 8 | # 9 | # ---------------------------------------------------------------------------- # 10 | 11 | { 12 | description = "A meaty starter flake"; 13 | 14 | inputs.nixpkgs.url = "github:NixOS/nixpkgs/master"; 15 | inputs.ak-nix.url = "github:aakropotkin/ak-nix/main"; 16 | inputs.ak-nix.inputs.nixpkgs.follows = "/nixpkgs"; 17 | 18 | # ---------------------------------------------------------------------------- # 19 | 20 | outputs = { nixpkgs, ak-nix, ... }: let 21 | 22 | # ---------------------------------------------------------------------------- # 23 | 24 | # Pure `lib' extensions. 25 | libOverlays.NAME = final: prev: let 26 | callLibWith = { lib ? final, ... } @ auto: x: let 27 | f = if prev.lib.isFunction x then x else import x; 28 | args = builtins.intersectAttrs ( builtins.functionArgs f ) 29 | ( { inherit lib; } // auto ); 30 | in f args; 31 | callLibsWith = auto: 32 | builtins.foldl' ( acc: x: acc // ( callLibWith auto x ) ) {}; 33 | callLib = callLibWith {}; 34 | callLibs = callLibsWith {}; 35 | in { 36 | # FIXME: put lib extensions here. 37 | 38 | # Import a file as a named sub-lib. 39 | # libfoo = callLib ./lib/foo.nix; 40 | 41 | # Join multiple files into a single named sub-lib. 42 | # libbar = callLibs [./lib/bar-a.nix ./lib/bar-b.nix]; 43 | 44 | # Write an inline definition of a sub-lib. 45 | libNAME = { 46 | greet = name: 47 | builtins.trace "\nHowdy ${name}!\n" null; 48 | }; 49 | 50 | # Add a new top-level function. 51 | phony = let 52 | die = throw "FIXME: You should delete these stub functions"; 53 | in builtins.deepSeq die null; 54 | 55 | # Add a function from a sub-lib to the top level. 56 | inherit (final.libNAME) greet; 57 | }; # End `libNAME' Overlay. 58 | 59 | # Any other `lib' overlays we depend on. 60 | libOverlays.deps = ak-nix.libOverlays.default; 61 | # Our overlay + our deps. 62 | libOverlays.default = nixpkgs.lib.composeExtensions libOverlays.deps 63 | libOverlays.NAME; 64 | 65 | # NOTE: Consume as `lib = nixpkgs.lib.extend NAME.libOverlays.default'. 66 | # Assuming the pattern of `libOverlays.{deps,NAME,default}' is followed 67 | # across your dependencies, you can compose arbitrary combinations of 68 | # direct dependencies' `libOverlays.default' extensions without worrying 69 | # about transitive dependencies' extensions. 70 | 71 | 72 | # ---------------------------------------------------------------------------- # 73 | 74 | overlays.deps = ak-nix.overlays.default; 75 | # Reccomended for multiple input overlays: 76 | # lib.composeManyExtensions [ak-nix.overlays.default ...]; 77 | 78 | # Nixpkgs overlay: Builders, Packages, Overrides, etc. 79 | overlays.NAME = final: prev: let 80 | callPackagesWith = auto: prev.lib.callPackagesWith ( final // auto ); 81 | callPackageWith = auto: prev.lib.callPackageWith ( final // auto ); 82 | callPackages = callPackagesWith {}; 83 | callPackage = callPackageWith {}; 84 | in { 85 | lib = prev.lib.extend libOverlays.default; 86 | # FIXME: Put real package definitions here. 87 | howdy = prev.writeShellScriptBin "howdy" ''echo "Howdy!";''; 88 | }; 89 | 90 | # By default, compose with our deps into a single overlay. 91 | # NOTE: Same rationale as described for `libOverlays'. 92 | overlays.default = nixpkgs.lib.composeExtensions overlays.deps 93 | overlays.NAME; 94 | 95 | # Nixpkgs + ak-nix + our extensions. 96 | # NOTE: You could expose this publicly as `legacyPackages.${system}', just 97 | # keep in mind that `nix flake check' may run a large number of audits. 98 | pkgsForSys = system: 99 | nixpkgs.legacyPackages.${system}.extend overlays.default; 100 | 101 | # ---------------------------------------------------------------------------- # 102 | 103 | # FIXME: Pick your poison: 104 | #supportedSystems = [ 105 | # "x86_64-linux" "aarch64-linux" 106 | # "x86_64-darwin" "aarch64-darwin" 107 | #]; 108 | supportedSystems = ak-nix.lib.defaultSystems; 109 | eachSupportedSystemMap = ak-nix.lib.eachSystemMap supportedSystems; 110 | 111 | 112 | # ---------------------------------------------------------------------------- # 113 | 114 | # FIXME: Remove this after setting up this template. 115 | 116 | ASSERT_SETUP = pkg: let 117 | # This prevents triggering the time bomb in upstream `ak-nix' checks. 118 | hasGitDir = builtins.pathExists "${toString ./.}/.git/."; 119 | msg = '' 120 | It looks like you need to setup your flake template! 121 | Read all the "FIXME" messages across the file, and then remove the 122 | `ASSERT_SETUP' time-bomb near the bottom when you're done. 123 | ''; 124 | in if hasGitDir then builtins.deepSeq ( throw msg ) pkg else pkg; 125 | 126 | # FIXME: Remove this after setting up this template. 127 | 128 | 129 | # ---------------------------------------------------------------------------- # 130 | 131 | in { # Begin Outputs 132 | 133 | # ---------------------------------------------------------------------------- # 134 | 135 | # Nixpkgs + ak-nix + our extensions. 136 | lib = nixpkgs.lib.extend libOverlays.default; 137 | 138 | # ---------------------------------------------------------------------------- # 139 | 140 | # Installable Packages for Flake CLI. 141 | packages = eachSupportedSystemMap ( system: let 142 | pkgsFor = pkgsForSys system; 143 | in { 144 | # FIXME: put real package definitions here. 145 | inherit (pkgsFor) howdy; 146 | ASSERT_SETUP_TIMEBOMB = ASSERT_SETUP pkgsFor.howdy; 147 | } ); 148 | 149 | 150 | # ---------------------------------------------------------------------------- # 151 | 152 | }; # End Outputs 153 | } 154 | 155 | 156 | # ---------------------------------------------------------------------------- # 157 | # 158 | # 159 | # 160 | # ============================================================================ # 161 | -------------------------------------------------------------------------------- /templates/nix-bin/default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? builtins.getFlake "nixpkgs" 2 | , system ? builtins.currentSystem 3 | , pkgsFor ? nixpkgs.legacyPackages.${system} 4 | , stdenv ? pkgsFor.stdenv 5 | , nix ? pkgsFor.nix 6 | , boost ? pkgsFor.boost 7 | , nlohmann_json ? pkgsFor.nlohmann_json 8 | , pkg-config ? pkgsFor.pkg-config 9 | }: import ./pkg-fun.nix { inherit stdenv nix boost nlohmann_json pkg-config; } 10 | -------------------------------------------------------------------------------- /templates/nix-bin/main.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | int 15 | main( int argc, char * argv[], char ** envp ) 16 | { 17 | nix::initNix(); 18 | nix::initGC(); 19 | 20 | nix::evalSettings.pureEval = false; 21 | 22 | nix::EvalState state( {}, nix::openStore() ); 23 | 24 | try 25 | { 26 | auto originalRef = parseFlakeRef( argv[1], nix::absPath( "." ) ); 27 | auto resolvedRef = originalRef.resolve( state.store ); 28 | } 29 | catch( std::exception & e ) 30 | { 31 | std::cerr << e.what() << std::endl; 32 | return EXIT_SUCCESS; 33 | } 34 | 35 | std::cout << resolvedRef.to_string() << std::endl; 36 | 37 | return EXIT_SUCCESS; 38 | } 39 | -------------------------------------------------------------------------------- /templates/nix-bin/pkg-fun.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { stdenv, nix, boost, nlohmann_json, pkg-config }: stdenv.mkDerivation { 8 | pname = "NAME"; 9 | version = "0.1.0"; 10 | src = builtins.path { 11 | path = ./.; 12 | filter = name: type: ! ( builtins.elem ( baseNameOf name ) [ 13 | "result" "result-dev" "result-man" "result-info" "result-lib" "result-bin" 14 | ".gitignore" 15 | "Makefile" 16 | ] ); 17 | }; 18 | nativeBuildInputs = [pkg-config]; 19 | buildInputs = [nix.dev boost nlohmann_json]; 20 | dontConfigure = true; 21 | buildPhase = '' 22 | $CXX \ 23 | -I${nix.dev}/include \ 24 | -I${boost.dev}/include \ 25 | -I${nlohmann_json}/include \ 26 | -include ${nix.dev}/include/nix/config.h \ 27 | ./main.cc \ 28 | -Wl,--as-needed \ 29 | $(pkg-config --libs --cflags nix-cmd nix-main nix-store nix-expr) \ 30 | -lnixfetchers \ 31 | -Wl,--no-as-needed \ 32 | -o "$pname" \ 33 | ; 34 | ''; 35 | installPhase = '' 36 | mkdir -p "$out/bin"; 37 | mv -- "./$pname" "$out/bin/$pname"; 38 | ''; 39 | } 40 | 41 | 42 | # ---------------------------------------------------------------------------- # 43 | # 44 | # 45 | # 46 | # ============================================================================ # 47 | -------------------------------------------------------------------------------- /templates/nix-plugin/default.nix: -------------------------------------------------------------------------------- 1 | { nixpkgs ? builtins.getFlake "nixpkgs" 2 | , system ? builtins.currentSystem 3 | , pkgsFor ? nixpkgs.legacyPackages.${system} 4 | , stdenv ? pkgsFor.stdenv 5 | , bash ? pkgsFor.bash 6 | , nix ? pkgsFor.nix 7 | , boost ? pkgsFor.boost 8 | , nlohmann_json ? pkgsFor.nlohmann_json 9 | , pkg-config ? pkgsFor.pkg-config 10 | }: import ./pkg-fun.nix { 11 | inherit stdenv bash nix boost nlohmann_json pkg-config; 12 | } 13 | -------------------------------------------------------------------------------- /templates/nix-plugin/pkg-fun.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { stdenv, bash, nix, boost, nlohmann_json, pkg-config }: stdenv.mkDerivation { 8 | pname = "NAME"; 9 | version = "0.1.0"; 10 | src = builtins.path { path = ./.; }; 11 | nativeBuildInputs = [pkg-config]; 12 | buildInputs = [nix nix.dev boost nlohmann_json]; 13 | propagatedBuildInputs = [bash nix]; 14 | dontConfigure = true; 15 | libExt = stdenv.hostPlatform.extensions.sharedLibrary; 16 | buildPhase = '' 17 | $CXX \ 18 | -shared \ 19 | -fPIC \ 20 | -I${nix.dev}/include \ 21 | -I${boost.dev}/include \ 22 | -I${nlohmann_json}/include \ 23 | -include ${nix.dev}/include/nix/config.h \ 24 | $(pkg-config --libs --cflags nix-main nix-store nix-expr) \ 25 | -o "lib$pname$libExt" \ 26 | ./*.cc \ 27 | ; 28 | ''; 29 | installPhase = '' 30 | mkdir -p "$out/bin" "$out/libexec"; 31 | mv "./lib$pname$libExt" "$out/libexec/lib$pname$libExt"; 32 | cat <"$out/bin/$pname" 33 | #! ${bash}/bin/bash 34 | # A wrapper around Nix that includes the \`libscrape' plugin. 35 | # First we add runtime executables to \`PATH', then pass off to Nix. 36 | for p in \$( <"$out/nix-support/propagated-build-inputs"; ); do 37 | if [[ -d "\$p/bin" ]]; then PATH="\$PATH:\$p/bin"; fi 38 | done 39 | exec "${nix}/bin/nix" --plugin-files "$out/libexec/lib$pname$libExt" "\$@"; 40 | EOF 41 | chmod +x "$out/bin/$pname"; 42 | ''; 43 | } 44 | 45 | 46 | # ---------------------------------------------------------------------------- # 47 | # 48 | # 49 | # 50 | # ============================================================================ # 51 | -------------------------------------------------------------------------------- /templates/nix-plugin/plugin.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace nix; 9 | using namespace nix::flake; 10 | using json = nlohmann::json; 11 | 12 | class FlakeCommand : virtual Args, public MixFlakeOptions 13 | { 14 | std::string flakeUrl = "."; 15 | 16 | public: 17 | 18 | FlakeCommand() 19 | { 20 | expectArgs( { 21 | .label = "flake-url", 22 | .optional = true, 23 | .handler = { & flakeUrl }, 24 | .completer = { [&]( size_t, std::string_view prefix ) { 25 | completeFlakeRef( getStore(), prefix ); 26 | } } 27 | } ); 28 | } 29 | 30 | FlakeRef getFlakeRef() 31 | { 32 | return parseFlakeRef( flakeUrl, absPath( "." ) ); //FIXME 33 | } 34 | 35 | LockedFlake lockFlake() 36 | { 37 | return flake::lockFlake( * getEvalState(), getFlakeRef(), lockFlags ); 38 | } 39 | 40 | std::vector getFlakesForCompletion() override 41 | { 42 | return { flakeUrl }; 43 | } 44 | }; 45 | 46 | struct CmdName : FlakeCommand { 47 | 48 | bool someOption = false; 49 | 50 | CmdFlakeScrape() 51 | { 52 | addFlag( { 53 | .longName = "some-option", 54 | .description = "TODO", 55 | .handler = { & someOption, true } 56 | } ); 57 | } 58 | 59 | std::string description() override 60 | { 61 | return "TODO"; 62 | } 63 | 64 | std::string doc() override 65 | { 66 | return "TODO"; 67 | } 68 | 69 | void run( nix::ref store ) override 70 | { 71 | evalSettings.enableImportFromDerivation.setDefault( false ); 72 | 73 | auto state = getEvalState(); 74 | auto flake = std::make_shared( lockFlake() ); 75 | auto localSystem = std::string( settings.thisSystem.get() ); 76 | 77 | logger->cout( "%s", "TODO" ); 78 | } 79 | }; 80 | 81 | static auto rScrapeCmd = registerCommand( "NAME" ); 82 | -------------------------------------------------------------------------------- /templates/tests-sub/default.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Provides sane defaults for running this set of tests. 4 | # This is likely not the "ideal" way to utilize the test suite, but for someone 5 | # who is consuming your project and knows nothing about it - this file should 6 | # allow them to simply run `nix build -f .' to see if the test suite passes. 7 | # 8 | # ---------------------------------------------------------------------------- # 9 | 10 | { lib ? PROJECT.lib or pkgsFor.lib 11 | , pkgsFor ? ( PROJECT.legacyPackages or nixpkgs.legacyPackages ).${system} 12 | , writeText ? pkgsFor.writeText 13 | , system ? builtins.currentSystem 14 | , PROJECT ? builtins.getFlake ( toString ../.. ) 15 | , nixpkgs ? builtins.getFlake "nixpkgs" 16 | 17 | # Options 18 | , keepFailed ? false # Useful if you run the test explicitly. 19 | , doTrace ? true # We want this disabled for `nix flake check' 20 | , ... 21 | } @ args: let 22 | 23 | # ---------------------------------------------------------------------------- # 24 | 25 | # Used to import test files. 26 | autoArgs = { inherit lib pkgsFor writeText; } // args; 27 | 28 | tests = let 29 | testsFrom = file: let 30 | fn = import file; 31 | fargs = builtins.functionArgs fn; 32 | ts = fn ( builtins.intersectAttrs fargs autoArgs ); 33 | in assert builtins.isAttrs ts; 34 | ts.tests or ts; 35 | in builtins.foldl' ( ts: file: ts // ( testsFrom file ) ) {} [ 36 | ./tests.nix 37 | ]; 38 | 39 | # ---------------------------------------------------------------------------- # 40 | 41 | # We need `check' and `checkerDrv' to use different `checker' functions which 42 | # is why we have explicitly provided an alternative `check' as a part 43 | # of `mkCheckerDrv'. 44 | harness = let 45 | name = "@NAME@-tests"; 46 | in lib.libdbg.mkTestHarness { 47 | inherit name keepFailed tests writeText; 48 | mkCheckerDrv = args: lib.libdbg.mkCheckerDrv { 49 | inherit name keepFailed writeText; 50 | check = lib.libdbg.checkerReport name harness.run; 51 | }; 52 | checker = name: run: let 53 | msg = lib.libdbg.checkerMsg name run; 54 | rsl = lib.libdbg.checkerDefault name run; 55 | in if doTrace then builtins.trace msg rsl else rsl; 56 | }; 57 | 58 | 59 | # ---------------------------------------------------------------------------- # 60 | 61 | in harness 62 | 63 | 64 | # ---------------------------------------------------------------------------- # 65 | # 66 | # 67 | # 68 | # ============================================================================ # 69 | -------------------------------------------------------------------------------- /templates/tests-sub/tests.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # General tests for `@NAME@' routines. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib 8 | , system 9 | , pkgsFor 10 | }: let 11 | 12 | # ---------------------------------------------------------------------------- # 13 | 14 | tests = { 15 | 16 | # ---------------------------------------------------------------------------- # 17 | 18 | # PASS 19 | testFoo = { 20 | expr = 1 + 1; 21 | expected = 2; 22 | }; 23 | 24 | # FAIL 25 | testBar = { 26 | expr = 3; 27 | expected = 2; 28 | }; 29 | 30 | 31 | # ---------------------------------------------------------------------------- # 32 | 33 | }; # End Tests 34 | 35 | 36 | # ---------------------------------------------------------------------------- # 37 | 38 | in tests 39 | 40 | 41 | # ---------------------------------------------------------------------------- # 42 | # 43 | # 44 | # 45 | # ============================================================================ # 46 | -------------------------------------------------------------------------------- /templates/tests/bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # ============================================================================ # 3 | # 4 | # Fills template strings in generated files. 5 | # 6 | # ---------------------------------------------------------------------------- # 7 | 8 | set -eu; 9 | 10 | _AS_ME="${BASH_SOURCE[0]##*/}"; 11 | _SDIR="${BASH_SOURCE[0]%/*}"; 12 | 13 | : "${GIT:=git}"; 14 | : "${SED:=sed}"; 15 | : "${REALPATH:=realpath}"; 16 | 17 | : "${PROJECT:=}"; 18 | : "${SUB_NAME:=}"; 19 | : "${ROOT:=}"; 20 | export PROJECT SUB_NAME ROOT; 21 | 22 | usage() { 23 | { 24 | echo "$_AS_ME [-p PROJECT] [-s SUB_NAME] [-r ROOT]"; 25 | echo "-p|--proj project name"; 26 | echo "-s|--sub test subdir name"; 27 | echo "-r|--root path to project root ( with flake.nix )"; 28 | } 29 | } 30 | 31 | 32 | # ---------------------------------------------------------------------------- # 33 | 34 | while test "$#" -gt 0; do 35 | case "$1" in 36 | -p|--proj) PROJECT="$2"; shift; ;; 37 | -s|--sub) SUB_NAME="$2"; shift; ;; 38 | -r|--root) ROOT="$2"; shift; ;; 39 | -h|--help) usage >&2; exit 0; ;; 40 | *) echo "$_AS_ME: Unrecognized arg: $1" >&2; usage >&2; exit 1; ;; 41 | esac 42 | shift; 43 | done 44 | 45 | 46 | # ---------------------------------------------------------------------------- # 47 | 48 | confirmVar() { 49 | local _var _val _p _dscp; 50 | _var="$1"; 51 | shift; 52 | eval _val="\$_${_var:-}"; 53 | _dscp="${*:+ ( $* )}"; 54 | if test -z "$_val"; then 55 | read -p "Could not infer $_var$_dscp. What should it be? " _val; 56 | echo ''; 57 | else 58 | read -n 1 -p "We guessed $_var$_dscp to be '$_val'. Sound good? [Yn] " _p; 59 | echo ''; 60 | case "$_p" in 61 | [Nn]*) 62 | read -p "Then what should it be? " _val; 63 | echo ''; 64 | ;; 65 | *) :; ;; 66 | esac 67 | fi 68 | eval $_var="$_val"; 69 | } 70 | 71 | 72 | # ---------------------------------------------------------------------------- # 73 | 74 | if test -z "$ROOT"; then 75 | if test -r "$_SDIR/../flake.nix"; then 76 | _ROOT="$_SDIR/.."; 77 | elif ! test -d "$_SDIR/.git" && test -d "$_SDIR/../.git"; then 78 | _ROOT="$_SDIR/.."; 79 | fi 80 | confirmVar ROOT path to project root with flake.nix; 81 | fi 82 | 83 | 84 | # ---------------------------------------------------------------------------- # 85 | 86 | if test -z "$PROJECT"; then 87 | _PROJECT="$( $GIT config --get remote.origin.url||:; )"; 88 | _PROJECT="${_PROJECT##*/}"; 89 | _PROJECT="${_PROJECT%.git}"; 90 | confirmVar PROJECT your project name; 91 | fi 92 | 93 | 94 | # ---------------------------------------------------------------------------- # 95 | 96 | if test -z "$SUB_NAME"; then 97 | _SUB_NAME=''; 98 | confirmVar SUB_NAME name of your first test subdir; 99 | fi 100 | 101 | 102 | # ---------------------------------------------------------------------------- # 103 | 104 | case "$SUB_NAME" in 105 | sub) :; ;; 106 | *) 107 | echo "Moving $_SDIR/sub to $_SDIR/$SUB_NAME" >&2; 108 | mv "$_SDIR/sub" "$_SDIR/$SUB_NAME"; 109 | ;; 110 | esac 111 | echo "Substituting variables in to template files:" >&2; 112 | echo " $_SDIR/"*.nix "$_SDIR/$SUB_NAME/"*; 113 | $SED -i \ 114 | -e "s/@NAME@/$SUB_NAME/g" \ 115 | -e "s/PROJECT/$PROJECT/g" \ 116 | "$_SDIR/"*.nix \ 117 | "$_SDIR/$SUB_NAME/"*; 118 | $SED -i "s,^ \./sub\$, ./$SUB_NAME," "$_SDIR/default.nix"; 119 | 120 | 121 | # ---------------------------------------------------------------------------- # 122 | 123 | if test "$( $REALPATH $ROOT; )" != "$( $REALPATH $_SDIR; )"; then 124 | read -n 1 -p "Would you like to move check.sh to the project root? [Yn]"; 125 | echo ''; 126 | case "$REPLY" in 127 | [Nn]*) 128 | { 129 | echo "NOTE: if you plan to use 'check.sh' outside of the project root"; 130 | echo "be sure to edit its 'SDIR' and 'FLAKE_REF' setup accordingly."; 131 | } >&2; 132 | sleep 1s; 133 | ;; 134 | *) mv "$_SDIR/check.sh" "$ROOT/check.sh"; ;; 135 | esac 136 | fi 137 | 138 | 139 | # ---------------------------------------------------------------------------- # 140 | 141 | read -n 1 -p "Would you like to delete ${BASH_SOURCE[0]}? [Yn]"; 142 | echo ''; 143 | case "$REPLY" in 144 | [Nn]*) :; ;; 145 | *) rm "${BASH_SOURCE[0]}"; ;; 146 | esac 147 | 148 | 149 | # ---------------------------------------------------------------------------- # 150 | 151 | read -n 1 -p "Would you like to add these files to 'git'? [Yn]"; 152 | echo ''; 153 | case "$REPLY" in 154 | [Nn]*) :; ;; 155 | *) 156 | if test -r "$ROOT/check.sh"; then 157 | $GIT add "$ROOT/check.sh"; 158 | fi 159 | $GIT add "$_SDIR"; 160 | ;; 161 | esac 162 | 163 | 164 | # ---------------------------------------------------------------------------- # 165 | 166 | exit 0; 167 | 168 | 169 | # ---------------------------------------------------------------------------- # 170 | # 171 | # 172 | # 173 | # ============================================================================ # 174 | -------------------------------------------------------------------------------- /templates/tests/check.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -eu; 3 | set -o pipefail; 4 | 5 | : "${REALPATH:=realpath}"; 6 | : "${NIX:=nix}"; 7 | : "${NIX_FLAGS:=--no-warn-dirty}"; 8 | : "${NIX_CMD_FLAGS:=-L --show-trace}"; 9 | : "${SYSTEM:=$( $NIX eval --raw --impure --expr builtins.currentSystem; )}"; 10 | : "${GREP:=grep}" 11 | : "${JQ:=jq}"; 12 | 13 | SDIR="$( $REALPATH "${BASH_SOURCE[0]}" )"; 14 | SDIR="${SDIR%/*}"; 15 | : "${FLAKE_REF:=$SDIR}"; 16 | 17 | trap '_es="$?"; exit "$_es";' HUP EXIT INT QUIT ABRT; 18 | 19 | nix_w() { 20 | { 21 | { 22 | $NIX $NIX_FLAGS "$@" 3>&2 2>&1 1>&3||exit 1; 23 | }|$GREP -v 'warning: unknown flake output'; 24 | } 3>&2 2>&1 1>&3; 25 | } 26 | 27 | nix_w flake check "$FLAKE_REF" $NIX_CMD_FLAGS --system "$SYSTEM"; 28 | nix_w flake check "$FLAKE_REF" $NIX_CMD_FLAGS --system "$SYSTEM" --impure; 29 | 30 | # Swallow traces, but show them on failure. 31 | check_lib() { 32 | nix_w eval "$FLAKE_REF#lib" --apply 'lib: builtins.deepSeq lib true'; 33 | } 34 | check_lib 2>/dev/null||check_lib; -------------------------------------------------------------------------------- /templates/tests/default.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Provides sane defaults for running this set of tests. 4 | # This is likely not the "ideal" way to utilize the test suite, but for someone 5 | # who is consuming your project and knows nothing about it - this file should 6 | # allow them to simply run `nix build -f .' to see if the test suite passes. 7 | # 8 | # ---------------------------------------------------------------------------- # 9 | # 10 | # XXX: GETTING STARTED 11 | # 12 | # * Find/replace the string "PROJECT" with your project name. 13 | # The `bootstrap.sh' script should handle this for you, but in case you're 14 | # editing by hand that the first thing to change. 15 | # * Move the `check.sh' script up to the root of your project ( or wherever your 16 | # flake lives ). 17 | # If you don't want it at the top level be sure to edit the `SDIR' or 18 | # `FLAKE_REF' env settings in the script to reflect the location. 19 | # * Users should likely set the formal arg for `pkgsFor' based on their 20 | # flake setup to avoid complexity. 21 | # If your flake produces overlays or sets `legacyPackages' - then inline it! 22 | # * If your tests are not sensitive to purity, "import from derivaiton" ( IFD ), 23 | # restricted reads ( `allowedPaths' ), or use any typecheckers - you can 24 | # remove the "Eval Env" formal arguments. 25 | # Having said that, if you create any derivations in your tests, you almost 26 | # certainly want to keep the `ifd' argument, since this can be used to block 27 | # tests from running on certain systems/platforms, or restricting 28 | # substitution of derivations from external binary caches/stores. 29 | # * Probably add your tests to your flake's `checks' attrset. 30 | # Example: 31 | # ``` 32 | # checks = at-node-nix.lib.eachDefaultSystemMap ( system: let 33 | # pkgsFor = self.legacyPackages.${sysem}; 34 | # testsWith = at-node-nix.lib.callWith pkgsFor ./tests; 35 | # in { 36 | # tests = testsWith { typecheck = false; }; 37 | # testsTyped = testsWith { nameExtra = "typed"; typecheck = true; }; 38 | # testsFoo = testsWith { nameExtra = "foo"; foo = true; }; 39 | # # ... 40 | # }; 41 | # ``` 42 | # This will give you nice pretty traces with info from `pure' and `system', 43 | # and any additional tags you add to `nameExtra'. 44 | # * Delete these instructions when you're done. 45 | # 46 | # ---------------------------------------------------------------------------- # 47 | 48 | { PROJECT ? builtins.getFlake ( toString ../. ) 49 | , lib ? PROJECT.lib 50 | , system ? builtins.currentSystem 51 | , pkgsFor ? let 52 | from = if PROJECT ? legacyPackages then PROJECT else PROJECT.inputs.nixpkgs; 53 | ov = PROJECT.overlays.default or null; 54 | base = from.legacyPackages.${system}; 55 | in if ov == null then base else base.extend ov; 56 | , writeText ? pkgsFor.writeText 57 | 58 | # Eval Env 59 | , pure ? lib.inPureEvalMode 60 | , ifd ? ( builtins.currentSystem or null ) == system 61 | , allowedPaths ? toString ../. 62 | , typecheck ? true 63 | 64 | # Options 65 | , keepFailed ? false # Useful if you run the test explicitly. 66 | , nameExtra ? "" 67 | , ... 68 | } @ args: let 69 | 70 | # ---------------------------------------------------------------------------- # 71 | 72 | # Used to import test files. 73 | auto = { inherit lib pkgsFor writeText; } // args; 74 | 75 | tests = let 76 | testsFrom = file: let 77 | fn = import file; 78 | fargs = builtins.functionArgs fn; 79 | ts = fn ( builtins.intersectAttrs fargs auto ); 80 | in assert builtins.isAttrs ts; 81 | ts.tests or ts; 82 | in builtins.foldl' ( ts: file: ts // ( testsFrom file ) ) {} [ 83 | ./sub 84 | ]; 85 | 86 | # ---------------------------------------------------------------------------- # 87 | 88 | # We need `check' and `checkerDrv' to use different `checker' functions which 89 | # is why we have explicitly provided an alternative `check' as a part 90 | # of `mkCheckerDrv'. 91 | harness = let 92 | purity = if pure then "pure" else "impure"; 93 | ne = if nameExtra != "" then " " + nameExtra else ""; 94 | name = "PROJECT-tests${ne} (${system}, ${purity})"; 95 | in lib.libdbg.mkTestHarness { 96 | inherit name keepFailed tests writeText; 97 | mkCheckerDrv = { 98 | __functionArgs = lib.functionArgs lib.libdbg.mkCheckerDrv; 99 | __innerFunction = lib.libdbg.mkCheckerDrv; 100 | __processArgs = self: args: self.__thunk // args; 101 | __thunk = { inherit name keepFailed writeText; }; 102 | __functor = self: x: self.__innerFunction ( self.__processArgs self x ); 103 | }; 104 | checker = name: run: let 105 | rsl = lib.libdbg.checkerReport name run; 106 | msg = builtins.trace rsl null; 107 | in builtins.deepSeq msg rsl; 108 | }; 109 | 110 | 111 | # ---------------------------------------------------------------------------- # 112 | 113 | in harness 114 | 115 | 116 | # ---------------------------------------------------------------------------- # 117 | # 118 | # 119 | # 120 | # ============================================================================ # 121 | -------------------------------------------------------------------------------- /templates/tests/sub/default.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Provides sane defaults for running this set of tests. 4 | # This is likely not the "ideal" way to utilize the test suite, but for someone 5 | # who is consuming your project and knows nothing about it - this file should 6 | # allow them to simply run `nix build -f .' to see if the test suite passes. 7 | # 8 | # ---------------------------------------------------------------------------- # 9 | # 10 | # XXX: GETTING STARTED 11 | # * Read the instructions in [[file:../default.nix]], and basically do the same 12 | # stuff here. 13 | # The only real difference is to relative path for `PROJECT' 14 | # and `allowedPaths'. 15 | # 16 | # ---------------------------------------------------------------------------- # 17 | 18 | { PROJECT ? builtins.getFlake ( toString ../../. ) 19 | , lib ? PROJECT.lib 20 | , system ? builtins.currentSystem 21 | , pkgsFor ? let 22 | from = if PROJECT ? legacyPackages then PROJECT else PROJECT.inputs.nixpkgs; 23 | ov = PROJECT.overlays.default or null; 24 | base = from.legacyPackages.${system}; 25 | in if ov == null then base else base.extend ov; 26 | , writeText ? pkgsFor.writeText 27 | 28 | # Eval Env 29 | , pure ? lib.inPureEvalMode 30 | , ifd ? ( builtins.currentSystem or null ) == system 31 | , allowedPaths ? toString ../../. 32 | , typecheck ? true 33 | 34 | # Options 35 | , keepFailed ? false # Useful if you run the test explicitly. 36 | , nameExtra ? "" 37 | , ... 38 | } @ args: let 39 | 40 | # ---------------------------------------------------------------------------- # 41 | 42 | # Used to import test files. 43 | auto = { inherit lib pkgsFor writeText; } // args; 44 | 45 | tests = let 46 | testsFrom = file: let 47 | fn = import file; 48 | fargs = builtins.functionArgs fn; 49 | ts = fn ( builtins.intersectAttrs fargs auto ); 50 | in assert builtins.isAttrs ts; 51 | ts.tests or ts; 52 | in builtins.foldl' ( ts: file: ts // ( testsFrom file ) ) {} [ 53 | ./tests.nix 54 | ]; 55 | 56 | # ---------------------------------------------------------------------------- # 57 | 58 | # We need `check' and `checkerDrv' to use different `checker' functions which 59 | # is why we have explicitly provided an alternative `check' as a part 60 | # of `mkCheckerDrv'. 61 | harness = let 62 | purity = if pure then "pure" else "impure"; 63 | ne = if nameExtra != "" then " " + nameExtra else ""; 64 | name = "PROJECT-tests${ne} (${system}, ${purity})"; 65 | in lib.libdbg.mkTestHarness { 66 | inherit name keepFailed tests writeText; 67 | mkCheckerDrv = { 68 | __functionArgs = lib.functionArgs lib.libdbg.mkCheckerDrv; 69 | __innerFunction = lib.libdbg.mkCheckerDrv; 70 | __processArgs = self: args: self.__thunk // args; 71 | __thunk = { inherit name keepFailed writeText; }; 72 | __functor = self: x: self.__innerFunction ( self.__processArgs self x ); 73 | }; 74 | checker = name: run: let 75 | rsl = lib.libdbg.checkerReport name run; 76 | msg = builtins.trace rsl null; 77 | in builtins.deepSeq msg rsl; 78 | }; 79 | 80 | 81 | # ---------------------------------------------------------------------------- # 82 | 83 | in harness 84 | 85 | 86 | # ---------------------------------------------------------------------------- # 87 | # 88 | # 89 | # 90 | # ============================================================================ # 91 | -------------------------------------------------------------------------------- /templates/tests/sub/tests.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # General tests for `@NAME@' routines. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib 8 | , system 9 | , pkgsFor 10 | }: let 11 | 12 | # ---------------------------------------------------------------------------- # 13 | 14 | tests = { 15 | 16 | # ---------------------------------------------------------------------------- # 17 | 18 | # PASS 19 | testFoo = { 20 | expr = 1 + 1; 21 | expected = 2; 22 | }; 23 | 24 | # FAIL 25 | testBar = { 26 | expr = 3; 27 | expected = 2; 28 | }; 29 | 30 | 31 | # ---------------------------------------------------------------------------- # 32 | 33 | }; # End Tests 34 | 35 | 36 | # ---------------------------------------------------------------------------- # 37 | 38 | in tests 39 | 40 | 41 | # ---------------------------------------------------------------------------- # 42 | # 43 | # 44 | # 45 | # ============================================================================ # 46 | -------------------------------------------------------------------------------- /tests/attrsets.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # General tests for `libattrs' routines. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | tests = { 12 | 13 | # ---------------------------------------------------------------------------- # 14 | 15 | testEachSystemMap = { 16 | expr = lib.eachSystemMap ["a" "b"] ( system: system + "-0" ); 17 | expected = { a = "a-0"; b = "b-0"; }; 18 | }; 19 | 20 | 21 | # ---------------------------------------------------------------------------- # 22 | 23 | testPushDownNames = { 24 | expr = lib.libattrs.pushDownNames { 25 | foo = { x = 1; }; 26 | bar = { y = 2; }; 27 | }; 28 | expected = { 29 | foo = { name = "foo"; x = 1; }; 30 | bar = { name = "bar"; y = 2; }; 31 | }; 32 | }; 33 | 34 | testAttrsToList = { 35 | expr = lib.attrsToList { foo = 1; bar = 2; }; 36 | expected = [{ name = "bar"; value = 2; } { name = "foo"; value = 1; }]; 37 | }; 38 | 39 | 40 | # ---------------------------------------------------------------------------- # 41 | 42 | testJoinAttrs_set = { 43 | expr = lib.joinAttrs { foo = { x = 1; }; bar = { y = 2; z = 3; }; }; 44 | expected = { x = 1; y = 2; z = 3; }; 45 | }; 46 | 47 | testJoinAttrs_list = { 48 | expr = lib.joinAttrs [{ x = 1; } { y = 2; z = 3; }]; 49 | expected = { x = 1; y = 2; z = 3; }; 50 | }; 51 | 52 | 53 | # ---------------------------------------------------------------------------- # 54 | 55 | }; # End Tests 56 | 57 | 58 | # ---------------------------------------------------------------------------- # 59 | 60 | in tests 61 | 62 | 63 | # ---------------------------------------------------------------------------- # 64 | # 65 | # 66 | # 67 | # ============================================================================ # 68 | -------------------------------------------------------------------------------- /tests/data/file0.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": 1, 3 | "b": ["hey", "there"], 4 | "c": { 5 | "d": null 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/data/file1.json: -------------------------------------------------------------------------------- 1 | { 2 | // Comment 3 | "a": 1, 4 | "b": ["hey", "there"], 5 | "c": { 6 | "d": null 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tests/debug.nix: -------------------------------------------------------------------------------- 1 | # =========================================================================== # 2 | 3 | # Test for your testers so we can test while we test! 4 | 5 | { lib }: let 6 | 7 | inherit (lib) libdbg; 8 | 9 | # --------------------------------------------------------------------------- # 10 | 11 | # Tests for our tests. 12 | innerTests = { 13 | testMaths = { expr = 1 + 1; expected = 2; }; 14 | testStrings = { expr = builtins.substring 0 1 "foo"; expected = "f"; }; 15 | }; 16 | 17 | 18 | # --------------------------------------------------------------------------- # 19 | 20 | tests = { 21 | 22 | # Sanity check the fields that `nixpkgs.lib.runTests' includes in its 23 | # list of failure cases. 24 | testRunTestsFields = { 25 | expr = let 26 | run = lib.runTests { testFail = { expr = 1; expected = 2; }; }; 27 | fields = builtins.attrNames ( builtins.head run ); 28 | in fields; 29 | # The order of these matters, `attrNames' is alphabetically sorted. 30 | expected = ["expected" "name" "result"]; 31 | }; 32 | 33 | # Sanity check that `nixpkgs.lib.runTests' returns an empty list when all 34 | # tests pass. 35 | testRunner = { 36 | expr = lib.runTests innerTests; 37 | expected = []; 38 | }; 39 | 40 | # Sanity check that `libdbg.checker' returns `true' when all tests pass. 41 | testChecker = { 42 | expr = libdbg.checkerDefault "tests" ( lib.runTests innerTests ); 43 | expected = true; 44 | }; 45 | 46 | }; # End tests 47 | 48 | 49 | # --------------------------------------------------------------------------- # 50 | in tests 51 | 52 | 53 | # --------------------------------------------------------------------------- # 54 | # 55 | # 56 | # 57 | # =========================================================================== # 58 | -------------------------------------------------------------------------------- /tests/default.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Provides sane defaults for running this set of tests. 4 | # This is likely not the "ideal" way to utilize the test suite, but for someone 5 | # who is consuming your project and knows nothing about it - this file should 6 | # allow them to simply run `nix build -f .' to see if the test suite passes. 7 | # 8 | # ---------------------------------------------------------------------------- # 9 | 10 | { ak-nix ? builtins.getFlake ( toString ../. ) 11 | , lib ? ak-nix.lib 12 | , system ? builtins.currentSystem 13 | , pkgsFor ? ak-nix.legacyPackages.${system} 14 | , writeText ? pkgsFor.writeText 15 | 16 | # Eval Env 17 | , pure ? lib.inPureEvalMode 18 | , ifd ? ( builtins.currentSystem or null ) == system 19 | , allowedPaths ? toString ../. 20 | , typecheck ? true 21 | 22 | # Options 23 | , keepFailed ? false # Useful if you run the test explicitly. 24 | , nameExtra ? "" 25 | , ... 26 | } @ args: let 27 | 28 | # ---------------------------------------------------------------------------- # 29 | 30 | # Used to import test files. 31 | autoArgs = { 32 | inherit lib pure ifd allowedPaths typecheck pkgsFor; 33 | } // args; 34 | 35 | tests = let 36 | testsFrom = file: let 37 | fn = import file; 38 | fargs = builtins.functionArgs fn; 39 | ts = fn ( builtins.intersectAttrs fargs autoArgs ); 40 | in assert builtins.isAttrs ts; 41 | ts.tests or ts; 42 | in builtins.foldl' ( ts: file: ts // ( testsFrom file ) ) {} [ 43 | ./libsemver.nix 44 | ./libfunk.nix 45 | ./libtag.nix 46 | ./libjson.nix 47 | ./liblist.nix 48 | ./attrsets.nix 49 | ./debug.nix 50 | ./strings.nix 51 | ./paths.nix 52 | ./encode.nix 53 | ./trivial.nix 54 | ]; 55 | 56 | # ---------------------------------------------------------------------------- # 57 | 58 | # We need `check' and `checkerDrv' to use different `checker' functions which 59 | # is why we have explicitly provided an alternative `check' as a part 60 | # of `mkCheckerDrv'. 61 | harness = let 62 | purity = if pure then "pure" else "impure"; 63 | ne = if nameExtra != "" then " " + nameExtra else ""; 64 | name = "ak-nix-${ne} (${system}, ${purity})"; 65 | in lib.libdbg.mkTestHarness { 66 | inherit name keepFailed tests writeText; 67 | mkCheckerDrv = { 68 | __functionArgs = lib.functionArgs lib.libdbg.mkCheckerDrv; 69 | __innerFunction = lib.libdbg.mkCheckerDrv; 70 | __processArgs = self: args: self.__thunk // args; 71 | __thunk = { inherit name keepFailed writeText; }; 72 | __functor = self: x: self.__innerFunction ( self.__processArgs self x ); 73 | }; 74 | checker = name: run: let 75 | rsl = lib.libdbg.checkerReport name run; 76 | msg = builtins.trace rsl null; 77 | in builtins.deepSeq msg rsl; 78 | }; 79 | 80 | 81 | # ---------------------------------------------------------------------------- # 82 | 83 | in harness 84 | 85 | 86 | # ---------------------------------------------------------------------------- # 87 | # 88 | # 89 | # 90 | # ============================================================================ # 91 | -------------------------------------------------------------------------------- /tests/encode.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Tests for `libencode' functions defined in `lib/encode.nix'. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | inherit (lib.libenc) 12 | toBaseDigits 13 | toBase16 fromBase16 14 | toBase32 fromBase32 15 | toBase64 fromBase64 16 | hexToSri 17 | algoFromB16Len 18 | ; 19 | 20 | inherit (lib.ytypes.Strings) 21 | md5_hash 22 | sha1_hash sha1_sri 23 | sha256_hash sha256_sri 24 | sha512_hash sha512_sri 25 | ; 26 | 27 | 28 | # ---------------------------------------------------------------------------- # 29 | 30 | sha512s = lib.splitString "\n" ( lib.fileContents ./data/sha512s.txt ); 31 | 32 | #sha1-b16 = "2346ad27d7568ba9896f1b7da6b5991251debdf2"; 33 | md5-b16 = builtins.hashFile "md5" ./default.nix; 34 | sha1-b16 = builtins.hashFile "sha1" ./default.nix; 35 | sha256-b16 = builtins.hashFile "sha256" ./default.nix; 36 | sha512-b16 = builtins.hashFile "sha512" ./default.nix; 37 | 38 | md5-sri = "md5-sVrTW42PJbm6YJ9He6843A=="; 39 | sha1-sri = "sha1-oVWx0LwYalqy8tdQFNCm0r5ng7g="; 40 | sha256-sri = "sha256-y/0hAE35nPzZ7XcsIA0wPuaWFopkU3f3slx/OTqkT9Q="; 41 | sha512-sri = "sha512-zl39eQhTMFM9CgIa6AGyLlULiJirY+65DFbVyrdWrv5G2ypuUE767tNqizmQbr54cayjVoPNehAa7KnLhhD2gA=="; 42 | 43 | 44 | # ---------------------------------------------------------------------------- # 45 | 46 | tests = { 47 | 48 | # ---------------------------------------------------------------------------- # 49 | 50 | testType_sha1_hash_0 = { 51 | expr = builtins.tryEval ( sha1_hash sha1-b16 ); 52 | expected = { success = true; value = sha1-b16; }; 53 | }; 54 | 55 | # Ensure length checking is enforced. 56 | testType_sha1_hash_1 = { 57 | expr = builtins.tryEval ( sha1_hash "${sha1-b16}a" ); 58 | expected = { success = false; value = false; }; 59 | }; 60 | 61 | 62 | # ---------------------------------------------------------------------------- # 63 | 64 | # Ensure length checking is enforced. 65 | testType_sha256_sri_0 = { 66 | expr = sha256_sri.check sha256-sri; 67 | expected = true; 68 | }; 69 | 70 | 71 | testType_sha512_sri_0 = { 72 | expr = sha512_sri.check sha512-sri; 73 | expected = true; 74 | }; 75 | 76 | testType_sha512_sri_1 = { 77 | expr = builtins.filter ( s: ! ( sha512_sri.check s ) ) sha512s; 78 | expected = []; 79 | }; 80 | 81 | 82 | # ---------------------------------------------------------------------------- # 83 | 84 | }; # End tests 85 | 86 | # ---------------------------------------------------------------------------- # 87 | 88 | in tests 89 | 90 | 91 | # ---------------------------------------------------------------------------- # 92 | # 93 | # 94 | # 95 | # ============================================================================ # 96 | -------------------------------------------------------------------------------- /tests/libfunk.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # General tests for `libfunk' routines. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | 8 | { lib }: let 9 | 10 | # ---------------------------------------------------------------------------- # 11 | 12 | inherit (lib.libfunk) 13 | defFnMeta 14 | defFunkCore 15 | defThunkedFunk 16 | 17 | callWith 18 | currySystems 19 | funkSystems 20 | mandatoryArgsStrict 21 | missingArgsStrict 22 | canPassStrict 23 | canCallStrict 24 | setFunctionArgProcessor 25 | 26 | callWithOvStrict 27 | callWithOvStash 28 | callWithOv 29 | ; 30 | 31 | realAttrs = x: let 32 | top = lib.filterAttrs ( k: v: ! ( lib.hasPrefix "__" k ) ) x; 33 | proc = k: v: if builtins.isAttrs v then realAttrs v else v; 34 | in builtins.mapAttrs proc top; 35 | 36 | 37 | # ---------------------------------------------------------------------------- # 38 | 39 | tests = { 40 | 41 | inherit 42 | lib 43 | callWith 44 | currySystems 45 | funkSystems 46 | mandatoryArgsStrict 47 | missingArgsStrict 48 | canPassStrict 49 | canCallStrict 50 | setFunctionArgProcessor 51 | ; 52 | 53 | # ---------------------------------------------------------------------------- # 54 | 55 | testFD_defFnMeta0 = { 56 | expr = defFnMeta { 57 | name = "inc"; 58 | argc = 1; 59 | vargs = false; 60 | argTypes = ["int"]; 61 | returnTypes = ["int"]; 62 | }; 63 | 64 | expected = { 65 | argTypes = ["int"]; 66 | argc = 1; 67 | keywords = []; 68 | name = "inc"; 69 | returnTypes = ["int"]; 70 | vargs = false; 71 | }; 72 | }; 73 | 74 | 75 | # ---------------------------------------------------------------------------- # 76 | 77 | testCallWithOvStrict_0 = { 78 | expr = let 79 | fn = { x, y }: { val = x + y; }; 80 | rsl = callWithOvStrict { z = 1; } fn { x = 2; y = 3; }; 81 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 82 | expected = { override = {}; val = 5; args = { x = 2; y = 3; }; }; 83 | }; 84 | 85 | testCallWithOvStrict_1 = { 86 | expr = let 87 | fn = { x, y }: { val = x + y; }; 88 | rsl0 = callWithOvStrict { z = 1; } fn { x = 2; y = 3; }; 89 | rsl = rsl0.override { x = 0; }; 90 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 91 | expected = { override = {}; val = 3; args = { x = 0; y = 3; }; }; 92 | }; 93 | 94 | 95 | # ---------------------------------------------------------------------------- # 96 | 97 | testCallWithOvStash_0 = { 98 | expr = let 99 | fn = { x, y }: x + y; 100 | rsl = callWithOvStash { z = 1; } fn { x = 2; y = 3; }; 101 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 102 | expected = { override = {}; result = 5; args = { x = 2; y = 3; }; }; 103 | }; 104 | 105 | testCallWithOvStash_1 = { 106 | expr = let 107 | fn = { x, y }: x + y; 108 | rsl0 = callWithOvStash { z = 1; } fn { x = 2; y = 3; }; 109 | rsl = rsl0.override { x = 0; }; 110 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 111 | expected = { override = {}; result = 3; args = { x = 0; y = 3; }; }; 112 | }; 113 | 114 | testCallWithOvStash_2 = { 115 | expr = let 116 | fn = { x, y }: { val = x + y; }; 117 | rsl0 = callWithOvStash { z = 1; } fn { x = 2; y = 3; }; 118 | rsl = rsl0.override { x = 0; }; 119 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 120 | expected = { override = {}; result.val = 3; args = { x = 0; y = 3; }; }; 121 | }; 122 | 123 | 124 | # ---------------------------------------------------------------------------- # 125 | 126 | testCallWithOv_0 = { 127 | expr = let 128 | fn = { x, y }: x + y; 129 | rsl = callWithOv { z = 1; } fn { x = 2; y = 3; }; 130 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 131 | expected = { override = {}; result = 5; args = { x = 2; y = 3; }; }; 132 | }; 133 | 134 | testCallWithOv_1 = { 135 | expr = let 136 | fn = { x, y }: x + y; 137 | rsl0 = callWithOv { z = 1; } fn { x = 2; y = 3; }; 138 | rsl = rsl0.override { x = 0; }; 139 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 140 | expected = { override = {}; result = 3; args = { x = 0; y = 3; }; }; 141 | }; 142 | 143 | testCallWithOv_2 = { 144 | expr = let 145 | fn = { x, y }: { val = x + y; }; 146 | rsl0 = callWithOv { z = 1; } fn { x = 2; y = 3; }; 147 | rsl = rsl0.override { x = 0; }; 148 | in ( realAttrs rsl ) // { args = rsl.override.__thunk; }; 149 | expected = { override = {}; val = 3; args = { x = 0; y = 3; }; }; 150 | }; 151 | 152 | 153 | # ---------------------------------------------------------------------------- # 154 | 155 | }; # End Tests 156 | 157 | 158 | # ---------------------------------------------------------------------------- # 159 | 160 | in tests 161 | 162 | 163 | # ---------------------------------------------------------------------------- # 164 | # 165 | # 166 | # 167 | # ============================================================================ # 168 | -------------------------------------------------------------------------------- /tests/libjson.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Tests for `libjson' functions. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | inherit (lib.libjson) 10 | importJSON' 11 | importJSONOr 12 | importJSONOr' 13 | ; 14 | 15 | # ---------------------------------------------------------------------------- # 16 | 17 | data0 = { a = 1; b = ["hey" "there"]; c = { d = null; }; }; 18 | file0 = ./data/file0.json; 19 | file1 = ./data/file1.json; 20 | 21 | 22 | # ---------------------------------------------------------------------------- # 23 | 24 | tests = { 25 | 26 | # ---------------------------------------------------------------------------- # 27 | 28 | testImportJSON'_0 = { 29 | expr = importJSON' file0; 30 | expected = data0; 31 | }; 32 | 33 | testImportJSON'_1 = { 34 | expr = importJSON' file1; 35 | expected = data0; 36 | }; 37 | 38 | 39 | # ---------------------------------------------------------------------------- # 40 | 41 | testImportJSONOr_0 = { 42 | expr = importJSONOr {} file0; 43 | expected = if lib.inPureEvalMode then {} else data0; 44 | }; 45 | 46 | testImportJSONOr_1 = { 47 | expr = importJSONOr data0 ./.fake-file.json; 48 | expected = data0; 49 | }; 50 | 51 | 52 | # ---------------------------------------------------------------------------- # 53 | 54 | testImportJSONOr'_0 = { 55 | expr = importJSONOr' {} file1; 56 | expected = if lib.inPureEvalMode then {} else data0; 57 | }; 58 | 59 | testImportJSONOr'_1 = { 60 | expr = importJSONOr' data0 ./.fake-file.json; 61 | expected = data0; 62 | }; 63 | 64 | 65 | # ---------------------------------------------------------------------------- # 66 | 67 | }; # End tests 68 | 69 | 70 | # ---------------------------------------------------------------------------- # 71 | 72 | in tests 73 | 74 | 75 | # ---------------------------------------------------------------------------- # 76 | # 77 | # 78 | # 79 | # ============================================================================ # 80 | -------------------------------------------------------------------------------- /tests/liblist.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Tests for `liblist' functions. 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | # ---------------------------------------------------------------------------- # 10 | 11 | inherit (lib.liblist) 12 | takeUntil 13 | dropAfter 14 | dropUntil 15 | takeAfter 16 | commonPrefix 17 | commonSuffix 18 | mapNoNulls 19 | mapDropNulls 20 | ; 21 | 22 | # ---------------------------------------------------------------------------- # 23 | 24 | tests = { 25 | 26 | # ---------------------------------------------------------------------------- # 27 | 28 | testTakeUntil_0 = { 29 | expr = takeUntil ( x: x == null ) [1 2 null 3]; 30 | expected = [1 2]; 31 | }; 32 | 33 | testTakeUntil_1 = { 34 | expr = takeUntil ( x: x == null ) [1 2 3]; 35 | expected = [1 2 3]; 36 | }; 37 | 38 | 39 | # ---------------------------------------------------------------------------- # 40 | 41 | testDropAfter_0 = { 42 | expr = dropAfter ( x: x == null ) [1 2 null 3]; 43 | expected = [1 2 null]; 44 | }; 45 | 46 | testDropAfter_1 = { 47 | expr = dropAfter ( x: x == null ) [1 2 3]; 48 | expected = [1 2 3]; 49 | }; 50 | 51 | 52 | # ---------------------------------------------------------------------------- # 53 | 54 | testDropUntil_0 = { 55 | expr = dropUntil ( x: x == null ) [1 2 null 3]; 56 | expected = [null 3]; 57 | }; 58 | 59 | testDropUntil_1 = { 60 | expr = dropUntil ( x: x == null ) [1 2 3]; 61 | expected = []; 62 | }; 63 | 64 | 65 | # ---------------------------------------------------------------------------- # 66 | 67 | testTakeAfter_0 = { 68 | expr = takeAfter ( x: x == null ) [1 2 null 3]; 69 | expected = [3]; 70 | }; 71 | 72 | testTakeAfter_1 = { 73 | expr = takeAfter ( x: x == null ) [1 2 3]; 74 | expected = []; 75 | }; 76 | 77 | 78 | # ---------------------------------------------------------------------------- # 79 | 80 | testCommonPrefix_0 = { 81 | expr = commonPrefix [1 2 3] [1 2 4]; 82 | expected = [1 2]; 83 | }; 84 | 85 | testCommonPrefix_1 = { 86 | expr = commonPrefix [1 2 3] [3 2 1]; 87 | expected = []; 88 | }; 89 | 90 | 91 | # ---------------------------------------------------------------------------- # 92 | 93 | testCommonSuffix_0 = { 94 | expr = commonSuffix [1 2 3] [4 2 3]; 95 | expected = [2 3]; 96 | }; 97 | 98 | testCommonSuffix_1 = { 99 | expr = commonSuffix [1 2 3] [3 2 1]; 100 | expected = []; 101 | }; 102 | 103 | 104 | # ---------------------------------------------------------------------------- # 105 | 106 | testMapNoNulls_0 = { 107 | expr = mapNoNulls ( x: x + 1 ) [0 null 2]; 108 | expected = [1 3]; 109 | }; 110 | 111 | testMapNoNulls_1 = { 112 | expr = mapNoNulls ( x: null ) [0 null 2]; 113 | expected = [null null]; 114 | }; 115 | 116 | 117 | # ---------------------------------------------------------------------------- # 118 | 119 | testMapDropNulls_0 = { 120 | expr = mapDropNulls ( x: if x != null then null else 0 ) [0 null 2]; 121 | expected = [0]; 122 | }; 123 | 124 | testMapDropNulls_1 = { 125 | expr = mapDropNulls ( x: null ) [0 null 2]; 126 | expected = []; 127 | }; 128 | 129 | 130 | # ---------------------------------------------------------------------------- # 131 | 132 | }; # End tests 133 | 134 | 135 | # ---------------------------------------------------------------------------- # 136 | 137 | in tests 138 | 139 | 140 | # ---------------------------------------------------------------------------- # 141 | # 142 | # 143 | # 144 | # ============================================================================ # 145 | -------------------------------------------------------------------------------- /tests/libtag.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # Tests for `libtag' functions defined in `lib/tags.nix'. 4 | # These routines were taken from TVL, but these tests were written from scratch. 5 | # 6 | # ---------------------------------------------------------------------------- # 7 | 8 | { lib }: let 9 | 10 | inherit (lib.libtag) 11 | verifyTag 12 | tagName 13 | tagValue 14 | discr 15 | discrDef 16 | match 17 | matchLam 18 | matchTag 19 | ; 20 | 21 | # ---------------------------------------------------------------------------- # 22 | 23 | tests = { 24 | 25 | # ---------------------------------------------------------------------------- # 26 | 27 | testVerifyTag_0 = { 28 | expr = ( verifyTag { foo = 1; } ).isTag; 29 | expected = true; 30 | }; 31 | 32 | testVerifyTag_1 = { 33 | expr = ( verifyTag { foo = 1; bar = 0; } ).isTag; 34 | expected = false; 35 | }; 36 | 37 | testTagName = { 38 | expr = tagName { foo = 1; }; 39 | expected = "foo"; 40 | }; 41 | 42 | testTagValue = { 43 | expr = tagValue { foo = 1; }; 44 | expected = 1; 45 | }; 46 | 47 | 48 | # ---------------------------------------------------------------------------- # 49 | 50 | testDiscrDef_0 = { 51 | expr = discrDef "smol" [ 52 | { biggerFive = i: i > 5; } 53 | { negative = i: i < 0; } 54 | ] ( -100 ); 55 | expected = { negative = -100; }; 56 | }; 57 | 58 | testDiscrDef_1 = { 59 | expr = discrDef "smol" [ 60 | { biggerFive = i: i > 5; } 61 | { negative = i: i < 0; } 62 | ] 1; 63 | expected = { smol = 1; }; 64 | }; 65 | 66 | 67 | # ---------------------------------------------------------------------------- # 68 | 69 | testDiscr_0 = { 70 | expr = builtins.tryEval ( discr [ 71 | { biggerFive = i: i > 5; } 72 | { negative = i: i < 0; } 73 | ] ( -100 ) ); 74 | expected = { success = true; value.negative = -100; }; 75 | }; 76 | 77 | testDiscr_1 = { 78 | expr = builtins.tryEval ( discr [ 79 | { biggerFive = i: i > 5; } 80 | { negative = i: i < 0; } 81 | ] 1 ); 82 | expected = { success = false; value = false; }; 83 | }; 84 | 85 | 86 | # ---------------------------------------------------------------------------- # 87 | 88 | testMatchTag = let 89 | matcher = { 90 | res = i: i + 1; 91 | err = _: 0; 92 | }; 93 | in { 94 | expr = { 95 | success = matchTag { res = 42; } matcher; 96 | failure = matchTag { err = "no answer"; } matcher; 97 | }; 98 | expected = { 99 | success = 43; 100 | failure = 0; 101 | }; 102 | }; 103 | 104 | 105 | # ---------------------------------------------------------------------------- # 106 | 107 | testMatchLam = { 108 | expr = lib.pipe { foo = 42; } [ 109 | ( matchLam { 110 | foo = i: if i < 23 then { small = i; } else { big = i; }; 111 | bar = _: { small = 5; }; 112 | } ) 113 | ( matchLam { 114 | small = i: "yay it was small"; 115 | big = i: "whoo it was big!"; 116 | } ) 117 | ]; 118 | expected = "whoo it was big!"; 119 | }; 120 | 121 | 122 | # ---------------------------------------------------------------------------- # 123 | 124 | }; # End tests 125 | 126 | 127 | # ---------------------------------------------------------------------------- # 128 | 129 | in tests 130 | 131 | 132 | # ---------------------------------------------------------------------------- # 133 | # 134 | # 135 | # 136 | # ============================================================================ # 137 | -------------------------------------------------------------------------------- /tests/paths.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib ? ( builtins.getFlake ( toString ../.. ) ).lib 8 | , nixpkgs ? builtins.getFlake "nixpkgs" 9 | , system ? builtins.currentSystem 10 | , pkgs ? nixpkgs.legacyPackages.${system} 11 | , writeText ? pkgs.writeText 12 | , ... 13 | } @ args: let 14 | 15 | inherit (lib) libdbg libpath; 16 | 17 | # ---------------------------------------------------------------------------- # 18 | 19 | tests = with libpath; { 20 | 21 | # ---------------------------------------------------------------------------- # 22 | 23 | testIsCoercibleToPath = { 24 | expr = builtins.mapAttrs ( _: isCoercibleToPath ) { 25 | emptyString = ""; 26 | dot = "."; 27 | pwdPath = ./.; 28 | setOutPath = { outPath = ""; }; 29 | }; 30 | expected = { 31 | emptyString = false; 32 | dot = true; 33 | pwdPath = true; 34 | setOutPath = true; 35 | }; 36 | }; 37 | 38 | 39 | # ---------------------------------------------------------------------------- # 40 | 41 | testExtSuffix = { 42 | expr = extSuffix "foo.bar.baz"; 43 | expected = "bar.baz"; 44 | }; 45 | 46 | testExtSuffix' = { 47 | expr = extSuffix' "foo.bar.baz"; 48 | expected = "baz"; 49 | }; 50 | 51 | 52 | # ---------------------------------------------------------------------------- # 53 | 54 | testDropLeadingDotSlash = { 55 | expr = map dropLeadingDotSlash [ 56 | "./foo" ".bar" "/baz" "quux/." "sally" "/" 57 | ]; 58 | expected = ["foo" ".bar" "/baz" "quux/." "sally" "/"]; 59 | }; 60 | 61 | 62 | # ---------------------------------------------------------------------------- # 63 | 64 | testStripComponents = { 65 | expr = 66 | ( map ( stripComponents 1 ) [ 67 | "./foo" "bar" "foo/bar" ( /. + "foo/bar/" ) 68 | ] ) ++ ( map ( stripComponents 2 ) [ 69 | "./foo" "bar" "foo/bar" ( /. + "foo/bar/" ) "foo/bar/baz/quux" 70 | "/foo/bar//baz" "foo/bar//baz" 71 | ] ); 72 | expected = [ 73 | "foo" "bar" "bar" "foo/bar" 74 | "foo" "bar" "bar" "bar" "baz/quux" 75 | "bar//baz" "baz" 76 | ]; 77 | }; 78 | 79 | 80 | # ---------------------------------------------------------------------------- # 81 | 82 | # FIXME: need to make example dir 83 | # TODO: check the "symlinkdir" works. 84 | #testCategorizePath = { 85 | # expr = map categorizePath []; 86 | # expected = []; 87 | #}; 88 | 89 | 90 | # ---------------------------------------------------------------------------- # 91 | 92 | }; # End tests 93 | 94 | # ---------------------------------------------------------------------------- # 95 | 96 | in tests 97 | 98 | 99 | # ---------------------------------------------------------------------------- # 100 | # 101 | # 102 | # 103 | # ============================================================================ # 104 | -------------------------------------------------------------------------------- /tests/strings.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | inherit (builtins) typeOf tryEval mapAttrs attrNames attrValues toFile; 10 | inherit (lib.libstr) 11 | yankN' yank' yankNs' yankN yank yankNs 12 | coerceString 13 | charN count test 14 | commonPrefix commonSuffix 15 | matchingLines linesInfix readLines linesGrep readLinesGrep readGrep; 16 | 17 | inherit (lib) libdbg libstr; 18 | 19 | # ---------------------------------------------------------------------------- # 20 | 21 | data = { 22 | file1 = toFile "file1" '' 23 | foo 24 | bar 25 | baz 26 | quux 27 | ''; 28 | }; 29 | 30 | # Common test pattern for all `testYank*' cases. 31 | _mkYanker = e: f: map ( f "(.*[^a-z]+)?([a-z]+)([^a-z]+)" ) 32 | ( [" aa " "AaaAAA" "aa bb ZZ" "aa "] ++ e ); 33 | mkYanker' = _mkYanker []; 34 | mkYanker = _mkYanker ["A"]; 35 | 36 | 37 | # ---------------------------------------------------------------------------- # 38 | 39 | tests = { 40 | 41 | testTest = { 42 | expr = map ( test "[aA][bB]*" ) ["a" "A" "Ab" "aBBb" "x" "" "b" ".*"]; 43 | expected = [true true true true false false false false]; 44 | }; 45 | 46 | 47 | # ---------------------------------------------------------------------------- # 48 | 49 | testYankN' = { 50 | expr = mkYanker' ( yankN' 1 ); 51 | expected = ["aa" "aa" "bb" "aa"]; 52 | }; 53 | 54 | testYank' = { 55 | expr = mkYanker' yank'; 56 | expected = [" " "A" "aa " null]; 57 | }; 58 | 59 | testYankNs' = { 60 | expr = mkYanker' ( yankNs' [0 1] ); 61 | expected = [[" " "aa"] ["A" "aa"] ["aa " "bb"] [null "aa"]]; 62 | }; 63 | 64 | /* The safer ones */ 65 | testYankN = { 66 | expr = mkYanker ( yankN 1 ); 67 | expected = ["aa" "aa" "bb" "aa" null]; 68 | }; 69 | 70 | testYank = { 71 | expr = mkYanker yank; 72 | expected = [" " "A" "aa " null null]; 73 | }; 74 | 75 | testYankNs = { 76 | expr = mkYanker ( yankNs [0 1] ); 77 | expected = [[" " "aa"] ["A" "aa"] ["aa " "bb"] [null "aa"] null]; 78 | }; 79 | 80 | 81 | # ---------------------------------------------------------------------------- # 82 | 83 | }; # End Tests 84 | 85 | 86 | # --------------------------------------------------------------------------- # 87 | 88 | in tests 89 | 90 | # --------------------------------------------------------------------------- # 91 | # 92 | # 93 | # 94 | # =========================================================================== # 95 | -------------------------------------------------------------------------------- /tests/tar.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib 8 | , untarSanPerms ? pkgsFor.untarSanPerms 9 | , runCommandNoCC ? pkgsFor.runCommandNoCC 10 | , pkgsFor 11 | }: let 12 | 13 | yt = lib.ytypes // lib.ytypes.Core // lib.ytypes.Prim; 14 | 15 | # ---------------------------------------------------------------------------- # 16 | 17 | tests = {}; 18 | 19 | drvs = { 20 | 21 | # Basic operation, tarball is already clean. 22 | testUntarSanPerms_0 = runCommandNoCC "test-unpack-safe" { 23 | untarred = untarSanPerms { 24 | name = "lodash-4.17.21"; 25 | tarball = builtins.fetchTree { 26 | type = "file"; 27 | url = "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"; 28 | narHash = "sha256-fn2qMkL7ePPYQyW/x9nvDOl05BDrC7VsfvyfW0xkQyE="; 29 | }; 30 | }; 31 | } '' 32 | set -eu; 33 | set -o pipefail; 34 | for d in $( find "$untarred/" -type d -print; ); do 35 | if ! test -x "$d"; then 36 | echo "FAIL" >&2; 37 | stat "$d" >&2; 38 | exit 1; 39 | fi 40 | done 41 | echo "PASS" > "$out"; 42 | ''; 43 | 44 | }; 45 | 46 | 47 | # ---------------------------------------------------------------------------- # 48 | 49 | in { inherit tests drvs; } 50 | 51 | # ---------------------------------------------------------------------------- # 52 | # 53 | # 54 | # 55 | # ============================================================================ # 56 | -------------------------------------------------------------------------------- /tests/trivial.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { lib }: let 8 | 9 | inherit (lib) libdbg libtriv; 10 | inherit (libtriv) 11 | sortVersions' 12 | sortVersions 13 | latestVersion 14 | ; 15 | 16 | # ---------------------------------------------------------------------------- # 17 | 18 | tests = { 19 | 20 | # ---------------------------------------------------------------------------- # 21 | 22 | testSortVersions_0 = { 23 | expr = sortVersions' { ascending = false; } ["1.0.0" "2.0" "3"]; 24 | expected = ["3" "2.0" "1.0.0"]; 25 | }; 26 | 27 | testSortVersions_1 = { 28 | expr = sortVersions' { ascending = true; } ["1.0.0" "2.0" "3"]; 29 | expected = ["1.0.0" "2.0" "3"]; 30 | }; 31 | 32 | testSortVersions_3 = { 33 | expr = sortVersions' { accessor = baseNameOf; } [ 34 | "foo/1.0.0" "bar/2.0.0" "baz/3.0.0" 35 | ]; 36 | expected = ["baz/3.0.0" "bar/2.0.0" "foo/1.0.0"]; 37 | }; 38 | 39 | testLatestVersion_0 = { 40 | expr = latestVersion ["1.0.0" "2.0.0" "3.0.0"]; 41 | expected = "3.0.0"; 42 | }; 43 | 44 | # ---------------------------------------------------------------------------- # 45 | 46 | }; # End tests 47 | 48 | # ---------------------------------------------------------------------------- # 49 | 50 | in tests 51 | 52 | 53 | # ---------------------------------------------------------------------------- # 54 | # 55 | # 56 | # 57 | # ============================================================================ # 58 | -------------------------------------------------------------------------------- /types/fs.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # 4 | # 5 | # ---------------------------------------------------------------------------- # 6 | 7 | { ytypes }: let 8 | 9 | lib.test = patt: s: ( builtins.match patt s ) != null; 10 | yt = ytypes // ytypes.Prim // ytypes.Core; 11 | inherit (yt) restrict string either eitherN sum; 12 | 13 | b32c = "0-9a-df-np-sv-z"; 14 | 15 | # ---------------------------------------------------------------------------- # 16 | 17 | RE = { 18 | evil_filename_c = "[^/\0]"; 19 | evil_path_c = "[^\0]"; 20 | 21 | # NOTE: requires that spaces be escaped 22 | uri_filename_c = "[:alnum:]%:@&=+$,_.!~*'()-"; # "param" cc 23 | uri_path_c = "${RE.uri_filename_c};?/"; 24 | 25 | # Sane filename characters for people who weren't raised in barns. 26 | sane_filename_c = "[:alnum:]_.@~-"; 27 | sane_path_c = "/${RE.sane_filename_c}"; 28 | 29 | filename_c = " ${RE.uri_filename_c}"; 30 | path_c = " ${RE.uri_path_c}"; 31 | }; # End RE 32 | 33 | 34 | # ---------------------------------------------------------------------------- # 35 | 36 | # TODO: `realpath'/`logicalpath' ( contains ".." ). 37 | Strings = { 38 | 39 | filename = let 40 | charsCond = lib.test "[${RE.filename_c}]+"; 41 | reservedCond = x: ( x != "." ) && ( x != ".." ); 42 | in restrict "filename" ( x: ( charsCond x ) && ( reservedCond x ) ) string; 43 | 44 | path = restrict "path" ( lib.test "[${RE.path_c}]*" ) string; 45 | 46 | abspath = restrict "absolute" ( lib.test "/.*" ) Strings.path; 47 | relpath = restrict "relative" ( lib.test "[^/].*" ) Strings.path; 48 | 49 | store_path = let 50 | patt = "(/nix/store/[${b32c}]{32}-[0-9a-zA-Z+.?_=-]*)(/.*)?"; 51 | cond = s: let 52 | m = builtins.match patt s; 53 | lc = ( builtins.stringLength ( builtins.head m ) ) <= 211; 54 | in ( m != null) && lc; 55 | in restrict "abspath[store]" cond yt.string; 56 | 57 | store_filename = let 58 | lenCond = s: ( builtins.stringLength s ) <= 168; 59 | pattCond = s: lib.test "[0-9a-zA-Z+-.?_=]*" s; 60 | cond = s: ( lenCond s ) && ( pattCond s ); 61 | in restrict "filename[store]" cond yt.string; 62 | 63 | }; # End Strings 64 | 65 | 66 | # ---------------------------------------------------------------------------- # 67 | 68 | Eithers = { 69 | 70 | abspath = ( either Strings.abspath yt.Prim.path ) // { 71 | name = "abspath"; 72 | toError = v: result: let 73 | pv = yt.__internal.prettyPrint v; 74 | common = "Expected an absolute path ( string or path primitive ), "; 75 | wrongType = 76 | common + "but value '${pv}' is of type '${builtins.typeOf v}'."; 77 | notAbs = 78 | common + "but pathlike string '${toString v}' is not absolute."; 79 | cp = Strings.path.checkType v; 80 | in if ! ( builtins.isString v ) then wrongType else 81 | if cp.ok then notAbs else cp.err; 82 | }; 83 | 84 | store_path = let 85 | cond = x: Strings.store_path.check ( toString x ); 86 | in either Strings.store_path ( restrict "store" cond yt.Prim.path ); 87 | 88 | }; # End Eithers 89 | 90 | 91 | # ---------------------------------------------------------------------------- # 92 | 93 | Enums = { 94 | 95 | inode_type = yt.enum "inode:type" [ 96 | "directory" "regular" "symlink" "unknown" 97 | ]; 98 | 99 | }; # End Enums 100 | 101 | 102 | # ---------------------------------------------------------------------------- # 103 | 104 | FunctionSigs = { 105 | 106 | filter = [Strings.path Enums.inode_type yt.bool]; 107 | 108 | }; # End FunctionSigs 109 | 110 | 111 | # ---------------------------------------------------------------------------- # 112 | 113 | in { 114 | 115 | inherit 116 | RE 117 | Strings 118 | Eithers 119 | FunctionSigs 120 | Enums 121 | ; 122 | 123 | inherit (Strings) 124 | filename 125 | relpath 126 | ; 127 | 128 | inherit (Eithers) 129 | abspath 130 | store_path 131 | ; 132 | 133 | } 134 | 135 | 136 | # ---------------------------------------------------------------------------- # 137 | # 138 | # 139 | # 140 | # ============================================================================ # 141 | -------------------------------------------------------------------------------- /types/overlay.yt.nix: -------------------------------------------------------------------------------- 1 | # ============================================================================ # 2 | # 3 | # YTypes Overlay. 4 | # 5 | # NOTE: `ytypes' is a member of `.lib.ytypes'. 6 | # 7 | # ---------------------------------------------------------------------------- # 8 | 9 | final: prev: { 10 | FS = import ./fs.nix { ytypes = final; }; 11 | } 12 | 13 | 14 | # ---------------------------------------------------------------------------- # 15 | # 16 | # 17 | # 18 | # ============================================================================ # 19 | -------------------------------------------------------------------------------- /update.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | set -eu; 3 | 4 | : "${NIX:=nix}"; 5 | : "${FIND:=find}"; 6 | : "${BASH:=bash}"; 7 | : "${GIT:=git}"; 8 | : "${ROOT_DIR:=${BASH_SOURCE[0]%/*}}"; 9 | export GIT NIX; 10 | 11 | $FIND "$ROOT_DIR" -name flake.lock \ 12 | -execdir $NIX flake update \; \ 13 | -execdir $BASH -c ' 14 | if ! $NIX flake check; then 15 | $GIT restore ./flake.lock; 16 | echo "Failed to update: $PWD" >&2; 17 | fi' \; \ 18 | ; 19 | --------------------------------------------------------------------------------