mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-07-14 06:00:33 +03:00
Merge pull request #270299 from adisbladis/lib-customisation-allocs
lib.customisation: Refactor nested set access & avoid some allocations
This commit is contained in:
commit
fc2b2af15e
1 changed files with 51 additions and 40 deletions
|
@ -1,5 +1,16 @@
|
||||||
{ lib }:
|
{ lib }:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (builtins)
|
||||||
|
intersectAttrs;
|
||||||
|
inherit (lib)
|
||||||
|
functionArgs isFunction mirrorFunctionArgs isAttrs setFunctionArgs levenshteinAtMost
|
||||||
|
optionalAttrs attrNames levenshtein filter elemAt concatStringsSep sort take length
|
||||||
|
filterAttrs optionalString flip pathIsDirectory head pipe isDerivation listToAttrs
|
||||||
|
mapAttrs seq flatten deepSeq warnIf isInOldestRelease extends
|
||||||
|
;
|
||||||
|
|
||||||
|
in
|
||||||
rec {
|
rec {
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,15 +54,15 @@ rec {
|
||||||
overrideDerivation = drv: f:
|
overrideDerivation = drv: f:
|
||||||
let
|
let
|
||||||
newDrv = derivation (drv.drvAttrs // (f drv));
|
newDrv = derivation (drv.drvAttrs // (f drv));
|
||||||
in lib.flip (extendDerivation (builtins.seq drv.drvPath true)) newDrv (
|
in flip (extendDerivation (seq drv.drvPath true)) newDrv (
|
||||||
{ meta = drv.meta or {};
|
{ meta = drv.meta or {};
|
||||||
passthru = if drv ? passthru then drv.passthru else {};
|
passthru = if drv ? passthru then drv.passthru else {};
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
(drv.passthru or {})
|
(drv.passthru or {})
|
||||||
//
|
//
|
||||||
lib.optionalAttrs (drv ? __spliced) {
|
optionalAttrs (drv ? __spliced) {
|
||||||
__spliced = {} // (lib.mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced);
|
__spliced = {} // (mapAttrs (_: sDrv: overrideDerivation sDrv f) drv.__spliced);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,30 +90,30 @@ rec {
|
||||||
makeOverridable = f:
|
makeOverridable = f:
|
||||||
let
|
let
|
||||||
# Creates a functor with the same arguments as f
|
# Creates a functor with the same arguments as f
|
||||||
mirrorArgs = lib.mirrorFunctionArgs f;
|
mirrorArgs = mirrorFunctionArgs f;
|
||||||
in
|
in
|
||||||
mirrorArgs (origArgs:
|
mirrorArgs (origArgs:
|
||||||
let
|
let
|
||||||
result = f origArgs;
|
result = f origArgs;
|
||||||
|
|
||||||
# Changes the original arguments with (potentially a function that returns) a set of new attributes
|
# Changes the original arguments with (potentially a function that returns) a set of new attributes
|
||||||
overrideWith = newArgs: origArgs // (if lib.isFunction newArgs then newArgs origArgs else newArgs);
|
overrideWith = newArgs: origArgs // (if isFunction newArgs then newArgs origArgs else newArgs);
|
||||||
|
|
||||||
# Re-call the function but with different arguments
|
# Re-call the function but with different arguments
|
||||||
overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs));
|
overrideArgs = mirrorArgs (newArgs: makeOverridable f (overrideWith newArgs));
|
||||||
# Change the result of the function call by applying g to it
|
# Change the result of the function call by applying g to it
|
||||||
overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
|
overrideResult = g: makeOverridable (mirrorArgs (args: g (f args))) origArgs;
|
||||||
in
|
in
|
||||||
if builtins.isAttrs result then
|
if isAttrs result then
|
||||||
result // {
|
result // {
|
||||||
override = overrideArgs;
|
override = overrideArgs;
|
||||||
overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
|
overrideDerivation = fdrv: overrideResult (x: overrideDerivation x fdrv);
|
||||||
${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
|
${if result ? overrideAttrs then "overrideAttrs" else null} = fdrv:
|
||||||
overrideResult (x: x.overrideAttrs fdrv);
|
overrideResult (x: x.overrideAttrs fdrv);
|
||||||
}
|
}
|
||||||
else if lib.isFunction result then
|
else if isFunction result then
|
||||||
# Transform the result into a functor while propagating its arguments
|
# Transform the result into a functor while propagating its arguments
|
||||||
lib.setFunctionArgs result (lib.functionArgs result) // {
|
setFunctionArgs result (functionArgs result) // {
|
||||||
override = overrideArgs;
|
override = overrideArgs;
|
||||||
}
|
}
|
||||||
else result);
|
else result);
|
||||||
|
@ -140,39 +151,39 @@ rec {
|
||||||
*/
|
*/
|
||||||
callPackageWith = autoArgs: fn: args:
|
callPackageWith = autoArgs: fn: args:
|
||||||
let
|
let
|
||||||
f = if lib.isFunction fn then fn else import fn;
|
f = if isFunction fn then fn else import fn;
|
||||||
fargs = lib.functionArgs f;
|
fargs = functionArgs f;
|
||||||
|
|
||||||
# All arguments that will be passed to the function
|
# All arguments that will be passed to the function
|
||||||
# This includes automatic ones and ones passed explicitly
|
# This includes automatic ones and ones passed explicitly
|
||||||
allArgs = builtins.intersectAttrs fargs autoArgs // args;
|
allArgs = intersectAttrs fargs autoArgs // args;
|
||||||
|
|
||||||
# a list of argument names that the function requires, but
|
# a list of argument names that the function requires, but
|
||||||
# wouldn't be passed to it
|
# wouldn't be passed to it
|
||||||
missingArgs = lib.attrNames
|
missingArgs =
|
||||||
# Filter out arguments that have a default value
|
# Filter out arguments that have a default value
|
||||||
(lib.filterAttrs (name: value: ! value)
|
(filterAttrs (name: value: ! value)
|
||||||
# Filter out arguments that would be passed
|
# Filter out arguments that would be passed
|
||||||
(removeAttrs fargs (lib.attrNames allArgs)));
|
(removeAttrs fargs (attrNames allArgs)));
|
||||||
|
|
||||||
# Get a list of suggested argument names for a given missing one
|
# Get a list of suggested argument names for a given missing one
|
||||||
getSuggestions = arg: lib.pipe (autoArgs // args) [
|
getSuggestions = arg: pipe (autoArgs // args) [
|
||||||
lib.attrNames
|
attrNames
|
||||||
# Only use ones that are at most 2 edits away. While mork would work,
|
# Only use ones that are at most 2 edits away. While mork would work,
|
||||||
# levenshteinAtMost is only fast for 2 or less.
|
# levenshteinAtMost is only fast for 2 or less.
|
||||||
(lib.filter (lib.strings.levenshteinAtMost 2 arg))
|
(filter (levenshteinAtMost 2 arg))
|
||||||
# Put strings with shorter distance first
|
# Put strings with shorter distance first
|
||||||
(lib.sort (x: y: lib.strings.levenshtein x arg < lib.strings.levenshtein y arg))
|
(sort (x: y: levenshtein x arg < levenshtein y arg))
|
||||||
# Only take the first couple results
|
# Only take the first couple results
|
||||||
(lib.take 3)
|
(take 3)
|
||||||
# Quote all entries
|
# Quote all entries
|
||||||
(map (x: "\"" + x + "\""))
|
(map (x: "\"" + x + "\""))
|
||||||
];
|
];
|
||||||
|
|
||||||
prettySuggestions = suggestions:
|
prettySuggestions = suggestions:
|
||||||
if suggestions == [] then ""
|
if suggestions == [] then ""
|
||||||
else if lib.length suggestions == 1 then ", did you mean ${lib.elemAt suggestions 0}?"
|
else if length suggestions == 1 then ", did you mean ${elemAt suggestions 0}?"
|
||||||
else ", did you mean ${lib.concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
|
else ", did you mean ${concatStringsSep ", " (lib.init suggestions)} or ${lib.last suggestions}?";
|
||||||
|
|
||||||
errorForArg = arg:
|
errorForArg = arg:
|
||||||
let
|
let
|
||||||
|
@ -180,16 +191,16 @@ rec {
|
||||||
# loc' can be removed once lib/minver.nix is >2.3.4, since that includes
|
# 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
|
# https://github.com/NixOS/nix/pull/3468 which makes loc be non-null
|
||||||
loc' = if loc != null then loc.file + ":" + toString loc.line
|
loc' = if loc != null then loc.file + ":" + toString loc.line
|
||||||
else if ! lib.isFunction fn then
|
else if ! isFunction fn then
|
||||||
toString fn + lib.optionalString (lib.sources.pathIsDirectory fn) "/default.nix"
|
toString fn + optionalString (pathIsDirectory fn) "/default.nix"
|
||||||
else "<unknown location>";
|
else "<unknown location>";
|
||||||
in "Function called without required argument \"${arg}\" at "
|
in "Function called without required argument \"${arg}\" at "
|
||||||
+ "${loc'}${prettySuggestions (getSuggestions arg)}";
|
+ "${loc'}${prettySuggestions (getSuggestions arg)}";
|
||||||
|
|
||||||
# Only show the error for the first missing argument
|
# Only show the error for the first missing argument
|
||||||
error = errorForArg (lib.head missingArgs);
|
error = errorForArg missingArgs.${head (attrNames missingArgs)};
|
||||||
|
|
||||||
in if missingArgs == [] then makeOverridable f allArgs else abort error;
|
in if missingArgs == {} then makeOverridable f allArgs else abort error;
|
||||||
|
|
||||||
|
|
||||||
/* Like callPackage, but for a function that returns an attribute
|
/* Like callPackage, but for a function that returns an attribute
|
||||||
|
@ -201,17 +212,17 @@ rec {
|
||||||
*/
|
*/
|
||||||
callPackagesWith = autoArgs: fn: args:
|
callPackagesWith = autoArgs: fn: args:
|
||||||
let
|
let
|
||||||
f = if lib.isFunction fn then fn else import fn;
|
f = if isFunction fn then fn else import fn;
|
||||||
auto = builtins.intersectAttrs (lib.functionArgs f) autoArgs;
|
auto = intersectAttrs (functionArgs f) autoArgs;
|
||||||
origArgs = auto // args;
|
origArgs = auto // args;
|
||||||
pkgs = f origArgs;
|
pkgs = f origArgs;
|
||||||
mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
|
mkAttrOverridable = name: _: makeOverridable (newArgs: (f newArgs).${name}) origArgs;
|
||||||
in
|
in
|
||||||
if lib.isDerivation pkgs then throw
|
if isDerivation pkgs then throw
|
||||||
("function `callPackages` was called on a *single* derivation "
|
("function `callPackages` was called on a *single* derivation "
|
||||||
+ ''"${pkgs.name or "<unknown-name>"}";''
|
+ ''"${pkgs.name or "<unknown-name>"}";''
|
||||||
+ " did you mean to use `callPackage` instead?")
|
+ " did you mean to use `callPackage` instead?")
|
||||||
else lib.mapAttrs mkAttrOverridable pkgs;
|
else mapAttrs mkAttrOverridable pkgs;
|
||||||
|
|
||||||
|
|
||||||
/* Add attributes to each output of a derivation without changing
|
/* Add attributes to each output of a derivation without changing
|
||||||
|
@ -224,7 +235,7 @@ rec {
|
||||||
let
|
let
|
||||||
outputs = drv.outputs or [ "out" ];
|
outputs = drv.outputs or [ "out" ];
|
||||||
|
|
||||||
commonAttrs = drv // (builtins.listToAttrs outputsList) //
|
commonAttrs = drv // (listToAttrs outputsList) //
|
||||||
({ all = map (x: x.value) outputsList; }) // passthru;
|
({ all = map (x: x.value) outputsList; }) // passthru;
|
||||||
|
|
||||||
outputToAttrListElement = outputName:
|
outputToAttrListElement = outputName:
|
||||||
|
@ -238,7 +249,7 @@ rec {
|
||||||
# TODO: give the derivation control over the outputs.
|
# TODO: give the derivation control over the outputs.
|
||||||
# `overrideAttrs` may not be the only attribute that needs
|
# `overrideAttrs` may not be the only attribute that needs
|
||||||
# updating when switching outputs.
|
# updating when switching outputs.
|
||||||
lib.optionalAttrs (passthru?overrideAttrs) {
|
optionalAttrs (passthru?overrideAttrs) {
|
||||||
# TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
|
# TODO: also add overrideAttrs when overrideAttrs is not custom, e.g. when not splicing.
|
||||||
overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
|
overrideAttrs = f: (passthru.overrideAttrs f).${outputName};
|
||||||
};
|
};
|
||||||
|
@ -264,11 +275,11 @@ rec {
|
||||||
|
|
||||||
commonAttrs =
|
commonAttrs =
|
||||||
{ inherit (drv) name system meta; inherit outputs; }
|
{ inherit (drv) name system meta; inherit outputs; }
|
||||||
// lib.optionalAttrs (drv._hydraAggregate or false) {
|
// optionalAttrs (drv._hydraAggregate or false) {
|
||||||
_hydraAggregate = true;
|
_hydraAggregate = true;
|
||||||
constituents = map hydraJob (lib.flatten drv.constituents);
|
constituents = map hydraJob (flatten drv.constituents);
|
||||||
}
|
}
|
||||||
// (lib.listToAttrs outputsList);
|
// (listToAttrs outputsList);
|
||||||
|
|
||||||
makeOutput = outputName:
|
makeOutput = outputName:
|
||||||
let output = drv.${outputName}; in
|
let output = drv.${outputName}; in
|
||||||
|
@ -283,9 +294,9 @@ rec {
|
||||||
|
|
||||||
outputsList = map makeOutput outputs;
|
outputsList = map makeOutput outputs;
|
||||||
|
|
||||||
drv' = (lib.head outputsList).value;
|
drv' = (head outputsList).value;
|
||||||
in if drv == null then null else
|
in if drv == null then null else
|
||||||
lib.deepSeq drv' drv';
|
deepSeq drv' drv';
|
||||||
|
|
||||||
/* Make a set of packages with a common scope. All packages called
|
/* Make a set of packages with a common scope. All packages called
|
||||||
with the provided `callPackage` will be evaluated with the same
|
with the provided `callPackage` will be evaluated with the same
|
||||||
|
@ -304,11 +315,11 @@ rec {
|
||||||
let self = f self // {
|
let self = f self // {
|
||||||
newScope = scope: newScope (self // scope);
|
newScope = scope: newScope (self // scope);
|
||||||
callPackage = self.newScope {};
|
callPackage = self.newScope {};
|
||||||
overrideScope = g: makeScope newScope (lib.fixedPoints.extends g f);
|
overrideScope = g: makeScope newScope (extends g f);
|
||||||
# Remove after 24.11 is released.
|
# Remove after 24.11 is released.
|
||||||
overrideScope' = g: lib.warnIf (lib.isInOldestRelease 2311)
|
overrideScope' = g: warnIf (isInOldestRelease 2311)
|
||||||
"`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`."
|
"`overrideScope'` (from `lib.makeScope`) has been renamed to `overrideScope`."
|
||||||
(makeScope newScope (lib.fixedPoints.extends g f));
|
(makeScope newScope (extends g f));
|
||||||
packages = f;
|
packages = f;
|
||||||
};
|
};
|
||||||
in self;
|
in self;
|
||||||
|
@ -384,7 +395,7 @@ rec {
|
||||||
overrideScope = g: (makeScopeWithSplicing'
|
overrideScope = g: (makeScopeWithSplicing'
|
||||||
{ inherit splicePackages newScope; }
|
{ inherit splicePackages newScope; }
|
||||||
{ inherit otherSplices keep extra;
|
{ inherit otherSplices keep extra;
|
||||||
f = lib.fixedPoints.extends g f;
|
f = extends g f;
|
||||||
});
|
});
|
||||||
packages = f;
|
packages = f;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue