Skip to content

Commit 00a218a

Browse files
committed
mkBinaryCache: support different compression methods: xz (default), zstd, none
1 parent 2f5bd17 commit 00a218a

File tree

6 files changed

+82
-24
lines changed

6 files changed

+82
-24
lines changed

doc/build-helpers/images/binarycache.section.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ It can also be a convenient way to make some Nix packages available inside a con
1111
`rootPaths` must be a list of derivations.
1212
The transitive closure of these derivations' outputs will be copied into the cache.
1313

14+
## Optional arguments {#sec-pkgs-binary-cache-arguments}
15+
16+
`compression` (`"none"` or `"xz"` or `"zstd"`; _optional_)
17+
18+
: The compression algorithm to use.
19+
20+
_Default value:_ `zstd`.
21+
1422
::: {.note}
1523
This function is meant for advanced use cases.
1624
The more idiomatic way to work with flat-file binary caches is via the [nix-copy-closure](https://nixos.org/manual/nix/stable/command-ref/nix-copy-closure.html) command.

doc/redirects.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,9 @@
19591959
"sec-pkgs-binary-cache": [
19601960
"index.html#sec-pkgs-binary-cache"
19611961
],
1962+
"sec-pkgs-binary-cache-arguments": [
1963+
"index.html#sec-pkgs-binary-cache-arguments"
1964+
],
19621965
"sec-pkgs-binary-cache-example": [
19631966
"index.html#sec-pkgs-binary-cache-example"
19641967
],

nixos/tests/all-tests.nix

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ in {
154154
beanstalkd = handleTest ./beanstalkd.nix {};
155155
bees = handleTest ./bees.nix {};
156156
benchexec = handleTest ./benchexec.nix {};
157-
binary-cache = handleTest ./binary-cache.nix {};
157+
binary-cache = handleTest ./binary-cache.nix { compression = "zstd"; };
158+
binary-cache-no-compression = handleTest ./binary-cache.nix { compression = "none"; };
159+
binary-cache-xz = handleTest ./binary-cache.nix { compression = "xz"; };
158160
bind = handleTest ./bind.nix {};
159161
bird = handleTest ./bird.nix {};
160162
birdwatcher = handleTest ./birdwatcher.nix {};

nixos/tests/binary-cache.nix

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
{ compression, ... }@args:
2+
13
import ./make-test-python.nix (
24
{ lib, pkgs, ... }:
35

46
{
5-
name = "binary-cache";
7+
name = "binary-cache-" + compression;
68
meta.maintainers = with lib.maintainers; [ thomasjm ];
79

810
nodes.machine =
@@ -24,7 +26,12 @@ import ./make-test-python.nix (
2426
nativeBuildInputs = [ openssl ];
2527
}
2628
''
27-
tar -czf tmp.tar.gz -C "${mkBinaryCache { rootPaths = [ hello ]; }}" .
29+
tar -czf tmp.tar.gz -C "${
30+
mkBinaryCache {
31+
rootPaths = [ hello ];
32+
inherit compression;
33+
}
34+
}" .
2835
openssl enc -aes-256-cbc -salt -in tmp.tar.gz -out $out -k mysecretpassword
2936
'';
3037

@@ -78,4 +85,4 @@ import ./make-test-python.nix (
7885
machine.succeed("[ -d %s ] || exit 1" % storePath)
7986
'';
8087
}
81-
)
88+
) args

pkgs/build-support/binary-cache/default.nix

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
python3,
77
nix,
88
xz,
9+
zstd,
910
}:
1011

1112
# This function is for creating a flat-file binary cache, i.e. the kind created by
@@ -16,9 +17,16 @@
1617

1718
{
1819
name ? "binary-cache",
20+
compression ? "zstd", # one of ["none" "xz" "zstd"]
1921
rootPaths,
2022
}:
2123

