From dbabf0ca0c0c4bce6ea5eaf65af5cb694d2082c7 Mon Sep 17 00:00:00 2001 From: Javed Mohamed Date: Sun, 25 Jun 2023 16:15:56 +0000 Subject: [PATCH] Add meld (#99) Meld allows you to break up a Nix Flake into parts while using the same inputs across all of them. This is useful for splitting up large flakes which are common in monorepos. --- README.md | 6 +++++ lib.nix | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/README.md b/README.md index 425a3c0..4103633 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,12 @@ eachSystem allSystems (system: { hello = 42; }) } ``` +### `meld :: attrs -> [ path ] -> attrs` + +Meld merges subflakes using common inputs. Useful when you want to +split up a large flake with many different components into more +manageable parts. + ### `mkApp { drv, name ? drv.pname or drv.name, exePath ? drv.passthru.exePath or "/bin/${name}"` A small utility that builds the structure expected by the special `apps` and `defaultApp` prefixes. diff --git a/lib.nix b/lib.nix index a66410d..a774f18 100644 --- a/lib.nix +++ b/lib.nix @@ -128,6 +128,79 @@ let # } filterPackages = import ./filterPackages.nix { inherit allSystems; }; + # Meld merges subflakes using common inputs. Useful when you want + # to split up a large flake with many different components into more + # manageable parts. + # + # For example: + # + # { + # inputs = { + # flutils.url = "github:numtide/flake-utils"; + # nixpkgs.url = "github:nixos/nixpkgs"; + # }; + # outputs = inputs@{ flutils, ... }: flutils.lib.meld inputs [ + # ./nix/packages + # ./nix/hardware + # ./nix/overlays + # # ... + # ]; + # } + # + # Where ./nix/packages/default.nix looks like just the output + # portion of a flake. + # + # { flutils, nixpkgs, ... }: flutils.lib.eachDefaultSystem (system: + # let pkgs = import nixpkgs { inherit system; }; in + # { + # packages = { + # foo = ...; + # bar = ...; + # # ... + # }; + # } + # ) + # + # You can also use meld within the subflakes to further subdivide + # your flake into a tree like structure. For example, + # ./nix/hardware/default.nix might look like: + # + # inputs@{ flutils, ... }: flutils.lib.meld inputs [ + # ./foobox.nix + # ./barbox.nix + # ] + meld = let + # Pulled from nixpkgs.lib + recursiveUpdateUntil = + # Predicate, taking the path to the current attribute as a list of strings for attribute names, and the two values at that path from the original arguments. + pred: + # Left attribute set of the merge. + lhs: + # Right attribute set of the merge. + rhs: + let + f = attrPath: + builtins.zipAttrsWith (n: values: + let here = attrPath ++ [ n ]; + in if builtins.length values == 1 + || pred here (builtins.elemAt values 1) (builtins.head values) then + builtins.head values + else + f here values); + in f [ ] [ rhs lhs ]; + + # Pulled from nixpkgs.lib + recursiveUpdate = + # Left attribute set of the merge. + lhs: + # Right attribute set of the merge. + rhs: + recursiveUpdateUntil (path: lhs: rhs: !(builtins.isAttrs lhs && builtins.isAttrs rhs)) lhs + rhs; + in inputs: + builtins.foldl' (output: subflake: + recursiveUpdate output (import subflake inputs)) { }; + # Returns the structure used by `nix app` mkApp = { drv @@ -156,6 +229,7 @@ let eachSystemMap filterPackages flattenTree + meld mkApp simpleFlake system