refactor: more elegant shorthand support

This commit is contained in:
Jake Hamilton 2024-06-15 02:35:37 -07:00
parent aa1c58f6ee
commit 2989fdc4fe
Signed by: jakehamilton
GPG key ID: 9762169A1B35EA68
13 changed files with 418 additions and 677 deletions

View file

@ -358,7 +358,7 @@ lib: {
in
if builtins.isAttrs subtree
then builtins.mapAttrs (name: f module) subtree
else builtins.throw "Value for `${builtins.concatStringsSep "." prefix} is of type `${builtins.typeOf subtree}` but an attribute set was expected."
else builtins.throw "Value for `${builtins.concatStringsSep "." prefix}` is of type `${builtins.typeOf subtree}` but an attribute set was expected."
)
modules);

View file

@ -493,5 +493,113 @@ in {
};
in
evaluated.config.aux.message == evaluated.config.aux.message2;
"function submodules" = let
expected = "Hello, World!";
evaluated = lib.modules.run {
modules = [
{
options = {
aux = lib.options.create {
type = lib.types.submodules.of {
shorthand = false;
modules = [
{
options.message = lib.options.create {
type = lib.types.string;
};
}
];
};
};
};
config = {
aux = args: {
config.message = expected;
};
};
}
];
};
in
evaluated.config.aux.message == expected;
"merges submodules" = let
expected = "Hello, World!";
evaluated = lib.modules.run {
modules = [
{
options = {
aux = lib.options.create {
type = lib.types.submodules.of {
shorthand = false;
modules = [
{
options.message = lib.options.create {
type = lib.types.string;
};
}
];
};
};
};
config = {
aux = args: {
options.message2 = lib.options.create {
type = lib.types.string;
};
config.message = expected;
};
};
}
{
config = {
aux.config.message2 = expected;
};
}
];
};
in
evaluated.config.aux.message == evaluated.config.aux.message2;
"flexible shorthand" = let
expected = "Hello, World!";
evaluated = lib.modules.run {
modules = [
{
options = {
aux = lib.options.create {
type = lib.types.submodules.of {
shorthand = true;
modules = [
{
options.message = lib.options.create {
type = lib.types.string;
};
}
];
};
};
};
config = {
aux = args: {
options.message2 = lib.options.create {
type = lib.types.string;
};
config.message = expected;
};
};
}
{
config = {
aux.message2 = expected;
};
}
];
};
in
evaluated.config.aux.message == evaluated.config.aux.message2;
};
}

View file

