1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-28 13:41:15 +02:00

Merge remote-tracking branch 'detsys/detsys-main' into lazy-trees-tmp

This commit is contained in:
Eelco Dolstra 2025-04-23 12:25:28 +02:00
commit a6faa69fc8
109 changed files with 1219 additions and 546 deletions

View file

@ -136,7 +136,10 @@ jobs:
production-branch: detsys-main production-branch: detsys-main
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
deploy-message: "Deploy from GitHub Actions" deploy-message: "Deploy from GitHub Actions"
enable-pull-request-comment: true # NOTE(cole-h): We have a perpetual PR displaying our changes against upstream open, but
# its conversation is locked, so this PR comment can never be posted.
# https://github.com/DeterminateSystems/nix-src/pull/4
enable-pull-request-comment: ${{ github.event.pull_request.number != 4 }}
enable-commit-comment: true enable-commit-comment: true
enable-commit-status: true enable-commit-status: true
overwrites-pull-request-comment: true overwrites-pull-request-comment: true

View file

@ -1 +1 @@
2.28.1 2.28.2

View file

@ -1 +1 @@
3.2.1 3.3.1

View file

@ -250,7 +250,6 @@ nix3_manpages = [
'nix3-print-dev-env', 'nix3-print-dev-env',
'nix3-profile-diff-closures', 'nix3-profile-diff-closures',
'nix3-profile-history', 'nix3-profile-history',
'nix3-profile-install',
'nix3-profile-list', 'nix3-profile-list',
'nix3-profile', 'nix3-profile',
'nix3-profile-remove', 'nix3-profile-remove',
@ -283,7 +282,6 @@ nix3_manpages = [
'nix3-store', 'nix3-store',
'nix3-store-optimise', 'nix3-store-optimise',
'nix3-store-path-from-hash-part', 'nix3-store-path-from-hash-part',
'nix3-store-ping',
'nix3-store-prefetch-file', 'nix3-store-prefetch-file',
'nix3-store-repair', 'nix3-store-repair',
'nix3-store-sign', 'nix3-store-sign',

View file

@ -128,6 +128,7 @@
- [Contributing](development/contributing.md) - [Contributing](development/contributing.md)
- [Determinate Nix Release Notes](release-notes-determinate/index.md) - [Determinate Nix Release Notes](release-notes-determinate/index.md)
- [Changes between Nix and Determinate Nix](release-notes-determinate/changes.md) - [Changes between Nix and Determinate Nix](release-notes-determinate/changes.md)
- [Release 3.3.0 (2025-04-11)](release-notes-determinate/rl-3.3.0.md)
- [Release 3.1.0 (2025-03-27)](release-notes-determinate/rl-3.1.0.md) - [Release 3.1.0 (2025-03-27)](release-notes-determinate/rl-3.1.0.md)
- [Release 3.0.0 (2025-03-04)](release-notes-determinate/rl-3.0.0.md) - [Release 3.0.0 (2025-03-04)](release-notes-determinate/rl-3.0.0.md)
- [Nix Release Notes](release-notes/index.md) - [Nix Release Notes](release-notes/index.md)

View file

@ -115,7 +115,7 @@ It creates an [attribute set] representing the string context, which can be insp
## Clearing string contexts ## Clearing string contexts
[`buitins.unsafeDiscardStringContext`](./builtins.md#builtins-unsafeDiscardStringContext) will make a copy of a string, but with an empty string context. [`builtins.unsafeDiscardStringContext`](./builtins.md#builtins-unsafeDiscardStringContext) will make a copy of a string, but with an empty string context.
The returned string can be used in more ways, e.g. by operators that require the string context to be empty. The returned string can be used in more ways, e.g. by operators that require the string context to be empty.
The requirement to explicitly discard the string context in such use cases helps ensure that string context elements are not lost by mistake. The requirement to explicitly discard the string context in such use cases helps ensure that string context elements are not lost by mistake.
The "unsafe" marker is only there to remind that Nix normally guarantees that dependencies are tracked, whereas the returned string has lost them. The "unsafe" marker is only there to remind that Nix normally guarantees that dependencies are tracked, whereas the returned string has lost them.

View file

@ -1,9 +1,11 @@
# Changes between Nix and Determinate Nix # Changes between Nix and Determinate Nix
This section lists the differences between upstream Nix 2.24 and Determinate Nix 3.1.0. This section lists the differences between upstream Nix 2.24 and Determinate Nix 3.3.0.
* In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature. * In Determinate Nix, flakes are stable. You no longer need to enable the `flakes` experimental feature.
* In Determinate Nix, the new Nix CLI (i.e. the `nix` command) is stable. You no longer need to enable the `nix-command` experimental feature. * In Determinate Nix, the new Nix CLI (i.e. the `nix` command) is stable. You no longer need to enable the `nix-command` experimental feature.
* Determinate Nix has a setting [`json-log-path`](@docroot@/command-ref/conf-file.md#conf-json-log-path) to send a copy of all Nix log messages (in JSON format) to a file or Unix domain socket. * Determinate Nix has a setting [`json-log-path`](@docroot@/command-ref/conf-file.md#conf-json-log-path) to send a copy of all Nix log messages (in JSON format) to a file or Unix domain socket.
* Determinate Nix has made `nix profile install` an alias to `nix profile add`, a more symmetrical antonym of `nix profile remove`.

View file

@ -0,0 +1,5 @@
# Release 3.3.0 (2025-04-11)
* Based on [upstream Nix 2.28.1](../release-notes/rl-2.28.md).
* The `nix profile install` command is now an alias to `nix profile add`, a more symmetrical antonym of `nix profile remove`.

View file

@ -38,6 +38,15 @@
Curl created sockets without setting `FD_CLOEXEC`/`SOCK_CLOEXEC`. This could previously cause connections to remain open forever when using commands like `nix shell`. This change sets the `FD_CLOEXEC` flag using a `CURLOPT_SOCKOPTFUNCTION` callback. Curl created sockets without setting `FD_CLOEXEC`/`SOCK_CLOEXEC`. This could previously cause connections to remain open forever when using commands like `nix shell`. This change sets the `FD_CLOEXEC` flag using a `CURLOPT_SOCKOPTFUNCTION` callback.
- Add BLAKE3 hash algorithm [#12379](https://github.com/NixOS/nix/pull/12379)
Nix now supports the BLAKE3 hash algorithm as an experimental feature (`blake3-hashes`):
```console
# nix hash file ./file --type blake3 --extra-experimental-features blake3-hashes
blake3-34P4p+iZXcbbyB1i4uoF7eWCGcZHjmaRn6Y7QdynLwU=
```
# Contributors # Contributors
This release was made possible by the following 21 contributors: This release was made possible by the following 21 contributors:

View file

@ -2,6 +2,8 @@
# vim: set filetype=bash: # vim: set filetype=bash:
#!nix shell .#changelog-d --command bash #!nix shell .#changelog-d --command bash
set -euo pipefail
# --- CONFIGURATION --- # --- CONFIGURATION ---
# This does double duty for # This does double duty for

View file

@ -237,12 +237,13 @@ void StorePathCommand::run(ref<Store> store, StorePaths && storePaths)
MixProfile::MixProfile() MixProfile::MixProfile()
{ {
addFlag( addFlag({
{.longName = "profile", .longName = "profile",
.description = "The profile to operate on.", .description = "The profile to operate on.",
.labels = {"path"}, .labels = {"path"},
.handler = {&profile}, .handler = {&profile},
.completer = completePath}); .completer = completePath,
});
} }
void MixProfile::updateProfile(const StorePath & storePath) void MixProfile::updateProfile(const StorePath & storePath)

View file

@ -62,7 +62,7 @@ MixEvalArgs::MixEvalArgs()
.description = "Pass the value *expr* as the argument *name* to Nix functions.", .description = "Pass the value *expr* as the argument *name* to Nix functions.",
.category = category, .category = category,
.labels = {"name", "expr"}, .labels = {"name", "expr"},
.handler = {[&](std::string name, std::string expr) { autoArgs.insert_or_assign(name, AutoArg{AutoArgExpr{expr}}); }} .handler = {[&](std::string name, std::string expr) { autoArgs.insert_or_assign(name, AutoArg{AutoArgExpr{expr}}); }},
}); });
addFlag({ addFlag({
@ -79,7 +79,7 @@ MixEvalArgs::MixEvalArgs()
.category = category, .category = category,
.labels = {"name", "path"}, .labels = {"name", "path"},
.handler = {[&](std::string name, std::string path) { autoArgs.insert_or_assign(name, AutoArg{AutoArgFile{path}}); }}, .handler = {[&](std::string name, std::string path) { autoArgs.insert_or_assign(name, AutoArg{AutoArgFile{path}}); }},
.completer = completePath .completer = completePath,
}); });
addFlag({ addFlag({
@ -104,7 +104,7 @@ MixEvalArgs::MixEvalArgs()
.labels = {"path"}, .labels = {"path"},
.handler = {[&](std::string s) { .handler = {[&](std::string s) {
lookupPath.elements.emplace_back(LookupPath::Elem::parse(s)); lookupPath.elements.emplace_back(LookupPath::Elem::parse(s));
}} }},
}); });
addFlag({ addFlag({
@ -130,7 +130,7 @@ MixEvalArgs::MixEvalArgs()
}}, }},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, openStore(), prefix); completeFlakeRef(completions, openStore(), prefix);
}} }},
}); });
addFlag({ addFlag({

View file

@ -64,21 +64,21 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&]() { .handler = {[&]() {
lockFlags.recreateLockFile = true; lockFlags.recreateLockFile = true;
warn("'--recreate-lock-file' is deprecated and will be removed in a future version; use 'nix flake update' instead."); warn("'--recreate-lock-file' is deprecated and will be removed in a future version; use 'nix flake update' instead.");
}} }},
}); });
addFlag({ addFlag({
.longName = "no-update-lock-file", .longName = "no-update-lock-file",
.description = "Do not allow any updates to the flake's lock file.", .description = "Do not allow any updates to the flake's lock file.",
.category = category, .category = category,
.handler = {&lockFlags.updateLockFile, false} .handler = {&lockFlags.updateLockFile, false},
}); });
addFlag({ addFlag({
.longName = "no-write-lock-file", .longName = "no-write-lock-file",
.description = "Do not write the flake's newly generated lock file.", .description = "Do not write the flake's newly generated lock file.",
.category = category, .category = category,
.handler = {&lockFlags.writeLockFile, false} .handler = {&lockFlags.writeLockFile, false},
}); });
addFlag({ addFlag({
@ -94,14 +94,14 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&]() { .handler = {[&]() {
lockFlags.useRegistries = false; lockFlags.useRegistries = false;
warn("'--no-registries' is deprecated; use '--no-use-registries'"); warn("'--no-registries' is deprecated; use '--no-use-registries'");
}} }},
}); });
addFlag({ addFlag({
.longName = "commit-lock-file", .longName = "commit-lock-file",
.description = "Commit changes to the flake's lock file.", .description = "Commit changes to the flake's lock file.",
.category = category, .category = category,
.handler = {&lockFlags.commitLockFile, true} .handler = {&lockFlags.commitLockFile, true},
}); });
addFlag({ addFlag({
@ -121,7 +121,7 @@ MixFlakeOptions::MixFlakeOptions()
}}, }},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix); completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
}} }},
}); });
addFlag({ addFlag({
@ -141,7 +141,7 @@ MixFlakeOptions::MixFlakeOptions()
} else if (n == 1) { } else if (n == 1) {
completeFlakeRef(completions, getEvalState()->store, prefix); completeFlakeRef(completions, getEvalState()->store, prefix);
} }
}} }},
}); });
addFlag({ addFlag({
@ -152,7 +152,7 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&](std::string lockFilePath) { .handler = {[&](std::string lockFilePath) {
lockFlags.referenceLockFilePath = {getFSSourceAccessor(), CanonPath(absPath(lockFilePath))}; lockFlags.referenceLockFilePath = {getFSSourceAccessor(), CanonPath(absPath(lockFilePath))};
}}, }},
.completer = completePath .completer = completePath,
}); });
addFlag({ addFlag({
@ -163,7 +163,7 @@ MixFlakeOptions::MixFlakeOptions()
.handler = {[&](std::string lockFilePath) { .handler = {[&](std::string lockFilePath) {
lockFlags.outputLockFilePath = lockFilePath; lockFlags.outputLockFilePath = lockFilePath;
}}, }},
.completer = completePath .completer = completePath,
}); });
addFlag({ addFlag({
@ -190,7 +190,7 @@ MixFlakeOptions::MixFlakeOptions()
}}, }},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, getEvalState()->store, prefix); completeFlakeRef(completions, getEvalState()->store, prefix);
}} }},
}); });
} }
@ -206,7 +206,7 @@ SourceExprCommand::SourceExprCommand()
.category = installablesCategory, .category = installablesCategory,
.labels = {"file"}, .labels = {"file"},
.handler = {&file}, .handler = {&file},
.completer = completePath .completer = completePath,
}); });
addFlag({ addFlag({
@ -214,7 +214,7 @@ SourceExprCommand::SourceExprCommand()
.description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.", .description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.",
.category = installablesCategory, .category = installablesCategory,
.labels = {"expr"}, .labels = {"expr"},
.handler = {&expr} .handler = {&expr},
}); });
} }
@ -831,7 +831,7 @@ RawInstallablesCommand::RawInstallablesCommand()
addFlag({ addFlag({
.longName = "stdin", .longName = "stdin",
.description = "Read installables from the standard input. No default installable applied.", .description = "Read installables from the standard input. No default installable applied.",
.handler = {&readFromStdIn, true} .handler = {&readFromStdIn, true},
}); });
expectArgs({ expectArgs({
@ -844,7 +844,7 @@ RawInstallablesCommand::RawInstallablesCommand()
void RawInstallablesCommand::applyDefaultInstallables(std::vector<std::string> & rawInstallables) void RawInstallablesCommand::applyDefaultInstallables(std::vector<std::string> & rawInstallables)
{ {
if (rawInstallables.empty()) { if (rawInstallables.empty()) {
// FIXME: commands like "nix profile install" should not have a // FIXME: commands like "nix profile add" should not have a
// default, probably. // default, probably.
rawInstallables.push_back("."); rawInstallables.push_back(".");
} }

View file

@ -20,7 +20,6 @@ headers = [config_pub_h] + files(
'gc-small-vector.hh', 'gc-small-vector.hh',
'get-drvs.hh', 'get-drvs.hh',
'json-to-value.hh', 'json-to-value.hh',
# internal: 'lexer-helpers.hh',
'nixexpr.hh', 'nixexpr.hh',
'parser-state.hh', 'parser-state.hh',
'primops.hh', 'primops.hh',

View file

@ -65,7 +65,7 @@ struct DocComment {
struct AttrName struct AttrName
{ {
Symbol symbol; Symbol symbol;
Expr * expr; Expr * expr = nullptr;
AttrName(Symbol s) : symbol(s) {}; AttrName(Symbol s) : symbol(s) {};
AttrName(Expr * e) : expr(e) {}; AttrName(Expr * e) : expr(e) {};
}; };
@ -159,7 +159,7 @@ struct ExprVar : Expr
`nullptr`: Not from a `with`. `nullptr`: Not from a `with`.
Valid pointer: the nearest, innermost `with` expression to query first. */ Valid pointer: the nearest, innermost `with` expression to query first. */
ExprWith * fromWith; ExprWith * fromWith = nullptr;
/* In the former case, the value is obtained by going `level` /* In the former case, the value is obtained by going `level`
levels up from the current environment and getting the levels up from the current environment and getting the
@ -167,7 +167,7 @@ struct ExprVar : Expr
value is obtained by getting the attribute named `name` from value is obtained by getting the attribute named `name` from
the set stored in the environment that is `level` levels up the set stored in the environment that is `level` levels up
from the current one.*/ from the current one.*/
Level level; Level level = 0;
Displacement displ = 0; Displacement displ = 0;
ExprVar(Symbol name) : name(name) { }; ExprVar(Symbol name) : name(name) { };

View file

@ -1,7 +1,4 @@
#include "lexer-tab.hh" #include "lexer-helpers.hh"
#include "parser-tab.hh"
#include "nix/expr/lexer-helpers.hh"
void nix::lexer::internal::initLoc(YYLTYPE * loc) void nix::lexer::internal::initLoc(YYLTYPE * loc)
{ {

View file

@ -25,8 +25,7 @@
#endif #endif
#include "nix/expr/nixexpr.hh" #include "nix/expr/nixexpr.hh"
#include "parser-tab.hh" #include "lexer-helpers.hh"
#include "nix/expr/lexer-helpers.hh"
namespace nix { namespace nix {
struct LexerState; struct LexerState;

View file

@ -14,6 +14,7 @@ overrides:
fetchTreeFinal: fetchTreeFinal:
let let
inherit (builtins) mapAttrs;
lockFile = builtins.fromJSON lockFileStr; lockFile = builtins.fromJSON lockFileStr;
@ -35,19 +36,26 @@ let
(resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path}) (resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path})
(builtins.tail path); (builtins.tail path);
allNodes = builtins.mapAttrs ( allNodes = mapAttrs (
key: node: key: node:
let let
parentNode = allNodes.${getInputByPath lockFile.root node.parent}; parentNode = allNodes.${getInputByPath lockFile.root node.parent};
flakeDir =
let
dir = overrides.${key}.dir or node.locked.path or "";
parentDir = parentNode.flakeDir;
in
if node ? parent then parentDir + ("/" + dir) else dir;
sourceInfo = sourceInfo =
if overrides ? ${key} then if overrides ? ${key} then
overrides.${key}.sourceInfo overrides.${key}.sourceInfo
else if node.locked.type == "path" && builtins.substring 0 1 node.locked.path != "/" then else if node.locked.type == "path" && builtins.substring 0 1 node.locked.path != "/" then
parentNode.sourceInfo parentNode.sourceInfo
// { // {
outPath = parentNode.outPath + ("/" + node.locked.path); outPath = parentNode.sourceInfo.outPath + ("/" + flakeDir);
} }
else else
# FIXME: remove obsolete node.info. # FIXME: remove obsolete node.info.
@ -60,7 +68,7 @@ let
flake = import (outPath + "/flake.nix"); flake = import (outPath + "/flake.nix");
inputs = builtins.mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}) ( inputs = mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}.result) (
node.inputs or { } node.inputs or { }
); );
@ -85,12 +93,17 @@ let
}; };
in in
{
result =
if node.flake or true then if node.flake or true then
assert builtins.isFunction flake.outputs; assert builtins.isFunction flake.outputs;
result result
else else
sourceInfo sourceInfo;
inherit flakeDir sourceInfo;
}
) lockFile.nodes; ) lockFile.nodes;
in in
allNodes.${lockFile.root} allNodes.${lockFile.root}.result

View file

@ -57,7 +57,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
if (hasPrefix(s.first, prefix)) if (hasPrefix(s.first, prefix))
completions.add(s.first, fmt("Set the `%s` setting.", s.first)); completions.add(s.first, fmt("Set the `%s` setting.", s.first));
} }
} },
}); });
addFlag({ addFlag({
@ -75,7 +75,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
.labels = Strings{"jobs"}, .labels = Strings{"jobs"},
.handler = {[=](std::string s) { .handler = {[=](std::string s) {
settings.set("max-jobs", s); settings.set("max-jobs", s);
}} }},
}); });
std::string cat = "Options to override configuration settings"; std::string cat = "Options to override configuration settings";

