lib: Add splicing utilities (#426889)
This commit is contained in:
@@ -864,4 +864,139 @@ rec {
|
|||||||
transformDrv
|
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
|
||||||
makeScopeWithSplicing'
|
makeScopeWithSplicing'
|
||||||
extendMkDerivation
|
extendMkDerivation
|
||||||
|
renameCrossIndexFrom
|
||||||
|
renameCrossIndexTo
|
||||||
|
mapCrossIndex
|
||||||
;
|
;
|
||||||
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
|
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
|
||||||
inherit (self.generators) mkLuaInline;
|
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";
|
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:
|
lib: pkgs: actuallySplice:
|
||||||
|
|
||||||
let
|
let
|
||||||
|
inherit (lib.customisation) mapCrossIndex renameCrossIndexFrom;
|
||||||
|
|
||||||
spliceReal =
|
spliceReal =
|
||||||
{
|
inputs:
|
||||||
pkgsBuildBuild,
|
|
||||||
pkgsBuildHost,
|
|
||||||
pkgsBuildTarget,
|
|
||||||
pkgsHostHost,
|
|
||||||
pkgsHostTarget,
|
|
||||||
pkgsTargetTarget,
|
|
||||||
}:
|
|
||||||
let
|
let
|
||||||
mash =
|
mash =
|
||||||
# Other pkgs sets
|
# Other pkgs sets
|
||||||
pkgsBuildBuild
|
inputs.buildBuild
|
||||||
// pkgsBuildTarget
|
// inputs.buildTarget
|
||||||
// pkgsHostHost
|
// inputs.hostHost
|
||||||
// pkgsTargetTarget
|
// inputs.targetTarget
|
||||||
# The same pkgs sets one probably intends
|
# The same pkgs sets one probably intends
|
||||||
// pkgsBuildHost
|
// inputs.buildHost
|
||||||
// pkgsHostTarget;
|
// inputs.hostTarget;
|
||||||
merge = name: {
|
merge = name: {
|
||||||
inherit name;
|
inherit name;
|
||||||
value =
|
value =
|
||||||
let
|
let
|
||||||
defaultValue = mash.${name};
|
defaultValue = mash.${name};
|
||||||
# `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
|
# `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
|
||||||
valueBuildBuild = pkgsBuildBuild.${name} or { };
|
value' = mapCrossIndex (x: x.${name} or { }) inputs;
|
||||||
valueBuildHost = pkgsBuildHost.${name} or { };
|
|
||||||
valueBuildTarget = pkgsBuildTarget.${name} or { };
|
|
||||||
valueHostHost = pkgsHostHost.${name} or { };
|
|
||||||
valueHostTarget = pkgsHostTarget.${name} or { };
|
|
||||||
valueTargetTarget = pkgsTargetTarget.${name} or { };
|
|
||||||
augmentedValue = defaultValue // {
|
augmentedValue = defaultValue // {
|
||||||
__spliced =
|
__spliced = lib.filterAttrs (k: v: inputs.${k} ? ${name}) value';
|
||||||
(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;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
# Get the set of outputs of a derivation. If one derivation fails to
|
# 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
|
# evaluate we don't want to diverge the entire splice, so we fall back
|
||||||
@@ -76,27 +58,12 @@ let
|
|||||||
# on to splice them together.
|
# on to splice them together.
|
||||||
if lib.isDerivation defaultValue then
|
if lib.isDerivation defaultValue then
|
||||||
augmentedValue
|
augmentedValue
|
||||||
// spliceReal {
|
// spliceReal (mapCrossIndex tryGetOutputs value' // { hostTarget = getOutputs value'.hostTarget; })
|
||||||
pkgsBuildBuild = tryGetOutputs valueBuildBuild;
|
|
||||||
pkgsBuildHost = tryGetOutputs valueBuildHost;
|
|
||||||
pkgsBuildTarget = tryGetOutputs valueBuildTarget;
|
|
||||||
pkgsHostHost = tryGetOutputs valueHostHost;
|
|
||||||
pkgsHostTarget = getOutputs valueHostTarget;
|
|
||||||
pkgsTargetTarget = tryGetOutputs valueTargetTarget;
|
|
||||||
# Just recur on plain attrsets
|
|
||||||
}
|
|
||||||
else if lib.isAttrs defaultValue then
|
else if lib.isAttrs defaultValue then
|
||||||
spliceReal {
|
spliceReal value'
|
||||||
pkgsBuildBuild = valueBuildBuild;
|
else
|
||||||
pkgsBuildHost = valueBuildHost;
|
|
||||||
pkgsBuildTarget = valueBuildTarget;
|
|
||||||
pkgsHostHost = valueHostHost;
|
|
||||||
pkgsHostTarget = valueHostTarget;
|
|
||||||
pkgsTargetTarget = valueTargetTarget;
|
|
||||||
# Don't be fancy about non-derivations. But we could have used used
|
# Don't be fancy about non-derivations. But we could have used used
|
||||||
# `__functor__` for functions instead.
|
# `__functor__` for functions instead.
|
||||||
}
|
|
||||||
else
|
|
||||||
defaultValue;
|
defaultValue;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
@@ -111,7 +78,7 @@ let
|
|||||||
pkgsHostTarget,
|
pkgsHostTarget,
|
||||||
pkgsTargetTarget,
|
pkgsTargetTarget,
|
||||||
}@args:
|
}@args:
|
||||||
if actuallySplice then spliceReal args else pkgsHostTarget;
|
if actuallySplice then spliceReal (renameCrossIndexFrom "pkgs" args) else pkgsHostTarget;
|
||||||
|
|
||||||
splicedPackages =
|
splicedPackages =
|
||||||
splicePackages {
|
splicePackages {
|
||||||
|
|||||||
Reference in New Issue
Block a user