From 1c226cc8c6562379ffd0ac36ca095396250d94d7 Mon Sep 17 00:00:00 2001 From: Jonas Chevalier Date: Sun, 9 Apr 2023 12:34:52 +0200 Subject: [PATCH] introduce externally extensible systems (#93) This PR is a back-compatible subset of #84. By adding a new flake input here, it makes it possible to override the list of systems using flake overrides. See for the full explanation. --- default.nix | 230 +--------------------------------------------------- flake.lock | 26 ++++++ flake.nix | 10 ++- lib.nix | 229 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 265 insertions(+), 230 deletions(-) create mode 100644 flake.lock create mode 100644 lib.nix diff --git a/default.nix b/default.nix index 2b01461..0c00fb0 100644 --- a/default.nix +++ b/default.nix @@ -1,228 +1,2 @@ -let - # The list of systems supported by nixpkgs and hydra - defaultSystems = [ - "aarch64-linux" - "aarch64-darwin" - "x86_64-darwin" - "x86_64-linux" - ]; - - # List of all systems defined in nixpkgs - # Keep in sync with nixpkgs wit the following command: - # $ nix-instantiate --json --eval --expr "with import {}; lib.platforms.all" | jq 'sort' | sed 's!,!!' - - allSystems = [ - "aarch64-darwin" - "aarch64-genode" - "aarch64-linux" - "aarch64-netbsd" - "aarch64-none" - "aarch64_be-none" - "arm-none" - "armv5tel-linux" - "armv6l-linux" - "armv6l-netbsd" - "armv6l-none" - "armv7a-darwin" - "armv7a-linux" - "armv7a-netbsd" - "armv7l-linux" - "armv7l-netbsd" - "avr-none" - "i686-cygwin" - "i686-darwin" - "i686-freebsd" - "i686-genode" - "i686-linux" - "i686-netbsd" - "i686-none" - "i686-openbsd" - "i686-windows" - "js-ghcjs" - "m68k-linux" - "m68k-netbsd" - "m68k-none" - "mips64el-linux" - "mipsel-linux" - "mipsel-netbsd" - "mmix-mmixware" - "msp430-none" - "or1k-none" - "powerpc-netbsd" - "powerpc-none" - "powerpc64-linux" - "powerpc64le-linux" - "powerpcle-none" - "riscv32-linux" - "riscv32-netbsd" - "riscv32-none" - "riscv64-linux" - "riscv64-netbsd" - "riscv64-none" - "s390-linux" - "s390-none" - "s390x-linux" - "s390x-none" - "vc4-none" - "wasm32-wasi" - "wasm64-wasi" - "x86_64-cygwin" - "x86_64-darwin" - "x86_64-freebsd" - "x86_64-genode" - "x86_64-linux" - "x86_64-netbsd" - "x86_64-none" - "x86_64-openbsd" - "x86_64-redox" - "x86_64-solaris" - "x86_64-windows" - ]; - - # A map from system to system. It's useful to detect typos. - # - # Instead of typing `"x86_64-linux"`, type `flake-utils.lib.system.x86_64-linux` - # and get an error back if you used a dash instead of an underscore. - system = - builtins.listToAttrs - (map (system: { name = system; value = system; }) allSystems); - - # eachSystem using defaultSystems - eachDefaultSystem = eachSystem defaultSystems; - - # Builds a map from =value to .=value for each system, - # except for the `hydraJobs` attribute, where it maps the inner attributes, - # from hydraJobs.=value to hydraJobs..=value. - # - eachSystem = systems: f: - let - # Taken from - isDerivation = x: builtins.isAttrs x && x ? type && x.type == "derivation"; - - # Used to match Hydra's convention of how to define jobs. Basically transforms - # - # hydraJobs = { - # hello = ; - # haskellPackages.aeson = ; - # } - # - # to - # - # hydraJobs = { - # hello.x86_64-linux = ; - # haskellPackages.aeson.x86_64-linux = ; - # } - # - # if the given flake does `eachSystem [ "x86_64-linux" ] { ... }`. - pushDownSystem = system: merged: - builtins.mapAttrs - (name: value: - if ! (builtins.isAttrs value) then value - else if isDerivation value then (merged.${name} or {}) // { ${system} = value; } - else pushDownSystem system (merged.${name} or {}) value); - - # Merge together the outputs for all systems. - op = attrs: system: - let - ret = f system; - op = attrs: key: - let - appendSystem = key: system: ret: - if key == "hydraJobs" - then (pushDownSystem system (attrs.hydraJobs or {}) ret.hydraJobs) - else { ${system} = ret.${key}; }; - in attrs // - { - ${key} = (attrs.${key} or { }) - // (appendSystem key system ret); - } - ; - in - builtins.foldl' op attrs (builtins.attrNames ret); - in - builtins.foldl' op { } systems - ; - - # eachSystemMap using defaultSystems - eachDefaultSystemMap = eachSystemMap defaultSystems; - - # Builds a map from =value to . = value. - eachSystemMap = systems: f: builtins.listToAttrs (builtins.map (system: { name = system; value = f system; }) systems); - - # Nix flakes insists on having a flat attribute set of derivations in - # various places like the `packages` and `checks` attributes. - # - # This function traverses a tree of attributes (by respecting - # recurseIntoAttrs) and only returns their derivations, with a flattened - # key-space. - # - # Eg: - # - # flattenTree { hello = pkgs.hello; gitAndTools = pkgs.gitAndTools }; - # - # Returns: - # - # { - # hello = «derivation»; - # "gitAndTools/git" = «derivation»; - # "gitAndTools/hub" = «derivation»; - # # ... - # } - flattenTree = tree: import ./flattenTree.nix tree; - - # Nix check functionality validates packages for various conditions, like if - # they build for any given platform or if they are marked broken. - # - # This function filters a flattend package set for conditinos that - # would *trivially* break `nix flake check`. It does not flatten a tree and it - # does not implement advanced package validation checks. - # - # Eg: - # - # filterPackages "x86_64-linux" { - # hello = pkgs.hello; - # "gitAndTools/git" = pkgs.gitAndTools // {meta.broken = true;}; - # }; - # - # Returns: - # - # { - # hello = «derivation»; - # } - filterPackages = import ./filterPackages.nix { inherit allSystems; }; - - # Returns the structure used by `nix app` - mkApp = - { drv - , name ? drv.pname or drv.name - , exePath ? drv.passthru.exePath or "/bin/${name}" - }: - { - type = "app"; - program = "${drv}${exePath}"; - }; - - # This function tries to capture a common flake pattern. - simpleFlake = import ./simpleFlake.nix { inherit lib defaultSystems; }; - - # Helper functions for Nix evaluation - check-utils = import ./check-utils.nix; - - lib = { - inherit - allSystems - check-utils - defaultSystems - eachDefaultSystem - eachSystem - eachDefaultSystemMap - eachSystemMap - filterPackages - flattenTree - mkApp - simpleFlake - system - ; - }; -in -lib +# Used for back-compat +import ./lib.nix { } diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c90a2bf --- /dev/null +++ b/flake.lock @@ -0,0 +1,26 @@ +{ + "nodes": { + "root": { + "inputs": { + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index ae76102..34afb1a 100644 --- a/flake.nix +++ b/flake.nix @@ -1,7 +1,13 @@ { description = "Pure Nix flake utility functions"; - outputs = { self }: { - lib = import ./.; + + # Externally extensible flake systems. See . + inputs.systems.url = "github:nix-systems/default"; + + outputs = { self, systems }: { + lib = import ./lib.nix { + defaultSystems = import systems; + }; templates = { simple-flake = { path = ./examples/simple-flake; diff --git a/lib.nix b/lib.nix new file mode 100644 index 0000000..17f3569 --- /dev/null +++ b/lib.nix @@ -0,0 +1,229 @@ +{ + # The list of systems supported by nixpkgs and hydra + defaultSystems ? [ + "aarch64-linux" + "aarch64-darwin" + "x86_64-darwin" + "x86_64-linux" + ] +}: +let + # List of all systems defined in nixpkgs + # Keep in sync with nixpkgs wit the following command: + # $ nix-instantiate --json --eval --expr "with import {}; lib.platforms.all" | jq 'sort' | sed 's!,!!' + + allSystems = [ + "aarch64-darwin" + "aarch64-genode" + "aarch64-linux" + "aarch64-netbsd" + "aarch64-none" + "aarch64_be-none" + "arm-none" + "armv5tel-linux" + "armv6l-linux" + "armv6l-netbsd" + "armv6l-none" + "armv7a-darwin" + "armv7a-linux" + "armv7a-netbsd" + "armv7l-linux" + "armv7l-netbsd" + "avr-none" + "i686-cygwin" + "i686-darwin" + "i686-freebsd" + "i686-genode" + "i686-linux" + "i686-netbsd" + "i686-none" + "i686-openbsd" + "i686-windows" + "js-ghcjs" + "m68k-linux" + "m68k-netbsd" + "m68k-none" + "mips64el-linux" + "mipsel-linux" + "mipsel-netbsd" + "mmix-mmixware" + "msp430-none" + "or1k-none" + "powerpc-netbsd" + "powerpc-none" + "powerpc64-linux" + "powerpc64le-linux" + "powerpcle-none" + "riscv32-linux" + "riscv32-netbsd" + "riscv32-none" + "riscv64-linux" + "riscv64-netbsd" + "riscv64-none" + "s390-linux" + "s390-none" + "s390x-linux" + "s390x-none" + "vc4-none" + "wasm32-wasi" + "wasm64-wasi" + "x86_64-cygwin" + "x86_64-darwin" + "x86_64-freebsd" + "x86_64-genode" + "x86_64-linux" + "x86_64-netbsd" + "x86_64-none" + "x86_64-openbsd" + "x86_64-redox" + "x86_64-solaris" + "x86_64-windows" + ]; + + # A map from system to system. It's useful to detect typos. + # + # Instead of typing `"x86_64-linux"`, type `flake-utils.lib.system.x86_64-linux` + # and get an error back if you used a dash instead of an underscore. + system = + builtins.listToAttrs + (map (system: { name = system; value = system; }) allSystems); + + # eachSystem using defaultSystems + eachDefaultSystem = eachSystem defaultSystems; + + # Builds a map from =value to .=value for each system, + # except for the `hydraJobs` attribute, where it maps the inner attributes, + # from hydraJobs.=value to hydraJobs..=value. + # + eachSystem = systems: f: + let + # Taken from + isDerivation = x: builtins.isAttrs x && x ? type && x.type == "derivation"; + + # Used to match Hydra's convention of how to define jobs. Basically transforms + # + # hydraJobs = { + # hello = ; + # haskellPackages.aeson = ; + # } + # + # to + # + # hydraJobs = { + # hello.x86_64-linux = ; + # haskellPackages.aeson.x86_64-linux = ; + # } + # + # if the given flake does `eachSystem [ "x86_64-linux" ] { ... }`. + pushDownSystem = system: merged: + builtins.mapAttrs + (name: value: + if ! (builtins.isAttrs value) then value + else if isDerivation value then (merged.${name} or {}) // { ${system} = value; } + else pushDownSystem system (merged.${name} or {}) value); + + # Merge together the outputs for all systems. + op = attrs: system: + let + ret = f system; + op = attrs: key: + let + appendSystem = key: system: ret: + if key == "hydraJobs" + then (pushDownSystem system (attrs.hydraJobs or {}) ret.hydraJobs) + else { ${system} = ret.${key}; }; + in attrs // + { + ${key} = (attrs.${key} or { }) + // (appendSystem key system ret); + } + ; + in + builtins.foldl' op attrs (builtins.attrNames ret); + in + builtins.foldl' op { } systems + ; + + # eachSystemMap using defaultSystems + eachDefaultSystemMap = eachSystemMap defaultSystems; + + # Builds a map from =value to . = value. + eachSystemMap = systems: f: builtins.listToAttrs (builtins.map (system: { name = system; value = f system; }) systems); + + # Nix flakes insists on having a flat attribute set of derivations in + # various places like the `packages` and `checks` attributes. + # + # This function traverses a tree of attributes (by respecting + # recurseIntoAttrs) and only returns their derivations, with a flattened + # key-space. + # + # Eg: + # + # flattenTree { hello = pkgs.hello; gitAndTools = pkgs.gitAndTools }; + # + # Returns: + # + # { + # hello = «derivation»; + # "gitAndTools/git" = «derivation»; + # "gitAndTools/hub" = «derivation»; + # # ... + # } + flattenTree = tree: import ./flattenTree.nix tree; + + # Nix check functionality validates packages for various conditions, like if + # they build for any given platform or if they are marked broken. + # + # This function filters a flattend package set for conditinos that + # would *trivially* break `nix flake check`. It does not flatten a tree and it + # does not implement advanced package validation checks. + # + # Eg: + # + # filterPackages "x86_64-linux" { + # hello = pkgs.hello; + # "gitAndTools/git" = pkgs.gitAndTools // {meta.broken = true;}; + # }; + # + # Returns: + # + # { + # hello = «derivation»; + # } + filterPackages = import ./filterPackages.nix { inherit allSystems; }; + + # Returns the structure used by `nix app` + mkApp = + { drv + , name ? drv.pname or drv.name + , exePath ? drv.passthru.exePath or "/bin/${name}" + }: + { + type = "app"; + program = "${drv}${exePath}"; + }; + + # This function tries to capture a common flake pattern. + simpleFlake = import ./simpleFlake.nix { inherit lib defaultSystems; }; + + # Helper functions for Nix evaluation + check-utils = import ./check-utils.nix; + + lib = { + inherit + allSystems + check-utils + defaultSystems + eachDefaultSystem + eachSystem + eachDefaultSystemMap + eachSystemMap + filterPackages + flattenTree + mkApp + simpleFlake + system + ; + }; +in +lib