View file

@ -231,7 +231,7 @@ LegacyArgs::LegacyArgs(const std::string & programName,
.handler = {[=](std::string s) { .handler = {[=](std::string s) {
auto n = string2IntWithUnitPrefix<uint64_t>(s); auto n = string2IntWithUnitPrefix<uint64_t>(s);
settings.set(dest, std::to_string(n)); settings.set(dest, std::to_string(n));
}} }},
}); });
}; };

View file

@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes-defaults.drv

View file

@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes-structured-attrs-defaults.drv

View file

@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes-structured-attrs.drv

View file

@ -1,41 +0,0 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar\"],\"disallowedRequisites\":[\"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo\"],\"allowedRequisites\":[\"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}",
"bin": "/nix/store/pbzb48v0ycf80jgligcp4n8z0rblna4n-advanced-attributes-structured-attrs-bin",
"dev": "/nix/store/7xapi8jv7flcz1qq8jhw55ar8ag8hldh-advanced-attributes-structured-attrs-dev",
"out": "/nix/store/mpq3l1l1qc2yr50q520g08kprprwv79f-advanced-attributes-structured-attrs"
},
"inputDrvs": {
"/nix/store/4xm4wccqsvagz9gjksn24s7rip2fdy7v-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"out"
]
},
"/nix/store/plsq5jbr5nhgqwcgb2qxw7jchc09dnl8-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"path": "/nix/store/pbzb48v0ycf80jgligcp4n8z0rblna4n-advanced-attributes-structured-attrs-bin"
},
"dev": {
"path": "/nix/store/7xapi8jv7flcz1qq8jhw55ar8ag8hldh-advanced-attributes-structured-attrs-dev"
},
"out": {
"path": "/nix/store/mpq3l1l1qc2yr50q520g08kprprwv79f-advanced-attributes-structured-attrs"
}
},
"system": "my-system"
}

View file

@ -1 +0,0 @@
../../../../tests/functional/derivation/advanced-attributes.drv

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes-defaults.drv

View file

@ -0,0 +1,25 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"builder": "/bin/bash",
"name": "advanced-attributes-defaults",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9",
"outputHashAlgo": "sha256",
"outputHashMode": "recursive",
"system": "my-system"
},
"inputDrvs": {},
"inputSrcs": [],
"name": "advanced-attributes-defaults",
"outputs": {
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes-structured-attrs-defaults.drv

View file

@ -0,0 +1,26 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"builder\":\"/bin/bash\",\"name\":\"advanced-attributes-structured-attrs-defaults\",\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"dev\"],\"system\":\"my-system\"}",
"dev": "/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
},
"inputDrvs": {},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs-defaults",
"outputs": {
"dev": {
"hashAlgo": "sha256",
"method": "nar"
},
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes-structured-attrs.drv

View file

@ -0,0 +1,46 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}",
"bin": "/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m",
"dev": "/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
},
"inputDrvs": {
"/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"hashAlgo": "sha256",
"method": "nar"
},
"dev": {
"hashAlgo": "sha256",
"method": "nar"
},
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ca/advanced-attributes.drv

View file

