mirror of
https://github.com/hercules-ci/flake-parts.git
synced 2024-12-14 11:47:31 +00:00
f427ecf1a0
The difference is that moduleLocation is "guaranteed" reliable data, whereas errorLocation is the best choice for error messages in the core. moduleLocation is suitable for the module key attribute. errorLocation is best for the *ROOT* module _file attribute. Initially I applied errorLocation in too many places. It is only needed when the flake output attribute names are strict in it. To avoid confusion, I'm not exposing errorLocation to the modules, until we have a concrete use case for it.
241 lines
7.2 KiB
Nix
241 lines
7.2 KiB
Nix
{ lib
|
|
# Optionally a string with extra version info to be included in the error message
|
|
# in case is lib is out of date. Empty or starts with space.
|
|
, revInfo ? ""
|
|
}:
|
|
let
|
|
inherit (lib)
|
|
mkOption
|
|
mkOptionType
|
|
defaultFunctor
|
|
isAttrs
|
|
isFunction
|
|
showOption
|
|
throwIf
|
|
types
|
|
warnIf
|
|
getAttrFromPath
|
|
setAttrByPath
|
|
attrByPath
|
|
optionalAttrs
|
|
;
|
|
inherit (lib.modules)
|
|
mkAliasAndWrapDefsWithPriority;
|
|
inherit (lib.types)
|
|
path
|
|
submoduleWith
|
|
;
|
|
|
|
# Polyfill isFlake until Nix with https://github.com/NixOS/nix/pull/7207 is common
|
|
isFlake = maybeFlake:
|
|
if maybeFlake ? _type
|
|
then maybeFlake._type == "flake"
|
|
else maybeFlake ? inputs && maybeFlake ? outputs && maybeFlake ? sourceInfo;
|
|
|
|
# Polyfill https://github.com/NixOS/nixpkgs/pull/163617
|
|
deferredModuleWith = lib.deferredModuleWith or (
|
|
attrs@{ staticModules ? [ ] }: mkOptionType {
|
|
name = "deferredModule";
|
|
description = "module";
|
|
check = x: isAttrs x || isFunction x || path.check x;
|
|
merge = loc: defs: staticModules ++ map (def: lib.setDefaultModuleLocation "${def.file}, via option ${showOption loc}" def.value) defs;
|
|
inherit (submoduleWith { modules = staticModules; })
|
|
getSubOptions
|
|
getSubModules;
|
|
substSubModules = m: deferredModuleWith (attrs // {
|
|
staticModules = m;
|
|
});
|
|
functor = defaultFunctor "deferredModuleWith" // {
|
|
type = deferredModuleWith;
|
|
payload = {
|
|
inherit staticModules;
|
|
};
|
|
binOp = lhs: rhs: {
|
|
staticModules = lhs.staticModules ++ rhs.staticModules;
|
|
};
|
|
};
|
|
}
|
|
);
|
|
|
|
errorExample = ''
|
|
For example:
|
|
|
|
outputs = inputs@{ flake-parts, ... }:
|
|
flake-parts.lib.mkFlake { inherit inputs; } { /* module */ };
|
|
|
|
To avoid an infinite recursion, *DO NOT* pass `self.inputs` and
|
|
*DO NOT* pass `inherit (self) inputs`, but pass the output function
|
|
arguments as `inputs` like above.
|
|
'';
|
|
|
|
flake-parts-lib = rec {
|
|
evalFlakeModule =
|
|
args@
|
|
{ inputs ? self.inputs
|
|
, specialArgs ? { }
|
|
|
|
# legacy
|
|
, self ? inputs.self or (throw ''
|
|
When invoking flake-parts, you must pass all the flake output arguments,
|
|
and not just `self.inputs`.
|
|
|
|
${errorExample}
|
|
'')
|
|
, moduleLocation ? "${self.outPath}/flake.nix"
|
|
}:
|
|
let
|
|
module = lib.setDefaultModuleLocation errorLocation module;
|
|
inputsPos = builtins.unsafeGetAttrPos "inputs" args;
|
|
errorLocation =
|
|
# Best case: user makes it explicit
|
|
args.moduleLocation or (
|
|
# Slightly worse: Nix does not technically commit to unsafeGetAttrPos semantics
|
|
if inputsPos != null
|
|
then inputsPos.file
|
|
# Slightly worse: self may not be valid when an error occurs
|
|
else if args?inputs.self.outPath
|
|
then args.inputs.self.outPath + "/flake.nix"
|
|
# Fallback
|
|
else "<mkFlake argument>"
|
|
);
|
|
in
|
|
throwIf
|
|
(!args?self && !args?inputs) ''
|
|
When invoking flake-parts, you must pass in the flake output arguments.
|
|
|
|
${errorExample}
|
|
''
|
|
warnIf
|
|
(!args?inputs) ''
|
|
When invoking flake-parts, it is recommended to pass all the flake output
|
|
arguments in the `inputs` parameter. If you only pass `self`, it's not
|
|
possible to use the `inputs` module argument in the module `imports`.
|
|
|
|
Please pass the output function arguments. ${errorExample}
|
|
''
|
|
|
|
(module:
|
|
lib.evalModules {
|
|
specialArgs = {
|
|
inherit self flake-parts-lib moduleLocation;
|
|
inputs = args.inputs or /* legacy, warned above */ self.inputs;
|
|
} // specialArgs;
|
|
modules = [ ./all-modules.nix module ];
|
|
}
|
|
);
|
|
|
|
# Function to extract the default flakeModule from
|
|
# what may be a flake, returning the argument unmodified
|
|
# if it's not a flake.
|
|
#
|
|
# Useful to map over an 'imports' list to make it less
|
|
# verbose in the common case.
|
|
defaultModule = maybeFlake:
|
|
if isFlake maybeFlake
|
|
then maybeFlake.flakeModules.default or maybeFlake
|
|
else maybeFlake;
|
|
|
|
mkFlake = args: module:
|
|
let
|
|
eval = flake-parts-lib.evalFlakeModule args module;
|
|
in
|
|
eval.config.flake;
|
|
|
|
# For extending options in an already declared submodule.
|
|
# Workaround for https://github.com/NixOS/nixpkgs/issues/146882
|
|
mkSubmoduleOptions =
|
|
options:
|
|
mkOption {
|
|
type = types.submoduleWith {
|
|
modules = [{ inherit options; }];
|
|
};
|
|
};
|
|
|
|
mkDeferredModuleType =
|
|
module:
|
|
deferredModuleWith {
|
|
staticModules = [ module ];
|
|
};
|
|
mkPerSystemType = mkDeferredModuleType;
|
|
|
|
mkDeferredModuleOption =
|
|
module:
|
|
mkOption {
|
|
type = flake-parts-lib.mkPerSystemType module;
|
|
};
|
|
mkPerSystemOption = mkDeferredModuleOption;
|
|
|
|
# Helper function for defining a per-system option that
|
|
# gets transposed by the usual flake system logic to a
|
|
# top-level flake attribute.
|
|
mkTransposedPerSystemModule = { name, option, file }: {
|
|
_file = file;
|
|
|
|
options = {
|
|
flake = flake-parts-lib.mkSubmoduleOptions {
|
|
${name} = mkOption {
|
|
type = types.lazyAttrsOf option.type;
|
|
default = { };
|
|
description = ''
|
|
See {option}`perSystem.${name}` for description and examples.
|
|
'';
|
|
};
|
|
};
|
|
|
|
perSystem = flake-parts-lib.mkPerSystemOption {
|
|
_file = file;
|
|
|
|
options.${name} = option;
|
|
};
|
|
};
|
|
|
|
config = {
|
|
transposition.${name} = { };
|
|
};
|
|
};
|
|
|
|
# Needed pending https://github.com/NixOS/nixpkgs/pull/198450
|
|
mkAliasOptionModule = from: to: { config, options, ... }:
|
|
let
|
|
fromOpt = getAttrFromPath from options;
|
|
toOf = attrByPath to
|
|
(abort "Renaming error: option `${showOption to}' does not exist.");
|
|
toType = let opt = attrByPath to { } options; in opt.type or (types.submodule { });
|
|
in
|
|
{
|
|
options = setAttrByPath from (mkOption
|
|
{
|
|
visible = true;
|
|
description = lib.mdDoc "Alias of {option}`${showOption to}`.";
|
|
apply = x: (toOf config);
|
|
} // optionalAttrs (toType != null) {
|
|
type = toType;
|
|
});
|
|
config = mkAliasAndWrapDefsWithPriority (setAttrByPath to) fromOpt;
|
|
};
|
|
|
|
# Helper function for importing while preserving module location. To be added
|
|
# in nixpkgs: https://github.com/NixOS/nixpkgs/pull/230588
|
|
# I expect these functions to remain identical. This one will stick around
|
|
# for a while to support older nixpkgs-lib.
|
|
importApply =
|
|
modulePath: staticArgs:
|
|
lib.setDefaultModuleLocation modulePath (import modulePath staticArgs);
|
|
};
|
|
|
|
# A best effort, lenient estimate. Please use a recent nixpkgs lib if you
|
|
# override it at all.
|
|
minVersion = "22.05";
|
|
|
|
in
|
|
|
|
if builtins.compareVersions lib.version minVersion < 0
|
|
then
|
|
abort ''
|
|
The nixpkgs-lib dependency of flake-parts was overridden but is too old.
|
|
The minimum supported version of nixpkgs-lib is ${minVersion},
|
|
but the actual version is ${lib.version}${revInfo}.
|
|
''
|
|
else
|
|
|
|
flake-parts-lib
|