Merge remote-tracking branch 'origin/master' into lazy-trees

This commit is contained in:
Eelco Dolstra 2022-06-17 13:39:03 +02:00
commit fd51cdcdd7
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
20 changed files with 107 additions and 31 deletions

View file

@ -88,7 +88,7 @@ jobs:
fetch-depth: 0 fetch-depth: 0
- uses: cachix/install-nix-action@v17 - uses: cachix/install-nix-action@v17
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV - run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- run: echo NIX_VERSION="$(nix-instantiate --eval -E '(import ./default.nix).defaultPackage.${builtins.currentSystem}.version' | tr -d \")" >> $GITHUB_ENV - run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV
- uses: cachix/cachix-action@v10 - uses: cachix/cachix-action@v10
if: needs.check_cachix.outputs.secret == 'true' if: needs.check_cachix.outputs.secret == 'true'
with: with:

View file

@ -12,6 +12,12 @@
[`--dry-run`] [`--dry-run`]
[{`--out-link` | `-o`} *outlink*] [{`--out-link` | `-o`} *outlink*]
# Disambiguation
This man page describes the command `nix-build`, which is distinct from `nix
build`. For documentation on the latter, run `nix build --help` or see `man
nix3-build`.
# Description # Description
The `nix-build` command builds the derivations described by the Nix The `nix-build` command builds the derivations described by the Nix

View file

@ -15,6 +15,12 @@
[`--keep` *name*] [`--keep` *name*]
{{`--packages` | `-p`} {*packages* | *expressions*} … | [*path*]} {{`--packages` | `-p`} {*packages* | *expressions*} … | [*path*]}
# Disambiguation
This man page describes the command `nix-shell`, which is distinct from `nix
shell`. For documentation on the latter, run `nix shell --help` or see `man
nix3-shell`.
# Description # Description
The command `nix-shell` will build the dependencies of the specified The command `nix-shell` will build the dependencies of the specified

View file

