From ea0ed58a7ea61587e0a4a51838be19d4cddb4a46 Mon Sep 17 00:00:00 2001 From: Jake Hamilton Date: Fri, 14 Jun 2024 01:26:16 -0700 Subject: [PATCH] feat: working module packages --- lib/src/types/default.nix | 143 ++++--- potluck/default.nix | 16 +- potluck/flake.lock | 16 +- potluck/src/lib/types.nix | 686 +++++++++++++++---------------- potluck/src/packages/default.nix | 47 ++- 5 files changed, 469 insertions(+), 439 deletions(-) diff --git a/lib/src/types/default.nix b/lib/src/types/default.nix index 3847370..a3bc880 100644 --- a/lib/src/types/default.nix +++ b/lib/src/types/default.nix @@ -360,6 +360,19 @@ lib: { ## @type Attrs port = lib.types.ints.u16; + ## A type that allows a string value specifying a version number. + ## + ## @type Attrs + version = lib.types.create { + name = "Version"; + description = "version"; + check = value: let + parts = builtins.splitVersion value; + in + builtins.isString value && builtins.length parts > 0; + merge = lib.options.merge.equal; + }; + ## A type that allows a string value. The merged definitions must all be ## the same. ## @@ -1038,72 +1051,72 @@ lib: { inherit initial final; }; }; - }; - dag = { - ## 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 - lib.types.create { - name = "Dag"; - description = "Dag of ${type.description}"; - check = resolved.check; - merge = resolved.merge; - fallback = resolved.fallback; - 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;}; - children = { - element = type; - resolved = resolved; - }; - }; - - ## 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; + dag = { + ## 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 - 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: - submodule.merge - location - ( - builtins.map - (definition: { - __file__ = definition.__file__; - value = normalize definition; - }) - definitions - ); - }; + lib.types.create { + name = "Dag"; + description = "Dag of ${type.description}"; + check = resolved.check; + merge = resolved.merge; + fallback = resolved.fallback; + 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;}; + children = { + element = type; + resolved = resolved; + }; + }; + + ## 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; + in + lib.types.create { + name = "DagEntry"; + description = "DagEntry (${type.description})"; + merge = location: definitions: + submodule.merge + location + ( + builtins.map + (definition: { + __file__ = definition.__file__; + value = normalize definition; + }) + definitions + ); + }; + }; }; } diff --git a/potluck/default.nix b/potluck/default.nix index 2c2f8d9..8568a91 100644 --- a/potluck/default.nix +++ b/potluck/default.nix @@ -10,22 +10,22 @@ ++ [ ./src/export.nix { - __file__ = "broken"; + __file__ = ./default.nix; # options.foundation = lib.options.create { # type = lib.types.attrs.of lib.types.derivation; # }; # config.foundation = foundation; - config.packages.foundation = - builtins.mapAttrs (name: package: { - name = package.name; + # config.packages.foundation = + # builtins.mapAttrs (name: package: { + # name = package.name; - inherit package; + # inherit package; - meta = package.meta; - }) - foundation; + # meta = package.meta; + # }) + # foundation; } ]; }; diff --git a/potluck/flake.lock b/potluck/flake.lock index 32c0ec0..f8cfcef 100644 --- a/potluck/flake.lock +++ b/potluck/flake.lock @@ -8,10 +8,10 @@ }, "locked": { "dir": "foundation", - "dirtyRev": "9c29945531c58ad81f05cd1f4958c8894a733216-dirty", - "dirtyShortRev": "9c29945-dirty", - "lastModified": 1718255029, - "narHash": "sha256-fmrDe4GfvVfXZ9lzaOt+tgBUMFCsyKr0Dlnm8aQwAXs=", + "dirtyRev": "856b88321e5f19019332f8b60b729095c2260340-dirty", + "dirtyShortRev": "856b883-dirty", + "lastModified": 1718299377, + "narHash": "sha256-L6zriSSFi45uJ8u3HVsZ6iDHjNtQBB+aDWQfiReoLkM=", "type": "git", "url": "file:../?dir=foundation" }, @@ -24,10 +24,10 @@ "lib": { "locked": { "dir": "lib", - "dirtyRev": "9c29945531c58ad81f05cd1f4958c8894a733216-dirty", - "dirtyShortRev": "9c29945-dirty", - "lastModified": 1718255029, - "narHash": "sha256-fmrDe4GfvVfXZ9lzaOt+tgBUMFCsyKr0Dlnm8aQwAXs=", + "dirtyRev": "856b88321e5f19019332f8b60b729095c2260340-dirty", + "dirtyShortRev": "856b883-dirty", + "lastModified": 1718299377, + "narHash": "sha256-L6zriSSFi45uJ8u3HVsZ6iDHjNtQBB+aDWQfiReoLkM=", "type": "git", "url": "file:../?dir=lib" }, diff --git a/potluck/src/lib/types.nix b/potluck/src/lib/types.nix index 102694d..8345669 100644 --- a/potluck/src/lib/types.nix +++ b/potluck/src/lib/types.nix @@ -71,7 +71,8 @@ in { }; license = lib.options.create { - type = config.lib.types.license; + type = lib.types.nullish config.lib.types.license; + default.value = null; description = "The license for the package."; }; @@ -107,362 +108,345 @@ in { }; }; - package = { - base = lib.types.submodule ({config}: { - freeform = lib.types.any; - - options = { - name = lib.options.create { - type = lib.types.string; - default = { - value = "${config.pname}-${config.version or "unknown"}"; - text = "\${config.pname}-\${config.version}"; - }; - description = "The name of the package."; - }; - - pname = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The name of the package."; - }; - - version = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The version of the package."; - }; - - meta = lib.options.create { - type = lib'.types.meta; - default = { - text = "{ name = .pname; }"; - value = { - name = config.pname; - }; - }; - description = "The metadata for the package."; - }; - - env = lib.options.create { - type = lib.types.attrs.of lib.types.string; - default.value = {}; - description = "Environment variables for the package's builder to use."; - }; - - phases = lib.options.create { - type = lib.types.dag.of ( - lib.types.either - lib.types.string - (lib.types.function lib.types.string) - ); - default.value = {}; - description = "Phases for the package's builder to use."; - }; - - platform = { - build = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The platform the package is built on."; - }; - - host = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The platform the package is run on."; - }; - - target = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The platform the package generates code for."; - }; - }; - - builder = lib.options.create { - type = lib'.types.builder; - description = "The builder for the package."; - }; - - package = lib.options.create { - type = lib.types.derivation; - default = { - value = config.builder.build config.builder config; - text = ""; - }; - description = "The package derivation."; - }; - - deps = { - build = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the build environment."; - }; - - build = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the build environment."; - }; - - host = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the host environment."; - }; - - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the target environment."; - }; - }; - - host = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the host environment."; - }; - - host = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the host environment."; - }; - - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the host environment which produces code for the target environment."; - }; - }; - - target = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the target environment."; - }; - - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the target environment."; - }; - }; - }; - - versions = lib.options.create { - type = lib.types.attrs.of lib'.types.package; - default.value = {}; - description = "Available versions of the package."; - }; - }; - }); - - targeted = lib.types.submodule ({config}: { - freeform = lib.types.any; - - options = { - name = lib.options.create { - type = lib.types.string; - default = { - value = "${config.pname}-${config.version or "unknown"}"; - text = "\${config.pname}-\${config.version}"; - }; - description = "The name of the package."; - }; - - pname = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The name of the package."; - }; - - version = lib.options.create { - type = lib.types.nullish lib.types.string; - default.value = null; - description = "The version of the package."; - }; - - meta = lib.options.create { - type = lib'.types.meta; - default = { - text = "{ name = .pname; }"; - value = { - name = config.pname; - }; - }; - description = "The metadata for the package."; - }; - - env = lib.options.create { - type = lib.types.attrs.of lib.types.string; - default.value = {}; - description = "Environment variables for the package's builder to use."; - }; - - phases = lib.options.create { - type = lib.types.dag.of ( - lib.types.either - lib.types.string - (lib.types.function lib.types.string) - ); - default.value = {}; - description = "Phases for the package's builder to use."; - }; - - platform = { - build = lib.options.create { - type = lib.types.string; - description = "The platform the package is built on."; - }; - - host = lib.options.create { - type = lib.types.string; - description = "The platform the package is run on."; - }; - - target = lib.options.create { - type = lib.types.string; - description = "The platform the package generates code for."; - }; - }; - - builder = lib.options.create { - type = lib'.types.builder; - description = "The builder for the package."; - }; - - package = lib.options.create { - type = lib.types.derivation; - default = { - value = config.builder.build config.builder config; - text = ""; - }; - description = "The package derivation."; - }; - - deps = { - build = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the build environment."; - }; - - build = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the build environment."; - }; - - host = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the host environment."; - }; - - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are created in the build environment and are run in the target environment."; - }; - }; - - host = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the host environment."; - }; - - host = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the host environment."; - }; - - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the host environment which produces code for the target environment."; - }; - }; - - target = { - only = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are only used in the target environment."; - }; - - target = lib.options.create { - type = lib'.types.dependencies; - default.value = {}; - description = "Dependencies which are run in the target environment."; - }; - }; - }; - - versions = lib.options.create { - type = lib.types.attrs.of lib'.types.package; - default.value = {}; - description = "Available versions of the package."; - }; - }; - }); - }; - - dependencies = lib.types.attrs.of (lib.types.nullish lib'.types.package); - - packages = { - base = lib.types.attrs.of (lib.types.submodule { - freeform = lib'.types.package.base; - - # options = - # builtins.foldl' (result: system: { - # "${system}" = lib.options.create { - # type = lib'.types.packages.targeted; - # default.value = {}; - # description = "Packages for the architecture `${system}`"; - # }; - # }) {} - # lib'.systems.doubles.all; - }); - - targeted = lib.types.attrs.of (lib.types.submodule { - freeform = lib.types.nullish lib'.types.package.targeted; - - options = { - cross = lib.options.create { - type = lib'.types.packages.cross; - default.value = {}; - description = "Cross-compiled packages targeting another architecture."; - }; - }; - }); - - # Cross-compiled packages are accessed via - # packages.cross... - cross = lib.types.attrs.of (lib.types.submodule { - freeform = lib.types.attrs.of (lib.types.submodule { - freeform = lib.types.nullish lib'.types.package.targeted; - }); - }); - }; - builder = lib.types.submodule { freeform = lib.types.any; options = { build = lib.options.create { type = lib.types.function lib.types.derivation; - description = "The function that creates the package derivation."; + }; + }; + }; + + packages = { + generic = lib.types.attrs.of (lib.types.submodule ({name}: { + freeform = lib.types.attrs.of (lib.types.submodule [ + lib'.types.package.generic' + ]); + })); + + # packages. + targeted = lib.types.attrs.of (lib.types.submodule ({name}: let + system = name; + in { + # packages.. + freeform = lib.types.attrs.of (lib.types.submodule ({name}: let + namespace = name; + in { + # packages... + freeform = lib.types.attrs.of (lib.types.submodule [ + lib'.types.package.targeted' + { + config = { + namespace = namespace; + + platform = { + build = system; + host = lib.modules.overrides.default system; + target = lib.modules.overrides.default system; + }; + }; + } + ]); + })); + + # packages.. + options.cross = lib.attrs.generate lib'.systems.doubles.all (cross: + lib.options.create { + default.value = {}; + # packages... + type = lib.types.attrs.of (lib.types.submodule ( + {name}: let + namespace = name; + in { + # packages.... + freeform = lib.types.attrs.of (lib.types.submodule [ + lib'.types.package.targeted' + { + config = { + namespace = namespace; + + platform = { + build = system; + host = cross; + target = lib.modules.overrides.default cross; + }; + }; + } + ]); + } + )); + }); + })); + }; + + dependencies = { + generic = lib.types.attrs.of (lib.types.nullish lib'.types.package.generic); + + targeted = lib.types.attrs.of (lib.types.nullish lib'.types.package.targeted); + }; + + package = { + generic = lib.types.submodule lib'.types.package.generic'; + + generic' = args @ { + name ? assert false; null, + config, + }: { + options = { + pname = lib.options.create { + type = lib.types.string; + default = { + text = " or \"unknown\""; + value = + if args ? name + then args.name + else "unknown"; + }; + }; + + version = lib.options.create { + type = lib.types.nullish lib.types.version; + default.value = null; + }; + + meta = lib.options.create { + type = lib'.types.meta; + default.value = { + name = config.pname; + }; + }; + + phases = lib.options.create { + type = lib.types.dag.of ( + lib.types.either + lib.types.string + (lib.types.function lib.types.string) + ); + default.value = {}; + }; + + env = lib.options.create { + type = lib.types.attrs.of lib.types.string; + default.value = {}; + }; + + builder = lib.options.create { + type = lib'.types.builder; + }; + + deps = { + build = { + only = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + + build = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + + host = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + + target = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + }; + + host = { + only = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + + host = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + + target = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + }; + + target = { + only = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + + target = lib.options.create { + type = lib'.types.dependencies.generic; + default.value = {}; + }; + }; + }; + + versions = lib.options.create { + type = lib.types.attrs.of lib'.types.packages.generic; + default.value = {}; + }; + }; + }; + + targeted = lib.types.submodule lib'.types.package.targeted'; + + targeted' = args @ { + name ? assert false; null, + config, + }: { + options = { + name = lib.options.create { + type = lib.types.string; + default = { + text = "\${namespace}-\${pname}-\${version} or \${pname}-\${version}"; + value = let + namespace = + if config.namespace == null + then "" + else "${config.namespace}-"; + version = + if config.version == null + then "" + else "-${config.version}"; + in "${namespace}${config.pname}${version}"; + }; + }; + + namespace = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + pname = lib.options.create { + type = lib.types.string; + default = { + text = " or \"unknown\""; + value = + if args ? name + then args.name + else "unknown"; + }; + }; + + version = lib.options.create { + type = lib.types.nullish lib.types.version; + default.value = null; + }; + + meta = lib.options.create { + type = lib'.types.meta; + default.value = { + name = config.pname; + }; + }; + + platform = { + build = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + host = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + }; + + target = lib.options.create { + type = lib.types.nullish lib.types.string; + default.value = null; + }; + }; + + phases = lib.options.create { + type = lib.types.dag.of ( + lib.types.either + lib.types.string + (lib.types.function lib.types.string) + ); + default.value = {}; + }; + + env = lib.options.create { + type = lib.types.attrs.of lib.types.string; + default.value = {}; + }; + + builder = lib.options.create { + type = lib'.types.builder; + }; + + package = lib.options.create { + type = lib.types.derivation; + }; + + deps = { + build = { + only = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + + build = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + + host = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + + target = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + }; + + host = { + only = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + + host = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + + target = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + }; + + target = { + only = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + + target = lib.options.create { + type = lib'.types.dependencies.targeted; + default.value = {}; + }; + }; + }; + + versions = lib.options.create { + type = lib.types.attrs.of lib'.types.packages.targeted; + default.value = {}; + }; + }; + + config = { + package = config.builder.build config; }; }; }; diff --git a/potluck/src/packages/default.nix b/potluck/src/packages/default.nix index edb6465..62f49df 100644 --- a/potluck/src/packages/default.nix +++ b/potluck/src/packages/default.nix @@ -6,22 +6,55 @@ doubles = lib'.systems.doubles.all; - generic = builtins.removeAttrs config.packages ["targeted"]; + generic = config.packages.generic; + + targeted = { + i686-linux = generic; + }; in { includes = [ # ./aux/foundation.nix ]; options = { - packages = lib.options.create { - default.value = {}; - type = lib.types.attrs.of (lib.types.submodule { - freeform = lib.types.any; - }); + packages = { + generic = lib.options.create { + type = lib'.types.packages.generic; + default.value = {}; + }; + + targeted = lib.options.create { + type = lib'.types.packages.targeted; + }; }; }; config = { - packages.targeted.i686-linux = generic; + packages = { + generic = { + example = { + x = { + version = "1.0.0"; + builder.build = package: + derivation { + name = package.name; + builder = "/bin/sh"; + system = package.platform.build; + }; + phases = { + build = '' + make + ''; + + install = lib.dag.entry.after ["build"] '' + make install DESTDIR=$out + ''; + }; + }; + }; + }; + + inherit targeted; + }; }; }