@ -0,0 +1,52 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__darwinAllowLocalNetworking": "1",
"__impureHostDeps": "/usr/bin/ditto",
"__noChroot": "1",
"__sandboxProfile": "sandcastle",
"allowSubstitutes": "",
"allowedReferences": "/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9",
"allowedRequisites": "/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z",
"builder": "/bin/bash",
"disallowedReferences": "/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g",
"disallowedRequisites": "/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8",
"impureEnvVars": "UNICORN",
"name": "advanced-attributes",
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9",
"outputHashAlgo": "sha256",
"outputHashMode": "recursive",
"preferLocalBuild": "1",
"requiredSystemFeatures": "rainbow uid-range",
"system": "my-system"
},
"inputDrvs": {
"/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes",
"outputs": {
"out": {
"hashAlgo": "sha256",
"method": "nar"
}
},
"system": "my-system"
}

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes-defaults.drv

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes-structured-attrs-defaults.drv

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes-structured-attrs.drv

View file

@ -0,0 +1,43 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__json": "{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar\"],\"disallowedRequisites\":[\"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo\"],\"allowedRequisites\":[\"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}",
"bin": "/nix/store/qjjj3zrlimpjbkk686m052b3ks9iz2sl-advanced-attributes-structured-attrs-bin",
"dev": "/nix/store/lpz5grl48v93pdadavyg5is1rqvfdipf-advanced-attributes-structured-attrs-dev",
"out": "/nix/store/nzvz1bmh1g89a5dkpqcqan0av7q3hgv3-advanced-attributes-structured-attrs"
},
"inputDrvs": {
"/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"path": "/nix/store/qjjj3zrlimpjbkk686m052b3ks9iz2sl-advanced-attributes-structured-attrs-bin"
},
"dev": {
"path": "/nix/store/lpz5grl48v93pdadavyg5is1rqvfdipf-advanced-attributes-structured-attrs-dev"
},
"out": {
"path": "/nix/store/nzvz1bmh1g89a5dkpqcqan0av7q3hgv3-advanced-attributes-structured-attrs"
}
},
"system": "my-system"
}

View file

@ -0,0 +1 @@
../../../../../tests/functional/derivation/ia/advanced-attributes.drv

View file

@ -0,0 +1,49 @@
{
"args": [
"-c",
"echo hello > $out"
],
"builder": "/bin/bash",
"env": {
"__darwinAllowLocalNetworking": "1",
"__impureHostDeps": "/usr/bin/ditto",
"__noChroot": "1",
"__sandboxProfile": "sandcastle",
"allowSubstitutes": "",
"allowedReferences": "/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo",
"allowedRequisites": "/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev",
"builder": "/bin/bash",
"disallowedReferences": "/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar",
"disallowedRequisites": "/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev",
"impureEnvVars": "UNICORN",
"name": "advanced-attributes",
"out": "/nix/store/swkj0mrq0cq3dfli95v4am0427mi2hxf-advanced-attributes",
"preferLocalBuild": "1",
"requiredSystemFeatures": "rainbow uid-range",
"system": "my-system"
},
"inputDrvs": {
"/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
}
},
"inputSrcs": [],
"name": "advanced-attributes",
"outputs": {
"out": {
"path": "/nix/store/swkj0mrq0cq3dfli95v4am0427mi2hxf-advanced-attributes"
}
},
"system": "my-system"
}

View file

@ -18,68 +18,93 @@ using nlohmann::json;
class DerivationAdvancedAttrsTest : public CharacterizationTest, public LibStoreTest class DerivationAdvancedAttrsTest : public CharacterizationTest, public LibStoreTest
{ {
std::filesystem::path unitTestData = getUnitTestData() / "derivation"; protected:
std::filesystem::path unitTestData = getUnitTestData() / "derivation" / "ia";
public: public:
std::filesystem::path goldenMaster(std::string_view testStem) const override std::filesystem::path goldenMaster(std::string_view testStem) const override
{ {
return unitTestData / testStem; return unitTestData / testStem;
} }
/**
* We set these in tests rather than the regular globals so we don't have
* to worry about race conditions if the tests run concurrently.
*/
ExperimentalFeatureSettings mockXpSettings;
}; };
class CaDerivationAdvancedAttrsTest : public DerivationAdvancedAttrsTest
{
void SetUp() override
{
unitTestData = getUnitTestData() / "derivation" / "ca";
mockXpSettings.set("experimental-features", "ca-derivations");
}
};
template<class Fixture>
class DerivationAdvancedAttrsBothTest : public Fixture
{};
using BothFixtures = ::testing::Types<DerivationAdvancedAttrsTest, CaDerivationAdvancedAttrsTest>;
TYPED_TEST_SUITE(DerivationAdvancedAttrsBothTest, BothFixtures);
#define TEST_ATERM_JSON(STEM, NAME) \ #define TEST_ATERM_JSON(STEM, NAME) \
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_from_json) \ TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_json) \
{ \ { \
readTest(NAME ".json", [&](const auto & encoded_) { \ this->readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \ auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \ /* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(goldenMaster(NAME ".drv")); \ auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*store, std::move(aterm), NAME); \ auto expected = parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings); \
Derivation got = Derivation::fromJSON(*store, encoded); \ Derivation got = Derivation::fromJSON(*this->store, encoded, this->mockXpSettings); \
EXPECT_EQ(got, expected); \ EXPECT_EQ(got, expected); \
}); \ }); \
} \ } \
\ \
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_to_json) \ TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_to_json) \
{ \ { \
writeTest( \ this->writeTest( \
NAME ".json", \ NAME ".json", \
[&]() -> json { \ [&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \ /* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(goldenMaster(NAME ".drv")); \ auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
return parseDerivation(*store, std::move(aterm), NAME).toJSON(*store); \ return parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings) \
.toJSON(*this->store); \
}, \ }, \
[](const auto & file) { return json::parse(readFile(file)); }, \ [](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \ [](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \ } \
\ \
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_from_aterm) \ TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_aterm) \
{ \ { \
readTest(NAME ".drv", [&](auto encoded) { \ this->readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \ /* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(goldenMaster(NAME ".json"))); \ auto json = json::parse(readFile(this->goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(*store, json); \ auto expected = Derivation::fromJSON(*this->store, json, this->mockXpSettings); \
auto got = parseDerivation(*store, std::move(encoded), NAME); \ auto got = parseDerivation(*this->store, std::move(encoded), NAME, this->mockXpSettings); \
EXPECT_EQ(got.toJSON(*store), expected.toJSON(*store)); \ EXPECT_EQ(got.toJSON(*this->store), expected.toJSON(*this->store)); \
EXPECT_EQ(got, expected); \ EXPECT_EQ(got, expected); \
}); \ }); \
} \ } \
\ \
/* No corresponding write test, because we need to read the drv to write the json file */ /* No corresponding write test, because we need to read the drv to write the json file */
TEST_ATERM_JSON(advancedAttributes_defaults, "advanced-attributes-defaults");
TEST_ATERM_JSON(advancedAttributes, "advanced-attributes-defaults"); TEST_ATERM_JSON(advancedAttributes, "advanced-attributes-defaults");
TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attributes-structured-attrs"); TEST_ATERM_JSON(advancedAttributes_defaults, "advanced-attributes");
TEST_ATERM_JSON(advancedAttributes_structuredAttrs, "advanced-attributes-structured-attrs-defaults"); TEST_ATERM_JSON(advancedAttributes_structuredAttrs, "advanced-attributes-structured-attrs-defaults");
TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attributes-structured-attrs");
#undef TEST_ATERM_JSON #undef TEST_ATERM_JSON
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults) TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)
{ {
readTest("advanced-attributes-defaults.drv", [&](auto encoded) { this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo"); auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true); auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got); ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv); DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
@ -101,25 +126,50 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults)
EXPECT_EQ(checksForAllOutputs.disallowedReferences, StringSet{}); EXPECT_EQ(checksForAllOutputs.disallowedReferences, StringSet{});
EXPECT_EQ(checksForAllOutputs.disallowedRequisites, StringSet{}); EXPECT_EQ(checksForAllOutputs.disallowedRequisites, StringSet{});
} }
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet()); EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.canBuildLocally(*store, got), false); EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true); EXPECT_EQ(options.substitutesAllowed(), true);
EXPECT_EQ(options.useUidRange(got), false); EXPECT_EQ(options.useUidRange(got), false);
}); });
}; };
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes) TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_defaults)
{ {
readTest("advanced-attributes.drv", [&](auto encoded) { this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo"); auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true); auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got); ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv); DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
StringSet systemFeatures{"rainbow", "uid-range"}; EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_defaults)
{
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes)
{
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_TRUE(!parsedDrv.hasStructuredAttrs()); EXPECT_TRUE(!parsedDrv.hasStructuredAttrs());
@ -128,34 +178,88 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes)
EXPECT_EQ(options.impureHostDeps, StringSet{"/usr/bin/ditto"}); EXPECT_EQ(options.impureHostDeps, StringSet{"/usr/bin/ditto"});
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"}); EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true); EXPECT_EQ(options.allowLocalNetworking, true);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
});
};
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes)
{
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{ {
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks); auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr); ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_; auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ( EXPECT_EQ(
checksForAllOutputs.allowedReferences, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"}); checksForAllOutputs.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ( EXPECT_EQ(
checksForAllOutputs.allowedRequisites, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"}); checksForAllOutputs.allowedRequisites,
StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
EXPECT_EQ( EXPECT_EQ(
checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"}); checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
EXPECT_EQ( EXPECT_EQ(
checksForAllOutputs.disallowedRequisites, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"}); checksForAllOutputs.disallowedRequisites,
StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"});
} }
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures); EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
}); });
}; };
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttrs_defaults) TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes)
{ {
readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) { this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo"); auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true); auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(
checksForAllOutputs.allowedReferences,
StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"});
EXPECT_EQ(
checksForAllOutputs.allowedRequisites,
StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"});
EXPECT_EQ(
checksForAllOutputs.disallowedReferences,
StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"});
EXPECT_EQ(
checksForAllOutputs.disallowedRequisites,
StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"});
}
StringSet systemFeatures{"rainbow", "uid-range"};
systemFeatures.insert("ca-derivations");
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_defaults)
{
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got); ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv); DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
@ -176,25 +280,50 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(checksPerOutput.size(), 0); EXPECT_EQ(checksPerOutput.size(), 0);
} }
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet()); EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.canBuildLocally(*store, got), false); EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true); EXPECT_EQ(options.substitutesAllowed(), true);
EXPECT_EQ(options.useUidRange(got), false); EXPECT_EQ(options.useUidRange(got), false);
}); });
}; };
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttrs) TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)
{ {
readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) { this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo"); auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*store, got, NoRepair, true); auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got); ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv); DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
StringSet systemFeatures{"rainbow", "uid-range"}; EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)
{
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
EXPECT_TRUE(parsedDrv.hasStructuredAttrs()); EXPECT_TRUE(parsedDrv.hasStructuredAttrs());
@ -204,25 +333,6 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"}); EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true); EXPECT_EQ(options.allowLocalNetworking, true);
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "bin");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.disallowedReferences, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
EXPECT_EQ(output.disallowedRequisites, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
}
{ {
auto output_ = get(std::get<1>(options.outputChecks), "dev"); auto output_ = get(std::get<1>(options.outputChecks), "dev");
ASSERT_TRUE(output_); ASSERT_TRUE(output_);
@ -231,14 +341,88 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(output.maxSize, 789); EXPECT_EQ(output.maxSize, 789);
EXPECT_EQ(output.maxClosureSize, 5909); EXPECT_EQ(output.maxClosureSize, 5909);
} }
}
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures); EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.canBuildLocally(*store, got), false); EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.substitutesAllowed(), false); EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true); EXPECT_EQ(options.useUidRange(got), true);
}); });
}; };
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "bin");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
EXPECT_EQ(
output.disallowedRequisites, StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"});
}
}
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
ParsedDerivation parsedDrv(drvPath, got);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "bin");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(
output.disallowedReferences, StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"});
EXPECT_EQ(
output.disallowedRequisites, StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"});
}
}
StringSet systemFeatures{"rainbow", "uid-range"};
systemFeatures.insert("ca-derivations");
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
};
} }

