Skip to content

Commit 3a3de65

Browse files
committed
feat: start using lazyDerivation for faster TUI response times
1 parent c4d2c85 commit 3a3de65

File tree

8 files changed

+198
-74
lines changed

8 files changed

+198
-74
lines changed

cells/lib/ops.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ in {
1414
mkSetup = import ./ops/mkSetup.nix {inherit inputs cell;};
1515
mkUser = import ./ops/mkUser.nix {inherit inputs cell;};
1616
writeScript = import ./ops/writeScript.nix {inherit inputs cell;};
17+
lazyDerivation = import ./ops/lazyDerivation.nix {inherit inputs cell;};
1718

1819
mkOCI = import ./ops/mkOCI.nix {inherit inputs cell;};
1920
mkDevOCI = import ./ops/mkDevOCI.nix {inherit inputs cell;};

cells/lib/ops/lazyDerivation.nix

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
{
2+
inputs,
3+
cell,
4+
}: let
5+
inherit (inputs) nixpkgs std;
6+
l = nixpkgs.lib // builtins;
7+
inherit (l) throwIfNot;
8+
in (
9+
if l ? lazyDerivation
10+
then l.lazyDerivation
11+
else
12+
{
13+
/*
14+
Restrict a derivation to a predictable set of attribute names, so
15+
that the returned attrset is not strict in the actual derivation,
16+
saving a lot of computation when the derivation is non-trivial.
17+
18+
This is useful in situations where a derivation might only be used for its
19+
passthru attributes, improving evaluation performance.
20+
21+
The returned attribute set is lazy in `derivation`. Specifically, this
22+
means that the derivation will not be evaluated in at least the
23+
situations below.
24+
25+
For illustration and/or testing, we define derivation such that its
26+
evaluation is very noticeable.
27+
28+
let derivation = throw "This won't be evaluated.";
29+
30+
In the following expressions, `derivation` will _not_ be evaluated:
31+
32+
(lazyDerivation { inherit derivation; }).type
33+
34+
attrNames (lazyDerivation { inherit derivation; })
35+
36+
(lazyDerivation { inherit derivation; } // { foo = true; }).foo
37+
38+
(lazyDerivation { inherit derivation; meta.foo = true; }).meta
39+
40+
In these expressions, it `derivation` _will_ be evaluated:
41+
42+
"${lazyDerivation { inherit derivation }}"
43+
44+
(lazyDerivation { inherit derivation }).outPath
45+
46+
(lazyDerivation { inherit derivation }).meta
47+
48+
And the following expressions are not valid, because the refer to
49+
implementation details and/or attributes that may not be present on
50+
some derivations:
51+
52+
(lazyDerivation { inherit derivation }).buildInputs
53+
54+
(lazyDerivation { inherit derivation }).passthru
55+
56+
(lazyDerivation { inherit derivation }).pythonPath
57+
58+
*/
59+
lazyDerivation = args @ {
60+
# The derivation to be wrapped.
61+
derivation,
62+
# Optional meta attribute.
63+
#
64+
# While this function is primarily about derivations, it can improve
65+
# the `meta` package attribute, which is usually specified through
66+
# `mkDerivation`.
67+
meta ? null,
68+
# Optional extra values to add to the returned attrset.
69+
#
70+
# This can be used for adding package attributes, such as `tests`.
71+
passthru ? {},
72+
}: let
73+
# These checks are strict in `drv` and some `drv` attributes, but the
74+
# attrset spine returned by lazyDerivation does not depend on it.
75+
# Instead, the individual derivation attributes do depend on it.
76+
checked =
77+
throwIfNot (derivation.type or null == "derivation")
78+
"lazySimpleDerivation: input must be a derivation."
79+
throwIfNot
80+
(derivation.outputs == ["out"])
81+
# Supporting multiple outputs should be a matter of inheriting more attrs.
82+
"The derivation ${derivation.name or "<unknown>"} has multiple outputs. This is not supported by lazySimpleDerivation yet. Support could be added, and be useful as long as the set of outputs is known in advance, without evaluating the actual derivation."
83+
derivation;
84+
in
85+
{
86+
# Hardcoded `type`
87+
#
88+
# `lazyDerivation` requires its `derivation` argument to be a derivation,
89+
# so if it is not, that is a programming error by the caller and not
90+
# something that `lazyDerivation` consumers should be able to correct
91+
# for after the fact.
92+
# So, to improve laziness, we assume correctness here and check it only
93+
# when actual derivation values are accessed later.
94+
type = "derivation";
95+
96+
# A fixed set of derivation values, so that `lazyDerivation` can return
97+
# its attrset before evaluating `derivation`.
98+
# This must only list attributes that are available on _all_ derivations.
99+
inherit (checked) outputs out outPath outputName drvPath name system;
100+
101+
# The meta attribute can either be taken from the derivation, or if the
102+
# `lazyDerivation` caller knew a shortcut, be taken from there.
103+
meta = args.meta or checked.meta;
104+
}
105+
// passthru;
106+
}
107+
.lazyDerivation
108+
)

cells/lib/ops/mkOCI.nix

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ in
4949
'';
5050
options' =
5151
{
52-
inherit name meta;
52+
inherit name;
5353

5454
# Layers are nested to reduce duplicate paths in the image
5555
layers =
@@ -92,12 +92,26 @@ in
9292
// l.throwIf (args ? tag && meta ? tags)
9393
"mkOCI: use of `tag` and `meta.tags` arguments are not supported together. Remove the former."
9494
(l.optionalAttrs (tag != "") {inherit tag;});
95-
95+
in let
9696
image = n2c.buildImage (l.recursiveUpdate options options');
97+
tag =
98+
options'.tag
99+
or builtins.unsafeDiscardStringContext
100+
(l.head (l.strings.splitString "-" (baseNameOf image.outPath)));
97101
in
98-
l.removeAttrs image [
99-
"copyTo"
100-
"copyToDockerDaemon"
101-
"copyToPodman"
102-
"copyToRegistry"
103-
]
102+
cell.ops.lazyDerivation {
103+
inherit meta;
104+
derivation = image;
105+
passthru = {
106+
image.name = "${name}:${tag}";
107+
image.repo = name;
108+
image.tag = tag;
109+
image.tags =
110+
meta.tags
111+
or (
112+
if options' ? tag
113+
then [options'.tag]
114+
else []
115+
);
116+
};
117+
}

cells/lib/ops/mkOperable.nix

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ in
3030
debugInputs ? [],
3131
livenessProbe ? null,
3232
readinessProbe ? null,
33+
meta ? {},
3334
}: let
3435
# nixpkgs.runtimeShell is a path to the shell, not a derivation
3536
runtimeShellBin =
@@ -69,18 +70,20 @@ in
6970
'';
7071
};
7172
in
72-
(cell.ops.writeScript
73-
({
74-
inherit runtimeInputs runtimeEnv;
75-
name = "operable-${package.name}";
76-
text = ''
77-
${runtimeScript}
78-
'';
79-
}
80-
// l.optionalAttrs (runtimeShell != null) {
81-
inherit runtimeShell;
82-
}))
83-
// {
73+
cell.ops.lazyDerivation {
74+
inherit meta;
75+
derivation =
76+
cell.ops.writeScript
77+
({
78+
inherit runtimeInputs runtimeEnv;
79+
name = "operable-${package.name}";
80+
text = ''
81+
${runtimeScript}
82+
'';
83+
}
84+
// l.optionalAttrs (runtimeShell != null) {
85+
inherit runtimeShell;
86+
});
8487
passthru =
8588
# These attributes are useful for informing later stages
8689
{

cells/lib/ops/mkStandardOCI.nix

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@ in
4040
options ? {},
4141
meta ? {},
4242
}: let
43-
inherit (operable) passthru;
44-
inherit (operable.passthru) livenessProbe readinessProbe runtimeInputs runtime debug;
43+
inherit (operable) livenessProbe readinessProbe runtimeInputs runtime debug;
4544

46-
hasLivenessProbe = passthru ? livenessProbe;
47-
hasReadinessProbe = passthru ? readinessProbe;
45+
hasLivenessProbe = operable ? livenessProbe;
46+
hasReadinessProbe = operable ? readinessProbe;
4847
hasDebug = args.debug or false;
4948

5049
# Link useful paths into the container.

cells/lib/ops/writeScript.nix

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,45 @@ in
1818
then (l.getExe runtimeShell)
1919
else runtimeShell;
2020
in
21-
nixpkgs.writeTextFile {
22-
inherit name;
23-
executable = true;
24-
destination = "/bin/${name}";
25-
text =
26-
''
27-
#!${runtimeShell'}
28-
# shellcheck shell=bash
29-
set -o errexit
30-
set -o pipefail
31-
set -o nounset
32-
set -o functrace
33-
set -o errtrace
34-
set -o monitor
35-
set -o posix
36-
shopt -s dotglob
37-
38-
''
39-
+ l.optionalString (runtimeInputs != []) ''
40-
export PATH="${l.makeBinPath runtimeInputs}:$PATH"
41-
''
42-
+ l.optionalString (runtimeEnv != {}) ''
43-
${l.concatStringsSep "\n" (l.mapAttrsToList (n: v: "export ${n}=${''"$''}{${n}:-${toString v}}${''"''}") runtimeEnv)}
44-
''
45-
+ ''
21+
cell.ops.lazyDerivation {
22+
meta.mainProgram = name;
23+
derivation = nixpkgs.writeTextFile {
24+
inherit name;
25+
executable = true;
26+
destination = "/bin/${name}";
27+
text =
28+
''
29+
#!${runtimeShell'}
30+
# shellcheck shell=bash
31+
set -o errexit
32+
set -o pipefail
33+
set -o nounset
34+
set -o functrace
35+
set -o errtrace
36+
set -o monitor
37+
set -o posix
38+
shopt -s dotglob
4639
47-
${text}
48-
'';
40+
''
41+
+ l.optionalString (runtimeInputs != []) ''
42+
export PATH="${l.makeBinPath runtimeInputs}:$PATH"
43+
''
44+
+ l.optionalString (runtimeEnv != {}) ''
45+
${l.concatStringsSep "\n" (l.mapAttrsToList (n: v: "export ${n}=${''"$''}{${n}:-${toString v}}${''"''}") runtimeEnv)}
46+
''
47+
+ ''
4948
50-
checkPhase =
51-
if checkPhase == null
52-
then ''
53-
runHook preCheck
54-
${nixpkgs.stdenv.shellDryRun} "$target"
55-
${nixpkgs.shellcheck}/bin/shellcheck "$target"
56-
runHook postCheck
57-
''
58-
else checkPhase;
49+
${text}
50+
'';
5951

60-
meta.mainProgram = name;
52+
checkPhase =
53+
if checkPhase == null
54+
then ''
55+
runHook preCheck
56+
${nixpkgs.stdenv.shellDryRun} "$target"
57+
${nixpkgs.shellcheck}/bin/shellcheck "$target"
58+
runHook postCheck
59+
''
60+
else checkPhase;
61+
};
6162
}

flake.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/blocktypes/containers.nix

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424
target,
2525
}: let
2626
inherit (n2c.packages.${currentSystem}) skopeo-nix2container;
27-
img = builtins.unsafeDiscardStringContext target.imageName;
28-
tags = target.meta.tags or [(builtins.unsafeDiscardStringContext target.imageTag)];
2927
tags' =
30-
builtins.toFile "${target.name}-tags.json" (builtins.unsafeDiscardStringContext (builtins.concatStringsSep "\n" tags));
28+
builtins.toFile "${target.name}-tags.json" (builtins.concatStringsSep "\n" target.image.tags);
3129
copyFn = let
3230
skopeo = "skopeo --insecure-policy";
3331
in ''
@@ -55,11 +53,11 @@
5553
(sharedActions.build currentSystem target)
5654
(mkCommand currentSystem {
5755
name = "print-image";
58-
description = "print out the image name with all tags";
56+
description = "print out the image.repo with all tags";
5957
command = ''
6058
echo
6159
for tag in $(<${tags'}); do
62-
echo "${img}:$tag"
60+
echo "${target.image.repo}:$tag"
6361
done
6462
'';
6563
})
@@ -68,9 +66,9 @@
6866
description = "copy the image to its remote registry";
6967
command = ''
7068
${copyFn}
71-
copy docker://${img}
69+
copy docker://${target.image.repo}
7270
'';
73-
meta.images = map (tag: "${img}:${tag}") tags;
71+
meta.image = target.image.name;
7472
proviso = let
7573
filter = ./container-publish-filter.jq;
7674
in
@@ -88,7 +86,7 @@
8886
--from-file "${filter}" \
8987
--arg available "$(
9088
parallel -j0 scopeo_inspect ::: "$(
91-
command jq --raw-output 'map(.meta.images[0]|strings)[]' <<< "$1"
89+
command jq --raw-output 'map(.meta.image|strings)[]' <<< "$1"
9290
)"
9391
)" <<< "$1"
9492
@@ -103,11 +101,11 @@
103101
${copyFn}
104102
if command -v podman &> /dev/null; then
105103
echo "Podman detected: copy to local podman"
106-
copy containers-storage:${img} "$@"
104+
copy containers-storage:${target.image.repo} "$@"
107105
fi
108106
if command -v docker &> /dev/null; then
109107
echo "Docker detected: copy to local docker"
110-
copy docker-daemon:${img} "$@"
108+
copy docker-daemon:${target.image.repo} "$@"
111109
fi
112110
'';
113111
})

0 commit comments

Comments
 (0)