summary refs log tree commit diff
path: root/pkgs/stdenv/booter.nix
diff options
context:
space:
mode:
authorJohn Ericson <Ericson2314@Yahoo.com>2016-12-16 05:22:02 -0800
committerJohn Ericson <Ericson2314@Yahoo.com>2017-01-13 13:23:23 -0500
commit3e197f7d81130defacfe5bdad71ca5ebe63324ff (patch)
treed06650289f9729f647814eff912e8d39bdd523a8 /pkgs/stdenv/booter.nix
parent0ef8b69d12d1ab1574568f5660b44feba1f44179 (diff)
downloadnixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.tar
nixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.tar.gz
nixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.tar.bz2
nixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.tar.lz
nixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.tar.xz
nixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.tar.zst
nixpkgs-3e197f7d81130defacfe5bdad71ca5ebe63324ff.zip
top-level: Normalize stdenv booting
Introduce new abstraction, `stdenv/booter.nix` for composing bootstraping
stages, and use it everywhere for consistency. See that file for more doc.

Stdenvs besides Linux and Darwin are completely refactored to utilize this.
Those two, due to their size and complexity, are minimally edited for
easier reviewing.

No hashes should be changed.
Diffstat (limited to 'pkgs/stdenv/booter.nix')
-rw-r--r--pkgs/stdenv/booter.nix65
1 files changed, 65 insertions, 0 deletions
diff --git a/pkgs/stdenv/booter.nix b/pkgs/stdenv/booter.nix
new file mode 100644
index 00000000000..b1e1e898aa3
--- /dev/null
+++ b/pkgs/stdenv/booter.nix
@@ -0,0 +1,65 @@
+# This file defines a single function for booting a package set from a list of
+# stages. The exact mechanics of that function are defined below; here I
+# (@Ericson2314) wish to describe the purpose of the abstraction.
+#
+# The first goal is consistency across stdenvs. Regardless of what this function
+# does, by making every stdenv use it for bootstrapping we ensure that they all
+# work in a similar way. [Before this abstraction, each stdenv was its own
+# special snowflake due to different authors writing in different times.]
+#
+# The second goal is consistency across each stdenv's stage functions. By
+# writing each stage it terms of the previous stage, commonalities between them
+# are more easily observable. [Before, there usually was a big attribute set
+# with each stage, and stages would access the previous stage by name.]
+#
+# The third goal is composition. Because each stage is written in terms of the
+# previous, the list can be reordered or, more practically, extended with new
+# stages. The latter is used for cross compiling and custom
+# stdenvs. Additionally, certain options should by default apply only to the
+# last stage, whatever it may be. By delaying the creation of stage package sets
+# until the final fold, we prevent these options from inhibiting composition.
+#
+# The fourth and final goal is debugging. Normal packages should only source
+# their dependencies from the current stage. But for the sake of debugging, it
+# is nice that all packages still remain accessible. We make sure previous
+# stages are kept around with a `stdenv.__bootPackges` attribute referring the
+# previous stage. It is idiomatic that attributes prefixed with `__` come with
+# special restrictions and should not be used under normal circumstances.
+{ lib, allPackages }:
+
+# Type:
+#   [ pkgset -> (args to stage/default.nix) or ({ __raw = true; } // pkgs) ]
+#   -> pkgset
+#
+# In english: This takes a list of function from the previous stage pkgset and
+# returns the final pkgset. Each of those functions returns, if `__raw` is
+# undefined or false, args for this stage's pkgset (the most complex and
+# important arg is the stdenv), or, if `__raw = true`, simply this stage's
+# pkgset itself.
+#
+# The list takes stages in order, so the final stage is last in the list. In
+# other words, this does a foldr not foldl.
+stageFuns: let
+
+  # Take the list and disallow custom overrides in all but the final stage,
+  # and allow it in the final flag. Only defaults this boolean field if it
+  # isn't already set.
+  withAllowCustomOverrides = lib.lists.imap
+    (index: stageFun: prevStage:
+      { allowCustomOverrides = index == 1; } # first element, 1-indexed
+      // (stageFun prevStage))
+    (lib.lists.reverseList stageFuns);
+
+  # Adds the stdenv to the arguments, and sticks in it the previous stage for
+  # debugging purposes.
+  folder = stageFun: finalSoFar: let
+    args = stageFun finalSoFar;
+    stdenv = args.stdenv // {
+      # For debugging
+      __bootPackages = finalSoFar;
+    };
+    args' = args // { inherit stdenv; };
+  in
+    (if args.__raw or false then lib.id else allPackages) args';
+
+in lib.lists.fold folder {} withAllowCustomOverrides