Skip to content
Merged
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
135 changes: 135 additions & 0 deletions lib/customisation.nix
Original file line number Diff line number Diff line change
Expand Up @@ -863,4 +863,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;
};
}
3 changes: 3 additions & 0 deletions lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@ let
makeScopeWithSplicing
makeScopeWithSplicing'
extendMkDerivation
renameCrossIndexFrom
renameCrossIndexTo
mapCrossIndex
;
inherit (self.derivations) lazyDerivation optionalDrvAttr warnOnInstantiate;
inherit (self.generators) mkLuaInline;
Expand Down
78 changes: 78 additions & 0 deletions lib/tests/misc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4432,4 +4432,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";
};
};

}
65 changes: 16 additions & 49 deletions pkgs/top-level/splice.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand Down
Loading