From 93b619554284af9a5829fff4245a276d85d9062a Mon Sep 17 00:00:00 2001
From: xeals <dev@xeal.me>
Date: Thu, 21 Sep 2023 12:27:35 +1000
Subject: [PATCH] all: refactor to follow RFC140

---
 callUnitRoot.nix                              | 15 -----
 default.nix                                   |  6 +-
 flake.nix                                     | 11 +---
 .../al/alacritty-ligatures/package.nix        |  0
 .../am/amdgpu-fan/package.nix                 |  0
 .../at/atlauncher/package.nix                 |  0
 .../0001-use-system-dependencies.patch        |  0
 .../ca/cardboard/package.nix                  |  0
 pkgs/{unit => by-name}/cu/cura5/package.nix   |  0
 .../{unit => by-name}/li/libhl/fix-link.patch |  0
 pkgs/{unit => by-name}/li/libhl/package.nix   |  0
 .../pa/pam_gnupg/package.nix                  |  0
 pkgs/{unit => by-name}/ps/psst/package.nix    |  0
 .../sa/samrewritten/package.nix               |  0
 .../sp/spotify-ripper/fix-setup.patch         |  0
 .../sp/spotify-ripper/package.nix             |  0
 .../yt/ytarchive/package.nix                  |  0
 pkgs/{unit => by-name}/zs/zsh-z/package.nix   |  0
 pkgs/top-level/by-name-overlay.nix            | 56 +++++++++++++++++++
 pkgs/top-level/default.nix                    | 19 +++++++
 pkgs/top-level/stage.nix                      | 24 ++++++++
 21 files changed, 103 insertions(+), 28 deletions(-)
 delete mode 100644 callUnitRoot.nix
 rename pkgs/{unit => by-name}/al/alacritty-ligatures/package.nix (100%)
 rename pkgs/{unit => by-name}/am/amdgpu-fan/package.nix (100%)
 rename pkgs/{unit => by-name}/at/atlauncher/package.nix (100%)
 rename pkgs/{unit => by-name}/ca/cardboard/0001-use-system-dependencies.patch (100%)
 rename pkgs/{unit => by-name}/ca/cardboard/package.nix (100%)
 rename pkgs/{unit => by-name}/cu/cura5/package.nix (100%)
 rename pkgs/{unit => by-name}/li/libhl/fix-link.patch (100%)
 rename pkgs/{unit => by-name}/li/libhl/package.nix (100%)
 rename pkgs/{unit => by-name}/pa/pam_gnupg/package.nix (100%)
 rename pkgs/{unit => by-name}/ps/psst/package.nix (100%)
 rename pkgs/{unit => by-name}/sa/samrewritten/package.nix (100%)
 rename pkgs/{unit => by-name}/sp/spotify-ripper/fix-setup.patch (100%)
 rename pkgs/{unit => by-name}/sp/spotify-ripper/package.nix (100%)
 rename pkgs/{unit => by-name}/yt/ytarchive/package.nix (100%)
 rename pkgs/{unit => by-name}/zs/zsh-z/package.nix (100%)
 create mode 100644 pkgs/top-level/by-name-overlay.nix
 create mode 100644 pkgs/top-level/default.nix
 create mode 100644 pkgs/top-level/stage.nix

diff --git a/callUnitRoot.nix b/callUnitRoot.nix
deleted file mode 100644
index 6ee290d..0000000
--- a/callUnitRoot.nix
+++ /dev/null
@@ -1,15 +0,0 @@
-{ pkgs
-, lib ? pkgs.lib
-, unitDir ? "unit"
-, packageFun ? "package.nix"
-, root ? "${./pkgs}/${unitDir}"
-}:
-let
-  shards = lib.attrNames (builtins.readDir root);
-  namesForShard = shard: lib.mapAttrs'
-    (name: _: { inherit name; value = root + "/${shard}/${name}"; })
-    (builtins.readDir (root + "/${shard}"));
-  namesToPath = lib.foldl' lib.recursiveUpdate { } (map namesForShard shards);
-  units = lib.mapAttrs (_: path: pkgs.callPackage (path + "/${packageFun}") { }) namesToPath;
-in
-units
diff --git a/default.nix b/default.nix
index df1b27a..f10a2a7 100644
--- a/default.nix
+++ b/default.nix
@@ -8,10 +8,10 @@
 
 { pkgs ? import <nixpkgs> { } }:
 let
-  legacy = import ./pkgs/top-level/all-packages.nix { inherit pkgs; };
-  units = import ./callUnitRoot.nix { inherit pkgs; root = ./pkgs/unit; };
+  system = pkgs.stdenv.hostPlatform.system;
+  packages = import ./pkgs/top-level { localSystem = system; inherit pkgs; };
 in
