1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-21 01:39:36 +01: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

@ -237,12 +237,13 @@ void StorePathCommand::run(ref<Store> store, StorePaths && storePaths)
MixProfile::MixProfile()
{
addFlag(
{.longName = "profile",
.description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath});
addFlag({
.longName = "profile",
.description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath,
});
}
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.",
.category = category,
.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({
@ -79,7 +79,7 @@ MixEvalArgs::MixEvalArgs()
.category = category,
.labels = {"name", "path"},
.handler = {[&](std::string name, std::string path) { autoArgs.insert_or_assign(name, AutoArg{AutoArgFile{path}}); }},
.completer = completePath
.completer = completePath,
});
addFlag({
@ -104,7 +104,7 @@ MixEvalArgs::MixEvalArgs()
.labels = {"path"},
.handler = {[&](std::string s) {
lookupPath.elements.emplace_back(LookupPath::Elem::parse(s));
}}
}},
});
addFlag({
@ -130,7 +130,7 @@ MixEvalArgs::MixEvalArgs()
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, openStore(), prefix);
}}
}},
});
addFlag({

View file

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

View file

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

View file

@ -65,7 +65,7 @@ struct DocComment {
struct AttrName
{
Symbol symbol;
Expr * expr;
Expr * expr = nullptr;
AttrName(Symbol s) : symbol(s) {};
AttrName(Expr * e) : expr(e) {};
};
@ -159,7 +159,7 @@ struct ExprVar : Expr
`nullptr`: Not from a `with`.
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`
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
the set stored in the environment that is `level` levels up
from the current one.*/
Level level;
Level level = 0;
Displacement displ = 0;
ExprVar(Symbol name) : name(name) { };

View file

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

View file

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

View file

@ -14,6 +14,7 @@ overrides:
fetchTreeFinal:
let
inherit (builtins) mapAttrs;
lockFile = builtins.fromJSON lockFileStr;
@ -35,19 +36,26 @@ let
(resolveInput lockFile.nodes.${nodeName}.inputs.${builtins.head path})
(builtins.tail path);
allNodes = builtins.mapAttrs (
allNodes = mapAttrs (
key: node:
let
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 =
if overrides ? ${key} then
overrides.${key}.sourceInfo
else if node.locked.type == "path" && builtins.substring 0 1 node.locked.path != "/" then
parentNode.sourceInfo
// {
outPath = parentNode.outPath + ("/" + node.locked.path);
outPath = parentNode.sourceInfo.outPath + ("/" + flakeDir);
}
else
# FIXME: remove obsolete node.info.
@ -60,7 +68,7 @@ let
flake = import (outPath + "/flake.nix");
inputs = builtins.mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}) (
inputs = mapAttrs (inputName: inputSpec: allNodes.${resolveInput inputSpec}.result) (
node.inputs or { }
);
@ -85,12 +93,17 @@ let
};
in
if node.flake or true then
assert builtins.isFunction flake.outputs;
result
else
sourceInfo
{
result =
if node.flake or true then
assert builtins.isFunction flake.outputs;
result
else
sourceInfo;
inherit flakeDir sourceInfo;
}
) lockFile.nodes;
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))
completions.add(s.first, fmt("Set the `%s` setting.", s.first));
}
}
},
});
addFlag({
@ -75,7 +75,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
.labels = Strings{"jobs"},
.handler = {[=](std::string s) {
settings.set("max-jobs", s);
}}
}},
});
std::string cat = "Options to override configuration settings";

View file

@ -231,7 +231,7 @@ LegacyArgs::LegacyArgs(const std::string & programName,
.handler = {[=](std::string s) {
auto n = string2IntWithUnitPrefix<uint64_t>(s);
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
{
std::filesystem::path unitTestData = getUnitTestData() / "derivation";
protected:
std::filesystem::path unitTestData = getUnitTestData() / "derivation" / "ia";
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
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;
};
#define TEST_ATERM_JSON(STEM, NAME) \
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_from_json) \
{ \
readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*store, std::move(aterm), NAME); \
Derivation got = Derivation::fromJSON(*store, encoded); \
EXPECT_EQ(got, expected); \
}); \
} \
\
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_to_json) \
{ \
writeTest( \
NAME ".json", \
[&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(goldenMaster(NAME ".drv")); \
return parseDerivation(*store, std::move(aterm), NAME).toJSON(*store); \
}, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \
\
TEST_F(DerivationAdvancedAttrsTest, Derivation_##STEM##_from_aterm) \
{ \
readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(*store, json); \
auto got = parseDerivation(*store, std::move(encoded), NAME); \
EXPECT_EQ(got.toJSON(*store), expected.toJSON(*store)); \
EXPECT_EQ(got, expected); \
}); \
} \
\
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) \
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_json) \
{ \
this->readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings); \
Derivation got = Derivation::fromJSON(*this->store, encoded, this->mockXpSettings); \
EXPECT_EQ(got, expected); \
}); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_to_json) \
{ \
this->writeTest( \
NAME ".json", \
[&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
return parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings) \
.toJSON(*this->store); \
}, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_aterm) \
{ \
this->readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(this->goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(*this->store, json, this->mockXpSettings); \
auto got = parseDerivation(*this->store, std::move(encoded), NAME, this->mockXpSettings); \
EXPECT_EQ(got.toJSON(*this->store), expected.toJSON(*this->store)); \
EXPECT_EQ(got, expected); \
}); \
} \
\
/* 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_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_defaults, "advanced-attributes-structured-attrs");
#undef TEST_ATERM_JSON
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults)
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)
{
readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
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);
@ -101,25 +126,50 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_defaults)
EXPECT_EQ(checksForAllOutputs.disallowedReferences, StringSet{});
EXPECT_EQ(checksForAllOutputs.disallowedRequisites, StringSet{});
}
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet());
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true);
EXPECT_EQ(options.useUidRange(got), false);
});
};
TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes)
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_defaults)
{
readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
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);
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());
@ -128,34 +178,88 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes)
EXPECT_EQ(options.impureHostDeps, StringSet{"/usr/bin/ditto"});
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
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);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(
checksForAllOutputs.allowedReferences, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
checksForAllOutputs.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(
checksForAllOutputs.allowedRequisites, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
checksForAllOutputs.allowedRequisites,
StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
EXPECT_EQ(
checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/7rhsm8i393hm1wcsmph782awg1hi2f7x-bar"});
checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
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.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) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes.drv", [&](auto encoded) {
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);
DerivationOptions options = DerivationOptions::fromParsedDerivation(parsedDrv);
@ -176,25 +280,50 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(checksPerOutput.size(), 0);
}
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet());
EXPECT_EQ(options.canBuildLocally(*store, got), false);
EXPECT_EQ(options.willBuildLocally(*store, got), false);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true);
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) {
auto got = parseDerivation(*store, std::move(encoded), "foo");
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
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);
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());
@ -204,14 +333,40 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true);
{
auto output_ = get(std::get<1>(options.outputChecks), "dev");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.maxSize, 789);
EXPECT_EQ(output.maxClosureSize, 5909);
}
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_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/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/3c08bzb71z4wiag719ipjxr277653ynp-foo"});
EXPECT_EQ(output.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
}
{
@ -219,25 +374,54 @@ TEST_F(DerivationAdvancedAttrsTest, Derivation_advancedAttributes_structuredAttr
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");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.maxSize, 789);
EXPECT_EQ(output.maxClosureSize, 5909);
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);
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);
});
};

View file

@ -73,6 +73,32 @@ TEST(machines, getMachinesWithSemicolonSeparator) {
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) {
auto actual = Machine::parseConfig({},
"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);
res.insert(j->get<std::string>());
}
checks.disallowedRequisites = res;
return res;
}
return {};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -160,7 +160,10 @@ ref<Aws::Client::ClientConfiguration> S3Helper::makeConfig(
S3Helper::FileTransferResult S3Helper::getObject(
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 =
Aws::S3::Model::GetObjectRequest()
@ -171,6 +174,22 @@ S3Helper::FileTransferResult S3Helper::getObject(
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;
auto now1 = std::chrono::steady_clock::now();
@ -180,6 +199,8 @@ S3Helper::FileTransferResult S3Helper::getObject(
auto result = checkAws(fmt("AWS error fetching '%s'", key),
client->GetObject(request));
act.progress(result.GetContentLength(), result.GetContentLength());
res.data = decompress(result.GetContentEncoding(),
dynamic_cast<std::stringstream &>(result.GetBody()).str());
@ -307,11 +328,35 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
std::shared_ptr<TransferManager> transferManager;
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,
std::shared_ptr<std::basic_iostream<char>> istream,
const std::string & mimeType,
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);
auto size = istream->tellg();
istream->seekg(0, istream->beg);
@ -330,16 +375,25 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
transferConfig.bufferSize = bufferSize;
transferConfig.uploadProgressCallback =
[](const TransferManager *transferManager,
const std::shared_ptr<const TransferHandle>
&transferHandle)
[](const TransferManager * transferManager,
const std::shared_ptr<const TransferHandle> & transferHandle)
{
//FIXME: find a way to properly abort the multipart upload.
//checkInterrupt();
debug("upload progress ('%s'): '%d' of '%d' bytes",
transferHandle->GetKey(),
transferHandle->GetBytesTransferred(),
transferHandle->GetBytesTotalSize());
auto context = std::dynamic_pointer_cast<const AsyncContext>(transferHandle->GetContext());
size_t bytesDone = transferHandle->GetBytesTransferred();
size_t bytesTotal = transferHandle->GetBytesTotalSize();
try {
checkInterrupt();
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);
@ -353,29 +407,51 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
if (contentEncoding != "")
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 =
transferManager->UploadFile(
istream, bucketName, path, mimeType,
Aws::Map<Aws::String, Aws::String>(),
nullptr /*, contentEncoding */);
context /*, contentEncoding */);
transferHandle->WaitUntilFinished();
TransferStatus status = transferHandle->GetStatus();
while (status == TransferStatus::IN_PROGRESS || status == TransferStatus::NOT_STARTED) {
if (!isInterrupted()) {
context->wait();
} else {
transferHandle->Cancel();
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",
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",
bucketName, path);
} else {
act.progress(0, size);
auto request =
Aws::S3::Model::PutObjectRequest()
.WithBucket(bucketName)
.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);
if (contentEncoding != "")
@ -385,6 +461,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto result = checkAws(fmt("AWS error uploading '%s'", path),
s3Helper.client->PutObject(request));
act.progress(size, size);
}
auto now2 = std::chrono::steady_clock::now();

View file

@ -42,7 +42,7 @@
/* Includes required for chroot support. */
#ifdef __linux__
# include "nix/store/fchmodat2-compat.hh"
# include "linux/fchmodat2-compat.hh"
# include <sys/ioctl.h>
# include <net/if.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',
'logging.cc',
'lru-cache.cc',
'monitorfdhup.cc',
'nix_api_util.cc',
'pool.cc',
'position.cc',

View file

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

View file

@ -647,4 +647,25 @@ nlohmann::json MultiCommand::toJSON()
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;
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:
std::string commandName = "";
bool aliasUsed = false;
};
Strings argvToStrings(int argc, char * * argv);

View file

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

View file

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

View file

@ -22,7 +22,12 @@ inline void setInterruptThrown()
/* Do nothing for now */
}
void inline checkInterrupt()
static inline bool isInterrupted()
{
/* Do nothing for now */
}
inline void checkInterrupt()
{
/* 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`.",
.labels = {"path"},
.handler = {&outLink},
.completer = completePath
.completer = completePath,
});
addFlag({

View file

@ -24,7 +24,7 @@ struct CmdBundle : InstallableValueCommand
.handler = {&bundler},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, getStore(), prefix);
}}
}},
});
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.",
.labels = {"path"},
.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.",
.labels = {"path"},
.handler = {&outLink},
.completer = completePath
.completer = completePath,
});
addFlag({

View file

@ -21,7 +21,7 @@ struct CmdShowDerivation : InstallablesCommand
.longName = "recursive",
.shortName = 'r',
.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"},
.handler = {[&](std::string installable, std::string outputsDir) {
redirects.push_back({installable, outputsDir});
}}
}},
});
}
@ -524,7 +524,7 @@ struct CmdDevelop : Common, MixEnvironment
.handler = {[&](std::vector<std::string> ss) {
if (ss.empty()) throw UsageError("--command requires at least one argument");
command = ss;
}}
}},
});
addFlag({

View file

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

View file

@ -90,7 +90,7 @@ public:
.handler={&flakeUrl},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeRef(completions, getStore(), prefix);
}}
}},
});
expectArgs({
.label="inputs",
@ -111,7 +111,7 @@ public:
}},
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
}}
}},
});
/* Remove flags that don't make sense. */
@ -342,12 +342,12 @@ struct CmdFlakeCheck : FlakeCommand
addFlag({
.longName = "no-build",
.description = "Do not build checks.",
.handler = {&build, false}
.handler = {&build, false},
});
addFlag({
.longName = "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,
defaultTemplateAttrPaths,
prefix);
}}
}},
});
}
@ -1040,7 +1040,7 @@ struct CmdFlakeClone : FlakeCommand
.shortName = 'f',
.description = "Clone the flake to path *dest*.",
.labels = {"path"},
.handler = {&destDir}
.handler = {&destDir},
});
}
@ -1063,7 +1063,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
.longName = "to",
.description = "URI of the destination Nix store",
.labels = {"store-uri"},
.handler = {&dstUri}
.handler = {&dstUri},
});
}
@ -1146,12 +1146,12 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
addFlag({
.longName = "legacy",
.description = "Show the contents of the `legacyPackages` output.",
.handler = {&showLegacy, true}
.handler = {&showLegacy, true},
});
addFlag({
.longName = "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.",
.labels = {"path"},
.handler = {&outLink},
.completer = completePath
.completer = completePath,
});
}

