Skip to content

Commit acb6191

Browse files
authored
lib: Add splicing utilities (NixOS#426889)
2 parents 8710254 + f8566d2 commit acb6191

File tree

4 files changed

+232
-49
lines changed

4 files changed

+232
-49
lines changed

lib/customisation.nix

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,4 +864,139 @@ rec {
864864
transformDrv
865865
;
866866
};
867+
868+
/**
869+
Removes a prefix from the attribute names of a cross index.
870+
871+
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
872+
organizing values by cross-compilation platform relationships.
873+
874+
# Inputs
875+
876+
`prefix`
877+
: The prefix to remove from cross index attribute names
878+
879+
`crossIndex`
880+
: A cross index with prefixed names
881+
882+
# Type
883+
884+
```
885+
renameCrossIndexFrom :: String -> AttrSet -> AttrSet
886+
```
887+
888+
# Examples
889+
890+
:::{.example}
891+
## `lib.customisation.renameCrossIndexFrom` usage example
892+
893+
```nix
894+
renameCrossIndexFrom "pkgs" { pkgsBuildBuild = ...; pkgsBuildHost = ...; ... }
895+
=> { buildBuild = ...; buildHost = ...; ... }
896+
```
897+
:::
898+
*/
899+
renameCrossIndexFrom = prefix: x: {
900+
buildBuild = x."${prefix}BuildBuild";
901+
buildHost = x."${prefix}BuildHost";
902+
buildTarget = x."${prefix}BuildTarget";
903+
hostHost = x."${prefix}HostHost";
904+
hostTarget = x."${prefix}HostTarget";
905+
targetTarget = x."${prefix}TargetTarget";
906+
};
907+
908+
/**
909+
Adds a prefix to the attribute names of a cross index.
910+
911+
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
912+
organizing values by cross-compilation platform relationships.
913+
914+
# Inputs
915+
916+
`prefix`
917+
: The prefix to add to cross index attribute names
918+
919+
`crossIndex`
920+
: A cross index to be prefixed
921+
922+
# Type
923+
924+
```
925+
renameCrossIndexTo :: String -> AttrSet -> AttrSet
926+
```
927+
928+
# Examples
929+
930+
:::{.example}
931+
## `lib.customisation.renameCrossIndexTo` usage example
932+
933+
```nix
934+
renameCrossIndexTo "self" { buildBuild = ...; buildHost = ...; ... }
935+
=> { selfBuildBuild = ...; selfBuildHost = ...; ... }
936+
```
937+
:::
938+
*/
939+
renameCrossIndexTo = prefix: x: {
940+
"${prefix}BuildBuild" = x.buildBuild;
941+
"${prefix}BuildHost" = x.buildHost;
942+
"${prefix}BuildTarget" = x.buildTarget;
943+
"${prefix}HostHost" = x.hostHost;
944+
"${prefix}HostTarget" = x.hostTarget;
945+
"${prefix}TargetTarget" = x.targetTarget;
946+
};
947+
948+
/**
949+
Takes a function and applies it pointwise to each field of a cross index.
950+
951+
A cross index (short for "Cross Platform Pair Index") is a 6-field structure
952+
organizing values by cross-compilation platform relationships.
953+
954+
# Inputs
955+
956+
`f`
957+
: Function to apply to each cross index value
958+
959+
`crossIndex`
960+
: A cross index to transform
961+
962+
# Type
963+
964+
```
965+
mapCrossIndex :: (a -> b) -> AttrSet -> AttrSet
966+
```
967+
968+
# Examples
969+
970+
:::{.example}
971+
## `lib.customisation.mapCrossIndex` usage example
972+
973+
```nix
974+
mapCrossIndex (x: x * 10) { buildBuild = 1; buildHost = 2; ... }
975+
=> { buildBuild = 10; buildHost = 20; ... }
976+
```
977+
978+
```nix
979+
# Extract a package from package sets
980+
mapCrossIndex (pkgs: pkgs.hello) crossIndexedPackageSets
981+
```
982+
:::
983+
*/
984+
mapCrossIndex =
985+
f:
986+
{
987+
buildBuild,
988+
buildHost,
989+
buildTarget,
990+
hostHost,
991+
hostTarget,
992+
targetTarget,
993+
}:
994+
{
995+
buildBuild = f buildBuild;
996+
buildHost = f buildHost;
997+
buildTarget = f buildTarget;
998+
hostHost = f hostHost;
999+
hostTarget = f hostTarget;
1000+
targetTarget = f targetTarget;
1001+
};
8671002
}

