diff --git a/README.md b/README.md index f03ea13..80a7e65 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ library instance with `mkLib`. description = "My Flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05"; snowfall-lib = { url = "github:snowfallorg/lib"; @@ -247,7 +247,7 @@ packages, overlays, and shells specified by the [Flake Structure](#flake-structu description = "My Flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05"; snowfall-lib = { url = "github:snowfallorg/lib"; @@ -279,7 +279,7 @@ You can apply overlays and modules from your flake's inputs with the following o description = "My Flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05"; snowfall-lib = { url = "github:snowfallorg/lib"; @@ -338,7 +338,7 @@ on `pkgs` and consumers of your flake can use the generated `.overla description = "My Flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05"; snowfall-lib = { url = "github:snowfallorg/lib"; @@ -391,7 +391,7 @@ mapping the `default` package or shell to the name of the one you want. description = "My Flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05"; snowfall-lib = { url = "github:snowfallorg/lib"; @@ -437,7 +437,7 @@ include `darwin` and/or `nixos-generators` as inputs. description = "My Flake"; inputs = { - nixpkgs.url = "github:nixos/nixpkgs/release-22.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05"; snowfall-lib = { url = "github:snowfallorg/lib"; @@ -995,6 +995,39 @@ Result: { x = 2; } ``` +#### `lib.snowfall.attrs.merge-shallow-packages` + +Merge shallow for packages, but allow one deeper layer of attributes sets. + +Type: `[Attrs] -> Attrs` + +Usage: + +```nix +merge-shallow-packages [ + { + inherit (pkgs) vim; + namespace.first = 1; + } + { + inherit (unstable) vim; + namespace.second = 2; + } +] +``` + +Result: + +```nix +{ + vim = {/* the vim package from the last entry */}; + namespace = { + first = 1; + second = 2; + }; +} +``` + ### `lib.snowfall.system` #### `lib.snowfall.system.is-darwin` @@ -1207,7 +1240,7 @@ Result: Utilities for working with channel overlays. -#### `lib.snowfall.overlay.create-overlays` +#### `lib.snowfall.overlay.create-overlays-builder` Create a flake-utils-plus overlays builder. @@ -1216,7 +1249,7 @@ Type: `Attrs -> Attrs -> [(a -> b -> c)]` Usage: ```nix -create-overlays { src = ./my-overlays; overlay-package-namespace = "my-packages"; } +create-overlays-builder { src = ./my-overlays; overlay-package-namespace = "my-packages"; extra-overlays = []; } ``` Result: @@ -1225,6 +1258,35 @@ Result: (channels: [ ... ]) ``` +#### `lib.snowfall.overlay.create-overlays` + +Create overlays to be used for flake outputs. + +Type: `Attrs -> Attrs` + +Usage: + +```nix +create-overlays { + src = ./my-overlays; + packages-src = ./my-packages; + overlay-package-namespace = "my-namespace"; + extra-overlays = { + my-example = final: prev: {}; + }; +} +``` + +Result: + +```nix +{ + default = final: prev: {}; + my-example = final: prev: {}; + some-overlay = final: prev: {}; +} +``` + ### `lib.snowfall.template` Utilities for working with flake templates. diff --git a/flake.lock b/flake.lock index 5154ca6..d8f9b49 100644 --- a/flake.lock +++ b/flake.lock @@ -1,26 +1,5 @@ { "nodes": { - "darwin": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1661882940, - "narHash": "sha256-4LaVFnV22WrOA0aolqqk9dXrM8crikcrLQt29G18F7M=", - "owner": "lnl7", - "repo": "nix-darwin", - "rev": "80cec5115aae74accc4ccfb9f84306d7863f0632", - "type": "github" - }, - "original": { - "owner": "lnl7", - "ref": "master", - "repo": "nix-darwin", - "type": "github" - } - }, "flake-compat": { "flake": false, "locked": { @@ -70,49 +49,13 @@ "type": "github" } }, - "nixlib": { - "locked": { - "lastModified": 1636849918, - "narHash": "sha256-nzUK6dPcTmNVrgTAC1EOybSMsrcx+QrVPyqRdyKLkjA=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "28a5b0557f14124608db68d3ee1f77e9329e9dd5", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixos-generators": { - "inputs": { - "nixlib": "nixlib", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1660727616, - "narHash": "sha256-zYTIvdPMYMx/EYqXODAwIIU30RiEHqNHdgarIHuEYZc=", - "owner": "nix-community", - "repo": "nixos-generators", - "rev": "adccd191a0e83039d537e021f19495b7bad546a1", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixos-generators", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1662316000, - "narHash": "sha256-NkJHCVi6sj1+QqqXaozSJ0K23ANmvsnDmeC/6WXo+wI=", + "lastModified": 1665216225, + "narHash": "sha256-SUuvJXGEXhmyaGJlDlptbc9I2Wai9tUx83QYIqvipfE=", "owner": "nixos", "repo": "nixpkgs", - "rev": "50c62eeda9df340ff6b83a0e2343a447af04237c", + "rev": "1a9935bf90e0f4225756f99e772f06d5fea9edb6", "type": "github" }, "original": { @@ -124,10 +67,8 @@ }, "root": { "inputs": { - "darwin": "darwin", "flake-compat": "flake-compat", "flake-utils-plus": "flake-utils-plus", - "nixos-generators": "nixos-generators", "nixpkgs": "nixpkgs" } } diff --git a/lib/attrs/default.nix b/lib/attrs/default.nix index 44c66ee..9896757 100644 --- a/lib/attrs/default.nix +++ b/lib/attrs/default.nix @@ -7,10 +7,12 @@ let inherit (core-inputs.nixpkgs.lib) assertMsg mapAttrsToList + mapAttrs flatten - fold + foldl recursiveUpdate - mergeAttrs; + mergeAttrs + isDerivation; in { attrs = { @@ -25,12 +27,33 @@ in # Type: [Attrs] -> Attrs # Usage: merge-deep [{ x = 1; } { x = 2; }] # result: { x = 2; } - merge-deep = fold recursiveUpdate { }; + merge-deep = foldl recursiveUpdate { }; # Merge the root of a list of attribute sets. # Type: [Attrs] -> Attrs # Usage: merge-shallow [{ x = 1; } { x = 2; }] # result: { x = 2; } - merge-shallow = fold mergeAttrs { }; + merge-shallow = foldl mergeAttrs { }; + + # Merge shallow for packages, but allow one deeper layer of attribute sets. + # Type: [Attrs] -> Attrs + # Usage: merge-shallow-packages [ { inherit (pkgs) vim; some.value = true; } { some.value = false; } ] + # result: { vim = ...; some.value = false; } + merge-shallow-packages = items: + foldl + (result: item: + result // (mapAttrs + (name: value: + if isDerivation value then + value + else if builtins.isAttrs value then + (result.${name} or { }) // value + else + value + ) + item) + ) + { } + items; }; } diff --git a/lib/flake/default.nix b/lib/flake/default.nix index 6e076eb..318739b 100644 --- a/lib/flake/default.nix +++ b/lib/flake/default.nix @@ -78,9 +78,10 @@ rec { modules = snowfall-lib.module.create-modules { overrides = (full-flake-options.modules or { }); }; - overlays = core-inputs.flake-utils-plus.lib.exportOverlays ({ - inherit (user-inputs.self) pkgs inputs; - }); + overlays = snowfall-lib.overlay.create-overlays { + overlay-package-namespace = full-flake-options.overlay-package-namespace or null; + extra-overlays = full-flake-options.extra-exported-overlays or { }; + }; outputs-builder = channels: let @@ -107,7 +108,7 @@ rec { snowfall-lib.attrs.merge-deep [ user-outputs outputs ]; flake-options = custom-flake-options // { - inherit hosts templates overlays; + inherit hosts templates; inherit (user-inputs) self; lib = snowfall-lib.internal.user-lib; @@ -117,7 +118,7 @@ rec { channelsConfig = full-flake-options.channels-config or { }; - channels.nixpkgs.overlaysBuilder = snowfall-lib.overlay.create-overlays { + channels.nixpkgs.overlaysBuilder = snowfall-lib.overlay.create-overlays-builder { overlay-package-namespace = full-flake-options.overlay-package-namespace or null; extra-overlays = full-flake-options.overlays or [ ]; }; @@ -125,36 +126,14 @@ rec { outputsBuilder = outputs-builder; }; - flake-outputs = + flake-utils-plus-outputs = core-inputs.flake-utils-plus.lib.mkFlake flake-options; - overlay = (final: prev: - let - overlay-package-namespace = full-flake-options.overlay-package-namespace or null; - user-overlay-packages = - (builtins.map (overlay: overlay final prev) (builtins.attrValues flake-outputs.overlays)); - namespaced-user-overlay-packages = - foldl - (namespaced-user-overlay-packages: user-overlay-package: - namespaced-user-overlay-packages // user-overlay-package.${overlay-package-namespace} - ) - { } - user-overlay-packages; - merged-user-overlay-packages = - if overlay-package-namespace == null then - snowfall-lib.attrs.merge-shallow - user-overlay-packages - else - { - ${overlay-package-namespace} = - (prev.${overlay-package-namespace} or { }) - // namespaced-user-overlay-packages; - }; - in - merged-user-overlay-packages - ); + flake-outputs = + flake-utils-plus-outputs // { + inherit overlays; + overlay = overlays.default; + }; in - flake-outputs // { - inherit overlay; - }; + flake-outputs; } diff --git a/lib/overlay/default.nix b/lib/overlay/default.nix index 5b3f6b6..d8edf25 100644 --- a/lib/overlay/default.nix +++ b/lib/overlay/default.nix @@ -4,9 +4,10 @@ }: let - inherit (core-inputs.nixpkgs.lib) assertMsg; + inherit (core-inputs.nixpkgs.lib) assertMsg foldl concatStringsSep; user-overlays-root = snowfall-lib.fs.get-file "overlays"; + user-packages-root = snowfall-lib.fs.get-file "packages"; in { overlay = { @@ -14,7 +15,7 @@ in # Type: Attrs -> Attrs -> [(a -> b -> c)] # Usage: create-overlays { src = ./my-overlays; overlay-package-namespace = "my-packages"; } # result: (channels: [ ... ]) - create-overlays = + create-overlays-builder = { src ? user-overlays-root , overlay-package-namespace ? null , extra-overlays ? [ ] @@ -42,5 +43,140 @@ in overlays = [ user-packages-overlay ] ++ extra-overlays ++ (builtins.map create-overlay user-overlays); in overlays; + + # Create exported overlays from the user flake. + # Adapted from flake-utils-plus: + # https://github.com/gytis-ivaskevicius/flake-utils-plus/blob/2bf0f91643c2e5ae38c1b26893ac2927ac9bd82a/lib/exportOverlays.nix + # Type: Attrs -> Attrs + # Usage: create-overlays { src = ./my-overlays; packages-src = ./my-packages; overlay-package-namespace = "my-namespace"; extra-overlays = {}; } + # result: { default = final: prev: ...; some-overlay = final: prev: ...; } + create-overlays = + { src ? user-overlays-root + , packages-src ? user-packages-root + , overlay-package-namespace ? null + , extra-overlays ? { } + }: + let + fake-pkgs = { + callPackage = x: x; + isFakePkgs = true; + lib = { }; + system = "fake-system"; + }; + + user-overlays = snowfall-lib.fs.get-default-nix-files-recursive src; + + channel-systems = user-inputs.self.pkgs; + + user-packages-overlay = final: prev: + let + user-packages = snowfall-lib.package.create-packages { + pkgs = final; + channels = channel-systems.${prev.system}; + }; + in + if overlay-package-namespace == null then + user-packages + else + { + ${overlay-package-namespace} = + (prev.${overlay-package-namespace} or { }) + // user-packages; + }; + + create-overlay = (overlays: file: + let + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory file); + overlay = final: prev: + let + channels = channel-systems.${prev.system}; + user-overlay = import file (user-inputs // { inherit channels; }); + packages = user-packages-overlay final prev; + prev-with-packages = + if overlay-package-namespace == null then + prev // packages + else + prev // { + ${overlay-package-namespace} = + (prev.${overlay-package-namespace} or { }) + // packages.${overlay-package-namespace}; + }; + user-overlay-packages = + user-overlay + final + prev-with-packages; + outputs = + user-overlay-packages; + in + if user-overlay-packages.__dontExport or false == true then + outputs // { __dontExport = true; } + else + outputs; + fake-overlay-result = overlay fake-pkgs fake-pkgs; + in + if fake-overlay-result.__dontExport or false == true then + overlays + else + overlays // { + "nixpkgs/${name}" = overlay; + } + ); + + overlays = + foldl + create-overlay + { } + user-overlays; + + user-packages = snowfall-lib.fs.get-default-nix-files-recursive packages-src; + + create-package-overlay = package-overlays: file: + let + name = builtins.unsafeDiscardStringContext (snowfall-lib.path.get-parent-directory file); + overlay = final: prev: + let + channels = channel-systems.${prev.system}; + packages = snowfall-lib.package.create-packages { + channels = channel-systems.${prev.system}; + }; + in + if overlay-package-namespace == null then + { ${name} = packages.${name}; } + else + { + ${overlay-package-namespace} = + (prev.${overlay-package-namespace} or { }) + // { ${name} = packages.${name}; }; + }; + in + package-overlays // + { + "nixpkgs/${name}" = overlay; + }; + + package-overlays = + foldl + create-package-overlay + { } + user-packages; + + default-overlay = final: prev: + let + overlays-list = builtins.attrValues overlays; + package-overlays-list = builtins.attrValues package-overlays; + + overlays-results = builtins.map (overlay: overlay final prev) overlays-list; + package-overlays-results = builtins.map (overlay: overlay final prev) package-overlays-list; + + merged-results = snowfall-lib.attrs.merge-shallow-packages + (package-overlays-results ++ overlays-results); + in + merged-results; + in + package-overlays + // overlays + // { default = default-overlay; } + // extra-overlays; }; } +