lib: Add splicing utilities (#426889)
This commit is contained in:
@@ -864,4 +864,139 @@ rec {
|
||||
transformDrv
|
||||
;
|
||||
};
|
||||
|
||||
/**
|
||||
Removes a prefix from the attribute names of a cross index.
|
||||
|
||||
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
|
||||
organizing values by cross-compilation platform relationships.
|
||||
|
||||
# Inputs
|
||||
|
||||
`prefix`
|
||||
: The prefix to remove from cross index attribute names
|
||||
|
||||
`crossIndex`
|
||||
: A cross index with prefixed names
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
renameCrossIndexFrom :: String -> AttrSet -> AttrSet
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.customisation.renameCrossIndexFrom` usage example
|
||||
|
||||
```nix
|
||||
renameCrossIndexFrom "pkgs" { pkgsBuildBuild = ...; pkgsBuildHost = ...; ... }
|
||||
=> { buildBuild = ...; buildHost = ...; ... }
|
||||
```
|
||||
:::
|
||||
*/
|
||||
renameCrossIndexFrom = prefix: x: {
|
||||
buildBuild = x."${prefix}BuildBuild";
|
||||
buildHost = x."${prefix}BuildHost";
|
||||
buildTarget = x."${prefix}BuildTarget";
|
||||
hostHost = x."${prefix}HostHost";
|
||||
hostTarget = x."${prefix}HostTarget";
|
||||
targetTarget = x."${prefix}TargetTarget";
|
||||
};
|
||||
|
||||
/**
|
||||
Adds a prefix to the attribute names of a cross index.
|
||||
|
||||
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
|
||||
organizing values by cross-compilation platform relationships.
|
||||
|
||||
# Inputs
|
||||
|
||||
`prefix`
|
||||
: The prefix to add to cross index attribute names
|
||||
|
||||
`crossIndex`
|
||||
: A cross index to be prefixed
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
renameCrossIndexTo :: String -> AttrSet -> AttrSet
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.customisation.renameCrossIndexTo` usage example
|
||||
|
||||
```nix
|
||||
renameCrossIndexTo "self" { buildBuild = ...; buildHost = ...; ... }
|
||||
=> { selfBuildBuild = ...; selfBuildHost = ...; ... }
|
||||
```
|
||||
:::
|
||||
*/
|
||||
renameCrossIndexTo = prefix: x: {
|
||||
"${prefix}BuildBuild" = x.buildBuild;
|
||||
"${prefix}BuildHost" = x.buildHost;
|
||||
"${prefix}BuildTarget" = x.buildTarget;
|
||||
"${prefix}HostHost" = x.hostHost;
|
||||
"${prefix}HostTarget" = x.hostTarget;
|
||||
"${prefix}TargetTarget" = x.targetTarget;
|
||||
};
|
||||
|
||||
/**
|
||||
Takes a function and applies it pointwise to each field of a cross index.
|
||||
|
||||
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
|
||||
organizing values by cross-compilation platform relationships.
|
||||
|
||||
# Inputs
|
||||
|
||||
`f`
|
||||
: Function to apply to each cross index value
|
||||
|
||||
`crossIndex`
|
||||
: A cross index to transform
|
||||
|
||||
# Type
|
||||
|
||||
```
|
||||
mapCrossIndex :: (a -> b) -> AttrSet -> AttrSet
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
:::{.example}
|
||||
## `lib.customisation.mapCrossIndex` usage example
|
||||
|
||||
```nix
|
||||
mapCrossIndex (x: x * 10) { buildBuild = 1; buildHost = 2; ... }
|
||||
=> { buildBuild = 10; buildHost = 20; ... }
|
||||
```
|
||||
|
||||
```nix
|
||||
# Extract a package from package sets
|
||||
mapCrossIndex (pkgs: pkgs.hello) crossIndexedPackageSets
|
||||
```
|
||||
:::
|
||||
*/
|
||||
mapCrossIndex =
|
||||
f:
|
||||
{
|
||||
buildBuild,
|
||||
buildHost,
|
||||
buildTarget,
|
||||
hostHost,
|
||||
hostTarget,
|
||||
targetTarget,
|
||||
}:
|
||||
{
|
||||
buildBuild = f buildBuild;
|
||||
buildHost = f buildHost;
|
||||
buildTarget = f buildTarget;
|
||||
hostHost = f hostHost;
|
||||
hostTarget = f hostTarget;
|
||||
targetTarget = f targetTarget;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -397,6 +397,9 @@ let
|
||||
makeScopeWithSplicing
|
||||
makeScopeWithSplicing'
|
||||
extendMkDerivation
|
||||
renameCrossIndexFrom
|
||||
renameCrossIndexTo
|
||||
mapCrossIndex
|
||||
;
|
||||
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
|
||||
inherit (self.generators) mkLuaInline;
|
||||
|
||||
@@ -4741,4 +4741,82 @@ runTests {
|
||||
expected = "/non-existent/this/does/not/exist/for/real/please-dont-mess-with-your-local-fs/default.nix";
|
||||
};
|
||||
|
||||
# Tests for cross index utilities
|
||||
|
||||
testRenameCrossIndexFrom = {
|
||||
expr = lib.renameCrossIndexFrom "pkgs" {
|
||||
pkgsBuildBuild = "dummy-build-build";
|
||||
pkgsBuildHost = "dummy-build-host";
|
||||
pkgsBuildTarget = "dummy-build-target";
|
||||
pkgsHostHost = "dummy-host-host";
|
||||
pkgsHostTarget = "dummy-host-target";
|
||||
pkgsTargetTarget = "dummy-target-target";
|
||||
};
|
||||
expected = {
|
||||
buildBuild = "dummy-build-build";
|
||||
buildHost = "dummy-build-host";
|
||||
buildTarget = "dummy-build-target";
|
||||
hostHost = "dummy-host-host";
|
||||
hostTarget = "dummy-host-target";
|
||||
targetTarget = "dummy-target-target";
|
||||
};
|
||||
};
|
||||
|
||||
testRenameCrossIndexTo = {
|
||||
expr = lib.renameCrossIndexTo "self" {
|
||||
buildBuild = "dummy-build-build";
|
||||
buildHost = "dummy-build-host";
|
||||
buildTarget = "dummy-build-target";
|
||||
hostHost = "dummy-host-host";
|
||||
hostTarget = "dummy-host-target";
|
||||
targetTarget = "dummy-target-target";
|
||||
};
|
||||
expected = {
|
||||
selfBuildBuild = "dummy-build-build";
|
||||
selfBuildHost = "dummy-build-host";
|
||||
selfBuildTarget = "dummy-build-target";
|
||||
selfHostHost = "dummy-host-host";
|
||||
selfHostTarget = "dummy-host-target";
|
||||
selfTargetTarget = "dummy-target-target";
|
||||
};
|
||||
};
|
||||
|
||||
testMapCrossIndex = {
|
||||
expr = lib.mapCrossIndex (x: x * 10) {
|
||||
buildBuild = 1;
|
||||
buildHost = 2;
|
||||
buildTarget = 3;
|
||||
hostHost = 4;
|
||||
hostTarget = 5;
|
||||
targetTarget = 6;
|
||||
};
|
||||
expected = {
|
||||
buildBuild = 10;
|
||||
buildHost = 20;
|
||||
buildTarget = 30;
|
||||
hostHost = 40;
|
||||
hostTarget = 50;
|
||||
targetTarget = 60;
|
||||
};
|
||||
};
|
||||
|
||||
testMapCrossIndexString = {
|
||||
expr = lib.mapCrossIndex (x: "prefix-${x}") {
|
||||
buildBuild = "bb";
|
||||
buildHost = "bh";
|
||||
buildTarget = "bt";
|
||||
hostHost = "hh";
|
||||
hostTarget = "ht";
|
||||
targetTarget = "tt";
|
||||
};
|
||||
expected = {
|
||||
buildBuild = "prefix-bb";
|
||||
buildHost = "prefix-bh";
|
||||
buildTarget = "prefix-bt";
|
||||
hostHost = "prefix-hh";
|
||||
hostTarget = "prefix-ht";
|
||||
targetTarget = "prefix-tt";
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -17,48 +17,30 @@
|
||||
lib: pkgs: actuallySplice:
|
||||
|
||||
let
|
||||
inherit (lib.customisation) mapCrossIndex renameCrossIndexFrom;
|
||||
|
||||
spliceReal =
|
||||
{
|
||||
pkgsBuildBuild,
|
||||
pkgsBuildHost,
|
||||
pkgsBuildTarget,
|
||||
pkgsHostHost,
|
||||
pkgsHostTarget,
|
||||
pkgsTargetTarget,
|
||||
}:
|
||||
inputs:
|
||||
let
|
||||
mash =
|
||||
# Other pkgs sets
|
||||
pkgsBuildBuild
|
||||
// pkgsBuildTarget
|
||||
// pkgsHostHost
|
||||
// pkgsTargetTarget
|
||||
inputs.buildBuild
|
||||
// inputs.buildTarget
|
||||
// inputs.hostHost
|
||||
// inputs.targetTarget
|
||||
# The same pkgs sets one probably intends
|
||||
// pkgsBuildHost
|
||||
// pkgsHostTarget;
|
||||
// inputs.buildHost
|
||||
// inputs.hostTarget;
|
||||
merge = name: {
|
||||
inherit name;
|
||||
value =
|
||||
let
|
||||
defaultValue = mash.${name};
|
||||
# `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
|
||||
valueBuildBuild = pkgsBuildBuild.${name} or { };
|
||||
valueBuildHost = pkgsBuildHost.${name} or { };
|
||||
valueBuildTarget = pkgsBuildTarget.${name} or { };
|
||||
valueHostHost = pkgsHostHost.${name} or { };
|
||||
valueHostTarget = pkgsHostTarget.${name} or { };
|
||||
valueTargetTarget = pkgsTargetTarget.${name} or { };
|
||||
value' = mapCrossIndex (x: x.${name} or { }) inputs;
|
||||
|
||||
augmentedValue = defaultValue // {
|
||||
__spliced =
|
||||
(lib.optionalAttrs (pkgsBuildBuild ? ${name}) { buildBuild = valueBuildBuild; })
|
||||
// (lib.optionalAttrs (pkgsBuildHost ? ${name}) { buildHost = valueBuildHost; })
|
||||
// (lib.optionalAttrs (pkgsBuildTarget ? ${name}) { buildTarget = valueBuildTarget; })
|
||||
// (lib.optionalAttrs (pkgsHostHost ? ${name}) { hostHost = valueHostHost; })
|
||||
// (lib.optionalAttrs (pkgsHostTarget ? ${name}) { hostTarget = valueHostTarget; })
|
||||
// (lib.optionalAttrs (pkgsTargetTarget ? ${name}) {
|
||||
targetTarget = valueTargetTarget;
|
||||
});
|
||||
__spliced = lib.filterAttrs (k: v: inputs.${k} ? ${name}) value';
|
||||
};
|
||||
# Get the set of outputs of a derivation. If one derivation fails to
|
||||
# evaluate we don't want to diverge the entire splice, so we fall back
|
||||
@@ -76,27 +58,12 @@ let
|
||||
# on to splice them together.
|
||||
if lib.isDerivation defaultValue then
|
||||
augmentedValue
|
||||
// spliceReal {
|
||||
pkgsBuildBuild = tryGetOutputs valueBuildBuild;
|
||||
pkgsBuildHost = tryGetOutputs valueBuildHost;
|
||||
pkgsBuildTarget = tryGetOutputs valueBuildTarget;
|
||||
pkgsHostHost = tryGetOutputs valueHostHost;
|
||||
pkgsHostTarget = getOutputs valueHostTarget;
|
||||
pkgsTargetTarget = tryGetOutputs valueTargetTarget;
|
||||
# Just recur on plain attrsets
|
||||
}
|
||||
// spliceReal (mapCrossIndex tryGetOutputs value' // { hostTarget = getOutputs value'.hostTarget; })
|
||||
else if lib.isAttrs defaultValue then
|
||||
spliceReal {
|
||||
pkgsBuildBuild = valueBuildBuild;
|
||||
pkgsBuildHost = valueBuildHost;
|
||||
pkgsBuildTarget = valueBuildTarget;
|
||||
pkgsHostHost = valueHostHost;
|
||||
pkgsHostTarget = valueHostTarget;
|
||||
pkgsTargetTarget = valueTargetTarget;
|
||||
# Don't be fancy about non-derivations. But we could have used used
|
||||
# `__functor__` for functions instead.
|
||||
}
|
||||
spliceReal value'
|
||||
else
|
||||
# Don't be fancy about non-derivations. But we could have used used
|
||||
# `__functor__` for functions instead.
|
||||
defaultValue;
|
||||
};
|
||||
in
|
||||
@@ -111,7 +78,7 @@ let
|
||||
pkgsHostTarget,
|
||||
pkgsTargetTarget,
|
||||
}@args:
|
||||
if actuallySplice then spliceReal args else pkgsHostTarget;
|
||||
if actuallySplice then spliceReal (renameCrossIndexFrom "pkgs" args) else pkgsHostTarget;
|
||||
|
||||
splicedPackages =
|
||||
splicePackages {
|
||||
|
||||
Reference in New Issue
Block a user