View file

@ -73,6 +73,32 @@ TEST(machines, getMachinesWithSemicolonSeparator) {
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl")))); EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
} }
TEST(machines, getMachinesWithCommentsAndSemicolonSeparator) {
auto actual = Machine::parseConfig({},
"# This is a comment ; this is still that comment\n"
"nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl\n"
"# This is also a comment ; this also is still that comment\n"
"nix@scabby.labs.cs.uu.nl\n");
EXPECT_THAT(actual, SizeIs(3));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scratchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scabby.labs.cs.uu.nl"))));
}
TEST(machines, getMachinesWithFunnyWhitespace) {
auto actual = Machine::parseConfig({},
" # commment ; comment\n"
" nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl \n"
"\n \n"
"\n ;;; \n"
"\n ; ; \n"
"nix@scabby.labs.cs.uu.nl\n\n");
EXPECT_THAT(actual, SizeIs(3));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scratchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@itchy.labs.cs.uu.nl"))));
EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, AuthorityMatches("nix@scabby.labs.cs.uu.nl"))));
}
TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) { TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) {
auto actual = Machine::parseConfig({}, auto actual = Machine::parseConfig({},
"nix@scratchy.labs.cs.uu.nl i686-linux " "nix@scratchy.labs.cs.uu.nl i686-linux "

View file

@ -68,7 +68,6 @@ DerivationOptions DerivationOptions::fromParsedDerivation(const ParsedDerivation
throw Error("attribute '%s' must be a list of strings", name); throw Error("attribute '%s' must be a list of strings", name);
res.insert(j->get<std::string>()); res.insert(j->get<std::string>());
} }
checks.disallowedRequisites = res;
return res; return res;
} }
return {}; return {};

View file

@ -1368,7 +1368,7 @@ Derivation Derivation::fromJSON(
for (auto & [outputName, output] : getObject(valueAt(json, "outputs"))) { for (auto & [outputName, output] : getObject(valueAt(json, "outputs"))) {
res.outputs.insert_or_assign( res.outputs.insert_or_assign(
outputName, outputName,
DerivationOutput::fromJSON(store, res.name, outputName, output)); DerivationOutput::fromJSON(store, res.name, outputName, output, xpSettings));
} }
} catch (Error & e) { } catch (Error & e) {
e.addTrace({}, "while reading key 'outputs'"); e.addTrace({}, "while reading key 'outputs'");

View file

@ -22,10 +22,8 @@
#include <curl/curl.h> #include <curl/curl.h>
#include <algorithm>
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <iostream>
#include <queue> #include <queue>
#include <random> #include <random>
#include <thread> #include <thread>
@ -95,7 +93,7 @@ struct curlFileTransfer : public FileTransfer
: fileTransfer(fileTransfer) : fileTransfer(fileTransfer)
, request(request) , request(request)
, act(*logger, lvlTalkative, actFileTransfer, , act(*logger, lvlTalkative, actFileTransfer,
request.post ? "" : fmt(request.data ? "uploading '%s'" : "downloading '%s'", request.uri), fmt("%sing '%s'", request.verb(), request.uri),
{request.uri}, request.parentAct) {request.uri}, request.parentAct)
, callback(std::move(callback)) , callback(std::move(callback))
, finalSink([this](std::string_view data) { , finalSink([this](std::string_view data) {
@ -272,19 +270,11 @@ struct curlFileTransfer : public FileTransfer
return getInterrupted(); return getInterrupted();
} }
int silentProgressCallback(curl_off_t dltotal, curl_off_t dlnow)
{
return getInterrupted();
}
static int progressCallbackWrapper(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) static int progressCallbackWrapper(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{ {
return ((TransferItem *) userp)->progressCallback(dltotal, dlnow); auto & item = *static_cast<TransferItem *>(userp);
} auto isUpload = bool(item.request.data);
return item.progressCallback(isUpload ? ultotal : dltotal, isUpload ? ulnow : dlnow);
static int silentProgressCallbackWrapper(void * userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
{
return ((TransferItem *) userp)->silentProgressCallback(dltotal, dlnow);
} }
static int debugCallback(CURL * handle, curl_infotype type, char * data, size_t size, void * userptr) static int debugCallback(CURL * handle, curl_infotype type, char * data, size_t size, void * userptr)
@ -353,9 +343,6 @@ struct curlFileTransfer : public FileTransfer
curl_easy_setopt(req, CURLOPT_HEADERFUNCTION, TransferItem::headerCallbackWrapper); curl_easy_setopt(req, CURLOPT_HEADERFUNCTION, TransferItem::headerCallbackWrapper);
curl_easy_setopt(req, CURLOPT_HEADERDATA, this); curl_easy_setopt(req, CURLOPT_HEADERDATA, this);
if (request.post)
curl_easy_setopt(req, CURLOPT_XFERINFOFUNCTION, silentProgressCallbackWrapper);
else
curl_easy_setopt(req, CURLOPT_XFERINFOFUNCTION, progressCallbackWrapper); curl_easy_setopt(req, CURLOPT_XFERINFOFUNCTION, progressCallbackWrapper);
curl_easy_setopt(req, CURLOPT_XFERINFODATA, this); curl_easy_setopt(req, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(req, CURLOPT_NOPROGRESS, 0); curl_easy_setopt(req, CURLOPT_NOPROGRESS, 0);
@ -449,7 +436,6 @@ struct curlFileTransfer : public FileTransfer
if (httpStatus == 304 && result.etag == "") if (httpStatus == 304 && result.etag == "")
result.etag = request.expectedETag; result.etag = request.expectedETag;
if (!request.post)
act.progress(result.bodySize, result.bodySize); act.progress(result.bodySize, result.bodySize);
done = true; done = true;
callback(std::move(result)); callback(std::move(result));
@ -539,6 +525,8 @@ struct curlFileTransfer : public FileTransfer
warn("%s; retrying from offset %d in %d ms", exc.what(), writtenToSink, ms); warn("%s; retrying from offset %d in %d ms", exc.what(), writtenToSink, ms);
else else
warn("%s; retrying in %d ms", exc.what(), ms); warn("%s; retrying in %d ms", exc.what(), ms);
decompressionSink.reset();
errorSink.reset();
embargo = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms); embargo = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms);
fileTransfer.enqueueItem(shared_from_this()); fileTransfer.enqueueItem(shared_from_this());
} }
@ -791,10 +779,6 @@ struct curlFileTransfer : public FileTransfer
S3Helper s3Helper(profile, region, scheme, endpoint); S3Helper s3Helper(profile, region, scheme, endpoint);
Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("downloading '%s'", request.uri),
{request.uri}, request.parentAct);
// FIXME: implement ETag // FIXME: implement ETag
auto s3Res = s3Helper.getObject(bucketName, key); auto s3Res = s3Helper.getObject(bucketName, key);
FileTransferResult res; FileTransferResult res;

View file

@ -280,21 +280,21 @@ template<> void BaseSetting<SandboxMode>::convertToArg(Args & args, const std::s
.aliases = aliases, .aliases = aliases,
.description = "Enable sandboxing.", .description = "Enable sandboxing.",
.category = category, .category = category,
.handler = {[this]() { override(smEnabled); }} .handler = {[this]() { override(smEnabled); }},
}); });
args.addFlag({ args.addFlag({
.longName = "no-" + name, .longName = "no-" + name,
.aliases = aliases, .aliases = aliases,
.description = "Disable sandboxing.", .description = "Disable sandboxing.",
.category = category, .category = category,
.handler = {[this]() { override(smDisabled); }} .handler = {[this]() { override(smDisabled); }},
}); });
args.addFlag({ args.addFlag({
.longName = "relaxed-" + name, .longName = "relaxed-" + name,
.aliases = aliases, .aliases = aliases,
.description = "Enable sandboxing, but allow builds to disable it.", .description = "Enable sandboxing, but allow builds to disable it.",
.category = category, .category = category,
.handler = {[this]() { override(smRelaxed); }} .handler = {[this]() { override(smRelaxed); }},
}); });
} }

View file

@ -77,7 +77,7 @@ struct FileTransferRequest
FileTransferRequest(std::string_view uri) FileTransferRequest(std::string_view uri)
: uri(uri), parentAct(getCurActivity()) { } : uri(uri), parentAct(getCurActivity()) { }
std::string verb() std::string verb() const
{ {
return data ? "upload" : "download"; return data ? "upload" : "download";
} }

View file

@ -1,6 +1,5 @@
include_dirs += include_directories('../..') include_dirs += include_directories('../..')
headers += files( headers += files(
'fchmodat2-compat.hh',
'personality.hh', 'personality.hh',
) )

View file

@ -105,13 +105,15 @@ ref<Store> Machine::openStore() const
static std::vector<std::string> expandBuilderLines(const std::string & builders) static std::vector<std::string> expandBuilderLines(const std::string & builders)
{ {
std::vector<std::string> result; std::vector<std::string> result;
for (auto line : tokenizeString<std::vector<std::string>>(builders, "\n;")) { for (auto line : tokenizeString<std::vector<std::string>>(builders, "\n")) {
trim(line);
line.erase(std::find(line.begin(), line.end(), '#'), line.end()); line.erase(std::find(line.begin(), line.end(), '#'), line.end());
if (line.empty()) continue; for (auto entry : tokenizeString<std::vector<std::string>>(line, ";")) {
entry = trim(entry);
if (line[0] == '@') { if (entry.empty()) {
const std::string path = trim(std::string(line, 1)); // skip blank entries
} else if (entry[0] == '@') {
const std::string path = trim(std::string_view{entry}.substr(1));
std::string text; std::string text;
try { try {
text = readFile(path); text = readFile(path);
@ -119,14 +121,15 @@ static std::vector<std::string> expandBuilderLines(const std::string & builders)
if (e.errNo != ENOENT) if (e.errNo != ENOENT)
throw; throw;
debug("cannot find machines file '%s'", path); debug("cannot find machines file '%s'", path);
}
const auto lines = expandBuilderLines(text);
result.insert(end(result), begin(lines), end(lines));
continue; continue;
} }
result.emplace_back(line); const auto entrys = expandBuilderLines(text);
result.insert(end(result), begin(entrys), end(entrys));
} else {
result.emplace_back(entry);
}
}
} }
return result; return result;
} }

View file

