callPackageWith
lib.customisation.callPackageWith
Docs pulled from | This Revision | 43 minutes ago
Call the package function in the file fn
with the required
arguments automatically. The function is called with the
arguments args
, but any missing arguments are obtained from
autoArgs
. This function is intended to be partially
parameterised, e.g.,
callPackage = callPackageWith pkgs;
pkgs = {
libfoo = callPackage ./foo.nix { };
libbar = callPackage ./bar.nix { };
};
If the libbar
function expects an argument named libfoo
, it is
automatically passed as an argument. Overrides or missing
arguments can be supplied in args
, e.g.
libbar = callPackage ./bar.nix {
libfoo = null;
enableX11 = true;
};
Inputs
autoArgs
-
1. Function argument
fn
-
2. Function argument
args
-
3. Function argument
Type
callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
Noogle detected
Implementation
The following is the current implementation of this function.
callPackageWith =
autoArgs: fn: args:
let
f = if isFunction fn then fn else import fn;
fargs = functionArgs f;
# All arguments that will be passed to the function
# This includes automatic ones and ones passed explicitly
allArgs = intersectAttrs fargs autoArgs // args;
# a list of argument names that the function requires, but
# wouldn't be passed to it
missingArgs =
# Filter out arguments that have a default value
(
filterAttrs (name: value: !value)
# Filter out arguments that would be passed
(removeAttrs fargs (attrNames allArgs))
);
# Get a list of suggested argument names for a given missing one
getSuggestions =
arg:
pipe (autoArgs // args) [
attrNames
# Only use ones that are at most 2 edits away. While mork would work,
# levenshteinAtMost is only fast for 2 or less.
(filter (levenshteinAtMost 2 arg))
# Put strings with shorter distance first
(sortOn (levenshtein arg))
# Only take the first couple results
(take 3)
# Quote all entries
(map (x: "\"" + x + "\""))
];
prettySuggestions =
suggestions:
if suggestions == [ ] then
""
else if length suggestions == 1 then
", did you mean ${elemAt suggestions 0}?"
else
", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
errorForArg =
arg:
let
loc = builtins.unsafeGetAttrPos arg fargs;
# loc' can be removed once lib/minver.nix is >2.3.4, since that includes
# https://github.com/NixOS/nix/pull/3468 which makes loc be non-null
loc' =
if loc != null then
loc.file + ":" + toString loc.line
else if !isFunction fn then
toString fn + optionalString (pathIsDirectory fn) "/default.nix"
else
"<unknown location>";
in
"Function called without required argument \"${arg}\" at "
+ "${loc'}${prettySuggestions (getSuggestions arg)}";
# Only show the error for the first missing argument
error = errorForArg (head (attrNames missingArgs));
in
if missingArgs == { } then
makeOverridable f allArgs
# This needs to be an abort so it can't be caught with `builtins.tryEval`,
# which is used by nix-env and ofborg to filter out packages that don't evaluate.
# This way we're forced to fix such errors in Nixpkgs,
# which is especially relevant with allowAliases = false
else
abort "lib.customisation.callPackageWith: ${error}";