query
On this page

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

Aliases

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}";