@ -160,7 +160,10 @@ ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(
S3Helper::FileTransferResult S3Helper::getObject( S3Helper::FileTransferResult S3Helper::getObject(
const std::string & bucketName, const std::string & key) const std::string & bucketName, const std::string & key)
{ {
debug("fetching 's3://%s/%s'...", bucketName, key); std::string uri = "s3://" + bucketName + "/" + key;
Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("downloading '%s'", uri),
Logger::Fields{uri}, getCurActivity());
auto request = auto request =
Aws::S3::Model::GetObjectRequest() Aws::S3::Model::GetObjectRequest()
@ -171,6 +174,22 @@ S3Helper::FileTransferResult S3Helper::getObject(
return Aws::New<std::stringstream>("STRINGSTREAM"); return Aws::New<std::stringstream>("STRINGSTREAM");
}); });
size_t bytesDone = 0;
size_t bytesExpected = 0;
request.SetDataReceivedEventHandler([&](const Aws::Http::HttpRequest * req, Aws::Http::HttpResponse * resp, long long l) {
if (!bytesExpected && resp->HasHeader("Content-Length")) {
if (auto length = string2Int<size_t>(resp->GetHeader("Content-Length"))) {
bytesExpected = *length;
}
}
bytesDone += l;
act.progress(bytesDone, bytesExpected);
});
request.SetContinueRequestHandler([](const Aws::Http::HttpRequest*) {
return !isInterrupted();
});
FileTransferResult res; FileTransferResult res;
auto now1 = std::chrono::steady_clock::now(); auto now1 = std::chrono::steady_clock::now();
@ -180,6 +199,8 @@ S3Helper::FileTransferResult S3Helper::getObject(
auto result = checkAws(fmt("AWS error fetching '%s'", key), auto result = checkAws(fmt("AWS error fetching '%s'", key),
client->GetObject(request)); client->GetObject(request));
act.progress(result.GetContentLength(), result.GetContentLength());
res.data = decompress(result.GetContentEncoding(), res.data = decompress(result.GetContentEncoding(),
dynamic_cast<std::stringstream &>(result.GetBody()).str()); dynamic_cast<std::stringstream &>(result.GetBody()).str());
@ -307,11 +328,35 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
std::shared_ptr<TransferManager> transferManager; std::shared_ptr<TransferManager> transferManager;
std::once_flag transferManagerCreated; std::once_flag transferManagerCreated;
struct AsyncContext : public Aws::Client::AsyncCallerContext
{
mutable std::mutex mutex;
mutable std::condition_variable cv;
const Activity & act;
void notify() const
{
cv.notify_one();
}
void wait() const
{
std::unique_lock<std::mutex> lk(mutex);
cv.wait(lk);
}
AsyncContext(const Activity & act) : act(act) {}
};
void uploadFile(const std::string & path, void uploadFile(const std::string & path,
std::shared_ptr<std::basic_iostream<char>> istream, std::shared_ptr<std::basic_iostream<char>> istream,
const std::string & mimeType, const std::string & mimeType,
const std::string & contentEncoding) const std::string & contentEncoding)
{ {
std::string uri = "s3://" + bucketName + "/" + path;
Activity act(*logger, lvlTalkative, actFileTransfer,
fmt("uploading '%s'", uri),
Logger::Fields{uri}, getCurActivity());
istream->seekg(0, istream->end); istream->seekg(0, istream->end);
auto size = istream->tellg(); auto size = istream->tellg();
istream->seekg(0, istream->beg); istream->seekg(0, istream->beg);
@ -331,15 +376,24 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
transferConfig.uploadProgressCallback = transferConfig.uploadProgressCallback =
[](const TransferManager * transferManager, [](const TransferManager * transferManager,
const std::shared_ptr<const TransferHandle> const std::shared_ptr<const TransferHandle> & transferHandle)
&transferHandle)
{ {
//FIXME: find a way to properly abort the multipart upload. auto context = std::dynamic_pointer_cast<const AsyncContext>(transferHandle->GetContext());
//checkInterrupt(); size_t bytesDone = transferHandle->GetBytesTransferred();
debug("upload progress ('%s'): '%d' of '%d' bytes", size_t bytesTotal = transferHandle->GetBytesTotalSize();
transferHandle->GetKey(), try {
transferHandle->GetBytesTransferred(), checkInterrupt();
transferHandle->GetBytesTotalSize()); context->act.progress(bytesDone, bytesTotal);
} catch (...) {
context->notify();
}
};
transferConfig.transferStatusUpdatedCallback =
[](const TransferManager * transferManager,
const std::shared_ptr<const TransferHandle> & transferHandle)
{
auto context = std::dynamic_pointer_cast<const AsyncContext>(transferHandle->GetContext());
context->notify();
}; };
transferManager = TransferManager::Create(transferConfig); transferManager = TransferManager::Create(transferConfig);
@ -353,29 +407,51 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
if (contentEncoding != "") if (contentEncoding != "")
throw Error("setting a content encoding is not supported with S3 multi-part uploads"); throw Error("setting a content encoding is not supported with S3 multi-part uploads");
auto context = std::make_shared<AsyncContext>(act);
std::shared_ptr<TransferHandle> transferHandle = std::shared_ptr<TransferHandle> transferHandle =
transferManager->UploadFile( transferManager->UploadFile(
istream, bucketName, path, mimeType, istream, bucketName, path, mimeType,
Aws::Map<Aws::String, Aws::String>(), Aws::Map<Aws::String, Aws::String>(),
nullptr /*, contentEncoding */); context /*, contentEncoding */);
TransferStatus status = transferHandle->GetStatus();
while (status == TransferStatus::IN_PROGRESS || status == TransferStatus::NOT_STARTED) {
if (!isInterrupted()) {
context->wait();
} else {
transferHandle->Cancel();
transferHandle->WaitUntilFinished(); transferHandle->WaitUntilFinished();
}
status = transferHandle->GetStatus();
}
act.progress(transferHandle->GetBytesTransferred(), transferHandle->GetBytesTotalSize());
if (transferHandle->GetStatus() == TransferStatus::FAILED) if (status == TransferStatus::FAILED)
throw Error("AWS error: failed to upload 's3://%s/%s': %s", throw Error("AWS error: failed to upload 's3://%s/%s': %s",
bucketName, path, transferHandle->GetLastError().GetMessage()); bucketName, path, transferHandle->GetLastError().GetMessage());
if (transferHandle->GetStatus() != TransferStatus::COMPLETED) if (status != TransferStatus::COMPLETED)
throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state", throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state",
bucketName, path); bucketName, path);
} else { } else {
act.progress(0, size);
auto request = auto request =
Aws::S3::Model::PutObjectRequest() Aws::S3::Model::PutObjectRequest()
.WithBucket(bucketName) .WithBucket(bucketName)
.WithKey(path); .WithKey(path);
size_t bytesSent = 0;
request.SetDataSentEventHandler([&](const Aws::Http::HttpRequest * req, long long l) {
bytesSent += l;
act.progress(bytesSent, size);
});
request.SetContinueRequestHandler([](const Aws::Http::HttpRequest*) {
return !isInterrupted();
});
request.SetContentType(mimeType); request.SetContentType(mimeType);
if (contentEncoding != "") if (contentEncoding != "")
@ -385,6 +461,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto result = checkAws(fmt("AWS error uploading '%s'", path), auto result = checkAws(fmt("AWS error uploading '%s'", path),
s3Helper.client->PutObject(request)); s3Helper.client->PutObject(request));
act.progress(size, size);
} }
auto now2 = std::chrono::steady_clock::now(); auto now2 = std::chrono::steady_clock::now();

View file

@ -42,7 +42,7 @@
/* Includes required for chroot support. */ /* Includes required for chroot support. */
#ifdef __linux__ #ifdef __linux__
# include "nix/store/fchmodat2-compat.hh" # include "linux/fchmodat2-compat.hh"
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <net/if.h> # include <net/if.h>
# include <netinet/ip.h> # include <netinet/ip.h>

View file

@ -1,41 +0,0 @@
#pragma once
#include "nix/util/fs-sink.hh"
namespace nix::test {
/**
* A `FileSystemObjectSink` that traces calls, writing to stderr.
*/
class TracingFileSystemObjectSink : public virtual FileSystemObjectSink
{
FileSystemObjectSink & sink;
public:
TracingFileSystemObjectSink(FileSystemObjectSink & sink)
: sink(sink)
{
}
void createDirectory(const CanonPath & path) override;
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn) override;
void createSymlink(const CanonPath & path, const std::string & target) override;
};
/**
* A `ExtendedFileSystemObjectSink` that traces calls, writing to stderr.
*/
class TracingExtendedFileSystemObjectSink : public TracingFileSystemObjectSink, public ExtendedFileSystemObjectSink
{
ExtendedFileSystemObjectSink & sink;
public:
TracingExtendedFileSystemObjectSink(ExtendedFileSystemObjectSink & sink)
: TracingFileSystemObjectSink(sink)
, sink(sink)
{
}
void createHardlink(const CanonPath & path, const CanonPath & target) override;
};
}

View file

@ -1,34 +0,0 @@
#include <iostream>
#include "nix/tracing-file-system-object-sink.hh"
namespace nix::test {
void TracingFileSystemObjectSink::createDirectory(const CanonPath & path)
{
std::cerr << "createDirectory(" << path << ")\n";
sink.createDirectory(path);
}
void TracingFileSystemObjectSink::createRegularFile(
const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn)
{
std::cerr << "createRegularFile(" << path << ")\n";
sink.createRegularFile(path, [&](CreateRegularFileSink & crf) {
// We could wrap this and trace about the chunks of data and such
fn(crf);
});
}
void TracingFileSystemObjectSink::createSymlink(const CanonPath & path, const std::string & target)
{
std::cerr << "createSymlink(" << path << ", target: " << target << ")\n";
sink.createSymlink(path, target);
}
void TracingExtendedFileSystemObjectSink::createHardlink(const CanonPath & path, const CanonPath & target)
{
std::cerr << "createHardlink(" << path << ", target: " << target << ")\n";
sink.createHardlink(path, target);
}
} // namespace nix::test

View file

@ -59,6 +59,7 @@ sources = files(
'json-utils.cc', 'json-utils.cc',
'logging.cc', 'logging.cc',
'lru-cache.cc', 'lru-cache.cc',
'monitorfdhup.cc',
'nix_api_util.cc', 'nix_api_util.cc',
'pool.cc', 'pool.cc',
'position.cc', 'position.cc',

View file

@ -1,5 +1,5 @@
#include "util.hh" #include "nix/util/util.hh"
#include "monitor-fd.hh" #include "nix/util/monitor-fd.hh"
#include <sys/file.h> #include <sys/file.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>

View file

@ -647,4 +647,25 @@ nlohmann::json MultiCommand::toJSON()
return res; return res;
} }
Strings::iterator MultiCommand::rewriteArgs(Strings & args, Strings::iterator pos)
{
if (command)
return command->second->rewriteArgs(args, pos);
if (aliasUsed || pos == args.end()) return pos;
auto arg = *pos;
auto i = aliases.find(arg);
if (i == aliases.end()) return pos;
auto & info = i->second;
if (info.status == AliasStatus::Deprecated) {
warn("'%s' is a deprecated alias for '%s'",
arg, concatStringsSep(" ", info.replacement));
}
pos = args.erase(pos);
for (auto j = info.replacement.rbegin(); j != info.replacement.rend(); ++j)
pos = args.insert(pos, *j);
aliasUsed = true;
return pos;
}
} }

View file