@ -638,6 +638,17 @@ place_channel_configuration() {
fi fi
} }
check_selinux() {
if command -v getenforce > /dev/null 2>&1; then
if ! [ "$(getenforce)" = "Disabled" ]; then
failure <<EOF
Nix does not work with selinux enabled yet!
see https://github.com/NixOS/nix/issues/2374
EOF
fi
fi
}
welcome_to_nix() { welcome_to_nix() {
ok "Welcome to the Multi-User Nix Installation" ok "Welcome to the Multi-User Nix Installation"
@ -866,6 +877,8 @@ when I need to.
EOF EOF
fi fi
check_selinux
if [ "$(uname -s)" = "Darwin" ]; then if [ "$(uname -s)" = "Darwin" ]; then
# shellcheck source=./install-darwin-multi-user.sh # shellcheck source=./install-darwin-multi-user.sh
. "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh" . "$EXTRACTED_NIX_PATH/install-darwin-multi-user.sh"

View file

@ -146,7 +146,8 @@ SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
.shortName = 'f', .shortName = 'f',
.description = .description =
"Interpret installables as attribute paths relative to the Nix expression stored in *file*. " "Interpret installables as attribute paths relative to the Nix expression stored in *file*. "
"If *file* is the character -, then a Nix expression will be read from standard input.", "If *file* is the character -, then a Nix expression will be read from standard input. "
"Implies `--impure`.",
.category = installablesCategory, .category = installablesCategory,
.labels = {"file"}, .labels = {"file"},
.handler = {&file}, .handler = {&file},
@ -924,6 +925,9 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> Installable::bui
break; break;
case Realise::Outputs: { case Realise::Outputs: {
if (settings.printMissing)
printMissing(store, pathsToBuild, lvlInfo);
for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) { for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) {
if (!buildResult.success()) if (!buildResult.success())
buildResult.rethrow(); buildResult.rethrow();

View file

@ -1039,6 +1039,11 @@ struct CmdRepl : StoreCommand, MixEvalArgs
}); });
} }
bool forceImpureByDefault() override
{
return true;
}
std::string description() override std::string description() override
{ {
return "start an interactive environment for evaluating Nix expressions"; return "start an interactive environment for evaluating Nix expressions";
@ -1053,8 +1058,6 @@ struct CmdRepl : StoreCommand, MixEvalArgs
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
evalSettings.pureEval = false;
auto evalState = make_ref<EvalState>(searchPath, store); auto evalState = make_ref<EvalState>(searchPath, store);
auto repl = std::make_unique<NixRepl>(evalState); auto repl = std::make_unique<NixRepl>(evalState);

View file

@ -494,9 +494,6 @@ LockedFlake lockFlake(
if (!lockFlags.allowUnlocked && !input.ref->input.isLocked() && !input.ref->input.isRelative()) if (!lockFlags.allowUnlocked && !input.ref->input.isLocked() && !input.ref->input.isRelative())
throw Error("cannot update unlocked flake input '%s' in pure mode", inputPathS); throw Error("cannot update unlocked flake input '%s' in pure mode", inputPathS);
if (input.isFlake) {
auto inputFlake = getInputFlake();
/* Note: in case of an --override-input, we use /* Note: in case of an --override-input, we use
the *original* ref (input2.ref) for the the *original* ref (input2.ref) for the
"original" field, rather than the "original" field, rather than the
@ -504,8 +501,12 @@ LockedFlake lockFlake(
nuked the next time we update the lock nuked the next time we update the lock
file. That is, overrides are sticky unless you file. That is, overrides are sticky unless you
use --no-write-lock-file. */ use --no-write-lock-file. */
auto childNode = std::make_shared<LockedNode>( auto ref = input2.ref ? *input2.ref : *input.ref;
inputFlake.lockedRef, input2.ref ? *input2.ref : *input.ref);
if (input.isFlake) {
auto inputFlake = getInputFlake();
auto childNode = std::make_shared<LockedNode>(inputFlake.lockedRef, ref);
node->inputs.insert_or_assign(id, childNode); node->inputs.insert_or_assign(id, childNode);
@ -536,7 +537,7 @@ LockedFlake lockFlake(
auto [accessor, lockedRef] = resolvedRef.lazyFetch(state.store); auto [accessor, lockedRef] = resolvedRef.lazyFetch(state.store);
node->inputs.insert_or_assign(id, node->inputs.insert_or_assign(id,
std::make_shared<LockedNode>(lockedRef, *input.ref, false)); std::make_shared<LockedNode>(lockedRef, ref, false));
} }
} }

View file

@ -86,7 +86,7 @@ bool storeCachedHead(const std::string & actualUrl, const std::string & headRef)
{ {
Path cacheDir = getCachePath(actualUrl); Path cacheDir = getCachePath(actualUrl);
try { try {
runProgram("git", true, { "-C", cacheDir, "symbolic-ref", "--", "HEAD", headRef }); runProgram("git", true, { "-C", cacheDir, "--git-dir", ".", "symbolic-ref", "--", "HEAD", headRef });
} catch (ExecError &e) { } catch (ExecError &e) {
if (!WIFEXITED(e.status)) throw; if (!WIFEXITED(e.status)) throw;
return false; return false;
@ -373,7 +373,7 @@ struct GitInputScheme : InputScheme
if (repoInfo.hasHead) { if (repoInfo.hasHead) {
// Using git diff is preferrable over lower-level operations here, // Using git diff is preferrable over lower-level operations here,
// because it's conceptually simpler and we only need the exit code anyways. // because it's conceptually simpler and we only need the exit code anyways.
auto gitDiffOpts = Strings({ "-C", repoInfo.url, "diff", "HEAD", "--quiet"}); auto gitDiffOpts = Strings({ "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "diff", "HEAD", "--quiet"});
if (!repoInfo.submodules) { if (!repoInfo.submodules) {
// Changes in submodules should only make the tree dirty // Changes in submodules should only make the tree dirty
// when those submodules will be copied as well. // when those submodules will be copied as well.
@ -394,7 +394,7 @@ struct GitInputScheme : InputScheme
std::set<CanonPath> listFiles(const RepoInfo & repoInfo) std::set<CanonPath> listFiles(const RepoInfo & repoInfo)
{ {
auto gitOpts = Strings({ "-C", repoInfo.url, "ls-files", "-z" }); auto gitOpts = Strings({ "-C", repoInfo.url, "--git-dir", repoInfo.gitDir, "ls-files", "-z" });
if (repoInfo.submodules) if (repoInfo.submodules)
gitOpts.emplace_back("--recurse-submodules"); gitOpts.emplace_back("--recurse-submodules");

View file

@ -392,7 +392,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
Headers headers = makeHeadersWithAuthTokens(host); Headers headers = makeHeadersWithAuthTokens(host);
std::string ref_uri; std::string refUri;
if (ref == "HEAD") { if (ref == "HEAD") {
auto file = store->toRealPath( auto file = store->toRealPath(
downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath); downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath);
@ -404,10 +404,11 @@ struct SourceHutInputScheme : GitArchiveInputScheme
if (!remoteLine) { if (!remoteLine) {
throw BadURL("in '%d', couldn't resolve HEAD ref '%d'", input.to_string(), ref); throw BadURL("in '%d', couldn't resolve HEAD ref '%d'", input.to_string(), ref);
} }
ref_uri = remoteLine->target; refUri = remoteLine->target;
} else { } else {
ref_uri = fmt("refs/(heads|tags)/%s", ref); refUri = fmt("refs/(heads|tags)/%s", ref);
} }
std::regex refRegex(refUri);
auto file = store->toRealPath( auto file = store->toRealPath(
downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath); downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath);
@ -417,7 +418,7 @@ struct SourceHutInputScheme : GitArchiveInputScheme
std::optional<std::string> id; std::optional<std::string> id;
while(!id && getline(is, line)) { while(!id && getline(is, line)) {
auto parsedLine = git::parseLsRemoteLine(line); auto parsedLine = git::parseLsRemoteLine(line);
if (parsedLine && parsedLine->reference == ref_uri) if (parsedLine && parsedLine->reference && std::regex_match(*parsedLine->reference, refRegex))
id = parsedLine->target; id = parsedLine->target;
} }

View file

@ -135,6 +135,7 @@ void LocalStore::addTempRoot(const StorePath & path)
state->fdRootsSocket.close(); state->fdRootsSocket.close();
goto restart; goto restart;
} }
throw;
} }
} }
@ -153,6 +154,7 @@ void LocalStore::addTempRoot(const StorePath & path)
state->fdRootsSocket.close(); state->fdRootsSocket.close();
goto restart; goto restart;
} }
throw;
} catch (EndOfFile & e) { } catch (EndOfFile & e) {
debug("GC socket disconnected"); debug("GC socket disconnected");
state->fdRootsSocket.close(); state->fdRootsSocket.close();

View file

@ -802,7 +802,7 @@ public:
)"}; )"};
Setting<StringSet> ignoredAcls{ Setting<StringSet> ignoredAcls{
this, {"security.selinux", "system.nfs4_acl"}, "ignored-acls", this, {"security.selinux", "system.nfs4_acl", "security.csm"}, "ignored-acls",
R"( R"(
A list of ACLs that should be ignored, normally Nix attempts to A list of ACLs that should be ignored, normally Nix attempts to
remove all ACLs from files and directories in the Nix store, but remove all ACLs from files and directories in the Nix store, but

View file

@ -69,6 +69,7 @@ protected:
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == ENOENT) if (e.errNo == ENOENT)
throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache", path); throw NoSuchBinaryCacheFile("file '%s' does not exist in binary cache", path);
throw;
} }
} }

View file

@ -67,13 +67,26 @@ bool UserLock::findFreeUser() {
#if __linux__ #if __linux__
/* Get the list of supplementary groups of this build user. This /* Get the list of supplementary groups of this build user. This
is usually either empty or contains a group such as "kvm". */ is usually either empty or contains a group such as "kvm". */
supplementaryGIDs.resize(10); int ngroups = 32; // arbitrary initial guess
int ngroups = supplementaryGIDs.size(); supplementaryGIDs.resize(ngroups);
int err = getgrouplist(pw->pw_name, pw->pw_gid,
supplementaryGIDs.data(), &ngroups);
if (err == -1)
throw Error("failed to get list of supplementary groups for '%1%'", pw->pw_name);
int err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(),
&ngroups);
// Our initial size of 32 wasn't sufficient, the correct size has
// been stored in ngroups, so we try again.
if (err == -1) {
supplementaryGIDs.resize(ngroups);
err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(),
&ngroups);
}
// If it failed once more, then something must be broken.
if (err == -1)
throw Error("failed to get list of supplementary groups for '%1%'",
pw->pw_name);
// Finally, trim back the GID list to its real size
supplementaryGIDs.resize(ngroups); supplementaryGIDs.resize(ngroups);
#endif #endif

View file

@ -25,6 +25,8 @@ public:
/* Return a short one-line description of the command. */ /* Return a short one-line description of the command. */
virtual std::string description() { return ""; } virtual std::string description() { return ""; }
virtual bool forceImpureByDefault() { return false; }
/* Return documentation about this command, in Markdown format. */ /* Return documentation about this command, in Markdown format. */
virtual std::string doc() { return ""; } virtual std::string doc() { return ""; }

View file

@ -548,6 +548,8 @@ static void main_nix_build(int argc, char * * argv)
restoreProcessContext(); restoreProcessContext();
logger->stop();
execvp(shell->c_str(), argPtrs.data()); execvp(shell->c_str(), argPtrs.data());
throw SysError("executing shell '%s'", *shell); throw SysError("executing shell '%s'", *shell);
@ -606,6 +608,8 @@ static void main_nix_build(int argc, char * * argv)
outPaths.push_back(outputPath); outPaths.push_back(outputPath);
} }
logger->stop();
for (auto & path : outPaths) for (auto & path : outPaths)
std::cout << store->printStorePath(path) << '\n'; std::cout << store->printStorePath(path) << '\n';
} }