lib/default.nix

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ let
397397
makeScopeWithSplicing
398398
makeScopeWithSplicing'
399399
extendMkDerivation
400+
renameCrossIndexFrom
401+
renameCrossIndexTo
402+
mapCrossIndex
400403
;
401404
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
402405
inherit (self.generators) mkLuaInline;

lib/tests/misc.nix

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4741,4 +4741,82 @@ runTests {
47414741
expected = "/non-existent/this/does/not/exist/for/real/please-dont-mess-with-your-local-fs/default.nix";
47424742
};
47434743

4744+
# Tests for cross index utilities
4745+
4746+
testRenameCrossIndexFrom = {
4747+
expr = lib.renameCrossIndexFrom "pkgs" {
4748+
pkgsBuildBuild = "dummy-build-build";
4749+
pkgsBuildHost = "dummy-build-host";
4750+
pkgsBuildTarget = "dummy-build-target";
4751+
pkgsHostHost = "dummy-host-host";
4752+
pkgsHostTarget = "dummy-host-target";
4753+
pkgsTargetTarget = "dummy-target-target";
4754+
};
4755+
expected = {
4756+
buildBuild = "dummy-build-build";
4757+
buildHost = "dummy-build-host";
4758+
buildTarget = "dummy-build-target";
4759+
hostHost = "dummy-host-host";
4760+
hostTarget = "dummy-host-target";
4761+
targetTarget = "dummy-target-target";
4762+
};
4763+
};
4764+
4765+
testRenameCrossIndexTo = {
4766+
expr = lib.renameCrossIndexTo "self" {
4767+
buildBuild = "dummy-build-build";
4768+
buildHost = "dummy-build-host";
4769+
buildTarget = "dummy-build-target";
4770+
hostHost = "dummy-host-host";
4771+
hostTarget = "dummy-host-target";
4772+
targetTarget = "dummy-target-target";
4773+
};
4774+
expected = {
4775+
selfBuildBuild = "dummy-build-build";
4776+
selfBuildHost = "dummy-build-host";
4777+
selfBuildTarget = "dummy-build-target";
4778+
selfHostHost = "dummy-host-host";
4779+
selfHostTarget = "dummy-host-target";
4780+
selfTargetTarget = "dummy-target-target";
4781+
};
4782+
};
4783+
4784+
testMapCrossIndex = {
4785+
expr = lib.mapCrossIndex (x: x * 10) {
4786+
buildBuild = 1;
4787+
buildHost = 2;
4788+
buildTarget = 3;
4789+
hostHost = 4;
4790+
hostTarget = 5;
4791+
targetTarget = 6;
4792+
};
4793+
expected = {
4794+
buildBuild = 10;
4795+
buildHost = 20;
4796+
buildTarget = 30;
4797+
hostHost = 40;
4798+
hostTarget = 50;
4799+
targetTarget = 60;
4800+
};
4801+
};
4802+
4803+
testMapCrossIndexString = {
4804+
expr = lib.mapCrossIndex (x: "prefix-${x}") {
4805+
buildBuild = "bb";
4806+
buildHost = "bh";
4807+
buildTarget = "bt";
4808+
hostHost = "hh";
4809+
hostTarget = "ht";
4810+
targetTarget = "tt";
4811+
};
4812+
expected = {
4813+
buildBuild = "prefix-bb";
4814+
buildHost = "prefix-bh";
4815+
buildTarget = "prefix-bt";
4816+
hostHost = "prefix-hh";
4817+
hostTarget = "prefix-ht";
4818+
targetTarget = "prefix-tt";
4819+
};
4820+
};
4821+
47444822
}

pkgs/top-level/splice.nix

Lines changed: 16 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,48 +17,30 @@
1717
lib: pkgs: actuallySplice:
1818

1919
let
20+
inherit (lib.customisation) mapCrossIndex renameCrossIndexFrom;
2021

