-
Notifications
You must be signed in to change notification settings - Fork 88
/
config.nix
434 lines (368 loc) · 16.8 KB
/
config.nix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
{ lib, libb, builtinz, arg, pkgs }:
let
allowFun = attrs0: attrName: default:
if builtins.hasAttr attrName attrs0 then
if lib.isFunction attrs0.${attrName} then
attrs0.${attrName} default
else
let
finalTy = builtins.typeOf default;
actualTy = builtins.typeOf attrs0.${attrName};
in
throw "${attrName} should be a function from ${finalTy} to ${finalTy}, but is a ${actualTy}"
else default;
mkAttrs = attrs0: rec
{
# The name of the derivation.
name = attrs0.name or null;
# The version of the derivation.
version = attrs0.version or null;
# Used by `naersk` as source input to the derivation. When `root` is not
# set, `src` is also used to discover the `Cargo.toml` and `Cargo.lock`.
src = attrs0.src or null;
# Used by `naersk` to read the `Cargo.toml` and `Cargo.lock` files. May
# be different from `src`. When `src` is not set, `root` is (indirectly)
# used as `src`.
root = attrs0.root or null;
# Whether to fetch all refs while fetching Git dependencies. Useful if
# the wanted revision isn't in the default branch. Requires Nix 2.4+.
gitAllRefs = attrs0.gitAllRefs or false;
# Whether to fetch submodules while fetching Git dependencies. Requires Nix
# 2.4+.
gitSubmodules = attrs0.gitSubmodules or false;
# Additional cargo lock used to specify crates required for build
additionalCargoLock = attrs0.additionalCargoLock or null;
# Url for downloading crates from an alternative source
cratesDownloadUrl = attrs0.cratesDownloadUrl or "https://crates.io";
# The command to use for the build.
cargoBuild =
allowFun attrs0 "cargoBuild"
''cargo $cargo_options build $cargo_build_options >> $cargo_build_output_json'';
# Options passed to cargo build, i.e. `cargo build <OPTS>`. These options
# can be accessed during the build through the environment variable
# `cargo_build_options`. <br/>
# Note: naersk relies on the
# `--out-dir out` option and the `--message-format` option.
# The `$cargo_message_format` variable is set
# based on the cargo version.<br/>
# Note: these values are not (shell) escaped, meaning that you can use
# environment variables but must be careful when introducing e.g. spaces. <br/>
cargoBuildOptions =
allowFun attrs0 "cargoBuildOptions" [ "$cargo_release" ''-j "$NIX_BUILD_CORES"'' "--message-format=$cargo_message_format" ];
# When `true`, rustc remaps the (`/nix/store`) source paths to `/sources`
# to reduce the number of dependencies in the closure.
remapPathPrefix = attrs0.remapPathPrefix or true;
# The commands to run in the `checkPhase`. Do not forget to set
# [`doCheck`](https://nixos.org/nixpkgs/manual/#ssec-check-phase).
cargoTestCommands =
allowFun attrs0 "cargoTestCommands" [ ''cargo $cargo_options test $cargo_test_options'' ];
# Options passed to cargo test, i.e. `cargo test <OPTS>`. These options
# can be accessed during the build through the environment variable
# `cargo_test_options`. <br/>
# Note: these values are not (shell) escaped, meaning that you can use
# environment variables but must be careful when introducing e.g. spaces. <br/>
cargoTestOptions =
allowFun attrs0 "cargoTestOptions" [ "$cargo_release" ''-j "$NIX_BUILD_CORES"'' ];
# Options passed to cargo clippy, i.e. `cargo clippy -- <OPTS>`. These options
# can be accessed during the build through the environment variable
# `cargo_clippy_options`. <br />
# Note: these values are not (shell) escaped, meaning that you can use
# environment variables but must be careful when introducing e.g. spaces. <br/>
cargoClippyOptions =
allowFun attrs0 "cargoClippyOptions" [ "-D warnings" ];
# Options passed to cargo fmt, i.e. `cargo fmt -- <OPTS>`. These options
# can be accessed during the build through the environment variable
# `cargo_fmt_options`. <br />
# Note: these values are not (shell) escaped, meaning that you can use
# environment variables but must be careful when introducing e.g. spaces. <br/>
cargoFmtOptions =
allowFun attrs0 "cargoFmtOptions" [ "--check" ];
# Extra `nativeBuildInputs` to all derivations.
nativeBuildInputs = attrs0.nativeBuildInputs or [];
# Extra `buildInputs` to all derivations.
buildInputs = attrs0.buildInputs or [];
# Options passed to all cargo commands, i.e. `cargo <OPTS> ...`. These
# options can be accessed during the build through the environment variable
# `cargo_options`. <br/>
# Note: these values are not (shell) escaped, meaning that you can use
# environment variables but must be careful when introducing e.g. spaces. <br/>
cargoOptions =
allowFun attrs0 "cargoOptions" [ ];
# When true, `cargo doc` is run and a new output `doc` is generated.
doDoc = attrs0.doDoc or false;
# The commands to run in the `docPhase`. Do not forget to set `doDoc`.
cargoDocCommands =
allowFun attrs0 "cargoDocCommands" [ ''cargo $cargo_options doc $cargo_doc_options'' ];
# Options passed to cargo doc, i.e. `cargo doc <OPTS>`. These options
# can be accessed during the build through the environment variable
# `cargo_doc_options`. <br/>
# Note: these values are not (shell) escaped, meaning that you can use
# environment variables but must be careful when introducing e.g. spaces. <br/>
cargoDocOptions =
allowFun attrs0 "cargoDocOptions" [ "--offline" "$cargo_release" ''-j "$NIX_BUILD_CORES"'' ];
# When true, all cargo builds are run with `--release`. The environment
# variable `cargo_release` is set to `--release` iff this option is set.
release = attrs0.release or true;
# An override for all derivations involved in the build.
override = attrs0.override or (x: x);
# An override for the top-level (last, main) derivation. If both `override`
# and `overrideMain` are specified, _both_ will be applied to the top-level
# derivation.
overrideMain = attrs0.overrideMain or (x: x);
# When true, no intermediary (dependency-only) build is run. Enabling
# `singleStep` greatly reduces the incrementality of the builds.
singleStep = attrs0.singleStep or false;
# When true, the resulting binaries are copied to `$out/bin`. <br/>
# Note: this relies on cargo's `--message-format` argument, set in the
# default `cargoBuildOptions`.
copyBins = attrs0.copyBins or true;
# When true, the resulting binaries are copied to `$out/lib`. <br/> Note:
# this relies on cargo's `--message-format` argument, set in the default
# `cargoBuildOptions`.
copyLibs = attrs0.copyLibs or false;
# A [`jq`](https://stedolan.github.io/jq) filter for selecting which build
# artifacts to release. This is run on cargo's
# [`--message-format`](https://doc.rust-lang.org/cargo/reference/external-tools.html#json-messages)
# JSON output. <br/>
# The value is written to the `cargo_bins_jq_filter` variable.
copyBinsFilter = attrs0.copyBinsFilter or
''select(.reason == "compiler-artifact" and .executable != null and .profile.test == false)'';
# A [`jq`](https://stedolan.github.io/jq) filter for selecting which build
# artifacts to release. This is run on cargo's
# [`--message-format`](https://doc.rust-lang.org/cargo/reference/external-tools.html#json-messages)
# JSON output. <br/> The value is written to the `cargo_libs_jq_filter`
# variable. Default: `''select(.reason == "compiler-artifact" and
# ((.target.kind | contains(["staticlib"])) or (.target.kind |
# contains(["cdylib"]))) and .filenames != null and .profile.test ==
# false)''`
copyLibsFilter = attrs0.copyLibsFilter or
''select(.reason == "compiler-artifact" and ((.target.kind | contains(["staticlib"])) or (.target.kind | contains(["cdylib"]))) and .filenames != null and .profile.test == false)'';
# When true, the documentation is generated in a different output, `doc`.
copyDocsToSeparateOutput = attrs0.copyDocsToSeparateOutput or true;
# When true, the build fails if the documentation step fails; otherwise
# the failure is ignored.
doDocFail = attrs0.doDocFail or false;
# When true, references to the nix store are removed from the generated
# documentation.
removeReferencesToSrcFromDocs = attrs0.removeReferencesToSrcFromDocs or true;
# When true, the build output of intermediary builds is compressed with
# [`Zstandard`](https://facebook.github.io/zstd/). This reduces the size
# of closures.
compressTarget = attrs0.compressTarget or true;
# When true, the `target/` directory is copied to `$out`.
copyTarget = attrs0.copyTarget or false;
# Optional hook to run after the compilation is done; inside this script,
# `$out/bin` contains compiled Rust binaries. Useful if your application
# needs e.g. custom environment variables, in which case you can simply run
# `wrapProgram $out/bin/your-app-name` in here.
postInstall = attrs0.postInstall or false;
# Whether to use the `fromTOML` built-in or not. When set to `false` the
# python package `remarshal` is used instead (in a derivation) and the
# JSON output is read with `builtins.fromJSON`.
# This is a workaround for old versions of Nix. May be used safely from
# Nix 2.3 onwards where all bugs in `builtins.fromTOML` seem to have been
# fixed.
usePureFromTOML = attrs0.usePureFromTOML or true;
# What to do when building the derivation. Either `build`, `check`, `test`, `fmt` or `clippy`. <br/>
# When set to something other than `build`, no binaries are generated.
mode = attrs0.mode or "build";
# Whether to automatically apply crate-specific overrides, mainly additional
# `buildInputs` for dependencies. <br />
# For example, if you use the `openssl` crate, `pkgs.pkg-config` and
# `pkgs.openssl` are automatically added as buildInputs.
autoCrateSpecificOverrides = attrs0.autoCrateSpecificOverrides or true;
};
argIsAttrs =
if lib.isDerivation arg then false
else if lib.isString arg then false
else if builtins.typeOf arg == "path" then false
else if builtins.hasAttr "outPath" arg then false
else true;
# if the argument is not an attribute set, then assume it's the 'root'.
attrs =
if argIsAttrs
then mkAttrs arg
else mkAttrs { root = arg; };
userAttrs =
if argIsAttrs
then removeAttrs arg (builtins.attrNames attrs)
else {};
# we differentiate 'src' and 'root'. 'src' is used as source for the build;
# 'root' is used to find files like 'Cargo.toml'. As often as possible 'root'
# should be a "path" to avoid reading values from the nix-store.
# Below we try to come up with some good values for src and root if they're
# not defined.
sr =
let
hasRoot = ! isNull attrs.root;
hasSrc = ! isNull attrs.src;
isPath = x: builtins.typeOf x == "path";
root = attrs.root;
src = attrs.src;
in
# src: yes, root: no
if hasSrc && ! hasRoot then
if isPath src then
{ src = lib.cleanSource src; root = src; }
else { inherit src; root = src; }
# src: yes, root: yes
else if hasRoot && hasSrc then
{ inherit src root; }
# src: no, root: yes
else if hasRoot && ! hasSrc then
if isPath root then
{ inherit root; src = lib.cleanSource root; }
else
{ inherit root; src = root; }
# src: no, root: yes
else throw "please specify either 'src' or 'root'";
usePureFromTOML = attrs.usePureFromTOML;
readTOML = builtinz.readTOML usePureFromTOML;
cargoCommand = let
mode = attrs.mode;
in
if (mode == "build") then
attrs.cargoBuild
else if (mode == "check") then
''cargo $cargo_options check $cargo_build_options >> $cargo_build_output_json''
else if (mode == "test") then
''cargo $cargo_options test $cargo_test_options >> $cargo_build_output_json''
else if (mode == "clippy") then
''cargo $cargo_options clippy $cargo_build_options -- $cargo_clippy_options >> $cargo_build_output_json''
else if (mode == "fmt") then
''cargo $cargo_options fmt -- $cargo_fmt_options''
else throw "Unknown mode ${mode}, allowed modes: build, check, test, clippy";
# config used during build the prebuild and the final build
buildConfig = {
inherit cargoCommand;
inherit (attrs)
nativeBuildInputs
buildInputs
release
override
cargoOptions
compressTarget
mode
cratesDownloadUrl
cargoBuildOptions
remapPathPrefix
copyBins
copyBinsFilter
copyLibs
copyLibsFilter
copyTarget
cargoTestCommands
cargoTestOptions
cargoClippyOptions
cargoFmtOptions
doDoc
doDocFail
cargoDocCommands
cargoDocOptions
copyDocsToSeparateOutput
removeReferencesToSrcFromDocs
autoCrateSpecificOverrides
postInstall
;
# The list of _all_ crates (incl. transitive dependencies) with name,
# version and sha256 of the crate
# Example:
# [ { name = "wabt", version = "2.0.6", sha256 = "..." } ]
cratesIoDependencies = libb.mkVersions buildPlanConfig.cargolock ++ lib.optionals (! isNull buildPlanConfig.additionalcargolock) (libb.mkVersions buildPlanConfig.additionalcargolock);
crateSpecificOverrides = import ./crate_specific.nix { inherit pkgs; };
};
# config used when planning the builds
buildPlanConfig = rec {
inherit userAttrs;
inherit (sr) src root;
inherit (attrs) overrideMain gitAllRefs gitSubmodules;
isSingleStep = attrs.singleStep;
# List of all the Cargo.tomls in the workspace.
#
# Note that the simplest thing here would be to read `workspace.members`,
# but somewhat unfortunately there's no requirement that all workspace
# crates should be listed there - for instance, some projects¹ do:
#
# ```
# [workspace]
# members = [ "crates/foo", "crates/bar" ]
#
# [dependencies]
# foo = { path = "crates/foo" }
# bar = { path = "crates/bar" }
# zar = { path = "crates/zar" }
# ```
#
# ... which Cargo allows and so should we.
#
# ¹ such as Nushell
cargotomls =
let
findCargoTomls = dir:
lib.mapAttrsToList
(name: type:
let
path = "${root}/${dir}/${name}";
in
if name == "Cargo.toml" then
[{ name = dir; toml = readTOML path; }]
else if type == "directory" then
findCargoTomls "${dir}/${name}"
else
[])
(builtins.readDir "${root}/${dir}");
in
lib.flatten (findCargoTomls ".");
# If `copySourcesFrom` is set, then it looks like the benefits brought by
# two-step caching break, for unclear reasons as of now. As such, do not set
# `copySourcesFrom` if there is no source to actually copy from.
copySourcesFrom = if copySources != [] then src else null;
copySources =
let
mkRelative = po:
if lib.hasPrefix "/" po.path
then throw "'${toString src}/Cargo.toml' contains the absolute path '${toString po.path}' which is not allowed under a [patch] section by naersk. Please make it relative to '${toString src}'"
else po.path;
in
arg.copySources or []
++
lib.optionals (builtins.hasAttr "patch" toplevelCargotoml)
(
map mkRelative
(
lib.collect (as: lib.isAttrs as && builtins.hasAttr "path" as)
toplevelCargotoml.patch
)
);
# Are we building a workspace (or is this a simple crate) ?
isWorkspace = builtins.hasAttr "workspace" toplevelCargotoml;
# The top level Cargo.toml, either a workspace or package
toplevelCargotoml = readTOML (root + "/Cargo.toml");
# The cargo lock
cargolock =
let
cargolock-file = root + "/Cargo.lock";
in
if builtins.pathExists cargolock-file then
readTOML (cargolock-file)
else
throw "Naersk requires Cargo.lock to be available in root. Check that it is not in .gitignore and stage it when using git to filter sources (which flakes does)";
additionalcargolock =
if ! isNull attrs.additionalCargoLock then
readTOML (attrs.additionalCargoLock)
else
null;
packageName =
if ! isNull attrs.name
then attrs.name
else toplevelCargotoml.package.name or
(if isWorkspace then "rust-workspace" else "rust-package");
packageVersion =
if ! isNull attrs.version
then attrs.version
else toplevelCargotoml.package.version
or toplevelCargotoml."workspace.package".version
or "unknown";
};
in
buildPlanConfig // { inherit buildConfig; }