diff --git a/foundation/flake.lock b/foundation/flake.lock index f4e0cb0..ba8c053 100644 --- a/foundation/flake.lock +++ b/foundation/flake.lock @@ -3,10 +3,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty", - "dirtyShortRev": "9850da8-dirty", - "lastModified": 1718529861, - "narHash": "sha256-tv/0C7ixH+9Ij+r+5nua48OlXXXnbdEsnenxX4eG/Sk=", + "dirtyRev": "a707b0f06be6b36bcbfe88d0a9a5b9a803983a06-dirty", + "dirtyShortRev": "a707b0f-dirty", + "lastModified": 1719079124, + "narHash": "sha256-4HwA3q5f7SUBmcXX9Vz9WsA9oHBQ/GiZTwE4iSVq9s8=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/lib/src/types/default.nix b/lib/src/types/default.nix index e088244..94f89fa 100644 --- a/lib/src/types/default.nix +++ b/lib/src/types/default.nix @@ -10,7 +10,7 @@ lib: { ## Assign a type to an attribute set. ## ## @type String -> Attrs -> Attrs - set = name: value: value // { __type__ = name; }; + set = name: value: value // {__type__ = name;}; ## Create a default functor for a type. This handles merging of type values ## by referencing wrapped and payload values. See the types implemented below @@ -28,61 +28,56 @@ lib: { ## Merge two types. ## ## @type Attrs -> Attrs -> Attrs - merge = - f: g: - let - wrapped = f.wrapped.mergeType g.wrapped.functor; - payload = f.merge f.payload g.payload; - in - if f.name != g.name then - null - else if f.wrapped == null && g.wrapped == null && f.payload == null && g.payload == null then - f.type - else if f.wrapped != null && g.wrapped != null && wrapped != null then - f.type wrapped - else if f.payload != null && g.payload != null && payload != null then - f.type payload - else - null; + merge = f: g: let + wrapped = f.wrapped.mergeType g.wrapped.functor; + payload = f.merge f.payload g.payload; + in + if f.name != g.name + then null + else if f.wrapped == null && g.wrapped == null && f.payload == null && g.payload == null + then f.type + else if f.wrapped != null && g.wrapped != null && wrapped != null + then f.type wrapped + else if f.payload != null && g.payload != null && payload != null + then f.type payload + else null; ## Create a new type. ## ## @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 ? { }, - }: - { - __type__ = "type"; - inherit - name - description - fallback - check - merge - functor - mergeType - getSubOptions - getSubModules - withSubModules - children - ; - }; + 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 ? {}, + }: { + __type__ = "type"; + inherit + name + description + fallback + check + merge + functor + mergeType + getSubOptions + getSubModules + withSubModules + children + ; + }; ## Add a check to a type. ## ## @type Attrs -> (Any -> Bool) -> Attrs - withCheck = type: check: type // { check = value: type.check value && check value; }; + withCheck = type: check: type // {check = value: type.check value && check value;}; ## A type that allows any value and will only use a single definition. ## @@ -102,63 +97,58 @@ lib: { name = "Any"; description = "any"; check = lib.fp.const true; - merge = - location: definitions: - let - identifier = lib.options.getIdentifier location; - first = builtins.elemAt definitions 0; + merge = location: definitions: let + identifier = lib.options.getIdentifier location; + first = builtins.elemAt definitions 0; - files = builtins.map lib.modules.getFiles definitions; - serializedFiles = builtins.concatStringsSep " and " files; + files = builtins.map lib.modules.getFiles definitions; + serializedFiles = builtins.concatStringsSep " and " files; - getType = - value: - if builtins.isAttrs value && lib.strings.validate.stringifiable value then - "StringifiableAttrs" - else - builtins.typeOf value; + getType = value: + if builtins.isAttrs value && lib.strings.validate.stringifiable value + then "StringifiableAttrs" + else builtins.typeOf value; - commonType = builtins.foldl' ( + 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; + if getType definition.value != type + then builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" + else type + ) (getType first.value) + definitions; - mergeStringifiableAttrs = lib.options.merge.one; + mergeStringifiableAttrs = lib.options.merge.one; - mergeSet = (lib.types.attrs.of lib.types.any).merge; + mergeSet = (lib.types.attrs.of lib.types.any).merge; - mergeList = - if builtins.length definitions > 1 then - builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" - else - (lib.types.list.of lib.types.any).merge; + mergeList = + if builtins.length definitions > 1 + then builtins.throw "The option `${identifier}` has conflicting definitions in ${files}" + else (lib.types.list.of lib.types.any).merge; - mergeLambda = - location: definitions: x: - let - resolvedLocation = location ++ [ "" ]; - resolvedDefinitions = builtins.map (definition: { - __file__ = definition.__file__; - value = definition.value x; - }) definitions; - in - lib.types.any.merge resolvedLocation resolvedDefinitions; - - merge = - if commonType == "set" then - mergeSet - else if commonType == "list" then - mergeList - else if commonType == "StringifiableAttrs" then - mergeStringifiableAttrs - else if commonType == "lambda" then - mergeLambda - else - lib.options.merge.equal; + mergeLambda = location: definitions: x: let + resolvedLocation = location ++ [""]; + resolvedDefinitions = + builtins.map (definition: { + __file__ = definition.__file__; + value = definition.value x; + }) + definitions; in + lib.types.any.merge resolvedLocation resolvedDefinitions; + + merge = + if commonType == "set" + then mergeSet + else if commonType == "list" + then mergeList + else if commonType == "StringifiableAttrs" + then mergeStringifiableAttrs + else if commonType == "lambda" + then mergeLambda + else lib.options.merge.equal; + in merge location definitions; }; @@ -192,106 +182,103 @@ lib: { merge = lib.options.merge.equal; }; - ints = - let - description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; - ## Create a type that allows an integer value between a given range. - ## - ## @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"; + ints = let + description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; + ## Create a type that allows an integer value between a given range. + ## + ## @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}"; }; - ## Create a type that allows an integer value between a given range with a specific - ## number of bits. - ## - ## @type Int -> Int -> Attrs - sign = - bits: range: - let - start = 0 - (range / 2); - end = range / 2 - 1; - in - between start end - // { - name = "IntSigned${builtins.toString bits}"; - description = "${builtins.toString bits} bit signed integer between ${description start end}"; - }; - - ## Create a type that allows an unsigned integer value between a given range with a specific - ## number of bits. - ## - ## @type Int -> Int -> Attrs - unsign = - bits: range: - let - start = 0; - end = range - 1; - in - between start end - // { - name = "IntUnsigned${builtins.toString bits}"; - description = "${builtins.toString bits} bit unsigned integer between ${description start end}"; - }; + ## Create a type that allows an integer value between a given range with a specific + ## number of bits. + ## + ## @type Int -> Int -> Attrs + sign = bits: range: let + start = 0 - (range / 2); + end = range / 2 - 1; in - { - inherit between; + between start end + // { + name = "IntSigned${builtins.toString bits}"; + description = "${builtins.toString bits} bit signed integer between ${description start end}"; + }; - ## A type that allows a positive integer value. - ## - ## @type Attrs - positive = lib.types.withCheck lib.types.int (value: value > 0) // { + ## Create a type that allows an unsigned integer value between a given range with a specific + ## number of bits. + ## + ## @type Int -> Int -> Attrs + unsign = bits: range: let + start = 0; + end = range - 1; + in + between start end + // { + name = "IntUnsigned${builtins.toString bits}"; + description = "${builtins.toString bits} bit unsigned integer between ${description start end}"; + }; + in { + inherit between; + + ## A type that allows a positive integer value. + ## + ## @type Attrs + positive = + lib.types.withCheck lib.types.int (value: value > 0) + // { name = "IntPositive"; description = "positive integer"; }; - ## A type that allows a positive integer value or zero. - ## - ## @type Attrs - unsigned = lib.types.withCheck lib.types.int (value: value >= 0) // { + ## A type that allows a positive integer value or zero. + ## + ## @type Attrs + unsigned = + lib.types.withCheck lib.types.int (value: value >= 0) + // { name = "IntUnsigned"; description = "unsigned integer"; }; - ## A type that allows an 8bit unsigned integer. - ## - ## @type Attrs - u8 = unsign 8 256; + ## A type that allows an 8bit unsigned integer. + ## + ## @type Attrs + u8 = unsign 8 256; - ## A type that allows a 16bit unsigned integer. - ## - ## @type Attrs - u16 = unsign 16 65536; + ## A type that allows a 16bit unsigned integer. + ## + ## @type Attrs + u16 = unsign 16 65536; - ## A type that allows a 32bit unsigned integer. - ## - ## @type Attrs - u32 = unsign 32 4294967296; + ## A type that allows a 32bit unsigned integer. + ## + ## @type Attrs + u32 = unsign 32 4294967296; - # u64 = unsign 64 18446744073709551616; + # u64 = unsign 64 18446744073709551616; - ## A type that allows an 8bit signed integer. - ## - ## @type Attrs - s8 = sign 8 256; + ## A type that allows an 8bit signed integer. + ## + ## @type Attrs + s8 = sign 8 256; - ## A type that allows a 16bit signed integer. - ## - ## @type Attrs - s16 = sign 16 65536; + ## A type that allows a 16bit signed integer. + ## + ## @type Attrs + s16 = sign 16 65536; - ## A type that allows a 32bit signed integer. - ## - ## @type Attrs - s32 = sign 32 4294967296; - }; + ## A type that allows a 32bit signed integer. + ## + ## @type Attrs + s32 = sign 32 4294967296; + }; ## A type that allows a floating point value. The merged definitions must all be ## the same. @@ -309,42 +296,43 @@ lib: { ## @type Attrs number = lib.types.either lib.types.int lib.types.float; - numbers = - let - description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; - ## Create a type that allows a number value between a given range. - ## - ## @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"; + numbers = let + description = start: end: "${builtins.toString start} and ${builtins.toString end} (inclusive)"; + ## Create a type that allows a number value between a given range. + ## + ## @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}"; }; - in - { - inherit between; + in { + inherit between; - ## A type that allows a positive number value. - ## - ## @type Attrs - positive = lib.types.withCheck lib.types.int (value: value > 0) // { + ## A type that allows a positive number value. + ## + ## @type Attrs + positive = + lib.types.withCheck lib.types.int (value: value > 0) + // { name = "NumberPositive"; description = "positive number"; }; - ## A type that allows a positive number value or zero. - ## - ## @type Attrs - positiveOrZero = lib.types.withCheck lib.types.int (value: value >= 0) // { + ## A type that allows a positive number value or zero. + ## + ## @type Attrs + positiveOrZero = + lib.types.withCheck lib.types.int (value: value >= 0) + // { name = "NumberPositiveOrZero"; description = "number that is zero or greater"; }; - }; + }; ## A type that allows a port value. This values an unsigned 16bit integer. ## @@ -357,11 +345,9 @@ lib: { version = lib.types.create { name = "Version"; description = "version"; - check = - value: - let - parts = builtins.splitVersion value; - in + check = value: let + parts = builtins.splitVersion value; + in builtins.isString value && builtins.length parts > 0; merge = lib.options.merge.equal; }; @@ -393,8 +379,7 @@ lib: { ## definitions must all be the same. ## ## @type String -> Attrs - matching = - pattern: + matching = pattern: lib.types.create { name = "StringMatching ${pattern}"; description = "string matching the pattern ${pattern}"; @@ -406,33 +391,34 @@ lib: { ## definitions must all be the same. ## ## @type String -> Attrs - concat = - separator: + concat = separator: lib.types.create { name = "StringConcat"; description = - if separator == "" then - "concatenated string" - else - "string concatenated with ${builtins.toJSON separator}"; + if separator == "" + then "concatenated string" + else "string concatenated with ${builtins.toJSON separator}"; check = value: lib.types.string.check value; - merge = - location: definitions: + merge = location: definitions: builtins.concatStringsSep separator (lib.options.getDefinitionValues definitions); - functor = lib.types.functor "strings.concat" // { - payload = separator; - merge = x: y: if x == y then x else null; - }; + functor = + lib.types.functor "strings.concat" + // { + payload = separator; + merge = x: y: + if x == y + then x + else null; + }; }; ## A type that allows a string value that is a single line with an optional new line ## at the end. ## ## @type Attrs - line = - let - matcher = lib.types.strings.matching "[^\n\r]*\n?"; - in + line = let + matcher = lib.types.strings.matching "[^\n\r]*\n?"; + in lib.types.create { name = "StringLine"; description = "single line string with an optional new line at the end"; @@ -455,47 +441,44 @@ lib: { name = "Attrs"; description = "attribute set"; fallback = { - value = { }; + value = {}; }; check = builtins.isAttrs; - merge = - location: definitions: - builtins.foldl' (result: definition: result // definition.value) { } definitions; + merge = location: definitions: + builtins.foldl' (result: definition: result // definition.value) {} definitions; }; ## Create a type that allows an attribute set containing a specific type of value. ## ## @type Attrs -> Attrs - of = - type: + of = type: lib.types.create { name = "AttrsOf"; description = "AttrsOf (${type.name})"; fallback = { - value = { }; + value = {}; }; check = builtins.isAttrs; - merge = - location: definitions: - let - normalize = - definition: - 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; - filtered = lib.attrs.filter (name: value: value ? value) (builtins.zipAttrsWith zipper normalized); - in + merge = location: definitions: let + normalize = definition: + 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; + filtered = lib.attrs.filter (name: value: value ? value) (builtins.zipAttrsWith zipper normalized); + in builtins.mapAttrs (name: value: value.value) filtered; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.attrs.of (type.withSubModules modules); - functor = lib.types.functor "attrs.of" // { - wrapped = type; - }; + functor = + lib.types.functor "attrs.of" + // { + wrapped = type; + }; children = { element = type; }; @@ -506,39 +489,36 @@ lib: { ## not support certain properties like `lib.modules.when`. ## ## @type Attrs -> Attrs - lazy = - type: + lazy = type: lib.types.create { name = "LazyAttrsOf"; description = "LazyAttrsOf (${type.name})"; fallback = { - value = { }; + value = {}; }; check = builtins.isAttrs; - merge = - location: definitions: - let - normalize = - definition: - 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; + merge = location: definitions: let + normalize = definition: + 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; + in builtins.zipAttrsWith zipper normalized; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.attrs.lazy (type.withSubModules modules); - functor = lib.types.functor "attrs.lazy" // { - wrapped = type; - }; + functor = + lib.types.functor "attrs.lazy" + // { + wrapped = type; + }; children = { element = type; }; @@ -552,15 +532,12 @@ lib: { name = "Derivation"; description = "derivation"; check = value: lib.packages.isDerivation value || lib.paths.validate.store value; - merge = - location: definitions: - let - merged = lib.options.merge.one location definitions; - in - if builtins.isPath merged || (builtins.isString merged && !(builtins.hasContext merged)) then - lib.paths.into.drv merged - else - merged; + merge = location: definitions: let + merged = lib.options.merge.one location definitions; + in + if builtins.isPath merged || (builtins.isString merged && !(builtins.hasContext merged)) + then lib.paths.into.drv merged + else merged; }; derivations = { @@ -568,9 +545,11 @@ lib: { ## `shellPath` attribute. ## ## @type Attrs - shell = lib.types.derivation // { - check = value: lib.packages.isDerivation && builtins.hasAttr "shellPath" value; - }; + shell = + lib.types.derivation + // { + check = value: lib.packages.isDerivation && builtins.hasAttr "shellPath" value; + }; }; ## A type that allows a path value. The merged definitions must all be the same. @@ -579,8 +558,7 @@ lib: { path = lib.types.create { name = "Path"; description = "path"; - check = - value: + check = value: lib.strings.validate.stringifiable value && builtins.substring 0 1 (builtins.toString value) == "/"; merge = lib.options.merge.equal; }; @@ -594,25 +572,22 @@ lib: { ## Create a type that allows a list containing a specific type of value. ## ## @type Attrs -> Attrs - of = - type: + of = type: lib.types.create { name = "ListOf"; description = "ListOf (${type.name})"; fallback = { - value = [ ]; + value = []; }; check = builtins.isList; - merge = - location: definitions: - let - result = lib.lists.mapWithIndex1 ( + 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}]" ]) + lib.lists.mapWithIndex1 ( + j: value: let + resolved = + lib.options.merge.definitions (location ++ ["[definition ${builtins.toString i}-entry ${j}]"]) type [ { @@ -620,21 +595,25 @@ lib: { value = value; } ]; - in - resolved.optional - ) definition.value - ) definitions; - merged = builtins.concatLists result; - filtered = builtins.filter (definition: definition ? value) merged; - values = lib.options.getDefinitionValues filtered; - in + in + resolved.optional + ) + definition.value + ) + definitions; + merged = builtins.concatLists result; + filtered = builtins.filter (definition: definition ? value) merged; + values = lib.options.getDefinitionValues filtered; + in values; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "*" ]); + getSubOptions = prefix: type.getSubOptions (prefix ++ ["*"]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.list.of (type.withSubModules modules); - functor = lib.types.functor "list.of" // { - wrapped = type; - }; + functor = + lib.types.functor "list.of" + // { + wrapped = type; + }; children = { element = type; }; @@ -643,20 +622,18 @@ lib: { ## A type that allows a non-empty list containing a specific type of value. ## ## @type Attrs -> Attrs - required = - type: - lib.types.withCheck (lib.types.list.of type) (value: value != [ ]) + required = type: + lib.types.withCheck (lib.types.list.of type) (value: value != []) // { description = "non-empty list of ${type.description}"; - fallback = { }; + fallback = {}; }; }; ## Create a type that must be a unique value. ## ## @type String -> Attrs -> Attrs - unique = - message: type: + unique = message: type: lib.types.create { name = "Unique"; description = type.description; @@ -666,9 +643,11 @@ lib: { getSubOptions = type.getSubOptions; getSubModules = type.getSubModules; withSubModules = modules: lib.types.unique message (type.withSubModules modules); - functor = lib.types.functor "unique" // { - wrapped = type; - }; + functor = + lib.types.functor "unique" + // { + wrapped = type; + }; children = { element = type; }; @@ -678,8 +657,7 @@ lib: { ## does not merge the definitions. ## ## @type Attrs -> Attrs - single = - type: + single = type: lib.types.create { name = "Single"; description = type.description; @@ -689,9 +667,11 @@ lib: { getSubOptions = type.getSubOptions; getSubModules = type.getSubModules; withSubModules = modules: lib.types.single (type.withSubModules modules); - functor = lib.types.functor "unique" // { - wrapped = type; - }; + functor = + lib.types.functor "unique" + // { + wrapped = type; + }; children = { element = type; }; @@ -700,8 +680,7 @@ lib: { ## Create a type that may be either a given type or null. ## ## @type Attrs -> Attrs - nullish = - type: + nullish = type: lib.types.create { name = "Nullish"; description = "null or ${type.description}"; @@ -709,26 +688,25 @@ lib: { value = null; }; check = value: value == null || type.check value; - merge = - location: definitions: - let - identifier = lib.options.getIdentifier location; - files = builtins.map lib.modules.getFiles definitions; - serializedFiles = builtins.concatStringsSep " and " files; - totalNulls = lib.lists.count (definition: definition == null) definitions; - in - if totalNulls == builtins.length definitions then - null - else if totalNulls != 0 then - builtins.throw "The option `${identifier}` is defined as both null and not null in ${serializedFiles}" - else - type.merge location definitions; + merge = location: definitions: let + identifier = lib.options.getIdentifier location; + files = builtins.map lib.modules.getFiles definitions; + serializedFiles = builtins.concatStringsSep " and " files; + totalNulls = lib.lists.count (definition: definition == null) definitions; + in + if totalNulls == builtins.length definitions + then null + else if totalNulls != 0 + then builtins.throw "The option `${identifier}` is defined as both null and not null in ${serializedFiles}" + else type.merge location definitions; getSubOptions = type.getSubOptions; getSubModules = type.getSubModules; withSubModules = modules: lib.types.nullish (type.withSubModules modules); - functor = lib.types.functor "nullish" // { - wrapped = type; - }; + functor = + lib.types.functor "nullish" + // { + wrapped = type; + }; children = { element = type; }; @@ -737,29 +715,28 @@ lib: { ## Create a type that allows a function which returns a given type. ## ## @type Attrs -> Attrs - function = - type: + function = type: lib.types.create { name = "Function"; description = "function that returns ${type.description}"; check = builtins.isFunction; - merge = - location: definitions: args: - let - normalize = definition: { - __file__ = definition.__file__; - value = definition.value args; - }; - normalized = builtins.map normalize definitions; - merged = lib.options.merge.definitions (location ++ [ "" ]) type normalized; - in + merge = location: definitions: args: let + normalize = definition: { + __file__ = definition.__file__; + value = definition.value args; + }; + normalized = builtins.map normalize definitions; + merged = lib.options.merge.definitions (location ++ [""]) type normalized; + in merged.merged; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.function (type.withSubModules modules); - functor = lib.types.functor "function" // { - wrapped = type; - }; + functor = + lib.types.functor "function" + // { + wrapped = type; + }; children = { element = type; }; @@ -768,7 +745,7 @@ lib: { ## Create a submodule from a list of modules (or a module directly). ## ## @type (Module | (List Module)) -> Attrs - submodule = modules: lib.types.submodules.of { modules = lib.lists.from.any modules; }; + submodule = modules: lib.types.submodules.of {modules = lib.lists.from.any modules;}; submodules = { ## Create a type from a list of submodules. This is particularly useful for use @@ -776,85 +753,85 @@ lib: { ## dynamic types. ## ## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs - of = - settings@{ - modules, - args ? { }, - description ? null, - shorthand ? true, - }: - let - getModules = builtins.map ( - definition: - if shorthand && builtins.isAttrs definition.value then - 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 ( + of = settings @ { + modules, + args ? {}, + description ? null, + shorthand ? true, + }: let + getModules = builtins.map ( + definition: + if shorthand && builtins.isAttrs definition.value + then 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" ]; - in - if definition.value ? config then + ) + definition.value) ["freeform"]; + in + if definition.value ? config + then rest // { __file__ = definition.__file__; config = definition.value.config; } - else - let - config = builtins.removeAttrs definition.value lib.modules.VALID_KEYS; - in + else let + config = builtins.removeAttrs definition.value lib.modules.VALID_KEYS; + in rest // { __file__ = definition.__file__; config = config; } - else - { - __file__ = definition.__file__; - includes = [ definition.value ]; - } - ); + else { + __file__ = definition.__file__; + includes = [definition.value]; + } + ); - base = lib.modules.run { - inherit args; + base = lib.modules.run { + inherit args; - modules = [ - { config.__module__.args.dynamic.name = lib.modules.overrides.default ""; } - ] ++ modules; - }; + modules = + [ + {config.__module__.args.dynamic.name = lib.modules.overrides.default "";} + ] + ++ modules; + }; - freeform = base.__module__.freeform; - name = "Submodule"; - in + freeform = base.__module__.freeform; + name = "Submodule"; + in lib.types.create { inherit name; - description = if description != null then description else freeform.description or name; + description = + if description != null + then description + else freeform.description or name; fallback = { - value = { }; + value = {}; }; check = value: builtins.isAttrs value || builtins.isFunction value || lib.types.path.check value; - merge = - location: definitions: - let - result = base.extend { - prefix = location; - modules = [ - { config.__module__.args.dynamic.name = lib.lists.last location; } - ] ++ getModules definitions; - }; - in + merge = location: definitions: let + result = base.extend { + prefix = location; + modules = + [ + {config.__module__.args.dynamic.name = lib.lists.last location;} + ] + ++ getModules definitions; + }; + in result.config; - getSubOptions = - prefix: - let - result = base.extend { inherit prefix; }; - in + getSubOptions = prefix: let + result = base.extend {inherit prefix;}; + in result.options - // lib.attrs.when (freeform != null) { __freeformOptions__ = freeform.getSubOptions prefix; }; + // lib.attrs.when (freeform != null) {__freeformOptions__ = freeform.getSubOptions prefix;}; getSubModules = modules; - withSubModules = - modules: + withSubModules = modules: lib.types.submodules.of { inherit args @@ -863,40 +840,39 @@ lib: { shorthand ; }; - children = lib.attrs.when (freeform != null) { inherit freeform; }; - functor = lib.types.functor "submodule" // { - type = lib.types.submodules.of; - payload = { - inherit - modules - args - description - shorthand - ; - }; - merge = x: y: { - modules = x.modules ++ y.modules; + children = lib.attrs.when (freeform != null) {inherit freeform;}; + functor = + lib.types.functor "submodule" + // { + type = lib.types.submodules.of; + payload = { + inherit + modules + args + description + shorthand + ; + }; + merge = x: y: { + modules = x.modules ++ y.modules; - args = - let + args = let intersection = builtins.intersectAttrs x.args y.args; in - if intersection == { } then - x.args // y.args - else - builtins.throw "A submodule option is declared multiple times with the same args: ${builtins.toString (builtins.attrNames intersection)}"; + if intersection == {} + then x.args // y.args + else builtins.throw "A submodule option is declared multiple times with the same args: ${builtins.toString (builtins.attrNames intersection)}"; - description = - if x.description == null then - y.description - else if y.description == null then - x.description - else if x.description == y.description then - x.description - else - builtins.throw "A submodule description is declared multiple times with conflicting values"; + description = + if x.description == null + then y.description + else if y.description == null + then x.description + else if x.description == y.description + then x.description + else builtins.throw "A submodule description is declared multiple times with conflicting values"; + }; }; - }; }; }; @@ -904,17 +880,15 @@ lib: { ## A module that is imported in another part of the configuration. ## ## @type Attrs - default = lib.types.deferred.of { modules = [ ]; }; + default = lib.types.deferred.of {modules = [];}; ## Create a submodule type from a list of modules which will be imported in ## another part of the configuration. ## ## @type { modules :: List Module } -> Attrs - of = - settings@{ modules }: - let - submodule = lib.types.submodule modules; - in + of = settings @ {modules}: let + submodule = lib.types.submodule modules; + in lib.types.create { name = "Deferred"; description = "module"; @@ -924,19 +898,22 @@ lib: { modules ++ builtins.map (definition: { __file__ = "${definition.__file__}; via ${lib.options.getIdentifier location}"; - includes = [ definition.value ]; - }) definitions; + includes = [definition.value]; + }) + definitions; }; getSubOptions = submodule.getSubOptions; getSubModules = submodule.getSubModules; - withSubModules = modules: lib.types.deferred.of { modules = modules; }; - functor = lib.types.functor "deferred.of" // { - type = lib.types.deferred.of; - payload = { - inherit modules; + withSubModules = modules: lib.types.deferred.of {modules = modules;}; + functor = + lib.types.functor "deferred.of" + // { + type = lib.types.deferred.of; + payload = { + inherit modules; + }; + merge = x: y: {modules = x.modules ++ y.modules;}; }; - merge = x: y: { modules = x.modules ++ y.modules; }; - }; }; }; @@ -957,94 +934,87 @@ lib: { name = "Option"; description = "option"; check = lib.types.is "option"; - merge = - location: definitions: - let - first = builtins.elemAt definitions 0; - modules = builtins.map (definition: { + merge = location: definitions: let + first = builtins.elemAt definitions 0; + 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; + 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; }; ## Create a type that allows a specific primitive value from a given list. ## ## @type List Any -> Attrs - enum = - values: - let - serialize = - value: - if builtins.isString value then - ''"${value}"'' - else if builtins.isInt value then - builtins.toString value - else if builtins.isBool value then - lib.bools.into.string value - else - ''<${builtins.typeOf value}>''; - in + enum = values: let + serialize = value: + if builtins.isString value + then ''"${value}"'' + else if builtins.isInt value + then builtins.toString value + else if builtins.isBool value + then lib.bools.into.string value + else ''<${builtins.typeOf value}>''; + in lib.types.create { name = "Enum"; description = - if values == [ ] then - "empty enum" - else if builtins.length values == 1 then - "value ${serialize (builtins.elemAt values 0)} (singular enum)" - else - "one of ${lib.strings.concatMapSep ", " serialize values}"; + if values == [] + then "empty enum" + else if builtins.length values == 1 + then "value ${serialize (builtins.elemAt values 0)} (singular enum)" + else "one of ${lib.strings.concatMapSep ", " serialize values}"; check = value: builtins.elem value values; merge = lib.options.merge.equal; - functor = lib.types.functor "enum" // { - payload = values; - merge = x: y: lib.lists.unique (x ++ y); - }; + functor = + lib.types.functor "enum" + // { + payload = values; + merge = x: y: lib.lists.unique (x ++ y); + }; }; ## Create a type that allows either of two types. ## ## @type Attrs -> Attrs -> Attrs - either = - left: right: - let - name = "Either"; - functor = lib.types.functor name // { + either = left: right: let + name = "Either"; + functor = + lib.types.functor name + // { wrapped = [ left right ]; }; - in + in lib.types.create { inherit name functor; description = "${left.description} or ${right.description}"; check = value: left.check value || right.check value; - merge = - location: definitions: - let - values = lib.options.getDefinitionValues definitions; - isLeft = builtins.all left.check values; - isRight = builtins.all right.check values; - in - if isLeft then - left.merge location definitions - else if isRight then - right.merge location definitions - else - lib.options.merge.one location definitions; - mergeType = - f: - let - mergedLeft = left.mergeType (builtins.elemAt f.wrapped 0).functor; - mergedRight = right.mergeType (builtins.elemAt f.wrapped 1).functor; - in - if (f.name == name) && (mergedLeft != null) && (mergedRight != null) then - functor.type mergedLeft mergedRight - else - null; + merge = location: definitions: let + values = lib.options.getDefinitionValues definitions; + isLeft = builtins.all left.check values; + isRight = builtins.all right.check values; + in + if isLeft + then left.merge location definitions + else if isRight + then right.merge location definitions + else lib.options.merge.one location definitions; + mergeType = f: let + mergedLeft = left.mergeType (builtins.elemAt f.wrapped 0).functor; + mergedRight = right.mergeType (builtins.elemAt f.wrapped 1).functor; + in + if (f.name == name) && (mergedLeft != null) && (mergedRight != null) + then functor.type mergedLeft mergedRight + else null; children = { inherit left right; }; @@ -1053,48 +1023,46 @@ lib: { ## Create a type that allows a value of one of the given types. ## ## @type List Attrs -> Attrs - one = - types: - let - first = builtins.elemAt types 0; - rest = builtins.tail types; - in - if types == [ ] then - builtins.throw "lib.types.one must be given at least one type" - else - builtins.foldl' lib.types.either first rest; + one = types: let + first = builtins.elemAt types 0; + rest = builtins.tail types; + in + if types == [] + then builtins.throw "lib.types.one must be given at least one type" + else builtins.foldl' lib.types.either first rest; ## Create a type that allows a value which is either the final type or is transformable ## to the final type. ## ## @type Attrs -> (Any -> Any) -> Attrs -> Attrs - coerce = - initial: transform: final: - let - in - if initial.getSubModules != null then - builtins.throw "lib.types.coerce's first argument may not have submodules, but got ${initial.description}" + coerce = initial: transform: final: let + in + if initial.getSubModules != null + then builtins.throw "lib.types.coerce's first argument may not have submodules, but got ${initial.description}" else lib.types.create { name = "Coerce"; description = "${initial.description} that is transformed to ${final.description}"; fallback = final.fallback; check = value: final.check value || (initial.check value && final.check (transform value)); - merge = - location: definitions: - let - process = value: if initial.check value then transform value else value; - normalize = definition: definition // { value = process definition.value; }; - normalized = builtins.map normalize definitions; - in + merge = location: definitions: let + process = value: + if initial.check value + then (builtins.trace "transforming...") transform value + else value; + normalize = definition: definition // {value = process definition.value;}; + normalized = builtins.map normalize definitions; + in final.merge location normalized; getSubOptions = final.getSubOptions; getSubModules = final.getSubModules; withSubModules = modules: lib.types.coerce initial transform (final.withSubModules modules); mergeType = x: y: null; - functor = lib.types.functor "coerce" // { - wrapped = final; - }; + functor = + lib.types.functor "coerce" + // { + wrapped = final; + }; children = { inherit initial final; }; @@ -1104,23 +1072,23 @@ lib: { ## Create a type that allows a DAG (Directed Acyclic Graph) of a given type. ## ## @type Attrs -> Attrs - of = - type: - let - resolved = lib.types.attrs.of (lib.types.dag.entry type); - in + of = type: let + resolved = lib.types.attrs.of (lib.types.dag.entry type); + in lib.types.create { name = "Dag"; description = "Dag of ${type.description}"; check = resolved.check; merge = resolved.merge; fallback = resolved.fallback; - getSubOptions = prefix: type.getSubOptions (prefix ++ [ "" ]); + getSubOptions = prefix: type.getSubOptions (prefix ++ [""]); getSubModules = type.getSubModules; withSubModules = modules: lib.types.dag.of (type.withSubModules modules); - functor = lib.types.functor "dag.of" // { - wrapped = type; - }; + functor = + lib.types.functor "dag.of" + // { + wrapped = type; + }; children = { element = type; resolved = resolved; @@ -1130,40 +1098,36 @@ lib: { ## Create a type that allows a DAG entry of a given type. ## ## @type Attrs -> Attrs - entry = - type: - let - submodule = lib.types.submodule ( - { name }: - { - options = { - value = lib.options.create { type = type; }; - before = lib.options.create { type = lib.types.list.of lib.types.string; }; - after = lib.options.create { type = lib.types.list.of lib.types.string; }; - }; - } - ); - normalize = - definition: - let - value = - if definition ? priority then - lib.modules.order definition.priority definition.value - else - definition.value; - in - if lib.dag.validate.entry definition.value then definition.value else lib.dag.entry.anywhere value; + entry = type: let + submodule = lib.types.submodule ( + {name}: { + options = { + value = lib.options.create {type = type;}; + before = lib.options.create {type = lib.types.list.of lib.types.string;}; + after = lib.options.create {type = lib.types.list.of lib.types.string;}; + }; + } + ); + normalize = definition: let + value = + if definition ? priority + then lib.modules.order definition.priority definition.value + else definition.value; in + if lib.dag.validate.entry definition.value + then definition.value + else lib.dag.entry.anywhere value; + in lib.types.create { name = "DagEntry"; description = "DagEntry (${type.description})"; - merge = - location: definitions: + merge = location: definitions: submodule.merge location ( builtins.map (definition: { __file__ = definition.__file__; value = normalize definition; - }) definitions + }) + definitions ); }; }; diff --git a/tidepool/flake.lock b/tidepool/flake.lock index 805747f..31590e0 100644 --- a/tidepool/flake.lock +++ b/tidepool/flake.lock @@ -8,10 +8,10 @@ }, "locked": { "dir": "foundation", - "dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty", - "dirtyShortRev": "9850da8-dirty", - "lastModified": 1718529861, - "narHash": "sha256-X1Wd6mDz8GTaoxt1ylkvZfrJOcZtspJrEjXMtJ2ZyG0=", + "dirtyRev": "a707b0f06be6b36bcbfe88d0a9a5b9a803983a06-dirty", + "dirtyShortRev": "a707b0f-dirty", + "lastModified": 1719079124, + "narHash": "sha256-hz9vVcHSvlq/W01UOh/GqPFUoH9DzCFB16n23oj7fnQ=", "type": "git", "url": "file:../?dir=foundation" }, @@ -24,10 +24,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "9850da8aa9dc9be22e237c9b424a18e801e53ecb-dirty", - "dirtyShortRev": "9850da8-dirty", - "lastModified": 1718529861, - "narHash": "sha256-X1Wd6mDz8GTaoxt1ylkvZfrJOcZtspJrEjXMtJ2ZyG0=", + "dirtyRev": "a707b0f06be6b36bcbfe88d0a9a5b9a803983a06-dirty", + "dirtyShortRev": "a707b0f-dirty", + "lastModified": 1719079124, + "narHash": "sha256-hz9vVcHSvlq/W01UOh/GqPFUoH9DzCFB16n23oj7fnQ=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/tidepool/src/builders/basic.nix b/tidepool/src/builders/basic.nix index 1864fb9..5e623d1 100644 --- a/tidepool/src/builders/basic.nix +++ b/tidepool/src/builders/basic.nix @@ -1,76 +1,89 @@ -{ lib, config }: -let +{ + lib, + config, +}: let cfg = config.builders.basic; lib' = config.lib; inherit (config) foundation; -in -{ +in { config.builders = { basic = { executable = "${foundation.stage2-bash}/bin/bash"; - build = - package: - let - phases = package.phases; - sorted = lib.dag.sort.topological phases; + build = package: let + phases = lib.dag.apply.defaults package.phases { + unpack = lib.dag.entry.before ["patch"] ""; - script = lib.strings.concatMapSep "\n" ( - entry: if builtins.isFunction entry.value then entry.value package else entry.value - ) sorted.result; + patch = lib.dag.entry.between ["configure"] ["unpack"] ""; - system = package.platform.build.double; + configure = lib.dag.entry.between ["build"] ["patch"] ""; - built = builtins.derivation ( - package.env - // { - inherit (package) name; - inherit script system; + build = lib.dag.entry.between ["install"] ["configure"] ""; - passAsFile = [ "script" ]; + install = lib.dag.entry.after ["build"] ""; + }; + sorted = lib.dag.sort.topographic phases; - SHELL = cfg.executable; + script = + lib.strings.concatMapSep "\n" ( + entry: + if builtins.isFunction entry.value + then entry.value package + else entry.value + ) + sorted.result; - PATH = - let - bins = lib.paths.bin ( - (lib'.packages.dependencies.getPackages package.deps.build.host) - ++ [ - foundation.stage2-bash - foundation.stage2-coreutils - ] - ); - in - builtins.concatStringsSep ":" ( - [ bins ] ++ (lib.lists.when (package.env ? PATH) [ package.env.PATH ]) - ); + system = package.platform.build.double; - builder = cfg.executable; + built = builtins.derivation ( + package.env + // { + inherit (package) name; + inherit script system; - args = [ - "-e" - (builtins.toFile "bash-builder.sh" '' - export CONFIG_SHELL=$SHELL + passAsFile = ["script"]; - # Normalize the NIX_BUILD_CORES variable. The value might be 0, which - # means that we're supposed to try and auto-detect the number of - # available CPU cores at run-time. - NIX_BUILD_CORES="''${NIX_BUILD_CORES:-1}" - if ((NIX_BUILD_CORES <= 0)); then - guess=$(nproc 2>/dev/null || true) - ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess)) - fi - export NIX_BUILD_CORES + SHELL = cfg.executable; - bash -eux $scriptPath - '') - ]; - } - ); - in - built // { inherit (package) meta; }; + PATH = let + bins = lib.paths.bin ( + (lib'.packages.dependencies.getPackages package.deps.build.host) + ++ [ + foundation.stage2-bash + foundation.stage2-coreutils + ] + ); + in + builtins.concatStringsSep ":" ( + [bins] ++ (lib.lists.when (package.env ? PATH) [package.env.PATH]) + ); + + builder = cfg.executable; + + args = [ + "-e" + (builtins.toFile "bash-builder.sh" '' + export CONFIG_SHELL=$SHELL + + # Normalize the NIX_BUILD_CORES variable. The value might be 0, which + # means that we're supposed to try and auto-detect the number of + # available CPU cores at run-time. + NIX_BUILD_CORES="''${NIX_BUILD_CORES:-1}" + if ((NIX_BUILD_CORES <= 0)); then + guess=$(nproc 2>/dev/null || true) + ((NIX_BUILD_CORES = guess <= 0 ? 1 : guess)) + fi + export NIX_BUILD_CORES + + bash -eux $scriptPath + '') + ]; + } + ); + in + built // {inherit (package) meta;}; }; }; } diff --git a/tidepool/src/export.nix b/tidepool/src/export.nix index 9909928..d2da3e5 100644 --- a/tidepool/src/export.nix +++ b/tidepool/src/export.nix @@ -1,10 +1,11 @@ # This file handles creating all of the exports for this project and is not # exported itself. -{ lib, config }: -let - lib' = config.lib; -in { + lib, + config, +}: let + lib' = config.lib; +in { freeform = lib.types.any; config = { @@ -13,6 +14,8 @@ in modules = import ./modules.nix; packages = { + aux-a = config.packages.aux.a; + # foundation-gcc-x86_64 = # (config.packages.foundation.gcc.versions."13.2.0".extend (args: { # config = { @@ -22,11 +25,11 @@ in # }; # })) # .config; - foundation-gcc = config.packages.foundation.gcc; - foundation-binutils = config.packages.foundation.binutils; - foundation-linux-headers = config.packages.foundation.linux-headers.versions.latest.extend { - platform.host = lib.modules.overrides.force "x86_64-linux"; - }; + # foundation-gcc = config.packages.foundation.gcc; + # foundation-binutils = config.packages.foundation.binutils; + # foundation-linux-headers = config.packages.foundation.linux-headers.versions.latest.extend { + # platform.host = lib.modules.overrides.force "x86_64-linux"; + # }; # example-x = config.packages.example.x; # cross-example-x-x86_64-linux = config.packages.cross.x86_64-linux.example.x; }; diff --git a/tidepool/src/lib/options.nix b/tidepool/src/lib/options.nix index 96c9ec0..4850da0 100644 --- a/tidepool/src/lib/options.nix +++ b/tidepool/src/lib/options.nix @@ -1,11 +1,12 @@ -{ lib, config }: -let -in { + lib, + config, +}: let +in { config = { lib.options = { package = lib.options.create { - type = config.lib.types.package; + type = config.lib.types.package.base; description = "A package definition."; }; }; diff --git a/tidepool/src/lib/packages.nix b/tidepool/src/lib/packages.nix index 1b1ae7b..9592292 100644 --- a/tidepool/src/lib/packages.nix +++ b/tidepool/src/lib/packages.nix @@ -2,76 +2,69 @@ lib, lib', config, -}: -{ +}: { config = { lib.packages = { dependencies = { - getPackages = - dependencies: - let - available = builtins.filter (dependency: !(builtins.isNull dependency)) ( - builtins.attrValues dependencies - ); - in + getPackages = dependencies: let + available = builtins.filter (dependency: !(builtins.isNull dependency)) ( + builtins.attrValues dependencies + ); + in builtins.map (dependency: dependency.package) available; }; - getLatest = - alias: - let - versions = builtins.attrNames alias.versions; - sorted = builtins.sort (lib.versions.gte) versions; - in + getLatest = alias: let + versions = builtins.attrNames alias.versions; + sorted = builtins.sort (lib.versions.gte) versions; + in builtins.head sorted; - build = - package: build: host: target: - let - resolved = - if package ? versions then - package.versions.${config.preferences.packages.version} - or (package.versions.${lib'.packages.getLatest package}) - else - package; + resolve = package: + if package ? versions + then + package.versions.${config.preferences.packages.version} + or (package.versions.${lib'.packages.getLatest package}) + else package; - buildDependencies = - build': host': target': - builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target'); + build = package: build: host: target: let + resolved = lib'.packages.resolve package; - result = resolved.extend ( - { config }: - { - config = { - platform = { - build = build; - host = host; - target = lib.modules.override 150 target; - }; + buildDependencies = build': host': target': + builtins.mapAttrs (name: dep: lib'.packages.build dep build' host' target'); - deps = { - build = { - only = buildDependencies build build build resolved.deps.build.only; - build = buildDependencies build build target resolved.deps.build.build; - host = buildDependencies build host target resolved.deps.build.host; - target = buildDependencies build target target resolved.deps.build.target; - }; - host = { - only = buildDependencies host host host resolved.deps.host.only; - host = buildDependencies host host target resolved.deps.host.host; - target = buildDependencies host target target resolved.deps.host.target; - }; - target = { - only = buildDependencies target target target resolved.deps.target.only; - target = buildDependencies target target target resolved.deps.target.target; - }; - }; - - package = config.builder.build config; + result = resolved.extend ( + {config}: { + config = { + platform = { + build = build; + host = host; + target = lib.modules.override 150 target; }; - } - ); - in + + deps = { + build = { + only = buildDependencies build build build resolved.deps.build.only; + build = buildDependencies build build target resolved.deps.build.build; + host = buildDependencies build host target resolved.deps.build.host; + target = buildDependencies build target target resolved.deps.build.target; + }; + host = { + only = buildDependencies host host host resolved.deps.host.only; + host = buildDependencies host host target resolved.deps.host.host; + target = buildDependencies host target target resolved.deps.host.target; + }; + target = { + only = buildDependencies target target target resolved.deps.target.only; + target = buildDependencies target target target resolved.deps.target.target; + }; + }; + + package = config.builder.build config; + }; + } + ); + in result; }; }; diff --git a/tidepool/src/lib/types.nix b/tidepool/src/lib/types.nix index 7833e30..78cdd72 100644 --- a/tidepool/src/lib/types.nix +++ b/tidepool/src/lib/types.nix @@ -2,57 +2,54 @@ lib, lib', config, -}: -{ +}: { config = { lib.types = { - license = - let - type = lib.types.submodule ( - { config }: - { - options = { - name = { - full = lib.options.create { - description = "The full name of the license."; - type = lib.types.string; - }; - - short = lib.options.create { - description = "The short name of the license."; - type = lib.types.string; - }; + license = let + type = lib.types.submodule ( + {config}: { + options = { + name = { + full = lib.options.create { + description = "The full name of the license."; + type = lib.types.string; }; - spdx = lib.options.create { - description = "The SPDX identifier for the license."; - type = lib.types.nullish lib.types.string; - default.value = null; - }; - - url = lib.options.create { - description = "The URL for the license."; - type = lib.types.nullish lib.types.string; - }; - - free = lib.options.create { - description = "Whether the license is free."; - type = lib.types.bool; - default.value = true; - }; - - redistributable = lib.options.create { - description = "Whether the license is allows redistribution."; - type = lib.types.bool; - default = { - text = "config.free"; - value = config.free; - }; + short = lib.options.create { + description = "The short name of the license."; + type = lib.types.string; }; }; - } - ); - in + + spdx = lib.options.create { + description = "The SPDX identifier for the license."; + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + url = lib.options.create { + description = "The URL for the license."; + type = lib.types.nullish lib.types.string; + }; + + free = lib.options.create { + description = "Whether the license is free."; + type = lib.types.bool; + default.value = true; + }; + + redistributable = lib.options.create { + description = "Whether the license is allows redistribution."; + type = lib.types.bool; + default = { + text = "config.free"; + value = config.free; + }; + }; + }; + } + ); + in lib.types.either type (lib.types.list.of type); builder = lib.types.submodule { @@ -73,249 +70,378 @@ options = { versions = lib.options.create { description = "All available package versions."; - type = lib.types.attrs.of lib'.types.package; + type = lib.types.attrs.of lib'.types.package.base; }; }; } ); dependencies = lib.types.attrs.of ( - lib.types.nullish (lib.types.either lib'.types.alias lib'.types.package) + lib.types.nullish (lib'.types.package.resolved) ); - package = lib.types.submodule ( - { config, meta }: - { - options = { - extend = lib.options.create { - description = "Extend the package's submodules with additional configuration."; - type = lib.types.function lib.types.raw; - default.value = - value: - let + package = { + resolved = let + initial = + lib.types.raw + // { + check = value: + !(value ? __merged__) + && lib.types.raw.check + value; + }; + + transform = value: let + package = lib'.packages.resolve value; + packageSubmodule = package.extend (args: { + options.__export__ = lib.options.create { + type = lib.types.raw; + default.value = { + inherit (args) options config; + }; + }; + + config.__export__ = { + inherit (args) options config; + }; + }); + type = lib'.types.package.base.withSubModules (lib'.types.package.base.getSubModules + ++ [ + (args: { + options.__export__ = lib.options.create { + type = lib.types.raw; + default.value = { + inherit (args) options config; + }; + }; + + config.__export__ = { + inherit (args) options config; + }; + }) + ]); + typeSubmodule = lib.modules.run { + modules = type.getSubModules; + args = type.functor.payload.args; + }; + + getOptions = export: let + process = path: option: + if builtins.isAttrs option + then + if lib.types.is "option" option + then [ + { + inherit path; + option = option; + } + ] + else + builtins.concatLists ( + lib.attrs.mapToList + (name: value: process (path ++ [name]) value) + option + ) + else []; + in + process [] export.options; + + packageOptions = getOptions packageSubmodule.__export__; + typeOptions = getOptions typeSubmodule.config.__export__; + + customOptions = + builtins.filter + ( + packageOption: + builtins.all (typeOption: packageOption.path != typeOption.path) typeOptions + ) + packageOptions; + + packageOptionsIds = builtins.map (option: builtins.concatStringsSep "." option.path) packageOptions; + typeOptionsIds = builtins.map (option: builtins.concatStringsSep "." option.path) typeOptions; + customOptionsIds = builtins.map (option: builtins.concatStringsSep "." option.path) customOptions; + + resolvedOptions = + builtins.foldl' ( + resolved: option: let + first = builtins.head option.path; + generated = lib.attrs.set option.path option.option; + in + if first == "__export__" || first == "__module__" || first == "__merged__" + then resolved + else lib.attrs.mergeRecursive resolved generated + ) {} + customOptions; + in + # (builtins.trace (builtins.deepSeq packageOptionsIds packageOptionsIds)) + # (builtins.trace (builtins.deepSeq typeOptionsIds typeOptionsIds)) + # (builtins.trace (builtins.deepSeq customOptionsIds customOptionsIds)) + # (builtins.trace packageSubmodule.__export__.config) + (args: { + __file__ = packageSubmodule.__export__.config.__file__ or "virtual:tidepool/src/lib/types.nix"; + + options = + resolvedOptions + // { + __merged__ = lib.options.create { + type = lib.types.bool; + default.value = true; + }; + }; + + config = + builtins.removeAttrs package ["extend" "package" "platform"] + // { + platform = { + build = lib.modules.overrides.default package.platform.build.triple; + host = lib.modules.overrides.default package.platform.host.triple; + target = lib.modules.overrides.default package.platform.target.triple; + }; + }; + # // { + # builder = + # (builtins.trace "builder") + # (builtins.trace (args.config ? builder)) + # lib.modules.alias + # packageSubmodule.__export__.options.builder; + # }; + }); + in + lib.types.coerce initial transform lib'.types.package.base; + + base = lib.types.submodule ( + { + config, + meta, + }: { + options = { + extend = lib.options.create { + description = "Extend the package's submodules with additional configuration."; + type = lib.types.function lib.types.raw; + default.value = value: let result = meta.extend { - modules = if builtins.isAttrs value then [ { config = value; } ] else lib.lists.from.any value; + modules = + if builtins.isAttrs value + then [{config = value;}] + else lib.lists.from.any value; }; in - result.config; - }; - - name = lib.options.create { - description = "The name of the package."; - type = lib.types.string; - default = { - text = "\${config.pname}-\${config.version}"; - value = - if config.pname != null && config.version != null then "${config.pname}-${config.version}" else ""; + result.config; }; - }; - pname = lib.options.create { - description = "The program name for the package"; - type = lib.types.nullish lib.types.string; - default.value = null; - }; + name = lib.options.create { + description = "The name of the package."; + type = lib.types.string; + default = { + text = "\${config.pname}-\${config.version}"; + value = + if config.pname != null && config.version != null + then "${config.pname}-${config.version}" + else ""; + }; + }; - version = lib.options.create { - description = "The version for the package."; - type = lib.types.nullish lib.types.version; - default.value = null; - }; - - meta = { - description = lib.options.create { - description = "The description for the package."; + pname = lib.options.create { + description = "The program name for the package"; type = lib.types.nullish lib.types.string; default.value = null; }; - homepage = lib.options.create { - description = "The homepage for the package."; - type = lib.types.nullish lib.types.string; + version = lib.options.create { + description = "The version for the package."; + type = lib.types.nullish lib.types.version; default.value = null; }; - license = lib.options.create { - description = "The license for the package."; - type = lib.types.nullish lib'.types.license; - default.value = null; - }; - - free = lib.options.create { - description = "Whether the package is free."; - type = lib.types.bool; - default.value = true; - }; - - insecure = lib.options.create { - description = "Whether the package is insecure."; - type = lib.types.bool; - default.value = false; - }; - - broken = lib.options.create { - description = "Whether the package is broken."; - type = lib.types.bool; - default.value = false; - }; - - main = lib.options.create { - description = "The main entry point for the package."; - type = lib.types.nullish lib.types.string; - default.value = null; - }; - - platforms = lib.options.create { - description = "The platforms the package supports."; - type = lib.types.list.of lib.types.string; - default.value = [ ]; - }; - }; - - platform = { - build = lib.options.create { - description = "The build platform for the package."; - type = lib.types.string; - default.value = "x86_64-linux"; - apply = - raw: - let - system = lib'.systems.from.string raw; - x = lib'.systems.withBuildInfo raw; - in - x; - }; - - host = lib.options.create { - description = "The host platform for the package."; - type = lib.types.string; - default.value = "x86_64-linux"; - # apply = raw: let - # system = lib'.systems.from.string raw; - # in { - # inherit raw system; - - # double = lib'.systems.into.double system; - # triple = lib'.systems.into.triple system; - # }; - apply = - raw: - let - system = lib'.systems.from.string raw; - x = lib'.systems.withBuildInfo raw; - in - x; - }; - - target = lib.options.create { - description = "The target platform for the package."; - type = lib.types.string; - default.value = "x86_64-linux"; - # apply = raw: let - # system = lib'.systems.from.string raw; - # in { - # inherit raw system; - - # double = lib'.systems.into.double system; - # triple = lib'.systems.into.triple system; - # }; - apply = - raw: - let - system = lib'.systems.from.string raw; - x = lib'.systems.withBuildInfo raw; - in - x; - }; - }; - - phases = lib.options.create { - description = "The phases for the package."; - type = lib.types.dag.of (lib.types.either lib.types.string (lib.types.function lib.types.string)); - default.value = { }; - }; - - env = lib.options.create { - description = "The environment for the package."; - type = lib.types.attrs.of lib.types.string; - default.value = { }; - }; - - builder = lib.options.create { - description = "The builder for the package."; - type = lib'.types.builder; - }; - - deps = { - build = { - only = lib.options.create { - description = "Dependencies which are only used in the build environment."; - type = lib'.types.dependencies; - default.value = { }; + meta = { + description = lib.options.create { + description = "The description for the package."; + type = lib.types.nullish lib.types.string; + default.value = null; }; + homepage = lib.options.create { + description = "The homepage for the package."; + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + license = lib.options.create { + description = "The license for the package."; + type = lib.types.nullish lib'.types.license; + default.value = null; + }; + + free = lib.options.create { + description = "Whether the package is free."; + type = lib.types.bool; + default.value = true; + }; + + insecure = lib.options.create { + description = "Whether the package is insecure."; + type = lib.types.bool; + default.value = false; + }; + + broken = lib.options.create { + description = "Whether the package is broken."; + type = lib.types.bool; + default.value = false; + }; + + main = lib.options.create { + description = "The main entry point for the package."; + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + platforms = lib.options.create { + description = "The platforms the package supports."; + type = lib.types.list.of lib.types.string; + default.value = []; + }; + }; + + platform = { build = lib.options.create { - description = "Dependencies which are created in the build environment and are executed in the build environment."; - type = lib'.types.dependencies; - default.value = { }; + description = "The build platform for the package."; + type = lib.types.string; + default.value = "x86_64-linux"; + apply = raw: let + system = lib'.systems.from.string raw; + x = lib'.systems.withBuildInfo raw; + in + x; }; host = lib.options.create { - description = "Dependencies which are created in the build environment and are executed in the host environment."; - type = lib'.types.dependencies; - default.value = { }; + description = "The host platform for the package."; + type = lib.types.string; + default.value = "x86_64-linux"; + # apply = raw: let + # system = lib'.systems.from.string raw; + # in { + # inherit raw system; + + # double = lib'.systems.into.double system; + # triple = lib'.systems.into.triple system; + # }; + apply = raw: let + system = lib'.systems.from.string raw; + x = lib'.systems.withBuildInfo raw; + in + x; }; target = lib.options.create { - description = "Dependencies which are created in the build environment and are executed in the target environment."; - type = lib'.types.dependencies; - default.value = { }; + description = "The target platform for the package."; + type = lib.types.string; + default.value = "x86_64-linux"; + # apply = raw: let + # system = lib'.systems.from.string raw; + # in { + # inherit raw system; + + # double = lib'.systems.into.double system; + # triple = lib'.systems.into.triple system; + # }; + apply = raw: let + system = lib'.systems.from.string raw; + x = lib'.systems.withBuildInfo raw; + in + x; }; }; - host = { - only = lib.options.create { - description = "Dependencies which are only used in the host environment."; - type = lib'.types.dependencies; - default.value = { }; + phases = lib.options.create { + description = "The phases for the package."; + type = lib.types.dag.of (lib.types.either lib.types.string (lib.types.function lib.types.string)); + default.value = {}; + }; + + env = lib.options.create { + description = "The environment for the package."; + type = lib.types.attrs.of lib.types.string; + default.value = {}; + }; + + builder = lib.options.create { + description = "The builder for the package."; + type = lib'.types.builder; + }; + + deps = { + build = { + only = lib.options.create { + description = "Dependencies which are only used in the build environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + build = lib.options.create { + description = "Dependencies which are created in the build environment and are executed in the build environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + host = lib.options.create { + description = "Dependencies which are created in the build environment and are executed in the host environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + target = lib.options.create { + description = "Dependencies which are created in the build environment and are executed in the target environment."; + type = lib'.types.dependencies; + default.value = {}; + }; }; - host = lib.options.create { - description = "Dependencies which are executed in the host environment."; - type = lib'.types.dependencies; - default.value = { }; + host = { + only = lib.options.create { + description = "Dependencies which are only used in the host environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + host = lib.options.create { + description = "Dependencies which are executed in the host environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + target = lib.options.create { + description = "Dependencies which are executed in the host environment which produces code for the target environment."; + type = lib'.types.dependencies; + default.value = {}; + }; }; - target = lib.options.create { - description = "Dependencies which are executed in the host environment which produces code for the target environment."; - type = lib'.types.dependencies; - default.value = { }; + target = { + only = lib.options.create { + description = "Dependencies which are only used in the target environment."; + type = lib'.types.dependencies; + default.value = {}; + }; + + target = lib.options.create { + description = "Dependencies which are executed in the target environment."; + type = lib'.types.dependencies; + default.value = {}; + }; }; }; - target = { - only = lib.options.create { - description = "Dependencies which are only used in the target environment."; - type = lib'.types.dependencies; - default.value = { }; - }; - - target = lib.options.create { - description = "Dependencies which are executed in the target environment."; - type = lib'.types.dependencies; - default.value = { }; - }; + package = lib.options.create { + description = "The built derivation."; + type = lib.types.derivation; + default.value = config.builder.build config; }; }; - - package = lib.options.create { - description = "The built derivation."; - type = lib.types.derivation; - default.value = config.builder.build config; - }; - }; - } - ); + } + ); + }; }; }; } diff --git a/tidepool/src/packages/aux/a.nix b/tidepool/src/packages/aux/a.nix new file mode 100644 index 0000000..97417ff --- /dev/null +++ b/tidepool/src/packages/aux/a.nix @@ -0,0 +1,33 @@ +{ + lib', + config, +}: let + inherit (config) builders packages; +in { + config.packages.aux.a = { + versions = { + "latest" = {config}: { + config = { + meta = { + platforms = ["i686-linux"]; + }; + + pname = "a"; + version = "1.0.0"; + + builder = builders.basic; + + deps.build.host = { + inherit (packages.aux) b; + }; + + phases = { + install = '' + echo "a" > $out + ''; + }; + }; + }; + }; + }; +} diff --git a/tidepool/src/packages/aux/b.nix b/tidepool/src/packages/aux/b.nix new file mode 100644 index 0000000..64b3e40 --- /dev/null +++ b/tidepool/src/packages/aux/b.nix @@ -0,0 +1,37 @@ +{ + lib', + config, +}: let + inherit (config) builders packages; +in { + config.packages.aux.b = { + versions = { + "latest" = {config}: { + options = { + custom = lib'.options.create { + type = lib'.types.bool; + }; + }; + + config = { + meta = { + platforms = ["i686-linux"]; + }; + + custom = true; + + pname = "b"; + version = "1.0.0"; + + builder = builders.basic; + + phases = { + install = '' + echo "b" > $out + ''; + }; + }; + }; + }; + }; +} diff --git a/tidepool/src/packages/default.nix b/tidepool/src/packages/default.nix index b6a57bf..a0ccb9b 100644 --- a/tidepool/src/packages/default.nix +++ b/tidepool/src/packages/default.nix @@ -2,28 +2,30 @@ lib, lib', config, -}: -let +}: let doubles = lib'.systems.doubles.all; - packages = builtins.removeAttrs config.packages [ "cross" ]; -in -{ - includes = [ ./foundation ]; + packages = builtins.removeAttrs config.packages ["cross"]; +in { + includes = [ + ./foundation + ./aux/a.nix + ./aux/b.nix + ]; options = { packages = lib.options.create { description = "The package set."; type = lib.types.submodule { - freeform = lib.types.attrs.of (lib.types.submodule { freeform = lib'.types.alias; }); + freeform = lib.types.attrs.of (lib.types.submodule {freeform = lib'.types.alias;}); options.cross = lib.attrs.generate doubles ( system: - lib.options.create { - description = "The cross-compiled package set for the ${system} target."; - type = lib'.types.packages; - default = { }; - } + lib.options.create { + description = "The cross-compiled package set for the ${system} target."; + type = lib'.types.packages; + default = {}; + } ); }; }; @@ -42,52 +44,53 @@ in config.packages.cross = lib.attrs.generate doubles ( system: - builtins.mapAttrs ( - namespace: builtins.mapAttrs ( - name: alias: - let - setHost = - package: - if package != { } then - (package.extend ( - { config }: - { - config = { - platform = { - host = lib.modules.overrides.force system; - target = lib.modules.overrides.default system; - }; + namespace: + builtins.mapAttrs ( + name: alias: let + setHost = package: + if package != {} + then + (package.extend ( + {config}: { + config = { + platform = { + host = lib.modules.overrides.force system; + target = lib.modules.overrides.default system; + }; - deps = { - build = { - only = setHost package.deps.build.only; - build = setHost package.deps.build.build; - host = setHost package.deps.build.host; - target = setHost package.deps.build.target; + deps = { + build = { + only = setHost package.deps.build.only; + build = setHost package.deps.build.build; + host = setHost package.deps.build.host; + target = setHost package.deps.build.target; + }; + host = { + only = setHost package.deps.host.only; + host = setHost package.deps.host.host; + target = setHost package.deps.host.target; + }; + target = { + only = setHost package.deps.target.only; + target = setHost package.deps.target.target; + }; + }; }; - host = { - only = setHost package.deps.host.only; - host = setHost package.deps.host.host; - target = setHost package.deps.host.target; - }; - target = { - only = setHost package.deps.target.only; - target = setHost package.deps.target.target; - }; - }; - }; - } - )).config - else - package; + } + )) + .config + else package; - 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/binutils/default.nix b/tidepool/src/packages/foundation/binutils/default.nix index b66ba7d..407b6f1 100644 --- a/tidepool/src/packages/foundation/binutils/default.nix +++ b/tidepool/src/packages/foundation/binutils/default.nix @@ -3,117 +3,121 @@ lib', config, options, -}: -let - inherit (config) +}: let + inherit + (config) mirrors builders # These are the upstream foundational packages exported from the Aux Foundation project. - + foundation + packages ; -in -{ +in { config.packages.foundation.binutils = { versions = { - "latest" = - { config, meta }: - { - options = { - src = lib.options.create { - type = lib.types.derivation; - description = "Source for the package."; - }; - }; - - config = { - meta = { - platforms = [ "i686-linux" ]; - }; - - pname = "binutils"; - version = "2.41"; - - builder = builders.basic; - - env = { - PATH = lib.paths.bin [ - foundation.stage2-gcc - foundation.stage2-binutils - foundation.stage2-gnumake - foundation.stage2-gnupatch - foundation.stage2-gnused - foundation.stage2-gnugrep - foundation.stage2-gawk - foundation.stage2-diffutils - foundation.stage2-findutils - foundation.stage2-gnutar - foundation.stage1-xz - ]; - }; - - phases = - let - patches = [ - # Make binutils output deterministic by default. - ./patches/deterministic.patch - ]; - - configureFlags = [ - # "CC=musl-gcc" - "LDFLAGS=--static" - "--prefix=${builtins.placeholder "out"}" - "--build=${config.platform.build.triple}" - "--host=${config.platform.host.triple}" - "--target=${config.platform.target.triple}" - - "--with-sysroot=/" - "--enable-deterministic-archives" - # depends on bison - "--disable-gprofng" - - # Turn on --enable-new-dtags by default to make the linker set - # RUNPATH instead of RPATH on binaries. This is important because - # RUNPATH can be overridden using LD_LIBRARY_PATH at runtime. - "--enable-new-dtags" - - # By default binutils searches $libdir for libraries. This brings in - # libbfd and libopcodes into a default visibility. Drop default lib - # path to force users to declare their use of these libraries. - "--with-lib-path=:" - - "--disable-multilib" - ]; - in - { - unpack = lib.dag.entry.before [ "patch" ] '' - tar xf ${config.src} - cd binutils-${config.version} - ''; - - patch = lib.dag.entry.between [ "configure" ] [ "unpack" ] '' - ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} - ''; - - configure = lib.dag.entry.between [ "build" ] [ "patch" ] '' - bash ./configure ${builtins.concatStringsSep " " configureFlags} - ''; - - build = lib.dag.entry.between [ "install" ] [ "configure" ] '' - make -j $NIX_BUILD_CORES - ''; - - install = lib.dag.entry.after [ "build" ] '' - make -j $NIX_BUILD_CORES install-strip - ''; - }; - - src = builtins.fetchurl { - url = "${mirrors.gnu}/binutils/binutils-${config.version}.tar.xz"; - sha256 = "rppXieI0WeWWBuZxRyPy0//DHAMXQZHvDQFb3wYAdFA="; - }; + "latest" = {config}: { + options = { + src = lib.options.create { + type = lib.types.derivation; + description = "Source for the package."; }; }; + + config = { + meta = { + platforms = ["i686-linux"]; + }; + + pname = "binutils"; + version = "2.41"; + + builder = builders.basic; + + # deps = { + # build = { + # host = { + # inherit (packages.foundation) gcc; + # }; + # }; + # }; + + env = { + PATH = lib.paths.bin [ + # foundation.stage2-gcc + foundation.stage2-binutils + foundation.stage2-gnumake + foundation.stage2-gnupatch + foundation.stage2-gnused + foundation.stage2-gnugrep + foundation.stage2-gawk + foundation.stage2-diffutils + foundation.stage2-findutils + foundation.stage2-gnutar + foundation.stage1-xz + ]; + }; + + phases = let + patches = [ + # Make binutils output deterministic by default. + ./patches/deterministic.patch + ]; + + configureFlags = [ + # "CC=musl-gcc" + "LDFLAGS=--static" + "--prefix=${builtins.placeholder "out"}" + "--build=${config.platform.build.triple}" + "--host=${config.platform.host.triple}" + "--target=${config.platform.target.triple}" + + "--with-sysroot=/" + "--enable-deterministic-archives" + # depends on bison + "--disable-gprofng" + + # Turn on --enable-new-dtags by default to make the linker set + # RUNPATH instead of RPATH on binaries. This is important because + # RUNPATH can be overridden using LD_LIBRARY_PATH at runtime. + "--enable-new-dtags" + + # By default binutils searches $libdir for libraries. This brings in + # libbfd and libopcodes into a default visibility. Drop default lib + # path to force users to declare their use of these libraries. + "--with-lib-path=:" + + "--disable-multilib" + ]; + in { + unpack = lib.dag.entry.before ["patch"] '' + tar xf ${config.src} + cd binutils-${config.version} + ''; + + patch = lib.dag.entry.between ["configure"] ["unpack"] '' + ${lib.strings.concatMapSep "\n" (file: "patch -Np1 -i ${file}") patches} + ''; + + configure = lib.dag.entry.between ["build"] ["patch"] '' + bash ./configure ${builtins.concatStringsSep " " configureFlags} + ''; + + build = lib.dag.entry.between ["install"] ["configure"] '' + make -j $NIX_BUILD_CORES + ''; + + install = lib.dag.entry.after ["build"] '' + make -j $NIX_BUILD_CORES install-strip + ''; + }; + + src = builtins.fetchurl { + url = "${mirrors.gnu}/binutils/binutils-${config.version}.tar.xz"; + sha256 = "rppXieI0WeWWBuZxRyPy0//DHAMXQZHvDQFb3wYAdFA="; + }; + }; + }; }; }; }