From 079d2226148b191d35aeaeff831ab49df0d7c1f0 Mon Sep 17 00:00:00 2001 From: Tim Van Baak Date: Sun, 28 Jul 2024 20:09:17 -0700 Subject: [PATCH] Support bundling nixos configurations --- default.nix | 105 ++++++++++++++++++++++++++++++++-------------------- flake.nix | 12 ++++-- 2 files changed, 73 insertions(+), 44 deletions(-) diff --git a/default.nix b/default.nix index ba24632..8ebf9c8 100644 --- a/default.nix +++ b/default.nix @@ -3,8 +3,11 @@ let inherit (builtins) genericClosure hasAttr + head length map + match + tail ; inherit (pkgs) runCommandLocal writeText; inherit (pkgs.lib) @@ -19,18 +22,32 @@ let ; in rec { - drvOutputs = drv: if hasAttr "outputs" drv then map (out: drv.${out}) drv.outputs else [ drv ]; + # Map a drv or list of drvs to a list of output drvs + drvOutputs = drv: + if isList drv then + concatMap drvOutputs drv + else if hasAttr "outputs" drv then + map (out: drv.${out}) drv.outputs + else [ drv ]; + + # Map a drv or list of drvs to the outputs of referenced derivations drvDeps = drv: - mapAttrsToList ( - k: v: - if isDerivation v then - (drvOutputs v) - else if isList v then - concatMap drvOutputs (filter isDerivation v) - else - [ ] - ) drv; + if isList drv then + concatMap drvDeps drv + else + mapAttrsToList ( + k: v: + if isDerivation v then + (drvOutputs v) + else if isList v then + concatMap drvOutputs (filter isDerivation v) + else + [ ] + ) drv; + + # Get the reference closure of a derivation or list of derivations + # This may miss dependencies that are only in-closure from string context drvClosure = let wrap = drv: { @@ -43,50 +60,58 @@ rec { startSet = map wrap (drvOutputs drv); operator = obj: map wrap (concatLists (drvDeps obj.drv.drvAttrs)); }); + maintainable = drv: hasAttr "meta" drv && hasAttr "maintainers" drv.meta; drvMaintainers = drv: if maintainable drv then drv.meta.maintainers else [ ]; - nobodyMaintains = - drv: hasAttr "meta" drv && hasAttr "maintainers" drv.meta && (length drv.meta.maintainers) == 0; + + # Construct a link to a derivation's source in github:NixOS/nixpkgs + drvSource = drv: + let + parts = match "/nix/store/[^/]+/(.*):([0-9]*)" drv.meta.position; + in + if hasAttr "meta" drv && hasAttr "position" drv.meta then + "https://github.com/NixOS/nixpkgs/blob/master/${head parts}#L${head (tail parts)}" + else + ""; + + mainInfo = drv: { + name = drv.name; + maintainers = map (main: toString main.github) (drvMaintainers drv); + source = drvSource drv; + }; + stringJoin = objToString: objs: writeText "txt" (concatLines (map objToString objs)); + closureInfo = drv: map mainInfo (filter maintainable (drvClosure drv)); + allMaintainers = drv: let - closure = drvClosure drv; - maintainers = concatMap drvMaintainers closure; - mainToString = m: "${m.name} (${m.email})"; + info = closureInfo drv; + infoToString = info: "${info.name} ${concatStringsSep "," info.maintainers}"; in - runCommandLocal "uniq-maintainers.txt" { } '' - <${stringJoin mainToString maintainers} sort | uniq -c > $out + runCommandLocal "all-maintainers.txt" { } '' + <${stringJoin infoToString info} sort -u | ${pkgs.unixtools.column}/bin/column -t > $out ''; noMaintainers = drv: let - closure = drvClosure drv; - unmaintained = filter nobodyMaintains closure; - drvToString = drv: "${drv.name} ${drv.meta.position}"; + info = closureInfo drv; + unmaintained = filter (info: (length info.maintainers) == 0) info; + infoToString = info: "${info.name} ${info.source}"; in - runCommandLocal "no-maintainers.txt" { } '' - <${stringJoin drvToString unmaintained} sort -u \ - | sed 's/\/nix\/store\/[^/]*/https:\/\/github.com\/NixOS\/nixpkgs\/blob\/master/' \ - | sed 's/.nix:\(.*\)$/.nix#L\1/' \ - | ${pkgs.unixtools.column}/bin/column -t \ - > $out + runCommandLocal "unmaintained.txt" { } '' + <${stringJoin infoToString unmaintained} sort -u | ${pkgs.unixtools.column}/bin/column -t > $out ''; - listMaintainers = - drv: - let - closure = drvClosure drv; - maintainableDrvs = filter maintainable closure; - maintainersToString = - maintainers: concatStringsSep "," (map (main: toString main.github) maintainers); - drvToString = drv: "${drv.name} ${maintainersToString (drvMaintainers drv)}"; - in - runCommandLocal "maintainers.txt" { } '' - <${stringJoin drvToString maintainableDrvs} sort -u \ - | ${pkgs.unixtools.column}/bin/column -t \ - > $out - ''; + expandInput = + input: + if (input.class or null == "nixos") && (input._type or null == "configuration") then + [ + input.config.system.build.toplevel + input.config.environment.systemPackages + ] + else + input; } diff --git a/flake.nix b/flake.nix index 8e8245f..bed8963 100644 --- a/flake.nix +++ b/flake.nix @@ -5,13 +5,17 @@ system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; lib = import ./default.nix { inherit pkgs; }; + inherit (lib) + allMaintainers + expandInput + noMaintainers + ; in { bundlers."x86_64-linux" = rec { - default = adopt; - maintainers = lib.allMaintainers; - adopt = lib.noMaintainers; - list = lib.listMaintainers; + default = unmaintained; + all = drv: allMaintainers (expandInput drv); + unmaintained = drv: noMaintainers (expandInput drv); }; formatter."x86_64-linux" = pkgs.nixfmt-rfc-style;