24+
assert lib.elem compression [
25+
"none"
26+
"xz"
27+
"zstd"
28+
];
29+
2230
stdenv.mkDerivation {
2331
inherit name;
2432

@@ -28,18 +36,20 @@ stdenv.mkDerivation {
2836

2937
preferLocalBuild = true;
3038

31-
nativeBuildInputs = [
32-
coreutils
33-
jq
34-
python3
35-
nix
36-
xz
37-
];
39+
nativeBuildInputs =
40+
[
41+
coreutils
42+
jq
43+
python3
44+
nix
45+
]
46+
++ lib.optional (compression == "xz") xz
47+
++ lib.optional (compression == "zstd") zstd;
3848

3949
buildCommand = ''
4050
mkdir -p $out/nar
4151
42-
python ${./make-binary-cache.py}
52+
python ${./make-binary-cache.py} --compression "${compression}"
4353
4454
# These directories must exist, or Nix might try to create them in LocalBinaryCacheStore::init(),
4555
# which fails if mounted read-only

pkgs/build-support/binary-cache/make-binary-cache.py

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import argparse
12
from functools import partial
23
import json
34
from multiprocessing import Pool
@@ -10,44 +11,64 @@ def dropPrefix(path, nixPrefix):
1011
return path[len(nixPrefix + "/") :]
1112

1213

13-
def processItem(item, nixPrefix, outDir):
14+
def processItem(
15+
item, nixPrefix, outDir, compression, compressionCommand, compressionExtension
16+
):
1417
narInfoHash = dropPrefix(item["path"], nixPrefix).split("-")[0]
1518

16-
xzFile = outDir / "nar" / f"{narInfoHash}.nar.xz"
17-
with open(xzFile, "wb") as f:
19+
narFile = outDir / "nar" / f"{narInfoHash}{compressionExtension}"
20+
with open(narFile, "wb") as f:
1821
subprocess.run(
19-
f"nix-store --dump {item['path']} | xz -c",
22+
f"nix-store --dump {item['path']} {compressionCommand}",
2023
stdout=f,
2124
shell=True,
2225
check=True,
2326
)
2427

2528
fileHash = (
2629
subprocess.run(
27-
["nix-hash", "--base32", "--type", "sha256", "--flat", xzFile],
30+
["nix-hash", "--base32", "--type", "sha256", "--flat", narFile],
2831
capture_output=True,
2932
check=True,
3033
)
3134
.stdout.decode()
3235
.strip()
3336
)
34-
fileSize = os.path.getsize(xzFile)
37+
fileSize = os.path.getsize(narFile)
3538

36-
finalXzFileName = Path("nar") / f"{fileHash}.nar.xz"
37-
os.rename(xzFile, outDir / finalXzFileName)
39+
finalNarFileName = Path("nar") / f"{fileHash}{compressionExtension}"
40+
os.rename(narFile, outDir / finalNarFileName)
3841

3942
with open(outDir / f"{narInfoHash}.narinfo", "wt") as f:
4043
f.write(f"StorePath: {item['path']}\n")
41-
f.write(f"URL: {finalXzFileName}\n")
42-
f.write("Compression: xz\n")
44+
f.write(f"URL: {finalNarFileName}\n")
45+
f.write(f"Compression: {compression}\n")
4346
f.write(f"FileHash: sha256:{fileHash}\n")
4447
f.write(f"FileSize: {fileSize}\n")
4548
f.write(f"NarHash: {item['narHash']}\n")
4649
f.write(f"NarSize: {item['narSize']}\n")
47-
f.write(f"References: {' '.join(dropPrefix(ref, nixPrefix) for ref in item['references'])}\n")
50+
f.write(
51+
f"References: {' '.join(dropPrefix(ref, nixPrefix) for ref in item['references'])}\n"
52+
)
4853

4954

5055
def main():
56+
parser = argparse.ArgumentParser()
57+
parser.add_argument("--compression", choices=["none", "xz", "zstd"])
58+
args = parser.parse_args()
59+
60+
compressionCommand = {
61+
"none": "",
62+
"xz": "| xz -c",
63+
"zstd": "| zstd",
64+
}[args.compression]
65+
66+
compressionExtension = {
67+
"none": "",
68+
"xz": ".xz",
69+
"zstd": ".zst",
70+
}[args.compression]
71+
5172
outDir = Path(os.environ["out"])
5273
nixPrefix = os.environ["NIX_STORE"]
5374
numWorkers = int(os.environ.get("NIX_BUILD_CORES", "4"))
@@ -61,7 +82,14 @@ def main():
6182
f.write(f"StoreDir: {nixPrefix}\n")
6283

6384
with Pool(processes=numWorkers) as pool:
64-
worker = partial(processItem, nixPrefix=nixPrefix, outDir=outDir)
85+
worker = partial(
86+
processItem,
87+
nixPrefix=nixPrefix,
88+
outDir=outDir,
89+
compression=args.compression,
90+
compressionCommand=compressionCommand,
91+
compressionExtension=compressionExtension,
92+
)
6593
pool.map(worker, closures)
6694

6795

0 commit comments

Comments
 (0)