View file

@ -51,19 +51,6 @@ void chrootHelper(int argc, char * * argv);
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. */
static bool haveInternet()
{
@ -151,54 +138,34 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs
.category = miscCategory,
.handler = {[&]() { refresh = true; }},
});
}
std::map<std::string, AliasInfo> aliases = {
{"add-to-store", { AliasStatus::Deprecated, {"store", "add-path"}}},
{"cat-nar", { AliasStatus::Deprecated, {"nar", "cat"}}},
{"cat-store", { AliasStatus::Deprecated, {"store", "cat"}}},
{"copy-sigs", { AliasStatus::Deprecated, {"store", "copy-sigs"}}},
{"dev-shell", { AliasStatus::Deprecated, {"develop"}}},
{"diff-closures", { AliasStatus::Deprecated, {"store", "diff-closures"}}},
{"dump-path", { AliasStatus::Deprecated, {"store", "dump-path"}}},
{"hash-file", { AliasStatus::Deprecated, {"hash", "file"}}},
{"hash-path", { AliasStatus::Deprecated, {"hash", "path"}}},
{"ls-nar", { AliasStatus::Deprecated, {"nar", "ls"}}},
{"ls-store", { AliasStatus::Deprecated, {"store", "ls"}}},
{"make-content-addressable", { AliasStatus::Deprecated, {"store", "make-content-addressed"}}},
{"optimise-store", { AliasStatus::Deprecated, {"store", "optimise"}}},
{"ping-store", { AliasStatus::Deprecated, {"store", "info"}}},
{"sign-paths", { AliasStatus::Deprecated, {"store", "sign"}}},
{"shell", { AliasStatus::AcceptedShorthand, {"env", "shell"}}},
{"show-derivation", { AliasStatus::Deprecated, {"derivation", "show"}}},
{"show-config", { AliasStatus::Deprecated, {"config", "show"}}},
{"to-base16", { AliasStatus::Deprecated, {"hash", "to-base16"}}},
{"to-base32", { AliasStatus::Deprecated, {"hash", "to-base32"}}},
{"to-base64", { AliasStatus::Deprecated, {"hash", "to-base64"}}},
{"verify", { AliasStatus::Deprecated, {"store", "verify"}}},
{"doctor", { AliasStatus::Deprecated, {"config", "check"}}},
aliases = {
{"add-to-store", { AliasStatus::Deprecated, {"store", "add-path"}}},
{"cat-nar", { AliasStatus::Deprecated, {"nar", "cat"}}},
{"cat-store", { AliasStatus::Deprecated, {"store", "cat"}}},
{"copy-sigs", { AliasStatus::Deprecated, {"store", "copy-sigs"}}},
{"dev-shell", { AliasStatus::Deprecated, {"develop"}}},
{"diff-closures", { AliasStatus::Deprecated, {"store", "diff-closures"}}},
{"dump-path", { AliasStatus::Deprecated, {"store", "dump-path"}}},
{"hash-file", { AliasStatus::Deprecated, {"hash", "file"}}},
{"hash-path", { AliasStatus::Deprecated, {"hash", "path"}}},
{"ls-nar", { AliasStatus::Deprecated, {"nar", "ls"}}},
{"ls-store", { AliasStatus::Deprecated, {"store", "ls"}}},
{"make-content-addressable", { AliasStatus::Deprecated, {"store", "make-content-addressed"}}},
{"optimise-store", { AliasStatus::Deprecated, {"store", "optimise"}}},
{"ping-store", { AliasStatus::Deprecated, {"store", "info"}}},
{"sign-paths", { AliasStatus::Deprecated, {"store", "sign"}}},
{"shell", { AliasStatus::AcceptedShorthand, {"env", "shell"}}},
{"show-derivation", { AliasStatus::Deprecated, {"derivation", "show"}}},
{"show-config", { AliasStatus::Deprecated, {"config", "show"}}},
{"to-base16", { AliasStatus::Deprecated, {"hash", "to-base16"}}},
{"to-base32", { AliasStatus::Deprecated, {"hash", "to-base32"}}},
{"to-base64", { AliasStatus::Deprecated, {"hash", "to-base64"}}},
{"verify", { AliasStatus::Deprecated, {"store", "verify"}}},
{"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
{
return "a tool for reproducible and declarative configuration management";

View file

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

View file

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

View file

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

View file

@ -16,7 +16,7 @@ struct CmdStoreDelete : StorePathsCommand
addFlag({
.longName = "ignore-liveness",
.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",
.description = "Stop after freeing *n* bytes of disk space.",
.labels = {"n"},
.handler = {&options.maxFreed}
.handler = {&options.maxFreed},
});
}

View file

@ -7,7 +7,7 @@
using namespace nix;
struct CmdPingStore : StoreCommand, MixJSON
struct CmdInfoStore : StoreCommand, MixJSON
{
std::string description() override
{
@ -46,15 +46,4 @@ struct CmdPingStore : StoreCommand, MixJSON
}
};
struct CmdInfoStore : CmdPingStore
{
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"});
static auto rCmdInfoStore = registerCommand2<CmdInfoStore>({"store", "info"});

View file

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

View file

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

View file

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