From 7d94b7f66590efaa49c4d0eb5f4ca363cd6e52b1 Mon Sep 17 00:00:00 2001 From: Jake Hamilton Date: Tue, 9 Jul 2024 02:54:33 -0700 Subject: [PATCH] feat: package extend, dynamic propagation --- lib/src/types/default.nix | 206 ++++++++++-------- tidepool/flake.lock | 16 +- tidepool/src/builders/basic.nix | 2 - tidepool/src/lib/packages.nix | 17 +- tidepool/src/lib/types.nix | 30 ++- tidepool/src/packages/aux/b.nix | 12 +- tidepool/src/packages/aux/c.nix | 44 ++++ tidepool/src/packages/default.nix | 51 +++-- .../src/packages/foundation/gcc/default.nix | 7 + 9 files changed, 251 insertions(+), 134 deletions(-) create mode 100644 tidepool/src/packages/aux/c.nix diff --git a/lib/src/types/default.nix b/lib/src/types/default.nix index bcc9c4a..48b1551 100644 --- a/lib/src/types/default.nix +++ b/lib/src/types/default.nix @@ -49,18 +49,18 @@ lib: { ## ## @type Attrs -> Attrs create = - settings@{ - name, - description ? name, - fallback ? { }, - check ? lib.fp.const true, - merge ? lib.options.merge.default, - functor ? lib.types.functor name, - mergeType ? lib.types.merge functor, - getSubOptions ? lib.fp.const { }, - getSubModules ? null, - withSubModules ? lib.fp.const null, - children ? { }, + settings@{ name + , description ? name + , fallback ? { } + , check ? lib.fp.const true + , merge ? lib.options.merge.default + , functor ? lib.types.functor name + , mergeType ? lib.types.merge functor + , getSubOptions ? lib.fp.const { } + , getSubModules ? null + , withSubModules ? lib.fp.const null + , children ? { } + , }: { __type__ = "type"; @@ -108,7 +108,7 @@ lib: { identifier = lib.options.getIdentifier location; first = builtins.elemAt definitions 0; - files = builtins.map lib.modules.getFiles definitions; + files = lib.modules.getFiles definitions; serializedFiles = builtins.concatStringsSep " and " files; getType = @@ -118,13 +118,16 @@ lib: { else builtins.typeOf value; - commonType = builtins.foldl' ( - type: definition: - if getType definition.value != type then - builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" - else - type - ) (getType first.value) definitions; + commonType = builtins.foldl' + ( + type: definition: + if getType definition.value != type then + builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}" + else + type + ) + (getType first.value) + definitions; mergeStringifiableAttrs = lib.options.merge.one; @@ -132,7 +135,7 @@ lib: { mergeList = if builtins.length definitions > 1 then - builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" + builtins.throw "The option `${identifier}` has conflicting definitions in ${serializedFiles}" else (lib.types.list.of lib.types.any).merge; @@ -140,10 +143,12 @@ lib: { location: definitions: x: let resolvedLocation = location ++ [ "" ]; - resolvedDefinitions = builtins.map (definition: { - __file__ = definition.__file__; - value = definition.value x; - }) definitions; + resolvedDefinitions = builtins.map + (definition: { + __file__ = definition.__file__; + value = definition.value x; + }) + definitions; in lib.types.any.merge resolvedLocation resolvedDefinitions; @@ -200,14 +205,15 @@ lib: { ## @type Int -> Int -> Attrs between = start: end: - assert lib.errors.trace ( - start <= end - ) "lib.types.ints.between start must be less than or equal to end"; - lib.types.withCheck lib.types.int (value: value >= start && value <= end) - // { - name = "IntBetween"; - description = "integer between ${description start end}"; - }; + assert lib.errors.trace + ( + start <= end + ) "lib.types.ints.between start must be less than or equal to end"; + lib.types.withCheck lib.types.int (value: value >= start && value <= end) + // { + name = "IntBetween"; + description = "integer between ${description start end}"; + }; ## Create a type that allows an integer value between a given range with a specific ## number of bits. @@ -317,14 +323,15 @@ lib: { ## @type Int -> Int -> Attrs between = start: end: - assert lib.errors.trace ( - start <= end - ) "lib.types.numbers.between start must be less than or equal to end"; - lib.types.withCheck lib.types.number (value: value >= start && value <= end) - // { - name = "NumberBetween"; - description = "numbereger between ${description start end}"; - }; + assert lib.errors.trace + ( + start <= end + ) "lib.types.numbers.between start must be less than or equal to end"; + lib.types.withCheck lib.types.number (value: value >= start && value <= end) + // { + name = "NumberBetween"; + description = "numbereger between ${description start end}"; + }; in { inherit between; @@ -447,8 +454,7 @@ lib: { }; attrs = { - ## A type that allows an attribute set containing any type of value. The merged - ## definitions must all be. + ## A type that allows an attribute set containing any type of value. ## ## @type Attrs any = lib.types.create { @@ -480,10 +486,12 @@ lib: { let normalize = definition: - builtins.mapAttrs (name: value: { - __file__ = definition.__file__; - value = value; - }) definition.value; + builtins.mapAttrs + (name: value: { + __file__ = definition.__file__; + value = value; + }) + definition.value; normalized = builtins.map normalize definitions; zipper = name: definitions: (lib.options.merge.definitions (location ++ [ name ]) type definitions).optional; @@ -520,17 +528,19 @@ lib: { let normalize = definition: - builtins.mapAttrs (name: value: { - __file__ = definition.__file__; - value = value; - }) definition.value; + builtins.mapAttrs + (name: value: { + __file__ = definition.__file__; + value = value; + }) + definition.value; normalized = builtins.map normalize definitions; zipper = name: definitions: let merged = lib.options.merge.definitions (location ++ [ name ]) type definitions; in - merged.optional.value or type.fallback.value or merged.merged; + merged.optional.value or type.fallback.value or merged.merged; in builtins.zipAttrsWith zipper normalized; getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); @@ -606,25 +616,30 @@ lib: { merge = location: definitions: let - result = lib.lists.mapWithIndex1 ( - i: definition: - lib.lists.mapWithIndex1 ( - j: value: - let - resolved = - lib.options.merge.definitions (location ++ [ "[definition ${builtins.toString i}-entry ${j}]" ]) - type - [ - { - file = definition.file; - value = value; - } - ]; - in - resolved.optional - ) definition.value - ) definitions; - merged = builtins.concatLists result; + result = lib.lists.mapWithIndex1 + ( + i: definition: + lib.lists.mapWithIndex1 + ( + j: value: + let + resolved = + lib.options.merge.definitions (location ++ [ "[definition ${builtins.toString i}-entry ${j}]" ]) + type + [ + { + file = definition.file; + value = value; + } + ]; + in + resolved.optional + ) + definition.value + ) + definitions; + + merged = lib.lists.flatten result; filtered = builtins.filter (definition: definition ? value) merged; values = lib.options.getDefinitionValues filtered; in @@ -777,11 +792,11 @@ lib: { ## ## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs of = - settings@{ - modules, - args ? { }, - description ? null, - shorthand ? true, + settings@{ modules + , args ? { } + , description ? null + , shorthand ? true + , }: let getModules = builtins.map ( @@ -790,9 +805,12 @@ lib: { let # TODO: Figure out if we can apply additional attributes to the generated module. # Currently this causes issues to do with redefined options. - rest = builtins.removeAttrs (lib.attrs.filter ( - name: value: builtins.elem name lib.modules.VALID_KEYS - ) definition.value) [ "freeform" ]; + rest = builtins.removeAttrs + (lib.attrs.filter + ( + name: value: builtins.elem name lib.modules.VALID_KEYS + ) + definition.value) [ "freeform" ]; in if definition.value ? config then rest @@ -922,10 +940,12 @@ lib: { merge = location: definitions: { includes = modules - ++ builtins.map (definition: { - __file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}"; - includes = [ definition.value ]; - }) definitions; + ++ builtins.map + (definition: { + __file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}"; + includes = [ definition.value ]; + }) + definitions; }; getSubOptions = submodule.getSubOptions; getSubModules = submodule.getSubModules; @@ -961,10 +981,12 @@ lib: { location: definitions: let first = builtins.elemAt definitions 0; - modules = builtins.map (definition: { - __file__ = definition.__file__; - options = lib.options.create { type = definition.value; }; - }) definitions; + modules = builtins.map + (definition: { + __file__ = definition.__file__; + options = lib.options.create { type = definition.value; }; + }) + definitions; merged = lib.modules.fixup location (lib.options.merge.declarations location modules); in if builtins.length definitions == 1 then first.value else merged.type; @@ -1197,10 +1219,12 @@ lib: { merge = location: definitions: submodule.merge location ( - builtins.map (definition: { - __file__ = definition.__file__; - value = normalize definition; - }) definitions + builtins.map + (definition: { + __file__ = definition.__file__; + value = normalize definition; + }) + definitions ); }; }; diff --git a/tidepool/flake.lock b/tidepool/flake.lock index 68df33a..990a516 100644 --- a/tidepool/flake.lock +++ b/tidepool/flake.lock @@ -8,10 +8,10 @@ }, "locked": { "dir": "foundation", - "dirtyRev": "42e69f7d43c0fb108ac70fde118c4a8ff6a777b0-dirty", - "dirtyShortRev": "42e69f7-dirty", - "lastModified": 1720466389, - "narHash": "sha256-Zrmbcb+42r6eZV05QbcG2znHXrOh0sbdRaEZYxV0C7A=", + "dirtyRev": "3f9d287065ac685ce500c2cddb35428b2927f5a2-dirty", + "dirtyShortRev": "3f9d287-dirty", + "lastModified": 1720514984, + "narHash": "sha256-AuixwSlYk34Z6+GEc7y4QotF3Hk963zC9I9hAwX5KCE=", "type": "git", "url": "file:../?dir=foundation" }, @@ -24,10 +24,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "42e69f7d43c0fb108ac70fde118c4a8ff6a777b0-dirty", - "dirtyShortRev": "42e69f7-dirty", - "lastModified": 1720466389, - "narHash": "sha256-Zrmbcb+42r6eZV05QbcG2znHXrOh0sbdRaEZYxV0C7A=", + "dirtyRev": "3f9d287065ac685ce500c2cddb35428b2927f5a2-dirty", + "dirtyShortRev": "3f9d287-dirty", + "lastModified": 1720514984, + "narHash": "sha256-AuixwSlYk34Z6+GEc7y4QotF3Hk963zC9I9hAwX5KCE=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/tidepool/src/builders/basic.nix b/tidepool/src/builders/basic.nix index 30992b8..e7badef 100644 --- a/tidepool/src/builders/basic.nix +++ b/tidepool/src/builders/basic.nix @@ -20,8 +20,6 @@ in hooks = lib.packages.hooks.create dependencies context; - cflags = builtins.concatStringsSep " " (context.build.host.cflags or [ ]); - phasesWithHooks = let all = lib.lists.flatten [ diff --git a/tidepool/src/lib/packages.nix b/tidepool/src/lib/packages.nix index cfc979a..d3af568 100644 --- a/tidepool/src/lib/packages.nix +++ b/tidepool/src/lib/packages.nix @@ -101,6 +101,7 @@ in dependencies = lib.attrs.selectOrThrow path collected; contexts = builtins.map (dependency: dependency.context or { }) dependencies; result = lib.modules.run { + prefix = [ "" ]; modules = builtins.map (context: { config = context; }) contexts ++ [ { freeform = lib.types.any; @@ -210,13 +211,15 @@ in path: let dependencies = lib.attrs.selectOrThrow path collected; - hooks = builtins.map ( - dependency: - let - getHooks = dependency.hooks or (lib.fp.const { }); - in - getHooks ctx - ) dependencies; + hooks = builtins.map + ( + dependency: + let + getHooks = dependency.hooks or (lib.fp.const { }); + in + getHooks ctx + ) + dependencies; in hooks; in diff --git a/tidepool/src/lib/types.nix b/tidepool/src/lib/types.nix index 2128b46..d4723b1 100644 --- a/tidepool/src/lib/types.nix +++ b/tidepool/src/lib/types.nix @@ -214,7 +214,7 @@ in }; submodule = - { config }: + { config, meta }: let build = config.platform.build; host = config.platform.host; @@ -230,6 +230,34 @@ in default.value = [ ]; }; + extend = lib.options.create { + description = "Extend the package definition."; + type = lib.types.function lib.types.raw; + internal = true; + writable = false; + default.value = module: + let + normalized = + if builtins.isList module then + module + else if builtins.isFunction module || module ? config then + [ module ] + else + [{ + config = module; + }]; + result = meta.extend { + modules = + normalized ++ [ + { + config.__modules__ = lib.modules.overrides.force (config.__modules__ ++ normalized); + } + ]; + }; + in + result.config; + }; + meta = { description = lib.options.create { description = "The description for the package."; diff --git a/tidepool/src/packages/aux/b.nix b/tidepool/src/packages/aux/b.nix index ae180c7..c94fc2b 100644 --- a/tidepool/src/packages/aux/b.nix +++ b/tidepool/src/packages/aux/b.nix @@ -26,8 +26,18 @@ in builder = builders.basic; + deps = { + build = { + host = { + c = packages.aux.c.versions.latest.extend { + propagate = true; + }; + }; + }; + }; + context = { - cflags = [ "-I $AUX_B/include" ]; + "foundation:cflags" = [ "-I $AUX_B/include" ]; }; hooks = ctx: { "aux:b:env" = lib.dag.entry.after [ "unpack" ] ''export AUX_B=${config.package}''; }; diff --git a/tidepool/src/packages/aux/c.nix b/tidepool/src/packages/aux/c.nix new file mode 100644 index 0000000..2f09cf2 --- /dev/null +++ b/tidepool/src/packages/aux/c.nix @@ -0,0 +1,44 @@ +{ config }: +let + inherit (config) lib builders packages; +in +{ + config.packages.aux.c = { + versions = { + "latest" = + { config }: + { + options = { + custom = lib.options.create { type = lib.types.bool; }; + }; + + config = { + meta = { + platforms = [ "i686-linux" ]; + }; + + name = "${config.pname}-${config.version}"; + + custom = true; + + pname = "c"; + version = "1.0.0"; + + builder = builders.basic; + + context = { + "foundation:cflags" = [ "-I $AUX_C/include" ]; + }; + + hooks = ctx: { "aux:c:env" = lib.dag.entry.after [ "unpack" ] ''export AUX_C=${config.package}''; }; + + phases = { + install = '' + echo "c" > $out + ''; + }; + }; + }; + }; + }; +} diff --git a/tidepool/src/packages/default.nix b/tidepool/src/packages/default.nix index 11bccee..1807094 100644 --- a/tidepool/src/packages/default.nix +++ b/tidepool/src/packages/default.nix @@ -11,6 +11,7 @@ in ./foundation ./aux/a.nix ./aux/b.nix + ./aux/c.nix ]; options = { @@ -55,32 +56,34 @@ in config = { packages.cross = lib.attrs.generate doubles ( system: - builtins.mapAttrs ( - namespace: - builtins.mapAttrs ( - name: alias: - let - setHost = - package: - package - // { - __modules__ = package.__modules__ ++ [ - { - config.platform = { - host = lib.modules.override 5 system; - target = lib.modules.override 5 system; - }; - } - ]; - }; + builtins.mapAttrs + ( + namespace: + builtins.mapAttrs ( + name: alias: + let + setHost = + package: + package + // { + __modules__ = package.__modules__ ++ [ + { + config.platform = { + host = lib.modules.override 5 system; + target = lib.modules.override 5 system; + }; + } + ]; + }; - updated = alias // { - versions = builtins.mapAttrs (version: package: setHost package) alias.versions; - }; - in - updated + updated = alias // { + versions = builtins.mapAttrs (version: package: setHost package) alias.versions; + }; + in + updated + ) ) - ) packages + packages ); }; } diff --git a/tidepool/src/packages/foundation/gcc/default.nix b/tidepool/src/packages/foundation/gcc/default.nix index dd96962..44df14e 100644 --- a/tidepool/src/packages/foundation/gcc/default.nix +++ b/tidepool/src/packages/foundation/gcc/default.nix @@ -11,6 +11,13 @@ let ; in { + config.packages.context.options = { + "foundation:cflags" = lib.options.create { + type = lib.types.list.of lib.types.string; + default.value = [ ]; + }; + }; + config.packages.foundation.gcc = { versions = { "latest" =