@ -756,7 +756,7 @@ lib: {
## with helpers like `lib.types.attrs.of` in order to produce more complex,
## dynamic types.
##
## @type { modules :: List Module, args? :: Attrs, description? :: String | Null } -> Attrs
## @type { modules :: List Module, args? :: Attrs, description? :: String | Null, shorthand? :: Bool } -> Attrs
of = settings @ {
modules,
args ? {},
@ -765,11 +765,24 @@ lib: {
}: let
getModules = builtins.map (
definition:
if shorthand && builtins.isAttrs definition
then {
__file__ = definition.__file__;
config = definition.value;
}
if shorthand && builtins.isAttrs definition.value
then let
config =
definition.value.config
or (
builtins.removeAttrs definition.value
(builtins.filter (key: key != "config") lib.modules.VALID_KEYS)
);
rest =
if definition.value ? config
then builtins.removeAttrs definition.value ["config"]
else lib.attrs.filter (name: value: builtins.elem name lib.modules.VALID_KEYS) definition.value;
in
rest
// {
__file__ = definition.__file__;
config = config;
}
else {
__file__ = definition.__file__;
includes = [definition.value];

View file

@ -8,10 +8,10 @@
},
"locked": {
"dir": "foundation",
"dirtyRev": "b3f9fe574e6ff545e4a6fe6ad5e90fc71baeece3-dirty",
"dirtyShortRev": "b3f9fe5-dirty",
"lastModified": 1718366115,
"narHash": "sha256-/ktNtlY/usvE1YaathJ0f6y60cv3gQjc32SMKApsp7Y=",
"dirtyRev": "aa1c58f6ee8a3ad6ad569f34477192462533c16b-dirty",
"dirtyShortRev": "aa1c58f-dirty",
"lastModified": 1718411218,
"narHash": "sha256-LOzQGGygC2U08zNwg1YNljjrJKJxnJ8S4RkX2v81yRw=",
"type": "git",
"url": "file:../?dir=foundation"
},
@ -24,10 +24,10 @@
"lib": {
"locked": {
"dir": "lib",
"dirtyRev": "b3f9fe574e6ff545e4a6fe6ad5e90fc71baeece3-dirty",
"dirtyShortRev": "b3f9fe5-dirty",
"lastModified": 1718366115,
"narHash": "sha256-/ktNtlY/usvE1YaathJ0f6y60cv3gQjc32SMKApsp7Y=",
"dirtyRev": "aa1c58f6ee8a3ad6ad569f34477192462533c16b-dirty",
"dirtyShortRev": "aa1c58f-dirty",
"lastModified": 1718411218,
"narHash": "sha256-LOzQGGygC2U08zNwg1YNljjrJKJxnJ8S4RkX2v81yRw=",
"type": "git",
"url": "file:../?dir=lib"
},

View file

@ -26,11 +26,9 @@ in {
sorted.result;
system = package.platform.build;
deps = lib'.packages.dependencies.resolve package.deps system;
in
(builtins.trace script)
builtins.derivation (package.env
builtins.derivation (
package.env
// {
inherit (package) name;
inherit script system;
@ -40,7 +38,7 @@ in {
SHELL = cfg.executable;
PATH = lib.paths.bin (
(lib'.packages.dependencies.getPackages "build.host" deps)
(lib'.packages.dependencies.getPackages package.deps.build.host)
++ [
foundation.stage2-bash
foundation.stage2-coreutils
@ -67,7 +65,8 @@ in {
bash -eux $scriptPath
'')
];
});
}
);
};
};
}

View file

@ -12,7 +12,7 @@ in {
modules = import ./modules.nix;
packages = {
example = lib'.packages.export "example.x";
example-x = config.packages.example.x;
};
};
};

View file

@ -1,6 +1,6 @@
{
config,
lib,
config,
}: let
in {
options = {

View file

@ -3,12 +3,10 @@
lib,
}: let
lib' = config.lib;
cfg = config.exports;
in {
options = {
exports.packages = lib.options.create {
type = lib.types.attrs.of (lib.types.function (lib.types.nullish lib.types.derivation));
type = lib.types.attrs.of (lib'.types.raw);
default.value = {};
};
@ -22,17 +20,27 @@ in {
exported.packages = let
all = lib.attrs.generate lib'.systems.doubles.all (
system: let
packages =
all =
builtins.mapAttrs
(name: resolve: resolve system)
cfg.packages;
(
name: package: let
result = lib'.packages.build package system system;
in
result
)
config.exports.packages;
available =
lib.attrs.filter
(name: package: package != null)
packages;
(name: package: builtins.elem system package.meta.platforms)
all;
packages =
builtins.mapAttrs
(name: package: package.package)
available;
in
available
packages
);
available =

View file

@ -19,4 +19,8 @@ in {
apply = value: lib.extend (final: prev: prev.attrs.mergeRecursive prev value);
};
};
config = {
__module__.args.dynamic.lib' = config.lib;
};
}

View file

@ -1,82 +1,65 @@
{
lib,
lib',
config,
}: let
lib' = config.lib;
in {
}: {
config = {
lib.packages = {
dependencies = {
getPackages = path: dependencies: let
resolved =
if builtins.isList path
then path
else lib.strings.split "." path;
attrs = lib.attrs.select resolved {} dependencies;
getPackages = dependencies: let
available =
builtins.filter
(dependency: !(builtins.isNull dependency))
(builtins.attrValues dependencies);
in
lib.attrs.mapToList (name: value: value.package) attrs;
resolve = dependencies: system:
builtins.mapAttrs
# Note that this does not correspond to the "host" and "target" platforms, but rather
# where the code is used and where it is intended to end up.
(
host: platforms:
builtins.mapAttrs
(
target: deps:
builtins.mapAttrs
(
name: dependency:
assert lib.errors.trace (dependency.namespace != null) "Namespace unknown for dependency `${name}`."; let
targeted = lib'.packages.export [dependency.namespace name] system;
in
if targeted == null
then builtins.throw "Dependency `${dependency.namespace}.${name}` does not support system `${system}`."
else targeted
)
deps
)
platforms
)
dependencies;
builtins.map (dependency: dependency.package) available;
};
## Get a package from the package set by its path. The path can be either
## a string or a list of strings that is used to access `config.packages.generic`.
##
## @type String | List String -> Package
get = path: let
resolved =
if builtins.isList path
then path
else lib.strings.split "." path;
package = lib.attrs.selectOrThrow resolved config.packages.generic;
getLatest = alias: let
versions = builtins.attrNames alias.versions;
sorted = builtins.sort (builtins.compareVersions) versions;
in
assert lib.errors.trace (builtins.length resolved > 1) "Cannot get package without a namespace.";
package
// {
namespace = lib.modules.override 99 (builtins.head resolved);
builtins.head sorted;
build = package: system: cross: let
resolved =
if package ? versions
then package.versions.${config.preferences.packages.version} or (lib'.packages.getLatest package)
else package;
buildDependencies = builtins.mapAttrs (name: dep: lib'.packages.build dep system cross);
result = resolved.extend ({config}: {
config = {
platform = {
build = system;
host = cross;
target = cross;
};
deps = {
build = {
only = buildDependencies resolved.deps.build.only;
build = buildDependencies resolved.deps.build.build;
host = buildDependencies resolved.deps.build.host;
target = buildDependencies resolved.deps.build.target;
};
host = {
only = buildDependencies resolved.deps.host.only;
host = buildDependencies resolved.deps.host.host;
target = buildDependencies resolved.deps.host.target;
};
target = {
only = buildDependencies resolved.deps.target.only;
target = buildDependencies resolved.deps.target.target;
};
};
package = config.builder.build config;
};
## Export a package by its path. Use this function with the `config.exports.packages.*`
## options.
##
## @type String | List String -> String -> Package
export = path: system: let
resolved =
if builtins.isList path
then path
else lib.strings.split "." path;
package = lib'.packages.get resolved;
targeted = lib.attrs.selectOrThrow resolved config.packages.targeted.${system};
});
in
if builtins.elem system package.meta.platforms
then targeted.package
else null;
result.config;
};
};
}

View file

@ -1,9 +1,8 @@
{
lib,
lib',
config,
}: let
lib' = config.lib;
in {
}: {
config = {
lib.types = {
license = let
@ -51,58 +50,6 @@ in {
in
lib.types.either type (lib.types.list.of type);
meta = lib.types.submodule {
options = {
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 config.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 = [];
};
};
};
builder = lib.types.submodule {
freeform = lib.types.any;
@ -114,523 +61,220 @@ in {
};
};
packages = {
generic = lib.types.attrs.of (lib.types.submodule ({name}: {
freeform = lib.types.attrs.of (lib.types.submodule [
lib'.types.package.generic'
]);
}));
packages = lib.types.attrs.of (lib'.types.alias);
versioned = lib.types.attrs.of (lib.types.submodule ({name}: {
freeform = lib.types.attrs.of (lib.types.submodule [
lib'.types.package.versioned'
]);
}));
# packages.<system>
targeted = lib.types.attrs.of (lib.types.submodule ({name}: let
system = name;
in {
# packages.<system>.<namespace>
freeform = lib.types.attrs.of (lib.types.submodule ({name}: let
namespace = name;
in {
# packages.<system>.<namespace>.<name>
freeform = lib.types.attrs.of (lib.types.submodule [
lib'.types.package.targeted'
{
config = {
namespace = lib.modules.override 99 namespace;
platform = {
build = system;
host = lib.modules.overrides.default system;
target = lib.modules.overrides.default system;
};
};
}
]);
}));
# packages.<system>.<cross>
options.cross = lib.attrs.generate lib'.systems.doubles.all (cross:
lib.options.create {
description = "A cross-compiling package set.";
default.value = {};
# packages.<system>.<cross>.<namespace>
type = lib.types.attrs.of (lib.types.submodule (
{name}: let
namespace = name;
in {
# packages.<system>.<cross>.<namespace>.<name>
freeform = lib.types.attrs.of (lib.types.submodule [
lib'.types.package.targeted'
{
config = {
namespace = lib.modules.override 99 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,
}: {
freeform = lib.types.any;
options = {
namespace = lib.options.create {
description = "The namespace for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
pname = lib.options.create {
description = "The program name for the package";
type = lib.types.string;
default = {
text = "<name> or \"unknown\"";
value =
if args ? name
then args.name
else "unknown";
};
};
version = lib.options.create {
description = "The version for the package.";
type = lib.types.nullish lib.types.version;
default.value = null;
};
meta = lib.options.create {
description = "Metadata for the package.";
type = lib'.types.meta;
default.value = {
name = config.pname;
};
};
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.generic;
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.generic;
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.generic;
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.generic;
default.value = {};
};
};
host = {
only = lib.options.create {
description = "Dependencies which are only used in the host environment.";
type = lib'.types.dependencies.generic;
default.value = {};
};
host = lib.options.create {
description = "Dependencies which are executed in the host environment.";
type = lib'.types.dependencies.generic;
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.generic;
default.value = {};
};
};
target = {
only = lib.options.create {
description = "Dependencies which are only used in the target environment.";
type = lib'.types.dependencies.generic;
default.value = {};
};
target = lib.options.create {
description = "Dependencies which are executed in the target environment.";
type = lib'.types.dependencies.generic;
default.value = {};
};
};
};
versions = lib.options.create {
description = "Available package versions.";
type = lib.types.attrs.of lib'.types.package.versioned;
default.value = {};
};
alias = lib.types.attrs.of (lib.types.submodule {
options = {
versions = lib.options.create {
description = "All available package versions.";
type = lib.types.attrs.of lib'.types.package;
};
};
});
versioned = lib.types.submodule lib'.types.package.versioned';
dependencies = lib.types.attrs.of (lib.types.nullish (lib.types.either lib'.types.alias lib'.types.package));
versioned' = args @ {
name ? assert false; null,
config,
}: {
freeform = lib.types.any;
options = {
namespace = lib.options.create {
description = "The namespace for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
pname = lib.options.create {
description = "The program name for the package";
type = lib.types.string;
default = {
text = "<name> or \"unknown\"";
value =
if args ? name
then args.name
else "unknown";
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:
meta.extend {
modules =
if builtins.isAttrs value
then [{config = value;}]
else lib.lists.from.any value;
};
};
};
version = lib.options.create {
description = "The version for the package.";
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 {
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.generic;
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.generic;
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.generic;
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.generic;
default.value = {};
};
};
host = {
only = lib.options.create {
description = "Dependencies which are only used in the host environment.";
type = lib'.types.dependencies.generic;
default.value = {};
};
host = lib.options.create {
description = "Dependencies which are executed in the host environment.";
type = lib'.types.dependencies.generic;
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.generic;
default.value = {};
};
};
target = {
only = lib.options.create {
description = "Dependencies which are only used in the target environment.";
type = lib'.types.dependencies.generic;
default.value = {};
};
target = lib.options.create {
description = "Dependencies which are executed in the target environment.";
type = lib'.types.dependencies.generic;
default.value = {};
};
};
};
versions = lib.options.create {
description = "Available package versions.";
type = lib.types.attrs.of lib'.types.package.versioned;
default.value = {};
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 "";
};
};
};
targeted = lib.types.submodule lib'.types.package.targeted';
pname = lib.options.create {
description = "The program name for the package";
type = lib.types.nullish lib.types.string;
default.value = null;
};
targeted' = args @ {
name ? assert false; null,
config,
}: {
options = {
freeform = lib.types.any;
version = lib.options.create {
description = "The version for the package.";
type = lib.types.nullish lib.types.version;
default.value = null;
};
name = lib.options.create {
description = "The name of the package.";
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 {
description = "The namespace for the package.";
meta = {
description = lib.options.create {
description = "The description for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
pname = lib.options.create {
description = "The program name for the package.";
type = lib.types.string;
default = {
text = "<name> or \"unknown\"";
value =
if args ? name
then args.name
else "unknown";
};
};
version = lib.options.create {
description = "The version for the package.";
type = lib.types.nullish lib.types.version;
homepage = lib.options.create {
description = "The homepage for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
};
meta = lib.options.create {
description = "Metadata for the package.";
type = lib'.types.meta;
default.value = {
name = config.pname;
};
license = lib.options.create {
description = "The license for the package.";
type = lib.types.nullish lib'.types.license;
default.value = null;
};
platform = {
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 = "unknown";
};
host = lib.options.create {
description = "The host platform for the package.";
type = lib.types.string;
default.value = "unknown";
};
target = lib.options.create {
description = "The target platform for the package.";
type = lib.types.string;
default.value = "unknown";
};
};
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 = "The build platform for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
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 = "The host platform for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
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 = "The target platform for the package.";
type = lib.types.nullish lib.types.string;
default.value = null;
description = "Dependencies which are created in the build environment and are executed in the target environment.";
type = lib'.types.dependencies;
default.value = {};
};
};
phases = lib.options.create {
description = "Build 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;
};
package = lib.options.create {
description = "The built derivation.";
type = lib.types.derivation;
};
deps = {
build = {
only = lib.options.create {
description = "Dependencies which are only used in the build environment.";
type = lib'.types.dependencies.targeted;
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.targeted;
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.targeted;
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.targeted;
default.value = {};
};
host = {
only = lib.options.create {
description = "Dependencies which are only used 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.targeted;
default.value = {};
};
host = lib.options.create {
description = "Dependencies which are executed in the host environment.";
type = lib'.types.dependencies.targeted;
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.targeted;
default.value = {};
};
host = lib.options.create {
description = "Dependencies which are executed in the host 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.targeted;
default.value = {};
};
target = lib.options.create {
description = "Dependencies which are executed in the target environment.";
type = lib'.types.dependencies.targeted;
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 = {};
};
};
versions = lib.options.create {
description = "Available package versions.";
type = lib.types.attrs.of lib'.types.package.versioned;
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 = {};
};
};
};
config = {
package = config.builder.build config;
package = lib.options.create {
description = "The built derivation.";
type = lib.types.derivation;
default.value = config.builder.build config;
};
};
};
});
};
};
}

View file

@ -1,32 +1,37 @@
{
lib,
lib',
config,
options,
}: let
lib' = config.lib;
builders = config.builders;
in {
config = {
packages = {
generic = {
example = {
x = {
meta.platforms = ["i686-linux" "x86_64-linux"];
version = "1.0.0";
example = {
x = {
versions = {
"latest" = {config}: {
config = {
meta = {
platforms = ["i686-linux" "x86_64-linux"];
};
builder = config.builders.basic;
pname = "x";
version = "1.0.0";
phases = {
build = package: ''
make --build ${package.platform.build} --host ${package.platform.host}
'';
builder = builders.basic;
install = lib.dag.entry.after ["build"] ''
make install DESTDIR=$out
'';
};
phases = {
build = ''
make --build ${config.platform.build} --host ${config.platform.host}
'';
versions = {
"latest" = config.packages.generic.example.x;
install = lib.dag.entry.after ["build"] ''
make install DESTDIR=$out
'';
};
};
};
};
};

View file

@ -5,46 +5,23 @@
lib' = config.lib;
doubles = lib'.systems.doubles.all;
generic = config.packages.generic;
getPackages = system:
builtins.mapAttrs
(
namespace: packages:
lib.attrs.filter
(name: package: builtins.elem system package.meta.platforms)
packages
);
targeted = lib.attrs.generate lib'.systems.doubles.all (system:
getPackages system generic
// {
cross = lib.attrs.generate doubles (
host: getPackages host generic
);
});
in {
includes = [
./aux/foundation.nix
];
options = {
packages = {
generic = lib.options.create {
type = lib'.types.packages.generic;
default.value = {};
};
targeted = lib.options.create {
type = lib'.types.packages.targeted;
};
packages = lib.options.create {
description = "The package set.";
type = lib'.types.packages;
};
};
config = {
packages = {
inherit targeted;
preferences.packages = {
version = lib.options.create {
description = "The preferred package version when using aliases.";
type = lib.types.enum ["latest" "stable"];
default.value = "latest";
};
};
};
}