2122
spliceReal =
22-
{
23-
pkgsBuildBuild,
24-
pkgsBuildHost,
25-
pkgsBuildTarget,
26-
pkgsHostHost,
27-
pkgsHostTarget,
28-
pkgsTargetTarget,
29-
}:
23+
inputs:
3024
let
3125
mash =
3226
# Other pkgs sets
33-
pkgsBuildBuild
34-
// pkgsBuildTarget
35-
// pkgsHostHost
36-
// pkgsTargetTarget
27+
inputs.buildBuild
28+
// inputs.buildTarget
29+
// inputs.hostHost
30+
// inputs.targetTarget
3731
# The same pkgs sets one probably intends
38-
// pkgsBuildHost
39-
// pkgsHostTarget;
32+
// inputs.buildHost
33+
// inputs.hostTarget;
4034
merge = name: {
4135
inherit name;
4236
value =
4337
let
4438
defaultValue = mash.${name};
4539
# `or {}` is for the non-derivation attsert splicing case, where `{}` is the identity.
46-
valueBuildBuild = pkgsBuildBuild.${name} or { };
47-
valueBuildHost = pkgsBuildHost.${name} or { };
48-
valueBuildTarget = pkgsBuildTarget.${name} or { };
49-
valueHostHost = pkgsHostHost.${name} or { };
50-
valueHostTarget = pkgsHostTarget.${name} or { };
51-
valueTargetTarget = pkgsTargetTarget.${name} or { };
40+
value' = mapCrossIndex (x: x.${name} or { }) inputs;
41+
5242
augmentedValue = defaultValue // {
53-
__spliced =
54-
(lib.optionalAttrs (pkgsBuildBuild ? ${name}) { buildBuild = valueBuildBuild; })
55-
// (lib.optionalAttrs (pkgsBuildHost ? ${name}) { buildHost = valueBuildHost; })
56-
// (lib.optionalAttrs (pkgsBuildTarget ? ${name}) { buildTarget = valueBuildTarget; })
57-
// (lib.optionalAttrs (pkgsHostHost ? ${name}) { hostHost = valueHostHost; })
58-
// (lib.optionalAttrs (pkgsHostTarget ? ${name}) { hostTarget = valueHostTarget; })
59-
// (lib.optionalAttrs (pkgsTargetTarget ? ${name}) {
60-
targetTarget = valueTargetTarget;
61-
});
43+
__spliced = lib.filterAttrs (k: v: inputs.${k} ? ${name}) value';
6244
};
6345
# Get the set of outputs of a derivation. If one derivation fails to
6446
# evaluate we don't want to diverge the entire splice, so we fall back
@@ -76,27 +58,12 @@ let
7658
# on to splice them together.
7759
if lib.isDerivation defaultValue then
7860
augmentedValue
79-
// spliceReal {
80-
pkgsBuildBuild = tryGetOutputs valueBuildBuild;
81-
pkgsBuildHost = tryGetOutputs valueBuildHost;
82-
pkgsBuildTarget = tryGetOutputs valueBuildTarget;
83-
pkgsHostHost = tryGetOutputs valueHostHost;
84-
pkgsHostTarget = getOutputs valueHostTarget;
85-
pkgsTargetTarget = tryGetOutputs valueTargetTarget;
86-
# Just recur on plain attrsets
87-
}
61+
// spliceReal (mapCrossIndex tryGetOutputs value' // { hostTarget = getOutputs value'.hostTarget; })
8862
else if lib.isAttrs defaultValue then
89-
spliceReal {
90-
pkgsBuildBuild = valueBuildBuild;
91-
pkgsBuildHost = valueBuildHost;
92-
pkgsBuildTarget = valueBuildTarget;
93-
pkgsHostHost = valueHostHost;
94-
pkgsHostTarget = valueHostTarget;
95-
pkgsTargetTarget = valueTargetTarget;
96-
# Don't be fancy about non-derivations. But we could have used used
97-
# `__functor__` for functions instead.
98-
}
63+
spliceReal value'
9964
else
65+
# Don't be fancy about non-derivations. But we could have used used
66+
# `__functor__` for functions instead.
10067
defaultValue;
10168
};
10269
in
@@ -111,7 +78,7 @@ let
11178
pkgsHostTarget,
11279
pkgsTargetTarget,
11380
}@args:
114-
if actuallySplice then spliceReal args else pkgsHostTarget;
81+
if actuallySplice then spliceReal (renameCrossIndexFrom "pkgs" args) else pkgsHostTarget;
11582

11683
splicedPackages =
11784
splicePackages {

0 commit comments

Comments
 (0)