View file

@ -37,6 +37,7 @@ void removeOldGenerations(std::string dir)
link = readLink(path); link = readLink(path);
} catch (SysError & e) { } catch (SysError & e) {
if (e.errNo == ENOENT) continue; if (e.errNo == ENOENT) continue;
throw;
} }
if (link.find("link") != std::string::npos) { if (link.find("link") != std::string::npos) {
printInfo(format("removing old generations of profile %1%") % path); printInfo(format("removing old generations of profile %1%") % path);

View file

@ -1490,7 +1490,7 @@ static int main_nix_env(int argc, char * * argv)
if (globals.profile == "") if (globals.profile == "")
globals.profile = getDefaultProfile(); globals.profile = getDefaultProfile();
op(globals, opFlags, opArgs); op(globals, std::move(opFlags), std::move(opArgs));
globals.state->printStats(); globals.state->printStats();

View file

@ -377,6 +377,9 @@ void mainWrapped(int argc, char * * argv)
settings.ttlPositiveNarInfoCache = 0; settings.ttlPositiveNarInfoCache = 0;
} }
if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) {
evalSettings.pureEval = false;
}
args.command->second->prepare(); args.command->second->prepare();
args.command->second->run(); args.command->second->run();
} }

View file

@ -42,6 +42,11 @@ testRepl () {
echo "$replOutput" echo "$replOutput"
echo "$replOutput" | grep -qs "while evaluating the file" \ echo "$replOutput" | grep -qs "while evaluating the file" \
|| fail "nix repl --show-trace doesn't show the trace" || fail "nix repl --show-trace doesn't show the trace"
nix repl "${nixArgs[@]}" --option pure-eval true 2>&1 <<< "builtins.currentSystem" \
| grep "attribute 'currentSystem' missing"
nix repl "${nixArgs[@]}" 2>&1 <<< "builtins.currentSystem" \
| grep "$(nix-instantiate --eval -E 'builtins.currentSystem')"
} }
# Simple test, try building a drv # Simple test, try building a drv

