From e3ec481111b9d57964fb613c5935e1df61403667 Mon Sep 17 00:00:00 2001 From: Timothy DeHerrera Date: Sun, 4 Aug 2024 20:51:15 -0600 Subject: [PATCH] feat: add internal features for the composer This is the first implementation of the kinds of features atoms will be able to set on themselves. The internal composer function has the ability to define it's own features as well. the semantic for declaring features is basically identical to doing so in a Cargo.toml from Rust, for those famililar: ```toml [features] my_feature = [] my_other_feature = ["my_feature"] default = ["my_feature"] ``` Here, the default feature enabled is `my_feature` because it is in the `default` list. When `my_other_feature` is enabled, it also implicitly enables `my_feature` since it is in it's list. --- compose.toml | 7 ++++--- default.nix | 29 +++++++++++++++++++-------- src/default.nix | 14 ++++++++----- test/std-import/import.nix | 12 +++--------- test/std-import/import.sh | 36 +++++++++++++++++++++++----------- test/std-import/import/mod.nix | 8 ++++++-- 6 files changed, 68 insertions(+), 38 deletions(-) diff --git a/compose.toml b/compose.toml index 14143cf..6f9fc8e 100644 --- a/compose.toml +++ b/compose.toml @@ -1,3 +1,4 @@ -[std] -use = true -nixpkgs_lib = false +[features] +std = [] +pkg_lib = ["std"] +default = ["std"] diff --git a/default.nix b/default.nix index ecdcb7e..ad73534 100644 --- a/default.nix +++ b/default.nix @@ -1,17 +1,21 @@ let - src = import ./src; l = builtins; + src = import ./src; pins = import ./npins; + toml = l.fromTOML (l.readFile ./compose.toml); in { extern ? { }, - config ? builtins.fromTOML (builtins.readFile ./compose.toml), + # internal features of the composer function + __features ? toml.features.default or [ ], }: dir: with src; let std = composeStd ./std; + __features' = src.features.parse toml.features __features; + f = f: pre: dir': let @@ -28,8 +32,8 @@ let }; scope = - injectOptionals - { + let + scope' = { atom = atom'; mod = self'; builtins = errors.builtins; @@ -40,19 +44,28 @@ let __currentTime = errors.time; __nixPath = errors.nixPath; __storePath = errors.storePath; - } - [ + }; + + scope'' = injectOptionals scope' [ preOpt { - _if = config.std.use or false; + _if = l.elem "std" __features'; std = std // cond { - _if = config.std.nixpkgs_lib or false; + _if = l.elem "pkg_lib" __features'; lib = import "${pins."nixpkgs.lib"}/lib"; }; } ]; + in + scope'' + // { + __internal = { + features = __features'; + scope = scope''; + }; + }; Import = scopedImport scope; diff --git a/src/default.nix b/src/default.nix index 8d49af8..cf43da4 100644 --- a/src/default.nix +++ b/src/default.nix @@ -3,17 +3,18 @@ # so instead we abstract them out here, into a manually specified "psuedo-module" # to keep the core impelementation clean let + l = builtins; compose = import ../.; fix = import ../std/fix.nix; cond = import ../std/set/cond.nix; filterMap = scopedImport { std = builtins; } ../std/set/filterMap.nix; strToPath = scopedImport { std = builtins; } ../std/path/strToPath.nix; parse = scopedImport { std = builtins; } ../std/file/parse.nix; + stdFilter = import ./stdFilter.nix; toLowerCase = scopedImport rec { std = builtins; mod = scopedImport { inherit std mod; } ../std/string/mod.nix; } ../std/string/toLowerCase.nix; - stdFilter = import ./stdFilter.nix; in { inherit @@ -36,26 +37,29 @@ in if s == k then null else { ${s} = v; } ); - rmNixSrcs = builtins.filterSource ( + rmNixSrcs = l.filterSource ( path: type: let file = parse (baseNameOf path); in (type == "regular" && file.ext or null != "nix") - || (type == "directory" && !builtins.pathExists "${path}/mod.nix") + || (type == "directory" && !l.pathExists "${path}/mod.nix") ); composeStd = path: compose { } path // filterMap stdFilter builtins; modIsValid = mod: dir: - builtins.isAttrs mod + l.isAttrs mod || throw '' The following module does not evaluate to a valid attribute set: ${toString dir}/mod.nix ''; - injectOptionals = builtins.foldl' (acc: x: acc // cond x); + injectOptionals = l.foldl' (acc: x: acc // cond x); hasMod = contents: contents."mod.nix" or null == "regular"; + + features.parse = + featureSet: l.foldl' (xs: x: if l.elem x xs then xs else [ x ] ++ featureSet.${x} ++ xs) [ ]; } diff --git a/test/std-import/import.nix b/test/std-import/import.nix index 3b701be..90c9931 100644 --- a/test/std-import/import.nix +++ b/test/std-import/import.nix @@ -3,13 +3,7 @@ let in { default = compose { }; - noStd = compose { config.std.use = false; }; - withNixpkgsLib = compose { - config.std.nixpkgs_lib = true; - config.std.use = true; - }; - noStdNixpkgs = compose { - config.std.nixpkgs_lib = true; - config.std.use = false; - }; + noStd = compose { __features = [ ]; }; + explicit = compose { __features = [ "std" ]; }; + withNixpkgsLib = compose { __features = [ "pkg_lib" ]; }; } diff --git a/test/std-import/import.sh b/test/std-import/import.sh index 4f36b25..dc0805b 100755 --- a/test/std-import/import.sh +++ b/test/std-import/import.sh @@ -2,20 +2,34 @@ set -ex -. ../common.sh - # defaults -nix eval -f import.nix default.std -should_fail nix eval -f import.nix default.lib +f="$(nix eval -f import.nix default.std)" +[[ "$f" == true ]] +f="$(nix eval -f import.nix default.lib)" +[[ "$f" == false ]] +f="$(nix eval -f import.nix default.core)" +[[ "$f" == '[ "std" ]' ]] -# no std set -should_fail nix eval -f import.nix noStd.std -should_fail nix eval -f import.nix noStd.lib +# explicit +f="$(nix eval -f import.nix explicit.std)" +[[ "$f" == true ]] +f="$(nix eval -f import.nix explicit.lib)" +[[ "$f" == false ]] +f="$(nix eval -f import.nix explicit.core)" +[[ "$f" == '[ "std" ]' ]] # no std set -nix eval -f import.nix withNixpkgsLib.std -nix eval -f import.nix withNixpkgsLib.lib +f="$(nix eval -f import.nix noStd.std)" +[[ "$f" == false ]] +f="$(nix eval -f import.nix noStd.lib)" +[[ "$f" == false ]] +f="$(nix eval -f import.nix noStd.core)" +[[ "$f" == '[ ]' ]] # no std set -should_fail nix eval -f import.nix noStdNixpkgs.std -should_fail nix eval -f import.nix noStdNixpkgs.lib +f="$(nix eval -f import.nix withNixpkgsLib.std)" +[[ "$f" == true ]] +f="$(nix eval -f import.nix withNixpkgsLib.lib)" +[[ "$f" == true ]] +f="$(nix eval -f import.nix withNixpkgsLib.core)" +[[ "$f" == '[ "pkg_lib" "std" ]' ]] diff --git a/test/std-import/import/mod.nix b/test/std-import/import/mod.nix index a277077..1168d67 100644 --- a/test/std-import/import/mod.nix +++ b/test/std-import/import/mod.nix @@ -1,4 +1,8 @@ +let + inherit (__internal) scope features; +in { - Std = std ? set || abort "std missing"; - Lib = std ? lib || abort "lib missing"; + Std = scope ? std; + Lib = scope ? std && scope.std ? lib; + Core = features; }