@ -393,8 +393,30 @@ public:
nlohmann::json toJSON() override; nlohmann::json toJSON() override;
enum struct AliasStatus {
/** Aliases that don't go away */
AcceptedShorthand,
/** Aliases that will go away */
Deprecated,
};
/** An alias, except for the original syntax, which is in the map key. */
struct AliasInfo {
AliasStatus status;
std::vector<std::string> replacement;
};
/**
* A list of aliases (remapping a deprecated/shorthand subcommand
* to something else).
*/
std::map<std::string, AliasInfo> aliases;
Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override;
protected: protected:
std::string commandName = ""; std::string commandName = "";
bool aliasUsed = false;
}; };
Strings argvToStrings(int argc, char * * argv); Strings argvToStrings(int argc, char * * argv);

View file

@ -26,6 +26,11 @@ static inline bool getInterrupted();
*/ */
void setInterruptThrown(); void setInterruptThrown();
/**
* @note Does nothing on Windows
*/
static inline bool isInterrupted();
/** /**
* @note Does nothing on Windows * @note Does nothing on Windows
*/ */

View file

@ -85,17 +85,22 @@ static inline bool getInterrupted()
return unix::_isInterrupted; return unix::_isInterrupted;
} }
static inline bool isInterrupted()
{
using namespace unix;
return _isInterrupted || (interruptCheck && interruptCheck());
}
/** /**
* Throw `Interrupted` exception if the process has been interrupted. * Throw `Interrupted` exception if the process has been interrupted.
* *
* Call this in long-running loops and between slow operations to terminate * Call this in long-running loops and between slow operations to terminate
* them as needed. * them as needed.
*/ */
void inline checkInterrupt() inline void checkInterrupt()
{ {
using namespace unix; if (isInterrupted())
if (_isInterrupted || (interruptCheck && interruptCheck())) unix::_interrupted();
_interrupted();
} }
/** /**

View file

@ -22,7 +22,12 @@ inline void setInterruptThrown()
/* Do nothing for now */ /* Do nothing for now */
} }
void inline checkInterrupt() static inline bool isInterrupted()
{
/* Do nothing for now */
}
inline void checkInterrupt()
{ {
/* Do nothing for now */ /* Do nothing for now */
} }

View file

@ -55,7 +55,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
.description = "Use *path* as prefix for the symlinks to the build results. It defaults to `result`.", .description = "Use *path* as prefix for the symlinks to the build results. It defaults to `result`.",
.labels = {"path"}, .labels = {"path"},
.handler = {&outLink}, .handler = {&outLink},
.completer = completePath .completer = completePath,
}); });
addFlag({ addFlag({

View file

@ -24,7 +24,7 @@ struct CmdBundle : InstallableValueCommand
.handler = {&bundler}, .handler = {&bundler},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, getStore(), prefix); completeFlakeRef(completions, getStore(), prefix);
}} }},
}); });
addFlag({ addFlag({
@ -33,7 +33,7 @@ struct CmdBundle : InstallableValueCommand
.description = "Override the name of the symlink to the build result. It defaults to the base name of the app.", .description = "Override the name of the symlink to the build result. It defaults to the base name of the app.",
.labels = {"path"}, .labels = {"path"},
.handler = {&outLink}, .handler = {&outLink},
.completer = completePath .completer = completePath,
}); });
} }

View file

@ -21,7 +21,7 @@ struct CmdCopy : virtual CopyCommand, virtual BuiltPathsCommand, MixProfile
.description = "Create symlinks prefixed with *path* to the top-level store paths fetched from the source store.", .description = "Create symlinks prefixed with *path* to the top-level store paths fetched from the source store.",
.labels = {"path"}, .labels = {"path"},
.handler = {&outLink}, .handler = {&outLink},
.completer = completePath .completer = completePath,
}); });
addFlag({ addFlag({

View file

@ -21,7 +21,7 @@ struct CmdShowDerivation : InstallablesCommand
.longName = "recursive", .longName = "recursive",
.shortName = 'r', .shortName = 'r',
.description = "Include the dependencies of the specified derivations.", .description = "Include the dependencies of the specified derivations.",
.handler = {&recursive, true} .handler = {&recursive, true},
}); });
} }

View file

@ -334,7 +334,7 @@ struct Common : InstallableCommand, MixProfile
.labels = {"installable", "outputs-dir"}, .labels = {"installable", "outputs-dir"},
.handler = {[&](std::string installable, std::string outputsDir) { .handler = {[&](std::string installable, std::string outputsDir) {
redirects.push_back({installable, outputsDir}); redirects.push_back({installable, outputsDir});
}} }},
}); });
} }
@ -524,7 +524,7 @@ struct CmdDevelop : Common, MixEnvironment
.handler = {[&](std::vector<std::string> ss) { .handler = {[&](std::vector<std::string> ss) {
if (ss.empty()) throw UsageError("--command requires at least one argument"); if (ss.empty()) throw UsageError("--command requires at least one argument");
command = ss; command = ss;
}} }},
}); });
addFlag({ addFlag({

View file

@ -38,8 +38,8 @@ struct CmdShell : InstallablesCommand, MixEnvironment
CmdShell() CmdShell()
{ {
addFlag( addFlag({
{.longName = "command", .longName = "command",
.shortName = 'c', .shortName = 'c',
.description = "Command and arguments to be executed, defaulting to `$SHELL`", .description = "Command and arguments to be executed, defaulting to `$SHELL`",
.labels = {"command", "args"}, .labels = {"command", "args"},
@ -47,7 +47,8 @@ struct CmdShell : InstallablesCommand, MixEnvironment
if (ss.empty()) if (ss.empty())
throw UsageError("--command requires at least one argument"); throw UsageError("--command requires at least one argument");
command = ss; command = ss;
}}}); }},
});
} }
std::string description() override std::string description() override

View file

@ -90,7 +90,7 @@ public:
.handler={&flakeUrl}, .handler={&flakeUrl},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, getStore(), prefix); completeFlakeRef(completions, getStore(), prefix);
}} }},
}); });
expectArgs({ expectArgs({
.label="inputs", .label="inputs",
@ -111,7 +111,7 @@ public:
}}, }},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix); completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
}} }},
}); });
/* Remove flags that don't make sense. */ /* Remove flags that don't make sense. */
@ -342,12 +342,12 @@ struct CmdFlakeCheck : FlakeCommand
addFlag({ addFlag({
.longName = "no-build", .longName = "no-build",
.description = "Do not build checks.", .description = "Do not build checks.",
.handler = {&build, false} .handler = {&build, false},
}); });
addFlag({ addFlag({
.longName = "all-systems", .longName = "all-systems",
.description = "Check the outputs for all systems.", .description = "Check the outputs for all systems.",
.handler = {&checkAllSystems, true} .handler = {&checkAllSystems, true},
}); });
} }
@ -880,7 +880,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
defaultTemplateAttrPathsPrefixes, defaultTemplateAttrPathsPrefixes,
defaultTemplateAttrPaths, defaultTemplateAttrPaths,
prefix); prefix);
}} }},
}); });
} }
@ -1040,7 +1040,7 @@ struct CmdFlakeClone : FlakeCommand
.shortName = 'f', .shortName = 'f',
.description = "Clone the flake to path *dest*.", .description = "Clone the flake to path *dest*.",
.labels = {"path"}, .labels = {"path"},
.handler = {&destDir} .handler = {&destDir},
}); });
} }
@ -1063,7 +1063,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
.longName = "to", .longName = "to",
.description = "URI of the destination Nix store", .description = "URI of the destination Nix store",
.labels = {"store-uri"}, .labels = {"store-uri"},
.handler = {&dstUri} .handler = {&dstUri},
}); });
} }
@ -1146,12 +1146,12 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
addFlag({ addFlag({
.longName = "legacy", .longName = "legacy",
.description = "Show the contents of the `legacyPackages` output.", .description = "Show the contents of the `legacyPackages` output.",
.handler = {&showLegacy, true} .handler = {&showLegacy, true},
}); });
addFlag({ addFlag({
.longName = "all-systems", .longName = "all-systems",
.description = "Show the contents of outputs for all systems.", .description = "Show the contents of outputs for all systems.",
.handler = {&showAllSystems, true} .handler = {&showAllSystems, true},
}); });
} }
@ -1452,7 +1452,7 @@ struct CmdFlakePrefetch : FlakeCommand, MixJSON
.description = "Create symlink named *path* to the resulting store path.", .description = "Create symlink named *path* to the resulting store path.",
.labels = {"path"}, .labels = {"path"},
.handler = {&outLink}, .handler = {&outLink},
.completer = completePath .completer = completePath,
}); });
} }

View file

@ -51,19 +51,6 @@ void chrootHelper(int argc, char * * argv);
namespace nix { namespace nix {
enum struct AliasStatus {
/** Aliases that don't go away */
AcceptedShorthand,
/** Aliases that will go away */
Deprecated,
};
/** An alias, except for the original syntax, which is in the map key. */
struct AliasInfo {
AliasStatus status;
std::vector<std::string> replacement;
};
/* Check if we have a non-loopback/link-local network interface. */ /* Check if we have a non-loopback/link-local network interface. */
static bool haveInternet() static bool haveInternet()
{ {
@ -151,9 +138,8 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs
.category = miscCategory, .category = miscCategory,
.handler = {[&]() { refresh = true; }}, .handler = {[&]() { refresh = true; }},
}); });
}
std::map<std::string, AliasInfo> aliases = { aliases = {
{"add-to-store", { AliasStatus::Deprecated, {"store", "add-path"}}}, {"add-to-store", { AliasStatus::Deprecated, {"store", "add-path"}}},
{"cat-nar", { AliasStatus::Deprecated, {"nar", "cat"}}}, {"cat-nar", { AliasStatus::Deprecated, {"nar", "cat"}}},
{"cat-store", { AliasStatus::Deprecated, {"store", "cat"}}}, {"cat-store", { AliasStatus::Deprecated, {"store", "cat"}}},
@ -178,26 +164,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs
{"verify", { AliasStatus::Deprecated, {"store", "verify"}}}, {"verify", { AliasStatus::Deprecated, {"store", "verify"}}},
{"doctor", { AliasStatus::Deprecated, {"config", "check"}}}, {"doctor", { AliasStatus::Deprecated, {"config", "check"}}},
}; };
};
bool aliasUsed = false;
Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override
{
if (aliasUsed || command || pos == args.end()) return pos;
auto arg = *pos;
auto i = aliases.find(arg);
if (i == aliases.end()) return pos;
auto & info = i->second;
if (info.status == AliasStatus::Deprecated) {
warn("'%s' is a deprecated alias for '%s'",
arg, concatStringsSep(" ", info.replacement));
}
pos = args.erase(pos);
for (auto j = info.replacement.rbegin(); j != info.replacement.rend(); ++j)
pos = args.insert(pos, *j);
aliasUsed = true;
return pos;
}
std::string description() override std::string description() override
{ {

View file

@ -7,7 +7,7 @@ project('nix', 'cpp',
'errorlogs=true', # Please print logs for tests that fail 'errorlogs=true', # Please print logs for tests that fail
'localstatedir=/nix/var', 'localstatedir=/nix/var',
], ],
meson_version : '>= 1.1', meson_version : '>= 1.4',
license : 'LGPL-2.1-or-later', license : 'LGPL-2.1-or-later',
) )

