Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions lib/customisation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,14 @@ rec {
f = if isFunction fn then fn else import fn;
fargs = functionArgs f;

argSelectors = f.argSelectors or { };
selectedArgs = mapAttrs (_: select: select autoArgs) argSelectors;

customArgs = selectedArgs // args;

# All arguments that will be passed to the function
# This includes automatic ones and ones passed explicitly
allArgs = intersectAttrs fargs autoArgs // args;
allArgs = intersectAttrs fargs autoArgs // customArgs;

# a list of argument names that the function requires, but
# wouldn't be passed to it
Expand All @@ -278,7 +283,7 @@ rec {
# Get a list of suggested argument names for a given missing one
getSuggestions =
arg:
pipe (autoArgs // args) [
pipe (autoArgs // customArgs) [
attrNames
# Only use ones that are at most 2 edits away. While mork would work,
# levenshteinAtMost is only fast for 2 or less.
Expand Down Expand Up @@ -312,9 +317,20 @@ rec {
# Only show the error for the first missing argument
error = errorForArg (head (attrNames missingArgs));

result = makeOverridable f allArgs;
in
if missingArgs == { } then
makeOverridable f allArgs
if lib.isAttrs result then
result
// {
override =
result.override
// optionalAttrs (args == { }) {
inherit argSelectors;
};
}
else
result
# 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,
Expand Down Expand Up @@ -353,9 +369,25 @@ rec {
f = if isFunction fn then fn else import fn;
auto = intersectAttrs (functionArgs f) autoArgs;
mirrorArgs = mirrorFunctionArgs f;
origArgs = auto // args;

argSelectors = f.argSelectors or { };
selectedArgs = mapAttrs (_: select: select autoArgs) argSelectors;

customArgs = selectedArgs // args;
origArgs = auto // customArgs;
pkgs = f origArgs;
mkAttrOverridable = name: _: makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs;
mkAttrOverridable =
name: _:
let
result = makeOverridable (mirrorArgs (newArgs: (f newArgs).${name})) origArgs;
in
if isAttrs result then
result
// {
override = result.override // optionalAttrs (args == { }) { inherit argSelectors; };
}
else
result;
in
if isDerivation pkgs then
throw (
Expand All @@ -366,6 +398,19 @@ rec {
else
mapAttrs mkAttrOverridable pkgs;

makeCallPackageWithArgSelectors =
callPackage: fn: extraArgSelectors:
let
f = if isFunction fn then fn else import fn;
f' = if isAttrs f then f else mirrorFunctionArgs f f;
in
callPackage (
f'
// {
argSelectors = f.argSelectors or { } // extraArgSelectors;
}
) { };

/**
Add attributes to each output of a derivation without changing
the derivation itself and check a given condition when evaluating.
Expand Down
1 change: 1 addition & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ let
makeOverridable
callPackageWith
callPackagesWith
makeCallPackageWithArgSelectors
extendDerivation
hydraJob
makeScope
Expand Down
34 changes: 33 additions & 1 deletion pkgs/top-level/by-name-overlay.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ let
lib = import ../../lib;

inherit (builtins)
pathExists
readDir
;

inherit (lib.attrsets)
getAttrFromPath
mapAttrs
mapAttrsToList
mergeAttrsList
optionalAttrs
;

inherit (lib.customisation)
makeCallPackageWithArgSelectors
;

# Package files for a single shard
Expand Down Expand Up @@ -49,6 +56,31 @@ self: super:
# and whether it's defined by this file here or `all-packages.nix`.
# TODO: This can be removed once `pkgs/by-name` can handle custom `callPackage` arguments without `all-packages.nix` (or any other way of achieving the same result).
# Because at that point the code in ./stage.nix can be changed to not allow definitions in `all-packages.nix` to override ones from `pkgs/by-name` anymore and throw an error if that happens instead.
_internalCallByNamePackageFile = file: self.callPackage file { };
_internalCallByNamePackageFile =
file:
let
fArg = import file;
isSibling = fArg.type or null == "sibling";
fArg' =
if isSibling then
(
if fArg ? package then
self.${fArg.package}
else if fArg ? packagePath then
getAttrFromPath fArg.packagePath self
else
throw "${baseNameOf (dirOf file)}: expect `package' or `packagePath' in sibling metadata."
).override
else
fArg;
transform = if isSibling && (fArg ? transform) then fArg.transform else { package, ... }: package;
package = makeCallPackageWithArgSelectors self.callPackage fArg' (
let
argSelectorsFile = "${toString (dirOf file)}/arg-selectors.nix";
in
optionalAttrs (pathExists argSelectorsFile) (import argSelectorsFile)
);
in
transform { inherit lib package; };
}
// mapAttrs (name: self._internalCallByNamePackageFile) packageFiles
2 changes: 2 additions & 0 deletions pkgs/top-level/splice.nix
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ in

callPackages = lib.callPackagesWith pkgsForCall;

callPackageWithArgSelectors = lib.makeCallPackageWithArgSelectors pkgs.callPackage;

newScope = extra: lib.callPackageWith (pkgsForCall // extra);

pkgs = if actuallySplice then splicedPackages // { recurseForDerivations = false; } else pkgs;
Expand Down
Loading