{ 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} '') }: 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; 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 loc = if args?inputs.self.outPath then args.inputs.self.outPath + "/flake.nix" else ""; mod = lib.setDefaultModuleLocation loc module; eval = flake-parts-lib.evalFlakeModule args mod; 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