View file

@ -275,7 +275,7 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON
.longName = "name", .longName = "name",
.description = "Override the name component of the resulting store path. It defaults to the base name of *url*.", .description = "Override the name component of the resulting store path. It defaults to the base name of *url*.",
.labels = {"name"}, .labels = {"name"},
.handler = {&name} .handler = {&name},
}); });
addFlag({ addFlag({
@ -284,7 +284,7 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON
.labels = {"hash"}, .labels = {"hash"},
.handler = {[&](std::string s) { .handler = {[&](std::string s) {
expectedHash = Hash::parseAny(s, hashAlgo); expectedHash = Hash::parseAny(s, hashAlgo);
}} }},
}); });
addFlag(flag::hashAlgo("hash-type", &hashAlgo)); addFlag(flag::hashAlgo("hash-type", &hashAlgo));

37
src/nix/profile-add.md Normal file
View file

@ -0,0 +1,37 @@
R""(
# Examples
- Add a package from Nixpkgs:
```console
# nix profile add nixpkgs#hello
```
- Add a package from a specific branch of Nixpkgs:
```console
# nix profile add nixpkgs/release-20.09#hello
```
- Add a package from a specific revision of Nixpkgs:
```console
# nix profile add nixpkgs/d73407e8e6002646acfdef0e39ace088bacc83da#hello
```
- Add a specific output of a package:
```console
# nix profile add nixpkgs#bash^man
```
# Description
This command adds [_installables_](./nix.md#installables) to a Nix profile.
> **Note**
>
> `nix profile install` is an alias for `nix profile add` in Determinate Nix.
)""

View file

@ -1,34 +0,0 @@
R""(
# Examples
* Install a package from Nixpkgs:
```console
# nix profile install nixpkgs#hello
```
* Install a package from a specific branch of Nixpkgs:
```console
# nix profile install nixpkgs/release-20.09#hello
```
* Install a package from a specific revision of Nixpkgs:
```console
# nix profile install nixpkgs/d73407e8e6002646acfdef0e39ace088bacc83da#hello
```
* Install a specific output of a package:
```console
# nix profile install nixpkgs#bash^man
```
# Description
This command adds [*installables*](./nix.md#installables) to a Nix profile.
)""

View file

@ -338,14 +338,14 @@ builtPathsPerInstallable(
return res; return res;
} }
struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile struct CmdProfileAdd : InstallablesCommand, MixDefaultProfile
{ {
std::optional<int64_t> priority; std::optional<int64_t> priority;
CmdProfileInstall() { CmdProfileAdd() {
addFlag({ addFlag({
.longName = "priority", .longName = "priority",
.description = "The priority of the package to install.", .description = "The priority of the package to add.",
.labels = {"priority"}, .labels = {"priority"},
.handler = {&priority}, .handler = {&priority},
}); });
@ -353,13 +353,13 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
std::string description() override std::string description() override
{ {
return "install a package into a profile"; return "add a package to a profile";
} }
std::string doc() override std::string doc() override
{ {
return return
#include "profile-install.md" #include "profile-add.md"
; ;
} }
@ -415,7 +415,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
&& existingSource->originalRef == elementSource->originalRef && existingSource->originalRef == elementSource->originalRef
&& existingSource->attrPath == elementSource->attrPath && existingSource->attrPath == elementSource->attrPath
) { ) {
warn("'%s' is already installed", elementName); warn("'%s' is already added", elementName);
continue; continue;
} }
} }
@ -462,15 +462,15 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
"\n" "\n"
" nix profile remove %3%\n" " nix profile remove %3%\n"
"\n" "\n"
"The new package can also be installed next to the existing one by assigning a different priority.\n" "The new package can also be added next to the existing one by assigning a different priority.\n"
"The conflicting packages have a priority of %5%.\n" "The conflicting packages have a priority of %5%.\n"
"To prioritise the new package:\n" "To prioritise the new package:\n"
"\n" "\n"
" nix profile install %4% --priority %6%\n" " nix profile add %4% --priority %6%\n"
"\n" "\n"
"To prioritise the existing package:\n" "To prioritise the existing package:\n"
"\n" "\n"
" nix profile install %4% --priority %7%\n", " nix profile add %4% --priority %7%\n",
originalConflictingFilePath, originalConflictingFilePath,
newConflictingFilePath, newConflictingFilePath,
originalEntryName, originalEntryName,
@ -708,16 +708,14 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
if (!element.source) { if (!element.source) {
warn( warn(
"Found package '%s', but it was not installed from a flake, so it can't be checked for upgrades!", "Found package '%s', but it was not added from a flake, so it can't be checked for upgrades!",
element.identifier() element.identifier());
);
continue; continue;
} }
if (element.source->originalRef.input.isLocked()) { if (element.source->originalRef.input.isLocked()) {
warn( warn(
"Found package '%s', but it was installed from a locked flake reference so it can't be upgraded!", "Found package '%s', but it was added from a locked flake reference so it can't be upgraded!",
element.identifier() element.identifier());
);
continue; continue;
} }
@ -787,7 +785,7 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro
{ {
std::string description() override std::string description() override
{ {
return "list installed packages"; return "list packages in the profile";
} }
std::string doc() override std::string doc() override
@ -978,7 +976,7 @@ struct CmdProfile : NixMultiCommand
: NixMultiCommand( : NixMultiCommand(
"profile", "profile",
{ {
{"install", []() { return make_ref<CmdProfileInstall>(); }}, {"add", []() { return make_ref<CmdProfileAdd>(); }},
{"remove", []() { return make_ref<CmdProfileRemove>(); }}, {"remove", []() { return make_ref<CmdProfileRemove>(); }},
{"upgrade", []() { return make_ref<CmdProfileUpgrade>(); }}, {"upgrade", []() { return make_ref<CmdProfileUpgrade>(); }},
{"list", []() { return make_ref<CmdProfileList>(); }}, {"list", []() { return make_ref<CmdProfileList>(); }},
@ -987,7 +985,11 @@ struct CmdProfile : NixMultiCommand
{"rollback", []() { return make_ref<CmdProfileRollback>(); }}, {"rollback", []() { return make_ref<CmdProfileRollback>(); }},
{"wipe-history", []() { return make_ref<CmdProfileWipeHistory>(); }}, {"wipe-history", []() { return make_ref<CmdProfileWipeHistory>(); }},
}) })
{ } {
aliases = {
{"install", { AliasStatus::Deprecated, {"add"}}},
};
}
std::string description() override std::string description() override
{ {

View file

@ -104,7 +104,7 @@ struct CmdSign : StorePathsCommand
.description = "File containing the secret signing key.", .description = "File containing the secret signing key.",
.labels = {"file"}, .labels = {"file"},
.handler = {&secretKeyFile}, .handler = {&secretKeyFile},
.completer = completePath .completer = completePath,
}); });
} }

View file

@ -16,7 +16,7 @@ struct CmdStoreDelete : StorePathsCommand
addFlag({ addFlag({
.longName = "ignore-liveness", .longName = "ignore-liveness",
.description = "Do not check whether the paths are reachable from a root.", .description = "Do not check whether the paths are reachable from a root.",
.handler = {&options.ignoreLiveness, true} .handler = {&options.ignoreLiveness, true},
}); });
} }

View file

@ -17,7 +17,7 @@ struct CmdStoreGC : StoreCommand, MixDryRun
.longName = "max", .longName = "max",
.description = "Stop after freeing *n* bytes of disk space.", .description = "Stop after freeing *n* bytes of disk space.",
.labels = {"n"}, .labels = {"n"},
.handler = {&options.maxFreed} .handler = {&options.maxFreed},
}); });
} }

View file

@ -7,7 +7,7 @@
using namespace nix; using namespace nix;
struct CmdPingStore : StoreCommand, MixJSON struct CmdInfoStore : StoreCommand, MixJSON
{ {
std::string description() override std::string description() override
{ {
@ -46,15 +46,4 @@ struct CmdPingStore : StoreCommand, MixJSON
} }
}; };
struct CmdInfoStore : CmdPingStore static auto rCmdInfoStore = registerCommand2<CmdInfoStore>({"store", "info"});
{
void run(nix::ref<nix::Store> store) override
{
warn("'nix store ping' is a deprecated alias for 'nix store info'");
CmdPingStore::run(store);
}
};
static auto rCmdPingStore = registerCommand2<CmdPingStore>({"store", "info"});
static auto rCmdInfoStore = registerCommand2<CmdInfoStore>({"store", "ping"});

View file

@ -5,7 +5,11 @@ using namespace nix;
struct CmdStore : NixMultiCommand struct CmdStore : NixMultiCommand
{ {
CmdStore() : NixMultiCommand("store", RegisterCommand::getCommandsFor({"store"})) CmdStore() : NixMultiCommand("store", RegisterCommand::getCommandsFor({"store"}))
{ } {
aliases = {
{"ping", { AliasStatus::Deprecated, {"info"}}},
};
}
std::string description() override std::string description() override
{ {

View file

@ -23,14 +23,14 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand
.shortName = 'p', .shortName = 'p',
.description = "The path to the Nix profile to upgrade.", .description = "The path to the Nix profile to upgrade.",
.labels = {"profile-dir"}, .labels = {"profile-dir"},
.handler = {&profileDir} .handler = {&profileDir},
}); });
addFlag({ addFlag({
.longName = "nix-store-paths-url", .longName = "nix-store-paths-url",
.description = "The URL of the file that contains the store paths of the latest Nix release.", .description = "The URL of the file that contains the store paths of the latest Nix release.",
.labels = {"url"}, .labels = {"url"},
.handler = {&(std::string&) settings.upgradeNixStorePathUrl} .handler = {&(std::string&) settings.upgradeNixStorePathUrl},
}); });
} }

View file

@ -37,7 +37,7 @@ struct CmdVerify : StorePathsCommand
.shortName = 's', .shortName = 's',
.description = "Use signatures from the specified store.", .description = "Use signatures from the specified store.",
.labels = {"store-uri"}, .labels = {"store-uri"},
.handler = {[&](std::string s) { substituterUris.push_back(s); }} .handler = {[&](std::string s) { substituterUris.push_back(s); }},
}); });
addFlag({ addFlag({
@ -45,7 +45,7 @@ struct CmdVerify : StorePathsCommand
.shortName = 'n', .shortName = 'n',
.description = "Require that each path is signed by at least *n* different keys.", .description = "Require that each path is signed by at least *n* different keys.",
.labels = {"n"}, .labels = {"n"},
.handler = {&sigsNeeded} .handler = {&sigsNeeded},
}); });
} }

View file

@ -6,6 +6,6 @@ file=build-hook-ca-floating.nix
enableFeatures "ca-derivations" enableFeatures "ca-derivations"
CONTENT_ADDRESSED=true NIX_TESTS_CA_BY_DEFAULT=true
source build-remote.sh source build-remote.sh

View file

@ -13,7 +13,7 @@ unset NIX_STATE_DIR
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; } function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
EXTRA_SYSTEM_FEATURES=() EXTRA_SYSTEM_FEATURES=()
if [[ -n "${CONTENT_ADDRESSED-}" ]]; then if [[ -n "${NIX_TESTS_CA_BY_DEFAULT-}" ]]; then
EXTRA_SYSTEM_FEATURES=("ca-derivations") EXTRA_SYSTEM_FEATURES=("ca-derivations")
fi fi