-legacy // units // {
+packages // {
   # The `lib`, `modules`, and `overlay` names are special
   lib = import ./lib { inherit pkgs; }; # functions
   modules = import ./modules; # NixOS modules
diff --git a/flake.nix b/flake.nix
index a1211f7..dbe3a75 100644
--- a/flake.nix
+++ b/flake.nix
@@ -15,16 +15,7 @@
           pkgs = import nixpkgs { inherit system; };
         in
         {
-          # nixos/rfcs#140
-          # Only produces the package set of the proposed functionality.
-          # Unstable names are variables.
-          packages =
-            let
-              legacyPackages = import ./pkgs/top-level/all-packages.nix { inherit pkgs; };
-              unitPackages = import ./callUnitRoot.nix { inherit pkgs; };
-              onlyAvailable = lib.filterAttrs (_: drv: builtins.elem system (drv.meta.platforms or [ ]));
-            in
-            onlyAvailable (legacyPackages // unitPackages);
+          packages = import ./pkgs/top-level { localSystem = system; inherit pkgs; };
 
           checks = {
             nixpkgs-fmt = pkgs.writeShellScriptBin "nixpkgs-fmt-check" ''
diff --git a/pkgs/unit/al/alacritty-ligatures/package.nix b/pkgs/by-name/al/alacritty-ligatures/package.nix
similarity index 100%
rename from pkgs/unit/al/alacritty-ligatures/package.nix
rename to pkgs/by-name/al/alacritty-ligatures/package.nix
diff --git a/pkgs/unit/am/amdgpu-fan/package.nix b/pkgs/by-name/am/amdgpu-fan/package.nix
similarity index 100%
rename from pkgs/unit/am/amdgpu-fan/package.nix
rename to pkgs/by-name/am/amdgpu-fan/package.nix
diff --git a/pkgs/unit/at/atlauncher/package.nix b/pkgs/by-name/at/atlauncher/package.nix
similarity index 100%
rename from pkgs/unit/at/atlauncher/package.nix
rename to pkgs/by-name/at/atlauncher/package.nix
diff --git a/pkgs/unit/ca/cardboard/0001-use-system-dependencies.patch b/pkgs/by-name/ca/cardboard/0001-use-system-dependencies.patch
similarity index 100%
rename from pkgs/unit/ca/cardboard/0001-use-system-dependencies.patch
rename to pkgs/by-name/ca/cardboard/0001-use-system-dependencies.patch
diff --git a/pkgs/unit/ca/cardboard/package.nix b/pkgs/by-name/ca/cardboard/package.nix
similarity index 100%
rename from pkgs/unit/ca/cardboard/package.nix
rename to pkgs/by-name/ca/cardboard/package.nix
diff --git a/pkgs/unit/cu/cura5/package.nix b/pkgs/by-name/cu/cura5/package.nix
similarity index 100%
rename from pkgs/unit/cu/cura5/package.nix
rename to pkgs/by-name/cu/cura5/package.nix
diff --git a/pkgs/unit/li/libhl/fix-link.patch b/pkgs/by-name/li/libhl/fix-link.patch
similarity index 100%
rename from pkgs/unit/li/libhl/fix-link.patch
rename to pkgs/by-name/li/libhl/fix-link.patch
diff --git a/pkgs/unit/li/libhl/package.nix b/pkgs/by-name/li/libhl/package.nix
similarity index 100%
rename from pkgs/unit/li/libhl/package.nix
rename to pkgs/by-name/li/libhl/package.nix
diff --git a/pkgs/unit/pa/pam_gnupg/package.nix b/pkgs/by-name/pa/pam_gnupg/package.nix
similarity index 100%
rename from pkgs/unit/pa/pam_gnupg/package.nix
rename to pkgs/by-name/pa/pam_gnupg/package.nix
diff --git a/pkgs/unit/ps/psst/package.nix b/pkgs/by-name/ps/psst/package.nix
similarity index 100%
rename from pkgs/unit/ps/psst/package.nix
rename to pkgs/by-name/ps/psst/package.nix
diff --git a/pkgs/unit/sa/samrewritten/package.nix b/pkgs/by-name/sa/samrewritten/package.nix
similarity index 100%
rename from pkgs/unit/sa/samrewritten/package.nix
rename to pkgs/by-name/sa/samrewritten/package.nix
diff --git a/pkgs/unit/sp/spotify-ripper/fix-setup.patch b/pkgs/by-name/sp/spotify-ripper/fix-setup.patch
similarity index 100%
rename from pkgs/unit/sp/spotify-ripper/fix-setup.patch
rename to pkgs/by-name/sp/spotify-ripper/fix-setup.patch
diff --git a/pkgs/unit/sp/spotify-ripper/package.nix b/pkgs/by-name/sp/spotify-ripper/package.nix
similarity index 100%
rename from pkgs/unit/sp/spotify-ripper/package.nix
rename to pkgs/by-name/sp/spotify-ripper/package.nix
diff --git a/pkgs/unit/yt/ytarchive/package.nix b/pkgs/by-name/yt/ytarchive/package.nix
similarity index 100%
rename from pkgs/unit/yt/ytarchive/package.nix
rename to pkgs/by-name/yt/ytarchive/package.nix
diff --git a/pkgs/unit/zs/zsh-z/package.nix b/pkgs/by-name/zs/zsh-z/package.nix
similarity index 100%
rename from pkgs/unit/zs/zsh-z/package.nix
rename to pkgs/by-name/zs/zsh-z/package.nix
diff --git a/pkgs/top-level/by-name-overlay.nix b/pkgs/top-level/by-name-overlay.nix
new file mode 100644
index 0000000..23eef54
--- /dev/null
+++ b/pkgs/top-level/by-name-overlay.nix
@@ -0,0 +1,56 @@
+# This file turns the pkgs/by-name directory (see its README.md for more info)
+# into an overlay that adds all the defined packages.
+#
+# No validity checks are done here, instead this file is optimised for
+# performance, and validity checks are done by CI on PRs.
+#
+# This file is based on Nixpkgs' `pkgs/top-level/by-name-overlay.nix` in order
+# to utilise the same infrastructure and layout, with some adjustments to fit
+# our derivative project.
+
+{ lib
+, pkgs
+}:
+
+# Type: Path -> Overlay
+baseDirectory:
+let
+  inherit (builtins)
+    readDir
+    ;
+
+  inherit (lib.attrsets)
+    mapAttrs
+    mapAttrsToList
+    mergeAttrsList
+    ;
+
+  # Package files for a single shard
+  # Type: String -> String -> AttrsOf Path
+  namesForShard = shard: type:
+    if type != "directory" then
+    # Ignore all non-directories. Technically only README.md is allowed as a file in the base directory, so we could alternatively:
+    # - Assume that README.md is the only file and change the condition to `shard == "README.md"` for a minor performance improvement.
+    #   This would however cause very poor error messages if there's other files.
+    # - Ensure that README.md is the only file, throwing a better error message if that's not the case.
+    #   However this would make for a poor code architecture, because one type of error would have to be duplicated in the validity checks and here.
+    # Additionally in either of those alternatives, we would have to duplicate the hardcoding of "README.md"
+      { }
+    else
+      mapAttrs
+        (name: _: baseDirectory + "/${shard}/${name}/package.nix")
+        (readDir (baseDirectory + "/${shard}"));
+
+  # The attribute set mapping names to the package files defining them
+  # This is defined up here in order to allow reuse of the value (it's kind of expensive to compute)
+  # if the overlay has to be applied multiple times
+  packageFiles = mergeAttrsList (mapAttrsToList namesForShard (readDir baseDirectory));
+in
+# TODO: Consider optimising this using `builtins.deepSeq packageFiles`,
+  # which could free up the above thunks and reduce GC times.
+  # Currently this would be hard to measure until we have more packages
+  # and ideally https://github.com/NixOS/nix/pull/8895
+_self: _super:
+mapAttrs
+  (_name: file: pkgs.callPackage file { })
+  packageFiles
diff --git a/pkgs/top-level/default.nix b/pkgs/top-level/default.nix
new file mode 100644
index 0000000..fcd46f7
--- /dev/null
+++ b/pkgs/top-level/default.nix
@@ -0,0 +1,19 @@
+# Composes the packages collection.
+
+{
+  # The system packages will be build and used on.
+  localSystem
+  # Nixpkgs
+, pkgs
+  # Nixpkgs lib
+, lib ? pkgs.lib
+}:
+let
+  allPackages = import ./stage.nix {
+    inherit lib pkgs;
+  };
+
+  available = lib.filterAttrs
+    (_: drv: builtins.elem localSystem (drv.meta.platforms or [ ]));
+in
+available allPackages
diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix
new file mode 100644
index 0000000..90d1fc6
--- /dev/null
+++ b/pkgs/top-level/stage.nix
@@ -0,0 +1,24 @@
+# Composes a single bootstrapping of the package collection. The result is a set
+# of all the packages for some particular platform.
+
+{ lib
+, pkgs
+}:
+let
+
+  # An overlay to auto-call packages in .../by-name.
+  autoCalledPackages =
+    import ./by-name-overlay.nix { inherit pkgs lib; } ../by-name;
+
+  allPackages = _self: _super:
+    import ./all-packages.nix { inherit pkgs; };
+
+  toFix = (lib.flip lib.composeManyExtensions) (_self: { }) [
+    autoCalledPackages
+    allPackages
+  ];
+
+in
+
+# Return the complete set of packages.
+lib.fix toFix