2024-08-29 11:37:23 +00:00
|
|
|
{ lib, config, inputs, extendModules, partitionStack, self, ... }:
|
|
|
|
let
|
|
|
|
inherit (lib)
|
|
|
|
literalMD
|
|
|
|
mapAttrs
|
|
|
|
mkOption
|
|
|
|
optionalAttrs
|
|
|
|
types
|
|
|
|
;
|
|
|
|
|
|
|
|
partitionModule = { config, options, name, ... }: {
|
|
|
|
options = {
|
|
|
|
extraInputsFlake = mkOption {
|
|
|
|
type = types.raw;
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
Location of a flake whose inputs to add to the inputs module argument in the partition.
|
2024-08-30 10:55:33 +00:00
|
|
|
Note that flake `follows` are resolved without any awareness of inputs that are not in the flake.
|
|
|
|
As a consequence, a `follows` entry in the flake inputs can not refer to inputs that are not in that specific flake.
|
|
|
|
|
|
|
|
Implementation note: if the type of `extraInputsFlake` is a path, it is loaded with an expression-based reimplementation of `builtins.getFlake`, as `getFlake` is incapable of loading paths in pure mode as of writing.
|
2024-08-29 11:37:23 +00:00
|
|
|
'';
|
2024-08-30 10:55:33 +00:00
|
|
|
example = lib.literalExpression "./dev";
|
2024-08-29 11:37:23 +00:00
|
|
|
};
|
|
|
|
extraInputs = mkOption {
|
|
|
|
type = types.lazyAttrsOf types.raw;
|
|
|
|
description = ''
|
|
|
|
Extra inputs to add to the inputs module argument in the partition.
|
|
|
|
|
|
|
|
This can be used as a workaround for the fact that transitive inputs are locked in the "end user" flake.
|
|
|
|
That's not desirable for inputs they don't need, such as development inputs.
|
|
|
|
'';
|
|
|
|
default = { };
|
|
|
|
defaultText = literalMD ''
|
|
|
|
if `extraInputsFlake` is set, then `builtins.getFlake extraInputsFlake`, else `{ }`
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
module = mkOption {
|
|
|
|
type = (extendModules {
|
|
|
|
specialArgs =
|
|
|
|
let
|
|
|
|
inputs2 = inputs // config.extraInputs // {
|
|
|
|
self = self2;
|
|
|
|
};
|
|
|
|
self2 = self // {
|
|
|
|
inputs = inputs2;
|
|
|
|
};
|
|
|
|
in
|
|
|
|
{
|
|
|
|
inputs = inputs2;
|
|
|
|
self = self2;
|
|
|
|
partitionStack = partitionStack ++ [ name ];
|
|
|
|
};
|
|
|
|
}).type;
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
A re-evaluation of the flake-parts top level modules.
|
|
|
|
|
2024-08-30 10:55:33 +00:00
|
|
|
You may define config definitions, `imports`, etc here, and it can be read like any other submodule.
|
|
|
|
'';
|
|
|
|
example = lib.literalExpression ''
|
|
|
|
{
|
|
|
|
imports = [
|
|
|
|
./dev/flake-module.nix
|
|
|
|
];
|
|
|
|
}
|
2024-08-29 11:37:23 +00:00
|
|
|
'';
|
2024-08-30 10:55:33 +00:00
|
|
|
visible = "shallow";
|
2024-08-29 11:37:23 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
config = {
|
|
|
|
extraInputs = lib.mkIf options.extraInputsFlake.isDefined (
|
|
|
|
let
|
|
|
|
p = options.extraInputsFlake.value;
|
|
|
|
flake =
|
|
|
|
if builtins.typeOf p == "path"
|
|
|
|
then get-flake p
|
|
|
|
else builtins.getFlake p;
|
|
|
|
in
|
|
|
|
flake.inputs
|
|
|
|
);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
# Nix does not recognize that a flake like "${./dev}", which is a content
|
|
|
|
# addressed store path is a pure input, so we have to fetch and wire it
|
|
|
|
# manually with get-flake.
|
|
|
|
# TODO: update this
|
|
|
|
get-flake = import (builtins.fetchTree {
|
|
|
|
type = "github";
|
|
|
|
owner = "ursi";
|
|
|
|
repo = "get-flake";
|
|
|
|
rev = "a6c57417d1b857b8be53aba4095869a0f438c502";
|
|
|
|
});
|
|
|
|
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
partitionedAttrs = mkOption {
|
|
|
|
type = types.attrsOf types.str;
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
A set of flake output attributes that are taken from a partition instead of the default top level flake-parts evaluation.
|
|
|
|
|
|
|
|
The attribute name refers to the flake output attribute name, and the value is the name of the partition to use.
|
|
|
|
|
|
|
|
The flake attributes are overridden with `lib.mkForce` priority.
|
|
|
|
|
|
|
|
See the `partitions` options to understand the purpose.
|
|
|
|
'';
|
2024-08-30 10:55:33 +00:00
|
|
|
example = {
|
|
|
|
"devShells" = "dev";
|
|
|
|
"checks" = "dev";
|
|
|
|
"herculesCI" = "dev";
|
|
|
|
};
|
2024-08-29 11:37:23 +00:00
|
|
|
};
|
|
|
|
partitions = mkOption {
|
|
|
|
type = types.attrsOf (types.submodule partitionModule);
|
|
|
|
default = { };
|
|
|
|
description = ''
|
|
|
|
By partitioning the flake, you can avoid fetching inputs that are not
|
|
|
|
needed for the evaluation of a particular attribute.
|
|
|
|
|
|
|
|
Each partition is a distinct module system evaluation. This allows
|
|
|
|
attributes of the final flake to be defined by multiple sets of modules,
|
|
|
|
so that for example the `packages` attribute can be evaluated without
|
|
|
|
loading development related inputs.
|
|
|
|
|
|
|
|
While the module system does a good job at preserving laziness, the fact
|
|
|
|
that a development related import can define `packages` means that
|
|
|
|
in order to evaluate `packages`, you need to evaluate at least to the
|
|
|
|
point where you can conclude that the development related import does
|
|
|
|
not actually define a `packages` attribute. While the actual evaluation
|
|
|
|
is cheap, it can only happen after fetching the input, which is not
|
|
|
|
as cheap.
|
|
|
|
'';
|
2024-08-30 10:55:33 +00:00
|
|
|
example = lib.literalExpression ''
|
|
|
|
{
|
|
|
|
dev = {
|
|
|
|
extraInputsFlake = ./dev;
|
|
|
|
module = ./dev/flake-module.nix;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
2024-08-29 11:37:23 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
config = {
|
|
|
|
# Default, overriden with specialArgs inside partitions.
|
|
|
|
_module.args.partitionStack = [ ];
|
|
|
|
flake = optionalAttrs (partitionStack == [ ]) (
|
|
|
|
mapAttrs
|
|
|
|
(attrName: partition: lib.mkForce (config.partitions.${partition}.module.flake.${attrName}))
|
|
|
|
config.partitionedAttrs
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|