View file

@ -0,0 +1,6 @@
#!/usr/bin/env bash
export NIX_TESTS_CA_BY_DEFAULT=1
cd ..
source derivation-advanced-attributes.sh

View file

@ -8,10 +8,11 @@ suites += {
'name': 'ca', 'name': 'ca',
'deps': [], 'deps': [],
'tests': [ 'tests': [
'build-cache.sh',
'build-with-garbage-path.sh', 'build-with-garbage-path.sh',
'build.sh', 'build.sh',
'build-cache.sh',
'concurrent-builds.sh', 'concurrent-builds.sh',
'derivation-advanced-attributes.sh',
'derivation-json.sh', 'derivation-json.sh',
'duplicate-realisation-in-closure.sh', 'duplicate-realisation-in-closure.sh',
'eval-store.sh', 'eval-store.sh',

View file

@ -2,6 +2,6 @@
source common.sh source common.sh
CONTENT_ADDRESSED=true NIX_TESTS_CA_BY_DEFAULT=true
cd .. cd ..
source ./nix-shell.sh source ./nix-shell.sh

View file

@ -12,11 +12,19 @@ badExitCode=0
store="$TEST_ROOT/store" store="$TEST_ROOT/store"
if [[ -z "${NIX_TESTS_CA_BY_DEFAULT:-}" ]]; then
drvDir=ia
flags=(--arg contentAddress false)
else
drvDir=ca
flags=(--arg contentAddress true --extra-experimental-features ca-derivations)
fi
for nixFile in derivation/*.nix; do for nixFile in derivation/*.nix; do
drvPath=$(env -u NIX_STORE nix-instantiate --store "$store" --pure-eval --expr "$(< "$nixFile")") drvPath=$(env -u NIX_STORE nix-instantiate --store "$store" --pure-eval "${flags[@]}" --expr "$(< "$nixFile")")
testName=$(basename "$nixFile" .nix) testName=$(basename "$nixFile" .nix)
got="${store}${drvPath}" got="${store}${drvPath}"
expected="derivation/$testName.drv" expected="derivation/${drvDir}/${testName}.drv"
diffAndAcceptInner "$testName" "$got" "$expected" diffAndAcceptInner "$testName" "$got" "$expected"
done done

View file

@ -1,6 +1,24 @@
derivation { { contentAddress }:
name = "advanced-attributes-defaults";
let
caArgs =
if contentAddress then
{
__contentAddressed = true;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
}
else
{ };
derivation' = args: derivation (caArgs // args);
system = "my-system"; system = "my-system";
in
derivation' {
inherit system;
name = "advanced-attributes-defaults";
builder = "/bin/bash"; builder = "/bin/bash";
args = [ args = [
"-c" "-c"

View file

@ -1,6 +1,24 @@
derivation { { contentAddress }:
name = "advanced-attributes-structured-attrs-defaults";
let
caArgs =
if contentAddress then
{
__contentAddressed = true;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
}
else
{ };
derivation' = args: derivation (caArgs // args);
system = "my-system"; system = "my-system";
in
derivation' {
inherit system;
name = "advanced-attributes-structured-attrs-defaults";
builder = "/bin/bash"; builder = "/bin/bash";
args = [ args = [
"-c" "-c"

View file

@ -1 +0,0 @@
Derive([("bin","/nix/store/pbzb48v0ycf80jgligcp4n8z0rblna4n-advanced-attributes-structured-attrs-bin","",""),("dev","/nix/store/7xapi8jv7flcz1qq8jhw55ar8ag8hldh-advanced-attributes-structured-attrs-dev","",""),("out","/nix/store/mpq3l1l1qc2yr50q520g08kprprwv79f-advanced-attributes-structured-attrs","","")],[("/nix/store/4xm4wccqsvagz9gjksn24s7rip2fdy7v-foo.drv",["out"]),("/nix/store/plsq5jbr5nhgqwcgb2qxw7jchc09dnl8-bar.drv",["out"])],[],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar\"],\"disallowedRequisites\":[\"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo\"],\"allowedRequisites\":[\"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo\"]}},\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/nix/store/pbzb48v0ycf80jgligcp4n8z0rblna4n-advanced-attributes-structured-attrs-bin"),("dev","/nix/store/7xapi8jv7flcz1qq8jhw55ar8ag8hldh-advanced-attributes-structured-attrs-dev"),("out","/nix/store/mpq3l1l1qc2yr50q520g08kprprwv79f-advanced-attributes-structured-attrs")])

View file

@ -1,6 +1,21 @@
{ contentAddress }:
let let
caArgs =
if contentAddress then
{
__contentAddressed = true;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
}
else
{ };
derivation' = args: derivation (caArgs // args);
system = "my-system"; system = "my-system";
foo = derivation {
foo = derivation' {
inherit system; inherit system;
name = "foo"; name = "foo";
builder = "/bin/bash"; builder = "/bin/bash";
@ -8,8 +23,13 @@ let
"-c" "-c"
"echo foo > $out" "echo foo > $out"
]; ];
outputs = [
"out"
"dev"
];
}; };
bar = derivation {
bar = derivation' {
inherit system; inherit system;
name = "bar"; name = "bar";
builder = "/bin/bash"; builder = "/bin/bash";
@ -17,9 +37,14 @@ let
"-c" "-c"
"echo bar > $out" "echo bar > $out"
]; ];
outputs = [
"out"
"dev"
];
}; };
in in
derivation { derivation' {
inherit system; inherit system;
name = "advanced-attributes-structured-attrs"; name = "advanced-attributes-structured-attrs";
builder = "/bin/bash"; builder = "/bin/bash";
@ -41,11 +66,11 @@ derivation {
outputChecks = { outputChecks = {
out = { out = {
allowedReferences = [ foo ]; allowedReferences = [ foo ];
allowedRequisites = [ foo ]; allowedRequisites = [ foo.dev ];
}; };
bin = { bin = {
disallowedReferences = [ bar ]; disallowedReferences = [ bar ];
disallowedRequisites = [ bar ]; disallowedRequisites = [ bar.dev ];
}; };
dev = { dev = {
maxSize = 789; maxSize = 789;

View file

@ -1 +0,0 @@
Derive([("out","/nix/store/33a6fdmn8q9ih9d7npbnrxn2q56a4l8q-advanced-attributes","","")],[("/nix/store/4xm4wccqsvagz9gjksn24s7rip2fdy7v-foo.drv",["out"]),("/nix/store/plsq5jbr5nhgqwcgb2qxw7jchc09dnl8-bar.drv",["out"])],[],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"),("allowedRequisites","/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"),("builder","/bin/bash"),("disallowedReferences","/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"),("disallowedRequisites","/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/nix/store/33a6fdmn8q9ih9d7npbnrxn2q56a4l8q-advanced-attributes"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")])

View file

@ -1,6 +1,21 @@
{ contentAddress }:
let let
caArgs =
if contentAddress then
{
__contentAddressed = true;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
}
else
{ };
derivation' = args: derivation (caArgs // args);
system = "my-system"; system = "my-system";
foo = derivation {
foo = derivation' {
inherit system; inherit system;
name = "foo"; name = "foo";
builder = "/bin/bash"; builder = "/bin/bash";
@ -8,8 +23,13 @@ let
"-c" "-c"
"echo foo > $out" "echo foo > $out"
]; ];
outputs = [
"out"
"dev"
];
}; };
bar = derivation {
bar = derivation' {
inherit system; inherit system;
name = "bar"; name = "bar";
builder = "/bin/bash"; builder = "/bin/bash";
@ -17,9 +37,14 @@ let
"-c" "-c"
"echo bar > $out" "echo bar > $out"
]; ];
outputs = [
"out"
"dev"
];
}; };
in in
derivation { derivation' {
inherit system; inherit system;
name = "advanced-attributes"; name = "advanced-attributes";
builder = "/bin/bash"; builder = "/bin/bash";
@ -33,9 +58,9 @@ derivation {
impureEnvVars = [ "UNICORN" ]; impureEnvVars = [ "UNICORN" ];
__darwinAllowLocalNetworking = true; __darwinAllowLocalNetworking = true;
allowedReferences = [ foo ]; allowedReferences = [ foo ];
allowedRequisites = [ foo ]; allowedRequisites = [ foo.dev ];
disallowedReferences = [ bar ]; disallowedReferences = [ bar ];
disallowedRequisites = [ bar ]; disallowedRequisites = [ bar.dev ];
requiredSystemFeatures = [ requiredSystemFeatures = [
"rainbow" "rainbow"
"uid-range" "uid-range"

View file

@ -0,0 +1 @@
Derive([("out","","r:sha256","")],[],[],"my-system","/bin/bash",["-c","echo hello > $out"],[("builder","/bin/bash"),("name","advanced-attributes-defaults"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("system","my-system")])

View file

@ -0,0 +1 @@
Derive([("dev","","r:sha256",""),("out","","r:sha256","")],[],[],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"builder\":\"/bin/bash\",\"name\":\"advanced-attributes-structured-attrs-defaults\",\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"dev\"],\"system\":\"my-system\"}"),("dev","/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")])

View file

@ -0,0 +1 @@
Derive([("bin","","r:sha256",""),("dev","","r:sha256",""),("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],[],"my-system","/bin/bash",["-c","echo hello > $out"],[("__json","{\"__darwinAllowLocalNetworking\":true,\"__impureHostDeps\":[\"/usr/bin/ditto\"],\"__noChroot\":true,\"__sandboxProfile\":\"sandcastle\",\"allowSubstitutes\":false,\"builder\":\"/bin/bash\",\"impureEnvVars\":[\"UNICORN\"],\"name\":\"advanced-attributes-structured-attrs\",\"outputChecks\":{\"bin\":{\"disallowedReferences\":[\"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g\"],\"disallowedRequisites\":[\"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8\"]},\"dev\":{\"maxClosureSize\":5909,\"maxSize\":789},\"out\":{\"allowedReferences\":[\"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9\"],\"allowedRequisites\":[\"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z\"]}},\"outputHashAlgo\":\"sha256\",\"outputHashMode\":\"recursive\",\"outputs\":[\"out\",\"bin\",\"dev\"],\"preferLocalBuild\":true,\"requiredSystemFeatures\":[\"rainbow\",\"uid-range\"],\"system\":\"my-system\"}"),("bin","/04f3da1kmbr67m3gzxikmsl4vjz5zf777sv6m14ahv22r65aac9m"),("dev","/02qcpld1y6xhs5gz9bchpxaw0xdhmsp5dv88lh25r2ss44kh8dxz"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")])

View file

@ -0,0 +1 @@
Derive([("out","","r:sha256","")],[("/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv",["dev","out"]),("/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",["dev","out"])],[],"my-system","/bin/bash",["-c","echo hello > $out"],[("__darwinAllowLocalNetworking","1"),("__impureHostDeps","/usr/bin/ditto"),("__noChroot","1"),("__sandboxProfile","sandcastle"),("allowSubstitutes",""),("allowedReferences","/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"),("allowedRequisites","/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"),("builder","/bin/bash"),("disallowedReferences","/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"),("disallowedRequisites","/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"),("impureEnvVars","UNICORN"),("name","advanced-attributes"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("preferLocalBuild","1"),("requiredSystemFeatures","rainbow uid-range"),("system","my-system")])

Some files were not shown because too many files have changed in this diff Show more