View file

@ -59,7 +59,7 @@ let
echo 'ref: refs/heads/master' > $out/HEAD echo 'ref: refs/heads/master' > $out/HEAD
mkdir -p $out/info mkdir -p $out/info
echo -e '${nixpkgs.rev}\trefs/heads/master' > $out/info/refs echo -e '${nixpkgs.rev}\trefs/heads/master\n${nixpkgs.rev}\trefs/tags/foo-bar' > $out/info/refs
''; '';
in in
@ -132,6 +132,17 @@ makeTest (
client.succeed("curl -v https://git.sr.ht/ >&2") client.succeed("curl -v https://git.sr.ht/ >&2")
client.succeed("nix registry list | grep nixpkgs") client.succeed("nix registry list | grep nixpkgs")
# Test that it resolves HEAD
rev = client.succeed("nix flake info sourcehut:~NixOS/nixpkgs --json | jq -r .revision")
assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
# Test that it resolves branches
rev = client.succeed("nix flake info sourcehut:~NixOS/nixpkgs/master --json | jq -r .revision")
assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
# Test that it resolves tags
rev = client.succeed("nix flake info sourcehut:~NixOS/nixpkgs/foo-bar --json | jq -r .revision")
assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"
# Registry and pinning test
rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision") rev = client.succeed("nix flake info nixpkgs --json | jq -r .revision")
assert rev.strip() == "${nixpkgs.rev}", "revision mismatch" assert rev.strip() == "${nixpkgs.rev}", "revision mismatch"