aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md4
-rw-r--r--.github/PULL_REQUEST_TEMPLATE/pull_request_template.md11
-rw-r--r--.github/workflows/ci.yml4
-rw-r--r--doc/manual/src/glossary.md5
-rw-r--r--flake.nix13
-rw-r--r--maintainers/README.md1
-rwxr-xr-xmk/debug-test.sh2
-rwxr-xr-xmk/run-test.sh5
-rw-r--r--src/build-remote/build-remote.cc2
-rw-r--r--src/libcmd/command.hh4
-rw-r--r--src/libcmd/installable-flake.cc3
-rw-r--r--src/libcmd/installables.cc4
-rw-r--r--src/libexpr/eval.cc4
-rw-r--r--src/libexpr/parser.y4
-rw-r--r--src/libexpr/primops/fetchTree.cc54
-rw-r--r--src/libexpr/tests/primops.cc4
-rw-r--r--src/libexpr/value-to-xml.cc8
-rw-r--r--src/libmain/progress-bar.cc6
-rw-r--r--src/libmain/shared.cc16
-rw-r--r--src/libstore/build/derivation-goal.cc2
-rw-r--r--src/libstore/build/drv-output-substitution-goal.cc23
-rw-r--r--src/libstore/build/drv-output-substitution-goal.hh12
-rw-r--r--src/libstore/build/goal.cc4
-rw-r--r--src/libstore/build/goal.hh2
-rw-r--r--src/libstore/build/local-derivation-goal.cc9
-rw-r--r--src/libstore/daemon.cc4
-rw-r--r--src/libstore/export-import.cc4
-rw-r--r--src/libstore/filetransfer.cc4
-rw-r--r--src/libstore/gc.cc53
-rw-r--r--src/libstore/globals.cc14
-rw-r--r--src/libstore/local-store.cc6
-rw-r--r--src/libstore/optimise-store.cc17
-rw-r--r--src/libstore/pathlocks.cc8
-rw-r--r--src/libstore/profiles.cc4
-rw-r--r--src/libstore/references.cc3
-rw-r--r--src/libstore/s3-binary-cache-store.cc12
-rw-r--r--src/libstore/store-api.cc4
-rw-r--r--src/libutil/archive.cc4
-rw-r--r--src/libutil/filesystem.cc4
-rw-r--r--src/libutil/fmt.hh15
-rw-r--r--src/libutil/logging.cc8
-rw-r--r--src/libutil/logging.hh6
-rw-r--r--src/libutil/serialise.cc4
-rw-r--r--src/libutil/util.cc15
-rw-r--r--src/libutil/util.hh6
-rw-r--r--src/nix-build/nix-build.cc4
-rw-r--r--src/nix-collect-garbage/nix-collect-garbage.cc5
-rwxr-xr-xsrc/nix-copy-closure/nix-copy-closure.cc2
-rw-r--r--src/nix-env/nix-env.cc22
-rw-r--r--src/nix-env/user-env.cc4
-rw-r--r--src/nix-store/nix-store.cc7
-rw-r--r--src/nix/build.md2
-rw-r--r--src/nix/bundle.md2
-rw-r--r--src/nix/daemon.cc6
-rw-r--r--src/nix/develop.md2
-rw-r--r--src/nix/doctor.cc2
-rw-r--r--src/nix/eval.md2
-rw-r--r--src/nix/flake.md4
-rw-r--r--src/nix/log.md3
-rw-r--r--src/nix/make-content-addressed.md4
-rw-r--r--src/nix/nix.md168
-rw-r--r--src/nix/path-info.md2
-rw-r--r--src/nix/print-dev-env.md2
-rw-r--r--src/nix/profile-install.md2
-rw-r--r--src/nix/run.md2
-rw-r--r--src/nix/search.md6
-rw-r--r--src/nix/shell.md2
-rw-r--r--src/nix/show-derivation.md2
-rw-r--r--src/nix/sigs.cc2
-rw-r--r--src/nix/store-delete.md2
-rw-r--r--src/nix/store-dump-path.md2
-rw-r--r--src/nix/store-repair.md2
-rw-r--r--src/nix/verify.md2
-rw-r--r--src/resolve-system-dependencies/resolve-system-dependencies.cc8
-rw-r--r--tests/binary-cache.sh24
-rw-r--r--tests/build-delete.sh2
-rw-r--r--tests/build-dry.sh2
-rw-r--r--tests/build-remote.sh31
-rw-r--r--tests/build.sh2
-rw-r--r--tests/ca/build.sh2
-rw-r--r--tests/check-refs.sh10
-rw-r--r--tests/check-reqs.sh4
-rw-r--r--tests/check.sh2
-rw-r--r--tests/common.sh2
-rw-r--r--tests/common/vars-and-functions.sh.in64
-rw-r--r--tests/compute-levels.sh2
-rw-r--r--tests/db-migration.sh4
-rw-r--r--tests/dependencies.sh6
-rw-r--r--tests/eval-store.sh2
-rw-r--r--tests/export-graph.sh2
-rw-r--r--tests/fetchClosure.sh4
-rw-r--r--tests/fetchGitRefs.sh2
-rw-r--r--tests/fetchTree-file.sh4
-rw-r--r--tests/fetchurl.sh2
-rw-r--r--tests/flakes/build-paths.sh2
-rw-r--r--tests/flakes/check.sh4
-rw-r--r--tests/flakes/common.sh2
-rw-r--r--tests/flakes/flakes.sh26
-rw-r--r--tests/flakes/follow-paths.sh2
-rw-r--r--tests/fmt.sh2
-rwxr-xr-xtests/function-trace.sh10
-rw-r--r--tests/gc.sh17
-rw-r--r--tests/hash.sh2
-rw-r--r--tests/impure-derivations.sh2
-rwxr-xr-xtests/init.sh2
-rwxr-xr-xtests/install-darwin.sh2
-rw-r--r--tests/lang.sh10
-rw-r--r--tests/linux-sandbox.sh4
-rw-r--r--tests/local.mk3
-rw-r--r--tests/misc.sh12
-rw-r--r--tests/multiple-outputs.sh8
-rw-r--r--tests/nar-access.sh4
-rw-r--r--tests/nix-channel.sh14
-rw-r--r--tests/nix-shell.sh6
-rw-r--r--tests/plugins.sh2
-rw-r--r--tests/pure-eval.sh2
-rw-r--r--tests/repl.sh12
-rw-r--r--tests/restricted.sh2
-rw-r--r--tests/search.sh6
-rw-r--r--tests/tarball.sh4
-rw-r--r--tests/test-infra.sh85
-rw-r--r--tests/timeout.sh7
-rw-r--r--tests/user-envs.sh50
-rw-r--r--tests/why-depends.sh10
124 files changed, 664 insertions, 499 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index db69e51db..60742cf6a 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -26,3 +26,7 @@ Maintainers: tick if completed or explain if not relevant
- [ ] code and comments are self-explanatory
- [ ] commit message explains why the change was made
- [ ] new feature or incompatible change: updated release notes
+
+# Priorities
+
+Add :+1: to [pull requests you find important](https://github.com/NixOS/nix/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
deleted file mode 100644
index 5311be01f..000000000
--- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
+++ /dev/null
@@ -1,11 +0,0 @@
-**Release Notes**
-Please include relevant [release notes](https://github.com/NixOS/nix/blob/master/doc/manual/src/release-notes/rl-next.md) as needed.
-
-
-**Testing**
-
-If this issue is a regression or something that should block release, please consider including a test either in the [testsuite](https://github.com/NixOS/nix/tree/master/tests) or as a [hydraJob]( https://github.com/NixOS/nix/blob/master/flake.nix#L396) so that it can be part of the [automatic checks](https://hydra.nixos.org/jobset/nix/master).
-
-**Priorities**
-
-Add :+1: to [pull requests you find important](https://github.com/NixOS/nix/pulls?q=is%3Aopen+sort%3Areactions-%2B1-desc).
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fe0976228..158eb057c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,9 +19,7 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- - uses: cachix/install-nix-action@v19
- with:
- install_url: https://releases.nixos.org/nix/nix-2.13.3/install
+ - uses: cachix/install-nix-action@v20
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
- uses: cachix/cachix-action@v12
if: needs.check_secrets.outputs.cachix == 'true'
diff --git a/doc/manual/src/glossary.md b/doc/manual/src/glossary.md
index d0aff34e2..1256b272f 100644
--- a/doc/manual/src/glossary.md
+++ b/doc/manual/src/glossary.md
@@ -193,6 +193,11 @@
A symlink to the current *user environment* of a user, e.g.,
`/nix/var/nix/profiles/default`.
+ - [installable]{#gloss-installable}\
+ Something that can be realised in the Nix store.
+
+ See [installables](./command-ref/new-cli/nix.md#installables) for [`nix` commands](./command-ref/new-cli/nix.md) (experimental) for details.
+
- [NAR]{#gloss-nar}\
A *N*ix *AR*chive. This is a serialisation of a path in the Nix
store. It can contain regular files, directories and symbolic
diff --git a/flake.nix b/flake.nix
index 5e0504a59..9d9bd8d81 100644
--- a/flake.nix
+++ b/flake.nix
@@ -369,6 +369,10 @@
postInstall = ''
mkdir -p $doc/nix-support
echo "doc manual $doc/share/doc/nix/manual" >> $doc/nix-support/hydra-build-products
+ ${lib.optionalString currentStdenv.hostPlatform.isStatic ''
+ mkdir -p $out/nix-support
+ echo "file binary-dist $out/bin/nix" >> $out/nix-support/hydra-build-products
+ ''}
${lib.optionalString currentStdenv.isDarwin ''
install_name_tool \
-change ${boost}/lib/libboost_context.dylib \
@@ -379,6 +383,7 @@
doInstallCheck = finalAttrs.doCheck;
installCheckFlags = "sysconfdir=$(out)/etc";
+ installCheckTarget = "installcheck"; # work around buggy detection in stdenv
separateDebugInfo = !currentStdenv.hostPlatform.isStatic;
@@ -519,18 +524,16 @@
enableParallelBuilding = true;
nativeBuildInputs = nativeBuildDeps;
- buildInputs = buildDeps ++ propagatedDeps ++ awsDeps;
+ buildInputs = buildDeps ++ propagatedDeps ++ awsDeps ++ checkDeps;
dontInstall = false;
doInstallCheck = true;
+ installCheckTarget = "installcheck"; # work around buggy detection in stdenv
lcovFilter = [ "*/boost/*" "*-tab.*" ];
- # We call `dot', and even though we just use it to
- # syntax-check generated dot files, it still requires some
- # fonts. So provide those.
- FONTCONFIG_FILE = texFunctions.fontsConf;
+ hardeningDisable = ["fortify"];
};
# System tests.
diff --git a/maintainers/README.md b/maintainers/README.md
index 08d197c1b..1864a279d 100644
--- a/maintainers/README.md
+++ b/maintainers/README.md
@@ -11,6 +11,7 @@ The goal of the team is to help other people to contribute to Nix.
- Valentin Gagarin (@fricklerhandwerk)
- Thomas Bereknyei (@tomberek)
- Robert Hensing (@roberth)
+- John Ericson (@Ericson2314)
## Meeting protocol
diff --git a/mk/debug-test.sh b/mk/debug-test.sh
index 6299e68a0..b5b628ecd 100755
--- a/mk/debug-test.sh
+++ b/mk/debug-test.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-set -eu
+set -eu -o pipefail
test=$1
diff --git a/mk/run-test.sh b/mk/run-test.sh
index 219c8577f..305396c11 100755
--- a/mk/run-test.sh
+++ b/mk/run-test.sh
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
-set -u
+set -eu -o pipefail
red=""
green=""
@@ -22,8 +22,7 @@ fi
run_test () {
(init_test 2>/dev/null > /dev/null)
- log="$(run_test_proper 2>&1)"
- status=$?
+ log="$(run_test_proper 2>&1)" && status=0 || status=$?
}
run_test
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index 174435e7c..63e3e3fa9 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -219,7 +219,7 @@ static int main_build_remote(int argc, char * * argv)
% concatStringsSep<StringSet>(", ", m.supportedFeatures)
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures);
- printMsg(couldBuildLocally ? lvlChatty : lvlWarn, error);
+ printMsg(couldBuildLocally ? lvlChatty : lvlWarn, error.str());
std::cerr << "# decline\n";
}
diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh
index 49c7b4f9b..0d84c8395 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -22,7 +22,7 @@ static constexpr Command::Category catSecondary = 100;
static constexpr Command::Category catUtility = 101;
static constexpr Command::Category catNixInstallation = 102;
-static constexpr auto installablesCategory = "Options that change the interpretation of installables";
+static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
struct NixMultiCommand : virtual MultiCommand, virtual Command
{
@@ -128,7 +128,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand
virtual bool useDefaultInstallables() { return true; }
- bool readFromStdIn;
+ bool readFromStdIn = false;
std::vector<std::string> getFlakesForCompletion() override;
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 60a97deaf..7b0cc376d 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -178,8 +178,7 @@ std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
std::vector<ref<eval_cache::AttrCursor>>
InstallableFlake::getCursors(EvalState & state)
{
- auto evalCache = openEvalCache(state,
- std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
+ auto evalCache = openEvalCache(state, getLockedFlake());
auto root = evalCache->getRoot();
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 7d444aac0..5ecf6293f 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -153,7 +153,7 @@ SourceExprCommand::SourceExprCommand()
.longName = "file",
.shortName = 'f',
.description =
- "Interpret installables as attribute paths relative to the Nix expression stored in *file*. "
+ "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#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. "
"Implies `--impure`.",
.category = installablesCategory,
@@ -164,7 +164,7 @@ SourceExprCommand::SourceExprCommand()
addFlag({
.longName = "expr",
- .description = "Interpret 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,
.labels = {"expr"},
.handler = {&expr}
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 21fc4d0fe..2721b6733 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -368,7 +368,7 @@ void initGC()
size = (pageSize * pages) / 4; // 25% of RAM
if (size > maxSize) size = maxSize;
#endif
- debug(format("setting initial heap size to %1% bytes") % size);
+ debug("setting initial heap size to %1% bytes", size);
GC_expand_hp(size);
}
@@ -609,7 +609,7 @@ Path EvalState::checkSourcePath(const Path & path_)
}
/* Resolve symlinks. */
- debug(format("checking access to '%s'") % abspath);
+ debug("checking access to '%s'", abspath);
Path path = canonPath(abspath, true);
for (auto & i : *allowedPaths) {
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index dec5818fc..0f75ed9a0 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -732,7 +732,7 @@ Expr * EvalState::parseExprFromString(std::string s, const Path & basePath)
Expr * EvalState::parseStdin()
{
- //Activity act(*logger, lvlTalkative, format("parsing standard input"));
+ //Activity act(*logger, lvlTalkative, "parsing standard input");
auto buffer = drainFD(0);
// drainFD should have left some extra space for terminators
buffer.append("\0\0", 2);
@@ -835,7 +835,7 @@ std::pair<bool, std::string> EvalState::resolveSearchPathElem(const SearchPathEl
}
}
- debug(format("resolved search path element '%s' to '%s'") % elem.second % res.second);
+ debug("resolved search path element '%s' to '%s'", elem.second, res.second);
searchPathResolved[elem.second] = res;
return res;
diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc
index c9faf3ffb..fd51dfb90 100644
--- a/src/libexpr/primops/fetchTree.cc
+++ b/src/libexpr/primops/fetchTree.cc
@@ -353,36 +353,44 @@ static RegisterPrimOp primop_fetchGit({
of the repo at that URL is fetched. Otherwise, it can be an
attribute with the following attributes (all except `url` optional):
- - url\
- The URL of the repo.
+ - `url`
- - name\
- The name of the directory the repo should be exported to in the
- store. Defaults to the basename of the URL.
+ The URL of the repo.
- - rev\
- The git revision to fetch. Defaults to the tip of `ref`.
+ - `name` (default: *basename of the URL*)
- - ref\
- The git ref to look for the requested revision under. This is
- often a branch or tag name. Defaults to `HEAD`.
+ The name of the directory the repo should be exported to in the store.
- By default, the `ref` value is prefixed with `refs/heads/`. As
- of Nix 2.3.0 Nix will not prefix `refs/heads/` if `ref` starts
- with `refs/`.
+ - `rev` (default: *the tip of `ref`*)
- - submodules\
- A Boolean parameter that specifies whether submodules should be
- checked out. Defaults to `false`.
+ The [Git revision] to fetch.
+ This is typically a commit hash.
- - shallow\
- A Boolean parameter that specifies whether fetching a shallow clone
- is allowed. Defaults to `false`.
+ [Git revision]: https://git-scm.com/docs/git-rev-parse#_specifying_revisions
- - allRefs\
- Whether to fetch all refs of the repository. With this argument being
- true, it's possible to load a `rev` from *any* `ref` (by default only
- `rev`s from the specified `ref` are supported).
+ - `ref` (default: `HEAD`)
+
+ The [Git reference] under which to look for the requested revision.
+ This is often a branch or tag name.
+
+ [Git reference]: https://git-scm.com/book/en/v2/Git-Internals-Git-References
+
+ By default, the `ref` value is prefixed with `refs/heads/`.
+ As of 2.3.0, Nix will not prefix `refs/heads/` if `ref` starts with `refs/`.
+
+ - `submodules` (default: `false`)
+
+ A Boolean parameter that specifies whether submodules should be checked out.
+
+ - `shallow` (default: `false`)
+
+ A Boolean parameter that specifies whether fetching a shallow clone is allowed.
+
+ - `allRefs`
+
+ Whether to fetch all references of the repository.
+ With this argument being true, it's possible to load a `rev` from *any* `ref`
+ (by default only `rev`s from the specified `ref` are supported).
Here are some examples of how to use `fetchGit`.
diff --git a/src/libexpr/tests/primops.cc b/src/libexpr/tests/primops.cc
index e1d3ac503..ce3b5d11f 100644
--- a/src/libexpr/tests/primops.cc
+++ b/src/libexpr/tests/primops.cc
@@ -15,8 +15,8 @@ namespace nix {
return oss.str();
}
- void log(Verbosity lvl, const FormatOrString & fs) override {
- oss << fs.s << std::endl;
+ void log(Verbosity lvl, std::string_view s) override {
+ oss << s << std::endl;
}
void logEI(const ErrorInfo & ei) override {
diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc
index 3f6222768..341c8922f 100644
--- a/src/libexpr/value-to-xml.cc
+++ b/src/libexpr/value-to-xml.cc
@@ -26,8 +26,8 @@ static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos)
{
if (auto path = std::get_if<Path>(&pos.origin))
xmlAttrs["path"] = *path;
- xmlAttrs["line"] = (format("%1%") % pos.line).str();
- xmlAttrs["column"] = (format("%1%") % pos.column).str();
+ xmlAttrs["line"] = fmt("%1%", pos.line);
+ xmlAttrs["column"] = fmt("%1%", pos.column);
}
@@ -64,7 +64,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
switch (v.type()) {
case nInt:
- doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % v.integer).str()));
+ doc.writeEmptyElement("int", singletonAttrs("value", fmt("%1%", v.integer)));
break;
case nBool:
@@ -156,7 +156,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
break;
case nFloat:
- doc.writeEmptyElement("float", singletonAttrs("value", (format("%1%") % v.fpoint).str()));
+ doc.writeEmptyElement("float", singletonAttrs("value", fmt("%1%", v.fpoint)));
break;
case nThunk:
diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc
index e9205a5e5..024259584 100644
--- a/src/libmain/progress-bar.cc
+++ b/src/libmain/progress-bar.cc
@@ -125,11 +125,11 @@ public:
return printBuildLogs;
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
if (lvl > verbosity) return;
auto state(state_.lock());
- log(*state, lvl, fs.s);
+ log(*state, lvl, s);
}
void logEI(const ErrorInfo & ei) override
@@ -142,7 +142,7 @@ public:
log(*state, ei.level, oss.str());
}
- void log(State & state, Verbosity lvl, const std::string & s)
+ void log(State & state, Verbosity lvl, std::string_view s)
{
if (state.active) {
writeToStderr("\r\e[K" + filterANSIEscapes(s, !isTTY) + ANSI_NORMAL "\n");
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index d4871a8e2..37664c065 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -84,8 +84,18 @@ void printMissing(ref<Store> store, const StorePathSet & willBuild,
downloadSizeMiB,
narSizeMiB);
}
- for (auto & i : willSubstitute)
- printMsg(lvl, " %s", store->printStorePath(i));
+ std::vector<const StorePath *> willSubstituteSorted = {};
+ std::for_each(willSubstitute.begin(), willSubstitute.end(),
+ [&](const StorePath &p) { willSubstituteSorted.push_back(&p); });
+ std::sort(willSubstituteSorted.begin(), willSubstituteSorted.end(),
+ [](const StorePath *lhs, const StorePath *rhs) {
+ if (lhs->name() == rhs->name())
+ return lhs->to_string() < rhs->to_string();
+ else
+ return lhs->name() < rhs->name();
+ });
+ for (auto p : willSubstituteSorted)
+ printMsg(lvl, " %s", store->printStorePath(*p));
}
if (!unknown.empty()) {
@@ -347,7 +357,7 @@ void parseCmdLine(const std::string & programName, const Strings & args,
void printVersion(const std::string & programName)
{
- std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
+ std::cout << fmt("%1% (Nix) %2%", programName, nixVersion) << std::endl;
if (verbosity > lvlInfo) {
Strings cfg;
#if HAVE_BOEHMGC
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 2021d0023..38b73d531 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -732,7 +732,7 @@ void replaceValidPath(const Path & storePath, const Path & tmpPath)
tmpPath (the replacement), so we have to move it out of the
way first. We'd better not be interrupted here, because if
we're repairing (say) Glibc, we end up with a broken system. */
- Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
+ Path oldPath = fmt("%1%.old-%2%-%3%", storePath, getpid(), random());
if (pathExists(storePath))
movePath(storePath, oldPath);
diff --git a/src/libstore/build/drv-output-substitution-goal.cc b/src/libstore/build/drv-output-substitution-goal.cc
index b7f7b5ab1..b30957c84 100644
--- a/src/libstore/build/drv-output-substitution-goal.cc
+++ b/src/libstore/build/drv-output-substitution-goal.cc
@@ -61,20 +61,25 @@ void DrvOutputSubstitutionGoal::tryNext()
// FIXME: Make async
// outputInfo = sub->queryRealisation(id);
- outPipe.create();
- promise = decltype(promise)();
+
+ /* The callback of the curl download below can outlive `this` (if
+ some other error occurs), so it must not touch `this`. So put
+ the shared state in a separate refcounted object. */
+ downloadState = std::make_shared<DownloadState>();
+ downloadState->outPipe.create();
sub->queryRealisation(
- id, { [&](std::future<std::shared_ptr<const Realisation>> res) {
+ id,
+ { [downloadState(downloadState)](std::future<std::shared_ptr<const Realisation>> res) {
try {
- Finally updateStats([this]() { outPipe.writeSide.close(); });
- promise.set_value(res.get());
+ Finally updateStats([&]() { downloadState->outPipe.writeSide.close(); });
+ downloadState->promise.set_value(res.get());
} catch (...) {
- promise.set_exception(std::current_exception());
+ downloadState->promise.set_exception(std::current_exception());
}
} });
- worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
+ worker.childStarted(shared_from_this(), {downloadState->outPipe.readSide.get()}, true, false);
state = &DrvOutputSubstitutionGoal::realisationFetched;
}
@@ -84,7 +89,7 @@ void DrvOutputSubstitutionGoal::realisationFetched()
worker.childTerminated(this);
try {
- outputInfo = promise.get_future().get();
+ outputInfo = downloadState->promise.get_future().get();
} catch (std::exception & e) {
printError(e.what());
substituterFailed = true;
@@ -155,7 +160,7 @@ void DrvOutputSubstitutionGoal::work()
void DrvOutputSubstitutionGoal::handleEOF(int fd)
{
- if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this());
+ if (fd == downloadState->outPipe.readSide.get()) worker.wakeUp(shared_from_this());
}
diff --git a/src/libstore/build/drv-output-substitution-goal.hh b/src/libstore/build/drv-output-substitution-goal.hh
index 948dbda8f..e4b044790 100644
--- a/src/libstore/build/drv-output-substitution-goal.hh
+++ b/src/libstore/build/drv-output-substitution-goal.hh
@@ -16,7 +16,7 @@ class Worker;
// 2. Substitute the corresponding output path
// 3. Register the output info
class DrvOutputSubstitutionGoal : public Goal {
-private:
+
// The drv output we're trying to substitue
DrvOutput id;
@@ -30,9 +30,13 @@ private:
/* The current substituter. */
std::shared_ptr<Store> sub;
- Pipe outPipe;
- std::thread thr;
- std::promise<std::shared_ptr<const Realisation>> promise;
+ struct DownloadState
+ {
+ Pipe outPipe;
+ std::promise<std::shared_ptr<const Realisation>> promise;
+ };
+
+ std::shared_ptr<DownloadState> downloadState;
/* Whether a substituter failed. */
bool substituterFailed = false;
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index 58e805f55..d59b94797 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -78,9 +78,9 @@ void Goal::amDone(ExitCode result, std::optional<Error> ex)
}
-void Goal::trace(const FormatOrString & fs)
+void Goal::trace(std::string_view s)
{
- debug("%1%: %2%", name, fs.s);
+ debug("%1%: %2%", name, s);
}
}
diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh
index 35121c5d9..776eb86bc 100644
--- a/src/libstore/build/goal.hh
+++ b/src/libstore/build/goal.hh
@@ -88,7 +88,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
abort();
}
- void trace(const FormatOrString & fs);
+ void trace(std::string_view s);
std::string getName()
{
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index a961d8eed..6fb9b86e0 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -650,7 +650,7 @@ void LocalDerivationGoal::startBuilder()
/* Clean up the chroot directory automatically. */
autoDelChroot = std::make_shared<AutoDelete>(chrootRootDir);
- printMsg(lvlChatty, format("setting up chroot environment in '%1%'") % chrootRootDir);
+ printMsg(lvlChatty, "setting up chroot environment in '%1%'", chrootRootDir);
// FIXME: make this 0700
if (mkdir(chrootRootDir.c_str(), buildUser && buildUser->getUIDCount() != 1 ? 0755 : 0750) == -1)
@@ -753,8 +753,7 @@ void LocalDerivationGoal::startBuilder()
throw Error("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir);
if (useChroot && settings.preBuildHook != "" && dynamic_cast<Derivation *>(drv.get())) {
- printMsg(lvlChatty, format("executing pre-build hook '%1%'")
- % settings.preBuildHook);
+ printMsg(lvlChatty, "executing pre-build hook '%1%'", settings.preBuildHook);
auto args = useChroot ? Strings({worker.store.printStorePath(drvPath), chrootRootDir}) :
Strings({ worker.store.printStorePath(drvPath) });
enum BuildHookState {
@@ -1104,7 +1103,7 @@ void LocalDerivationGoal::initEnv()
env["NIX_STORE"] = worker.store.storeDir;
/* The maximum number of cores to utilize for parallel building. */
- env["NIX_BUILD_CORES"] = (format("%d") % settings.buildCores).str();
+ env["NIX_BUILD_CORES"] = fmt("%d", settings.buildCores);
initTmpDir();
@@ -2063,7 +2062,7 @@ void LocalDerivationGoal::runChild()
/* The tmpDir in scope points at the temporary build directory for our derivation. Some packages try different mechanisms
to find temporary directories, so we want to open up a broader place for them to dump their files, if needed. */
- Path globalTmpDir = canonPath(getEnv("TMPDIR").value_or("/tmp"), true);
+ Path globalTmpDir = canonPath(getEnvNonEmpty("TMPDIR").value_or("/tmp"), true);
/* They don't like trailing slashes on subpath directives */
if (globalTmpDir.back() == '/') globalTmpDir.pop_back();
diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc
index 5e6fd011f..7f8b0f905 100644
--- a/src/libstore/daemon.cc
+++ b/src/libstore/daemon.cc
@@ -67,12 +67,12 @@ struct TunnelLogger : public Logger
state->pendingMsgs.push_back(s);
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
if (lvl > verbosity) return;
StringSink buf;
- buf << STDERR_NEXT << (fs.s + "\n");
+ buf << STDERR_NEXT << (s + "\n");
enqueueMsg(buf.s);
}
diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc
index 9875da909..4eb838b68 100644
--- a/src/libstore/export-import.cc
+++ b/src/libstore/export-import.cc
@@ -16,7 +16,7 @@ void Store::exportPaths(const StorePathSet & paths, Sink & sink)
//logger->incExpected(doneLabel, sorted.size());
for (auto & path : sorted) {
- //Activity act(*logger, lvlInfo, format("exporting path '%s'") % path);
+ //Activity act(*logger, lvlInfo, "exporting path '%s'", path);
sink << 1;
exportPath(path, sink);
//logger->incProgress(doneLabel);
@@ -71,7 +71,7 @@ StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs)
auto path = parseStorePath(readString(source));
- //Activity act(*logger, lvlInfo, format("importing path '%s'") % info.path);
+ //Activity act(*logger, lvlInfo, "importing path '%s'", info.path);
auto references = worker_proto::read(*this, source, Phantom<StorePathSet> {});
auto deriver = readString(source);
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 6a4778d1f..b5fe7c03b 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -185,7 +185,7 @@ struct curlFileTransfer : public FileTransfer
{
size_t realSize = size * nmemb;
std::string line((char *) contents, realSize);
- printMsg(lvlVomit, format("got header for '%s': %s") % request.uri % trim(line));
+ printMsg(lvlVomit, "got header for '%s': %s", request.uri, trim(line));
static std::regex statusLine("HTTP/[^ ]+ +[0-9]+(.*)", std::regex::extended | std::regex::icase);
std::smatch match;
if (std::regex_match(line, match, statusLine)) {
@@ -209,7 +209,7 @@ struct curlFileTransfer : public FileTransfer
long httpStatus = 0;
curl_easy_getinfo(req, CURLINFO_RESPONSE_CODE, &httpStatus);
if (result.etag == request.expectedETag && httpStatus == 200) {
- debug(format("shutting down on 200 HTTP response with expected ETag"));
+ debug("shutting down on 200 HTTP response with expected ETag");
return 0;
}
} else if (name == "content-encoding")
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 996f26a95..0038ec802 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -34,8 +34,7 @@ static void makeSymlink(const Path & link, const Path & target)
createDirs(dirOf(link));
/* Create the new symlink. */
- Path tempLink = (format("%1%.tmp-%2%-%3%")
- % link % getpid() % random()).str();
+ Path tempLink = fmt("%1%.tmp-%2%-%3%", link, getpid(), random());
createSymlink(target, tempLink);
/* Atomically replace the old one. */
@@ -197,7 +196,7 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor)
pid_t pid = std::stoi(i.name);
- debug(format("reading temporary root file '%1%'") % path);
+ debug("reading temporary root file '%1%'", path);
AutoCloseFD fd(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666));
if (!fd) {
/* It's okay if the file has disappeared. */
@@ -263,7 +262,7 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
target = absPath(target, dirOf(path));
if (!pathExists(target)) {
if (isInDir(path, stateDir + "/" + gcRootsDir + "/auto")) {
- printInfo(format("removing stale link from '%1%' to '%2%'") % path % target);
+ printInfo("removing stale link from '%1%' to '%2%'", path, target);
unlink(path.c_str());
}
} else {
@@ -372,29 +371,29 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
while (errno = 0, ent = readdir(procDir.get())) {
checkInterrupt();
if (std::regex_match(ent->d_name, digitsRegex)) {
- readProcLink(fmt("/proc/%s/exe" ,ent->d_name), unchecked);
- readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked);
-
- auto fdStr = fmt("/proc/%s/fd", ent->d_name);
- auto fdDir = AutoCloseDir(opendir(fdStr.c_str()));
- if (!fdDir) {
- if (errno == ENOENT || errno == EACCES)
- continue;
- throw SysError("opening %1%", fdStr);
- }
- struct dirent * fd_ent;
- while (errno = 0, fd_ent = readdir(fdDir.get())) {
- if (fd_ent->d_name[0] != '.')
- readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked);
- }
- if (errno) {
- if (errno == ESRCH)
- continue;
- throw SysError("iterating /proc/%1%/fd", ent->d_name);
- }
- fdDir.reset();
-
try {
+ readProcLink(fmt("/proc/%s/exe" ,ent->d_name), unchecked);
+ readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked);
+
+ auto fdStr = fmt("/proc/%s/fd", ent->d_name);
+ auto fdDir = AutoCloseDir(opendir(fdStr.c_str()));
+ if (!fdDir) {
+ if (errno == ENOENT || errno == EACCES)
+ continue;
+ throw SysError("opening %1%", fdStr);
+ }
+ struct dirent * fd_ent;
+ while (errno = 0, fd_ent = readdir(fdDir.get())) {
+ if (fd_ent->d_name[0] != '.')
+ readProcLink(fmt("%s/%s", fdStr, fd_ent->d_name), unchecked);
+ }
+ if (errno) {
+ if (errno == ESRCH)
+ continue;
+ throw SysError("iterating /proc/%1%/fd", ent->d_name);
+ }
+ fdDir.reset();
+
auto mapFile = fmt("/proc/%s/maps", ent->d_name);
auto mapLines = tokenizeString<std::vector<std::string>>(readFile(mapFile), "\n");
for (const auto & line : mapLines) {
@@ -863,7 +862,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
continue;
}
- printMsg(lvlTalkative, format("deleting unused link '%1%'") % path);
+ printMsg(lvlTalkative, "deleting unused link '%1%'", path);
if (unlink(path.c_str()) == -1)
throw SysError("deleting '%1%'", path);
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 8e33a3dec..fae79c1a0 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -30,15 +30,15 @@ static GlobalConfig::Register rSettings(&settings);
Settings::Settings()
: nixPrefix(NIX_PREFIX)
- , nixStore(canonPath(getEnv("NIX_STORE_DIR").value_or(getEnv("NIX_STORE").value_or(NIX_STORE_DIR))))
- , nixDataDir(canonPath(getEnv("NIX_DATA_DIR").value_or(NIX_DATA_DIR)))
- , nixLogDir(canonPath(getEnv("NIX_LOG_DIR").value_or(NIX_LOG_DIR)))
- , nixStateDir(canonPath(getEnv("NIX_STATE_DIR").value_or(NIX_STATE_DIR)))
- , nixConfDir(canonPath(getEnv("NIX_CONF_DIR").value_or(NIX_CONF_DIR)))
+ , nixStore(canonPath(getEnvNonEmpty("NIX_STORE_DIR").value_or(getEnvNonEmpty("NIX_STORE").value_or(NIX_STORE_DIR))))
+ , nixDataDir(canonPath(getEnvNonEmpty("NIX_DATA_DIR").value_or(NIX_DATA_DIR)))
+ , nixLogDir(canonPath(getEnvNonEmpty("NIX_LOG_DIR").value_or(NIX_LOG_DIR)))
+ , nixStateDir(canonPath(getEnvNonEmpty("NIX_STATE_DIR").value_or(NIX_STATE_DIR)))
+ , nixConfDir(canonPath(getEnvNonEmpty("NIX_CONF_DIR").value_or(NIX_CONF_DIR)))
, nixUserConfFiles(getUserConfigFiles())
- , nixBinDir(canonPath(getEnv("NIX_BIN_DIR").value_or(NIX_BIN_DIR)))
+ , nixBinDir(canonPath(getEnvNonEmpty("NIX_BIN_DIR").value_or(NIX_BIN_DIR)))
, nixManDir(canonPath(NIX_MAN_DIR))
- , nixDaemonSocketFile(canonPath(getEnv("NIX_DAEMON_SOCKET_PATH").value_or(nixStateDir + DEFAULT_SOCKET_PATH)))
+ , nixDaemonSocketFile(canonPath(getEnvNonEmpty("NIX_DAEMON_SOCKET_PATH").value_or(nixStateDir + DEFAULT_SOCKET_PATH)))
{
buildUsersGroup = getuid() == 0 ? "nixbld" : "";
lockCPU = getEnv("NIX_AFFINITY_HACK") == "1";
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 82edaa9bf..c9a466ee8 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -280,7 +280,7 @@ LocalStore::LocalStore(const Params & params)
else if (curSchema == 0) { /* new store */
curSchema = nixSchemaVersion;
openDB(*state, true);
- writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
+ writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true);
}
else if (curSchema < nixSchemaVersion) {
@@ -329,7 +329,7 @@ LocalStore::LocalStore(const Params & params)
txn.commit();
}
- writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
+ writeFile(schemaPath, fmt("%1%", nixSchemaVersion), 0666, true);
lockFile(globalLock.get(), ltRead, true);
}
@@ -1560,7 +1560,7 @@ void LocalStore::invalidatePathChecked(const StorePath & path)
bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
{
- printInfo(format("reading the Nix store..."));
+ printInfo("reading the Nix store...");
bool errors = false;
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index 4d2781180..4a79cf4a1 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -55,7 +55,7 @@ LocalStore::InodeHash LocalStore::loadInodeHash()
}
if (errno) throw SysError("reading directory '%1%'", linksDir);
- printMsg(lvlTalkative, format("loaded %1% hash inodes") % inodeHash.size());
+ printMsg(lvlTalkative, "loaded %1% hash inodes", inodeHash.size());
return inodeHash;
}
@@ -73,7 +73,7 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa
checkInterrupt();
if (inodeHash.count(dirent->d_ino)) {
- debug(format("'%1%' is already linked") % dirent->d_name);
+ debug("'%1%' is already linked", dirent->d_name);
continue;
}
@@ -102,7 +102,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
if (std::regex_search(path, std::regex("\\.app/Contents/.+$")))
{
- debug(format("'%1%' is not allowed to be linked in macOS") % path);
+ debug("'%1%' is not allowed to be linked in macOS", path);
return;
}
#endif
@@ -146,7 +146,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
contents of the symlink (i.e. the result of readlink()), not
the contents of the target (which may not even exist). */
Hash hash = hashPath(htSHA256, path).first;
- debug(format("'%1%' has hash '%2%'") % path % hash.to_string(Base32, true));
+ debug("'%1%' has hash '%2%'", path, hash.to_string(Base32, true));
/* Check if this is a known hash. */
Path linkPath = linksDir + "/" + hash.to_string(Base32, false);
@@ -196,11 +196,11 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
auto stLink = lstat(linkPath);
if (st.st_ino == stLink.st_ino) {
- debug(format("'%1%' is already linked to '%2%'") % path % linkPath);
+ debug("'%1%' is already linked to '%2%'", path, linkPath);
return;
}
- printMsg(lvlTalkative, format("linking '%1%' to '%2%'") % path % linkPath);
+ printMsg(lvlTalkative, "linking '%1%' to '%2%'", path, linkPath);
/* Make the containing directory writable, but only if it's not
the store itself (we don't want or need to mess with its
@@ -213,8 +213,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
its timestamp back to 0. */
MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : "");
- Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
- % realStoreDir % getpid() % random()).str();
+ Path tempLink = fmt("%1%/.tmp-link-%2%-%3%", realStoreDir, getpid(), random());
if (link(linkPath.c_str(), tempLink.c_str()) == -1) {
if (errno == EMLINK) {
@@ -222,7 +221,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
systems). This is likely to happen with empty files.
Just shrug and ignore. */
if (st.st_size)
- printInfo(format("'%1%' has maximum number of links") % linkPath);
+ printInfo("'%1%' has maximum number of links", linkPath);
return;
}
throw SysError("cannot link '%1%' to '%2%'", tempLink, linkPath);
diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc
index 42023cd0a..adc763e6a 100644
--- a/src/libstore/pathlocks.cc
+++ b/src/libstore/pathlocks.cc
@@ -96,7 +96,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
checkInterrupt();
Path lockPath = path + ".lock";
- debug(format("locking path '%1%'") % path);
+ debug("locking path '%1%'", path);
AutoCloseFD fd;
@@ -118,7 +118,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
}
}
- debug(format("lock acquired on '%1%'") % lockPath);
+ debug("lock acquired on '%1%'", lockPath);
/* Check that the lock file hasn't become stale (i.e.,
hasn't been unlinked). */
@@ -130,7 +130,7 @@ bool PathLocks::lockPaths(const PathSet & paths,
a lock on a deleted file. This means that other
processes may create and acquire a lock on
`lockPath', and proceed. So we must retry. */
- debug(format("open lock file '%1%' has become stale") % lockPath);
+ debug("open lock file '%1%' has become stale", lockPath);
else
break;
}
@@ -163,7 +163,7 @@ void PathLocks::unlock()
"error (ignored): cannot close lock file on '%1%'",
i.second);
- debug(format("lock released on '%1%'") % i.second);
+ debug("lock released on '%1%'", i.second);
}
fds.clear();
diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc
index c551c5f3e..179161ff7 100644
--- a/src/libstore/profiles.cc
+++ b/src/libstore/profiles.cc
@@ -64,7 +64,7 @@ std::pair<Generations, std::optional<GenerationNumber>> findGenerations(Path pro
static void makeName(const Path & profile, GenerationNumber num,
Path & outLink)
{
- Path prefix = (format("%1%-%2%") % profile % num).str();
+ Path prefix = fmt("%1%-%2%", profile, num);
outLink = prefix + "-link";
}
@@ -269,7 +269,7 @@ void switchGeneration(
void lockProfile(PathLocks & lock, const Path & profile)
{
- lock.lockPaths({profile}, (format("waiting for lock on profile '%1%'") % profile).str());
+ lock.lockPaths({profile}, fmt("waiting for lock on profile '%1%'", profile));
lock.setDeletion(true);
}
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index 3bb297fc8..345f4528b 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -39,8 +39,7 @@ static void search(
if (!match) continue;
std::string ref(s.substr(i, refLength));
if (hashes.erase(ref)) {
- debug(format("found reference to '%1%' at offset '%2%'")
- % ref % i);
+ debug("found reference to '%1%' at offset '%2%'", ref, i);
seen.insert(ref);
}
++i;
diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc
index 8d76eee99..8006bd733 100644
--- a/src/libstore/s3-binary-cache-store.cc
+++ b/src/libstore/s3-binary-cache-store.cc
@@ -40,12 +40,12 @@ struct S3Error : public Error
/* Helper: given an Outcome<R, E>, return R in case of success, or
throw an exception in case of an error. */
template<typename R, typename E>
-R && checkAws(const FormatOrString & fs, Aws::Utils::Outcome<R, E> && outcome)
+R && checkAws(std::string_view s, Aws::Utils::Outcome<R, E> && outcome)
{
if (!outcome.IsSuccess())
throw S3Error(
outcome.GetError().GetErrorType(),
- fs.s + ": " + outcome.GetError().GetMessage());
+ s + ": " + outcome.GetError().GetMessage());
return outcome.GetResultWithOwnership();
}
@@ -430,9 +430,9 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
std::string marker;
do {
- debug(format("listing bucket 's3://%s' from key '%s'...") % bucketName % marker);
+ debug("listing bucket 's3://%s' from key '%s'...", bucketName, marker);
- auto res = checkAws(format("AWS error listing bucket '%s'") % bucketName,
+ auto res = checkAws(fmt("AWS error listing bucket '%s'", bucketName),
s3Helper.client->ListObjects(
Aws::S3::Model::ListObjectsRequest()
.WithBucket(bucketName)
@@ -441,8 +441,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual
auto & contents = res.GetContents();
- debug(format("got %d keys, next marker '%s'")
- % contents.size() % res.GetNextMarker());
+ debug("got %d keys, next marker '%s'",
+ contents.size(), res.GetNextMarker());
for (auto object : contents) {
auto & key = object.GetKey();
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 9ef641a3d..19b0a7f5f 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -790,13 +790,13 @@ std::string Store::makeValidityRegistration(const StorePathSet & paths,
if (showHash) {
s += info->narHash.to_string(Base16, false) + "\n";
- s += (format("%1%\n") % info->narSize).str();
+ s += fmt("%1%\n", info->narSize);
}
auto deriver = showDerivers && info->deriver ? printStorePath(*info->deriver) : "";
s += deriver + "\n";
- s += (format("%1%\n") % info->references.size()).str();
+ s += fmt("%1%\n", info->references.size());
for (auto & j : info->references)
s += printStorePath(j) + "\n";
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index 0e2b9d12c..268a798d9 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -87,7 +87,7 @@ static time_t dump(const Path & path, Sink & sink, PathFilter & filter)
std::string name(i.name);
size_t pos = i.name.find(caseHackSuffix);
if (pos != std::string::npos) {
- debug(format("removing case hack suffix from '%1%'") % (path + "/" + i.name));
+ debug("removing case hack suffix from '%1%'", path + "/" + i.name);
name.erase(pos);
}
if (!unhacked.emplace(name, i.name).second)
@@ -262,7 +262,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
if (archiveSettings.useCaseHack) {
auto i = names.find(name);
if (i != names.end()) {
- debug(format("case collision between '%1%' and '%2%'") % i->first % name);
+ debug("case collision between '%1%' and '%2%'", i->first, name);
name += caseHackSuffix;
name += std::to_string(++i->second);
} else
diff --git a/src/libutil/filesystem.cc b/src/libutil/filesystem.cc
index 3a732cff8..56be76ecc 100644
--- a/src/libutil/filesystem.cc
+++ b/src/libutil/filesystem.cc
@@ -15,9 +15,9 @@ static Path tempName(Path tmpRoot, const Path & prefix, bool includePid,
{
tmpRoot = canonPath(tmpRoot.empty() ? getEnv("TMPDIR").value_or("/tmp") : tmpRoot, true);
if (includePid)
- return (format("%1%/%2%-%3%-%4%") % tmpRoot % prefix % getpid() % counter++).str();
+ return fmt("%1%/%2%-%3%-%4%", tmpRoot, prefix, getpid(), counter++);
else
- return (format("%1%/%2%-%3%") % tmpRoot % prefix % counter++).str();
+ return fmt("%1%/%2%-%3%", tmpRoot, prefix, counter++);
}
Path createTempDir(const Path & tmpRoot, const Path & prefix,
diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh
index e879fd3b8..e11426b88 100644
--- a/src/libutil/fmt.hh
+++ b/src/libutil/fmt.hh
@@ -17,16 +17,6 @@ using boost::format;
struct nop { template<typename... T> nop(T...) {} };
-struct FormatOrString
-{
- std::string s;
- FormatOrString(std::string s) : s(std::move(s)) { };
- template<class F>
- FormatOrString(const F & f) : s(f.str()) { };
- FormatOrString(const char * s) : s(s) { };
-};
-
-
/* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
equivalent to ‘boost::format(format) % a_0 % ... %
... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
@@ -53,11 +43,6 @@ inline std::string fmt(const char * s)
return s;
}
-inline std::string fmt(const FormatOrString & fs)
-{
- return fs.s;
-}
-
template<typename... Args>
inline std::string fmt(const std::string & fs, const Args & ... args)
{
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index 56bdaf87a..7cac75ce1 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -54,7 +54,7 @@ public:
return printBuildLogs;
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
if (lvl > verbosity) return;
@@ -72,7 +72,7 @@ public:
prefix = std::string("<") + c + ">";
}
- writeToStderr(prefix + filterANSIEscapes(fs.s, !tty) + "\n");
+ writeToStderr(prefix + filterANSIEscapes(s, !tty) + "\n");
}
void logEI(const ErrorInfo & ei) override
@@ -174,12 +174,12 @@ struct JSONLogger : Logger {
prevLogger.log(lvlError, "@nix " + json.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace));
}
- void log(Verbosity lvl, const FormatOrString & fs) override
+ void log(Verbosity lvl, std::string_view s) override
{
nlohmann::json json;
json["action"] = "msg";
json["level"] = lvl;
- json["msg"] = fs.s;
+ json["msg"] = s;
write(json);
}
diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh
index a68edd15a..59a707eef 100644
--- a/src/libutil/logging.hh
+++ b/src/libutil/logging.hh
@@ -75,11 +75,11 @@ public:
// Whether the logger prints the whole build log
virtual bool isVerbose() { return false; }
- virtual void log(Verbosity lvl, const FormatOrString & fs) = 0;
+ virtual void log(Verbosity lvl, std::string_view s) = 0;
- void log(const FormatOrString & fs)
+ void log(std::string_view s)
{
- log(lvlInfo, fs);
+ log(lvlInfo, s);
}
virtual void logEI(const ErrorInfo & ei) = 0;
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index c653db9d0..7476e6f6c 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -415,7 +415,7 @@ Error readError(Source & source)
auto msg = readString(source);
ErrorInfo info {
.level = level,
- .msg = hintformat(std::move(format("%s") % msg)),
+ .msg = hintformat(fmt("%s", msg)),
};
auto havePos = readNum<size_t>(source);
assert(havePos == 0);
@@ -424,7 +424,7 @@ Error readError(Source & source)
havePos = readNum<size_t>(source);
assert(havePos == 0);
info.traces.push_back(Trace {
- .hint = hintformat(std::move(format("%s") % readString(source)))
+ .hint = hintformat(fmt("%s", readString(source)))
});
}
return Error(std::move(info));
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 885bae69c..17ccf3554 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -54,6 +54,11 @@ std::optional<std::string> getEnv(const std::string & key)
return std::string(value);
}
+std::optional<std::string> getEnvNonEmpty(const std::string & key) {
+ auto value = getEnv(key);
+ if (value == "") return {};
+ return value;
+}
std::map<std::string, std::string> getEnv()
{
@@ -523,7 +528,7 @@ void deletePath(const Path & path)
void deletePath(const Path & path, uint64_t & bytesFreed)
{
- //Activity act(*logger, lvlDebug, format("recursively deleting path '%1%'") % path);
+ //Activity act(*logger, lvlDebug, "recursively deleting path '%1%'", path);
bytesFreed = 0;
_deletePath(path, bytesFreed);
}
@@ -1394,14 +1399,14 @@ std::string statusToString(int status)
{
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
if (WIFEXITED(status))
- return (format("failed with exit code %1%") % WEXITSTATUS(status)).str();
+ return fmt("failed with exit code %1%", WEXITSTATUS(status));
else if (WIFSIGNALED(status)) {
int sig = WTERMSIG(status);
#if HAVE_STRSIGNAL
const char * description = strsignal(sig);
- return (format("failed due to signal %1% (%2%)") % sig % description).str();
+ return fmt("failed due to signal %1% (%2%)", sig, description);
#else
- return (format("failed due to signal %1%") % sig).str();
+ return fmt("failed due to signal %1%", sig);
#endif
}
else
@@ -1470,7 +1475,7 @@ bool shouldANSI()
&& !getEnv("NO_COLOR").has_value();
}
-std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned int width)
+std::string filterANSIEscapes(std::string_view s, bool filterAll, unsigned int width)
{
std::string t, e;
size_t w = 0;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index b5625ecef..326c6b143 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -39,6 +39,10 @@ extern const std::string nativeSystem;
/* Return an environment variable. */
std::optional<std::string> getEnv(const std::string & key);
+/* Return a non empty environment variable. Returns nullopt if the env
+variable is set to "" */
+std::optional<std::string> getEnvNonEmpty(const std::string & key);
+
/* Get the entire environment. */
std::map<std::string, std::string> getEnv();
@@ -569,7 +573,7 @@ bool shouldANSI();
some escape sequences (such as colour setting) are copied but not
included in the character count. Also, tabs are expanded to
spaces. */
-std::string filterANSIEscapes(const std::string & s,
+std::string filterANSIEscapes(std::string_view s,
bool filterAll = false,
unsigned int width = std::numeric_limits<unsigned int>::max());
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index da76c2ace..a4b3b1f96 100644
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -219,9 +219,9 @@ static void main_nix_build(int argc, char * * argv)
// read the shebang to understand which packages to read from. Since
// this is handled via nix-shell -p, we wrap our ruby script execution
// in ruby -e 'load' which ignores the shebangs.
- envCommand = (format("exec %1% %2% -e 'load(ARGV.shift)' -- %3% %4%") % execArgs % interpreter % shellEscape(script) % joined.str()).str();
+ envCommand = fmt("exec %1% %2% -e 'load(ARGV.shift)' -- %3% %4%", execArgs, interpreter, shellEscape(script), joined.str());
} else {
- envCommand = (format("exec %1% %2% %3% %4%") % execArgs % interpreter % shellEscape(script) % joined.str()).str();
+ envCommand = fmt("exec %1% %2% %3% %4%", execArgs, interpreter, shellEscape(script), joined.str());
}
}
diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc
index e413faffe..3cc57af4e 100644
--- a/src/nix-collect-garbage/nix-collect-garbage.cc
+++ b/src/nix-collect-garbage/nix-collect-garbage.cc
@@ -40,7 +40,7 @@ void removeOldGenerations(std::string dir)
throw;
}
if (link.find("link") != std::string::npos) {
- printInfo(format("removing old generations of profile %1%") % path);
+ printInfo("removing old generations of profile %s", path);
if (deleteOlderThan != "")
deleteGenerationsOlderThan(path, deleteOlderThan, dryRun);
else
@@ -77,8 +77,7 @@ static int main_nix_collect_garbage(int argc, char * * argv)
return true;
});
- auto profilesDir = settings.nixStateDir + "/profiles";
- if (removeOld) removeOldGenerations(profilesDir);
+ if (removeOld) removeOldGenerations(profilesDir());
// Run the actual garbage collector.
if (!dryRun) {
diff --git a/src/nix-copy-closure/nix-copy-closure.cc b/src/nix-copy-closure/nix-copy-closure.cc
index 841d50fd3..7f2bb93b6 100755
--- a/src/nix-copy-closure/nix-copy-closure.cc
+++ b/src/nix-copy-closure/nix-copy-closure.cc
@@ -22,7 +22,7 @@ static int main_nix_copy_closure(int argc, char ** argv)
printVersion("nix-copy-closure");
else if (*arg == "--gzip" || *arg == "--bzip2" || *arg == "--xz") {
if (*arg != "--gzip")
- printMsg(lvlError, format("Warning: '%1%' is not implemented, falling back to gzip") % *arg);
+ warn("'%1%' is not implemented, falling back to gzip", *arg);
gzip = true;
} else if (*arg == "--from")
toMode = false;
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index 0daf374de..3a012638b 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -500,7 +500,7 @@ static bool keep(DrvInfo & drv)
static void installDerivations(Globals & globals,
const Strings & args, const Path & profile)
{
- debug(format("installing derivations"));
+ debug("installing derivations");
/* Get the set of user environment elements to be installed. */
DrvInfos newElems, newElemsTmp;
@@ -579,7 +579,7 @@ typedef enum { utLt, utLeq, utEq, utAlways } UpgradeType;
static void upgradeDerivations(Globals & globals,
const Strings & args, UpgradeType upgradeType)
{
- debug(format("upgrading derivations"));
+ debug("upgrading derivations");
/* Upgrade works as follows: we take all currently installed
derivations, and for any derivation matching any selector, look
@@ -768,7 +768,7 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs)
if (globals.dryRun) return;
globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal);
- debug(format("switching to new user environment"));
+ debug("switching to new user environment");
Path generation = createGeneration(
ref<LocalFSStore>(store2),
globals.profile,
@@ -1093,7 +1093,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
try {
if (i.hasFailed()) continue;
- //Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath);
+ //Activity act(*logger, lvlDebug, "outputting query result '%1%'", i.attrPath);
if (globals.prebuiltOnly &&
!validPaths.count(i.queryOutPath()) &&
@@ -1229,11 +1229,11 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs)
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nInt) {
attrs2["type"] = "int";
- attrs2["value"] = (format("%1%") % v->integer).str();
+ attrs2["value"] = fmt("%1%", v->integer);
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nFloat) {
attrs2["type"] = "float";
- attrs2["value"] = (format("%1%") % v->fpoint).str();
+ attrs2["value"] = fmt("%1%", v->fpoint);
xml.writeEmptyElement("meta", attrs2);
} else if (v->type() == nBool) {
attrs2["type"] = "bool";
@@ -1337,11 +1337,11 @@ static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs
for (auto & i : gens) {
tm t;
if (!localtime_r(&i.creationTime, &t)) throw Error("cannot convert time");
- cout << format("%|4| %|4|-%|02|-%|02| %|02|:%|02|:%|02| %||\n")
- % i.number
- % (t.tm_year + 1900) % (t.tm_mon + 1) % t.tm_mday
- % t.tm_hour % t.tm_min % t.tm_sec
- % (i.number == curGen ? "(current)" : "");
+ logger->cout("%|4| %|4|-%|02|-%|02| %|02|:%|02|:%|02| %||",
+ i.number,
+ t.tm_year + 1900, t.tm_mon + 1, t.tm_mday,
+ t.tm_hour, t.tm_min, t.tm_sec,
+ i.number == curGen ? "(current)" : "");
}
}
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index cad7f9c88..745e9e174 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -41,7 +41,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
if (auto drvPath = i.queryDrvPath())
drvsToBuild.push_back({*drvPath});
- debug(format("building user environment dependencies"));
+ debug("building user environment dependencies");
state.store->buildPaths(
toDerivedPaths(drvsToBuild),
state.repair ? bmRepair : bmNormal);
@@ -159,7 +159,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
return false;
}
- debug(format("switching to new user environment"));
+ debug("switching to new user environment");
Path generation = createGeneration(ref<LocalFSStore>(store2), profile, topLevelOut);
switchLink(profile, generation);
}
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index d4218550a..54479489f 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -72,11 +72,13 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true)
Derivation drv = store->derivationFromPath(path.path);
rootNr++;
+ /* FIXME: Encode this empty special case explicitly in the type. */
if (path.outputs.empty())
for (auto & i : drv.outputs) path.outputs.insert(i.first);
PathSet outputs;
for (auto & j : path.outputs) {
+ /* Match outputs of a store path with outputs of the derivation that produces it. */
DerivationOutputs::iterator i = drv.outputs.find(j);
if (i == drv.outputs.end())
throw Error("derivation '%s' does not have an output named '%s'",
@@ -141,6 +143,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
toDerivedPaths(paths),
willBuild, willSubstitute, unknown, downloadSize, narSize);
+ /* Filter out unknown paths from `paths`. */
if (ignoreUnknown) {
std::vector<StorePathWithOutputs> paths2;
for (auto & i : paths)
@@ -457,7 +460,7 @@ static void opPrintEnv(Strings opFlags, Strings opArgs)
/* Print each environment variable in the derivation in a format
* that can be sourced by the shell. */
for (auto & i : drv.env)
- cout << format("export %1%; %1%=%2%\n") % i.first % shellEscape(i.second);
+ logger->cout("export %1%; %1%=%2%\n", i.first, shellEscape(i.second));
/* Also output the arguments. This doesn't preserve whitespace in
arguments. */
@@ -1020,7 +1023,7 @@ static int main_nix_store(int argc, char * * argv)
{
Strings opFlags, opArgs;
Operation op = 0;
- bool readFromStdIn;
+ bool readFromStdIn = false;
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
Operation oldOp = op;
diff --git a/src/nix/build.md b/src/nix/build.md
index 6a79f308c..ee414dc86 100644
--- a/src/nix/build.md
+++ b/src/nix/build.md
@@ -82,7 +82,7 @@ R""(
# Description
-`nix build` builds the specified *installables*. Installables that
+`nix build` builds the specified *installables*. [Installables](./nix.md#installables) that
resolve to derivations are built (or substituted if possible). Store
path installables are substituted.
diff --git a/src/nix/bundle.md b/src/nix/bundle.md
index a18161a3c..89458aaaa 100644
--- a/src/nix/bundle.md
+++ b/src/nix/bundle.md
@@ -29,7 +29,7 @@ R""(
# Description
-`nix bundle`, by default, packs the closure of the *installable* into a single
+`nix bundle`, by default, packs the closure of the [*installable*](./nix.md#installables) into a single
self-extracting executable. See the [`bundlers`
homepage](https://github.com/NixOS/bundlers) for more details.
diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc
index a22bccba1..7e4a7ba86 100644
--- a/src/nix/daemon.cc
+++ b/src/nix/daemon.cc
@@ -249,9 +249,9 @@ static void daemonLoop()
if ((!trusted && !matchUser(user, group, allowedUsers)) || group == settings.buildUsersGroup)
throw Error("user '%1%' is not allowed to connect to the Nix daemon", user);
- printInfo(format((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""))
- % (peer.pidKnown ? std::to_string(peer.pid) : "<unknown>")
- % (peer.uidKnown ? user : "<unknown>"));
+ printInfo((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : ""),
+ peer.pidKnown ? std::to_string(peer.pid) : "<unknown>",
+ peer.uidKnown ? user : "<unknown>");
// Fork a child to handle the connection.
ProcessOptions options;
diff --git a/src/nix/develop.md b/src/nix/develop.md
index 4e8542d1b..c49b39669 100644
--- a/src/nix/develop.md
+++ b/src/nix/develop.md
@@ -76,7 +76,7 @@ R""(
`nix develop` starts a `bash` shell that provides an interactive build
environment nearly identical to what Nix would use to build
-*installable*. Inside this shell, environment variables and shell
+[*installable*](./nix.md#installables). Inside this shell, environment variables and shell
functions are set up so that you can interactively and incrementally
build your package.
diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc
index ea87e3d87..7da4549a1 100644
--- a/src/nix/doctor.cc
+++ b/src/nix/doctor.cc
@@ -18,7 +18,7 @@ std::string formatProtocol(unsigned int proto)
if (proto) {
auto major = GET_PROTOCOL_MAJOR(proto) >> 8;
auto minor = GET_PROTOCOL_MINOR(proto);
- return (format("%1%.%2%") % major % minor).str();
+ return fmt("%1%.%2%", major, minor);
}
return "unknown";
}
diff --git a/src/nix/eval.md b/src/nix/eval.md
index 61334cde1..3b510737a 100644
--- a/src/nix/eval.md
+++ b/src/nix/eval.md
@@ -50,7 +50,7 @@ R""(
# Description
-This command evaluates the Nix expression *installable* and prints the
+This command evaluates the given Nix expression and prints the
result on standard output.
# Output format
diff --git a/src/nix/flake.md b/src/nix/flake.md
index 810e9ebea..9073d0c3b 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -275,8 +275,8 @@ Currently the `type` attribute can be one of the following:
# Flake format
As an example, here is a simple `flake.nix` that depends on the
-Nixpkgs flake and provides a single package (i.e. an installable
-derivation):
+Nixpkgs flake and provides a single package (i.e. an
+[installable](./nix.md#installables) derivation):
```nix
{
diff --git a/src/nix/log.md b/src/nix/log.md
index 1c76226a3..01e9801df 100644
--- a/src/nix/log.md
+++ b/src/nix/log.md
@@ -22,8 +22,7 @@ R""(
# Description
-This command prints the log of a previous build of the derivation
-*installable* on standard output.
+This command prints the log of a previous build of the [*installable*](./nix.md#installables) on standard output.
Nix looks for build logs in two places:
diff --git a/src/nix/make-content-addressed.md b/src/nix/make-content-addressed.md
index 32eecc880..b1f7da525 100644
--- a/src/nix/make-content-addressed.md
+++ b/src/nix/make-content-addressed.md
@@ -35,7 +35,9 @@ R""(
# Description
This command converts the closure of the store paths specified by
-*installables* to content-addressed form. Nix store paths are usually
+[*installables*](./nix.md#installables) to content-addressed form.
+
+Nix store paths are usually
*input-addressed*, meaning that the hash part of the store path is
computed from the contents of the derivation (i.e., the build-time
dependency graph). Input-addressed paths need to be signed by a
diff --git a/src/nix/nix.md b/src/nix/nix.md
index db60c59ff..0a90fa6c9 100644
--- a/src/nix/nix.md
+++ b/src/nix/nix.md
@@ -48,102 +48,112 @@ manual](https://nixos.org/manual/nix/stable/).
# Installables
-Many `nix` subcommands operate on one or more *installables*. These are
-command line arguments that represent something that can be built in
-the Nix store. Here are the recognised types of installables:
-
-* **Flake output attributes**: `nixpkgs#hello`
-
- These have the form *flakeref*[`#`*attrpath*], where *flakeref* is a
- flake reference and *attrpath* is an optional attribute path. For
- more information on flakes, see [the `nix flake` manual
- page](./nix3-flake.md). Flake references are most commonly a flake
- identifier in the flake registry (e.g. `nixpkgs`), or a raw path
- (e.g. `/path/to/my-flake` or `.` or `../foo`), or a full URL
- (e.g. `github:nixos/nixpkgs` or `path:.`)
-
- When the flake reference is a raw path (a path without any URL
- scheme), it is interpreted as a `path:` or `git+file:` url in the following
- way:
-
- - If the path is within a Git repository, then the url will be of the form
- `git+file://[GIT_REPO_ROOT]?dir=[RELATIVE_FLAKE_DIR_PATH]`
- where `GIT_REPO_ROOT` is the path to the root of the git repository,
- and `RELATIVE_FLAKE_DIR_PATH` is the path (relative to the directory
- root) of the closest parent of the given path that contains a `flake.nix` within
- the git repository.
- If no such directory exists, then Nix will error-out.
-
- Note that the search will only include files indexed by git. In particular, files
- which are matched by `.gitignore` or have never been `git add`-ed will not be
- available in the flake. If this is undesirable, specify `path:<directory>` explicitly;
-
- For example, if `/foo/bar` is a git repository with the following structure:
- ```
- .
- └── baz
- ├── blah
- │  └── file.txt
- └── flake.nix
- ```
+Many `nix` subcommands operate on one or more *installables*.
+These are command line arguments that represent something that can be realised in the Nix store.
- Then `/foo/bar/baz/blah` will resolve to `git+file:///foo/bar?dir=baz`
+The following types of installable are supported by most commands:
- - If the supplied path is not a git repository, then the url will have the form
- `path:FLAKE_DIR_PATH` where `FLAKE_DIR_PATH` is the closest parent
- of the supplied path that contains a `flake.nix` file (within the same file-system).
- If no such directory exists, then Nix will error-out.
-
- For example, if `/foo/bar/flake.nix` exists, then `/foo/bar/baz/` will resolve to
- `path:/foo/bar`
+- [Flake output attribute](#flake-output-attribute)
+- [Store path](#store-path)
+- [Nix file](#nix-file), optionally qualified by an attribute path
+- [Nix expression](#nix-expression), optionally qualified by an attribute path
- If *attrpath* is omitted, Nix tries some default values; for most
- subcommands, the default is `packages.`*system*`.default`
- (e.g. `packages.x86_64-linux.default`), but some subcommands have
- other defaults. If *attrpath* *is* specified, *attrpath* is
- interpreted as relative to one or more prefixes; for most
- subcommands, these are `packages.`*system*,
- `legacyPackages.*system*` and the empty prefix. Thus, on
- `x86_64-linux` `nix build nixpkgs#hello` will try to build the
- attributes `packages.x86_64-linux.hello`,
- `legacyPackages.x86_64-linux.hello` and `hello`.
+For most commands, if no installable is specified, `.` as assumed.
+That is, Nix will operate on the default flake output attribute of the flake in the current directory.
-* **Store paths**: `/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10`
+### Flake output attribute
- These are paths inside the Nix store, or symlinks that resolve to a
- path in the Nix store.
+Example: `nixpkgs#hello`
-* **Store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv`
+These have the form *flakeref*[`#`*attrpath*], where *flakeref* is a
+[flake reference](./nix3-flake.md#flake-references) and *attrpath* is an optional attribute path. For
+more information on flakes, see [the `nix flake` manual
+page](./nix3-flake.md). Flake references are most commonly a flake
+identifier in the flake registry (e.g. `nixpkgs`), or a raw path
+(e.g. `/path/to/my-flake` or `.` or `../foo`), or a full URL
+(e.g. `github:nixos/nixpkgs` or `path:.`)
- By default, if you pass a [store derivation] path to a `nix` subcommand, the command will operate on the [output path]s of the derivation.
+When the flake reference is a raw path (a path without any URL
+scheme), it is interpreted as a `path:` or `git+file:` url in the following
+way:
- [output path]: ../../glossary.md#gloss-output-path
+- If the path is within a Git repository, then the url will be of the form
+ `git+file://[GIT_REPO_ROOT]?dir=[RELATIVE_FLAKE_DIR_PATH]`
+ where `GIT_REPO_ROOT` is the path to the root of the git repository,
+ and `RELATIVE_FLAKE_DIR_PATH` is the path (relative to the directory
+ root) of the closest parent of the given path that contains a `flake.nix` within
+ the git repository.
+ If no such directory exists, then Nix will error-out.
- For example, `nix path-info` prints information about the output paths:
+ Note that the search will only include files indexed by git. In particular, files
+ which are matched by `.gitignore` or have never been `git add`-ed will not be
+ available in the flake. If this is undesirable, specify `path:<directory>` explicitly;
- ```console
- # nix path-info --json /nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv
- [{"path":"/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10",…}]
+ For example, if `/foo/bar` is a git repository with the following structure:
+ ```
+ .
+ └── baz
+ ├── blah
+ │  └── file.txt
+ └── flake.nix
```
- If you want to operate on the store derivation itself, pass the
- `--derivation` flag.
+ Then `/foo/bar/baz/blah` will resolve to `git+file:///foo/bar?dir=baz`
+
+- If the supplied path is not a git repository, then the url will have the form
+ `path:FLAKE_DIR_PATH` where `FLAKE_DIR_PATH` is the closest parent
+ of the supplied path that contains a `flake.nix` file (within the same file-system).
+ If no such directory exists, then Nix will error-out.
+
+ For example, if `/foo/bar/flake.nix` exists, then `/foo/bar/baz/` will resolve to
+ `path:/foo/bar`
+
+If *attrpath* is omitted, Nix tries some default values; for most
+subcommands, the default is `packages.`*system*`.default`
+(e.g. `packages.x86_64-linux.default`), but some subcommands have
+other defaults. If *attrpath* *is* specified, *attrpath* is
+interpreted as relative to one or more prefixes; for most
+subcommands, these are `packages.`*system*,
+`legacyPackages.*system*` and the empty prefix. Thus, on
+`x86_64-linux` `nix build nixpkgs#hello` will try to build the
+attributes `packages.x86_64-linux.hello`,
+`legacyPackages.x86_64-linux.hello` and `hello`.
+
+### Store path
+
+Example: `/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10`
+
+These are paths inside the Nix store, or symlinks that resolve to a path in the Nix store.
+
+A [store derivation] is also addressed by store path.
+
+Example: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv`
+
+If you want to refer to an output path of that store derivation, add the output name preceded by a caret (`^`).
+
+Example: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^out`
+
+All outputs can be referred to at once with the special syntax `^*`.
+
+Example: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^*`
+
+### Nix file
+
+Example: `--file /path/to/nixpkgs hello`
-* **Nix attributes**: `--file /path/to/nixpkgs hello`
+When the option `-f` / `--file` *path* \[*attrpath*...\] is given, installables are interpreted as the value of the expression in the Nix file at *path*.
+If attribute paths are provided, commands will operate on the corresponding values accessible at these paths.
+The Nix expression in that file, or any selected attribute, must evaluate to a derivation.
- When the `-f` / `--file` *path* option is given, installables are
- interpreted as attribute paths referencing a value returned by
- evaluating the Nix file *path*.
+### Nix expression
-* **Nix expressions**: `--expr '(import <nixpkgs> {}).hello.overrideDerivation (prev: { name = "my-hello"; })'`.
+Example: `--expr 'import <nixpkgs> {}' hello`
- When the `--expr` option is given, all installables are interpreted
- as Nix expressions. You may need to specify `--impure` if the
- expression references impure inputs (such as `<nixpkgs>`).
+When the option `--expr` *expression* \[*attrpath*...\] is given, installables are interpreted as the value of the of the Nix expression.
+If attribute paths are provided, commands will operate on the corresponding values accessible at these paths.
+The Nix expression, or any selected attribute, must evaluate to a derivation.
-For most commands, if no installable is specified, the default is `.`,
-i.e. Nix will operate on the default flake output attribute of the
-flake in the current directory.
+You may need to specify `--impure` if the expression references impure inputs (such as `<nixpkgs>`).
## Derivation output selection
diff --git a/src/nix/path-info.md b/src/nix/path-info.md
index b30898ac0..6ad23a02e 100644
--- a/src/nix/path-info.md
+++ b/src/nix/path-info.md
@@ -80,7 +80,7 @@ R""(
# Description
This command shows information about the store paths produced by
-*installables*, or about all paths in the store if you pass `--all`.
+[*installables*](./nix.md#installables), or about all paths in the store if you pass `--all`.
By default, this command only prints the store paths. You can get
additional information by passing flags such as `--closure-size`,
diff --git a/src/nix/print-dev-env.md b/src/nix/print-dev-env.md
index 2aad491de..a8ce9d36a 100644
--- a/src/nix/print-dev-env.md
+++ b/src/nix/print-dev-env.md
@@ -40,7 +40,7 @@ R""(
This command prints a shell script that can be sourced by `bash` and
that sets the variables and shell functions defined by the build
-process of *installable*. This allows you to get a similar build
+process of [*installable*](./nix.md#installables). This allows you to get a similar build
environment in your current shell rather than in a subshell (as with
`nix develop`).
diff --git a/src/nix/profile-install.md b/src/nix/profile-install.md
index aed414963..4c0f82c09 100644
--- a/src/nix/profile-install.md
+++ b/src/nix/profile-install.md
@@ -29,6 +29,6 @@ R""(
# Description
-This command adds *installables* to a Nix profile.
+This command adds [*installables*](./nix.md#installables) to a Nix profile.
)""
diff --git a/src/nix/run.md b/src/nix/run.md
index a0f362076..250ea65aa 100644
--- a/src/nix/run.md
+++ b/src/nix/run.md
@@ -35,7 +35,7 @@ R""(
# Description
-`nix run` builds and runs *installable*, which must evaluate to an
+`nix run` builds and runs [*installable*](./nix.md#installables), which must evaluate to an
*app* or a regular Nix derivation.
If *installable* evaluates to an *app* (see below), it executes the
diff --git a/src/nix/search.md b/src/nix/search.md
index 5a5b5ae05..4caa90654 100644
--- a/src/nix/search.md
+++ b/src/nix/search.md
@@ -62,10 +62,10 @@ R""(
# Description
-`nix search` searches *installable* (which must be evaluatable, e.g. a
-flake) for packages whose name or description matches all of the
+`nix search` searches [*installable*](./nix.md#installables) (which can be evaluated, that is, a
+flake or Nix expression, but not a store path or store derivation path) for packages whose name or description matches all of the
regular expressions *regex*. For each matching package, It prints the
-full attribute name (from the root of the installable), the version
+full attribute name (from the root of the [installable](./nix.md#installables)), the version
and the `meta.description` field, highlighting the substrings that
were matched by the regular expressions. If no regular expressions are
specified, all packages are shown.
diff --git a/src/nix/shell.md b/src/nix/shell.md
index 9fa1031f5..13a389103 100644
--- a/src/nix/shell.md
+++ b/src/nix/shell.md
@@ -48,7 +48,7 @@ R""(
# Description
`nix shell` runs a command in an environment in which the `$PATH` variable
-provides the specified *installables*. If no command is specified, it starts the
+provides the specified [*installables*](./nix.md#installable). If no command is specified, it starts the
default shell of your user account specified by `$SHELL`.
)""
diff --git a/src/nix/show-derivation.md b/src/nix/show-derivation.md
index 2cd93aa62..1d37c6f5a 100644
--- a/src/nix/show-derivation.md
+++ b/src/nix/show-derivation.md
@@ -39,7 +39,7 @@ R""(
# Description
This command prints on standard output a JSON representation of the
-[store derivation]s to which *installables* evaluate. Store derivations
+[store derivation]s to which [*installables*](./nix.md#installables) evaluate. Store derivations
are used internally by Nix. They are store paths with extension `.drv`
that represent the build-time dependency graph to which a Nix
expression evaluates.
diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc
index ee27e3725..1431652e0 100644
--- a/src/nix/sigs.cc
+++ b/src/nix/sigs.cc
@@ -45,7 +45,7 @@ struct CmdCopySigs : StorePathsCommand
//logger->setExpected(doneLabel, storePaths.size());
auto doPath = [&](const Path & storePathS) {
- //Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath);
+ //Activity act(*logger, lvlInfo, "getting signatures for '%s'", storePath);
checkInterrupt();
diff --git a/src/nix/store-delete.md b/src/nix/store-delete.md
index db535f87c..431bc5f5e 100644
--- a/src/nix/store-delete.md
+++ b/src/nix/store-delete.md
@@ -10,7 +10,7 @@ R""(
# Description
-This command deletes the store paths specified by *installables*. ,
+This command deletes the store paths specified by [*installables*](./nix.md#installables),
but only if it is safe to do so; that is, when the path is not
reachable from a root of the garbage collector. This means that you
can only delete paths that would also be deleted by `nix store
diff --git a/src/nix/store-dump-path.md b/src/nix/store-dump-path.md
index 4ef563526..56e2174b6 100644
--- a/src/nix/store-dump-path.md
+++ b/src/nix/store-dump-path.md
@@ -18,6 +18,6 @@ R""(
# Description
This command generates a NAR file containing the serialisation of the
-store path *installable*. The NAR is written to standard output.
+store path [*installable*](./nix.md#installables). The NAR is written to standard output.
)""
diff --git a/src/nix/store-repair.md b/src/nix/store-repair.md
index 92d2205a9..180c577ac 100644
--- a/src/nix/store-repair.md
+++ b/src/nix/store-repair.md
@@ -17,7 +17,7 @@ R""(
# Description
This command attempts to "repair" the store paths specified by
-*installables* by redownloading them using the available
+[*installables*](./nix.md#installables) by redownloading them using the available
substituters. If no substitutes are available, then repair is not
possible.
diff --git a/src/nix/verify.md b/src/nix/verify.md
index 1c43792e7..cc1122c02 100644
--- a/src/nix/verify.md
+++ b/src/nix/verify.md
@@ -24,7 +24,7 @@ R""(
# Description
-This command verifies the integrity of the store paths *installables*,
+This command verifies the integrity of the store paths [*installables*](./nix.md#installables),
or, if `--all` is given, the entire Nix store. For each path, it
checks that
diff --git a/src/resolve-system-dependencies/resolve-system-dependencies.cc b/src/resolve-system-dependencies/resolve-system-dependencies.cc
index c6023eb03..4ea268d24 100644
--- a/src/resolve-system-dependencies/resolve-system-dependencies.cc
+++ b/src/resolve-system-dependencies/resolve-system-dependencies.cc
@@ -157,13 +157,9 @@ int main(int argc, char ** argv)
uname(&_uname);
- auto cacheParentDir = (format("%1%/dependency-maps") % settings.nixStateDir).str();
+ auto cacheParentDir = fmt("%1%/dependency-maps", settings.nixStateDir);
- cacheDir = (format("%1%/%2%-%3%-%4%")
- % cacheParentDir
- % _uname.machine
- % _uname.sysname
- % _uname.release).str();
+ cacheDir = fmt("%1%/%2%-%3%-%4%", cacheParentDir, _uname.machine, _uname.sysname, _uname.release);
mkdir(cacheParentDir.c_str(), 0755);
mkdir(cacheDir.c_str(), 0755);
diff --git a/tests/binary-cache.sh b/tests/binary-cache.sh
index b38db8a15..7c64a115c 100644
--- a/tests/binary-cache.sh
+++ b/tests/binary-cache.sh
@@ -15,11 +15,11 @@ outPath=$(nix-build dependencies.nix --no-out-link)
nix copy --to file://$cacheDir $outPath
# Test copying build logs to the binary cache.
-nix log --store file://$cacheDir $outPath 2>&1 | grep 'is not available'
+expect 1 nix log --store file://$cacheDir $outPath 2>&1 | grep 'is not available'
nix store copy-log --to file://$cacheDir $outPath
nix log --store file://$cacheDir $outPath | grep FOO
rm -rf $TEST_ROOT/var/log/nix
-nix log $outPath 2>&1 | grep 'is not available'
+expect 1 nix log $outPath 2>&1 | grep 'is not available'
nix log --substituters file://$cacheDir $outPath | grep FOO
# Test copying build logs from the binary cache.
@@ -78,8 +78,8 @@ mv $nar $nar.good
mkdir -p $TEST_ROOT/empty
nix-store --dump $TEST_ROOT/empty | xz > $nar
-nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log
-grep -q "hash mismatch" $TEST_ROOT/log
+expect 1 nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log
+grepQuiet "hash mismatch" $TEST_ROOT/log
mv $nar.good $nar
@@ -126,9 +126,9 @@ clearStore
rm -v $(grep -l "StorePath:.*dependencies-input-2" $cacheDir/*.narinfo)
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log
-grep -q "copying path.*input-0" $TEST_ROOT/log
-grep -q "copying path.*input-2" $TEST_ROOT/log
-grep -q "copying path.*top" $TEST_ROOT/log
+grepQuiet "copying path.*input-0" $TEST_ROOT/log
+grepQuiet "copying path.*input-2" $TEST_ROOT/log
+grepQuiet "copying path.*top" $TEST_ROOT/log
# Idem, but without cached .narinfo.
@@ -136,11 +136,11 @@ clearStore
clearCacheCache
nix-build --substituters "file://$cacheDir" --no-require-sigs dependencies.nix -o $TEST_ROOT/result 2>&1 | tee $TEST_ROOT/log
-grep -q "don't know how to build" $TEST_ROOT/log
-grep -q "building.*input-1" $TEST_ROOT/log
-grep -q "building.*input-2" $TEST_ROOT/log
-grep -q "copying path.*input-0" $TEST_ROOT/log
-grep -q "copying path.*top" $TEST_ROOT/log
+grepQuiet "don't know how to build" $TEST_ROOT/log
+grepQuiet "building.*input-1" $TEST_ROOT/log
+grepQuiet "building.*input-2" $TEST_ROOT/log
+grepQuiet "copying path.*input-0" $TEST_ROOT/log
+grepQuiet "copying path.*top" $TEST_ROOT/log
# Create a signed binary cache.
diff --git a/tests/build-delete.sh b/tests/build-delete.sh
index 636681f64..9c56b00e8 100644
--- a/tests/build-delete.sh
+++ b/tests/build-delete.sh
@@ -2,8 +2,6 @@ source common.sh
clearStore
-set -o pipefail
-
# https://github.com/NixOS/nix/issues/6572
issue_6572_independent_outputs() {
nix build -f multiple-outputs.nix --json independent --no-link > $TEST_ROOT/independent.json
diff --git a/tests/build-dry.sh b/tests/build-dry.sh
index 5f29239dc..6d1754af5 100644
--- a/tests/build-dry.sh
+++ b/tests/build-dry.sh
@@ -54,7 +54,7 @@ clearCache
RES=$(nix build -f dependencies.nix --dry-run --json)
-if [[ -z "$NIX_TESTS_CA_BY_DEFAULT" ]]; then
+if [[ -z "${NIX_TESTS_CA_BY_DEFAULT-}" ]]; then
echo "$RES" | jq '.[0] | [
(.drvPath | test("'$NIX_STORE_DIR'.*\\.drv")),
(.outputs.out | test("'$NIX_STORE_DIR'"))
diff --git a/tests/build-remote.sh b/tests/build-remote.sh
index 25a482003..6da128d1b 100644
--- a/tests/build-remote.sh
+++ b/tests/build-remote.sh
@@ -7,7 +7,7 @@ unset NIX_STATE_DIR
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
EXTRA_SYSTEM_FEATURES=()
-if [[ -n "$CONTENT_ADDRESSED" ]]; then
+if [[ -n "${CONTENT_ADDRESSED-}" ]]; then
EXTRA_SYSTEM_FEATURES=("ca-derivations")
fi
@@ -42,25 +42,26 @@ testPrintOutPath=$(nix build -L -v -f $file --no-link --print-out-paths --max-jo
[[ $testPrintOutPath =~ store.*build-remote ]]
-set -o pipefail
-
# Ensure that input1 was built on store1 due to the required feature.
-nix path-info --store $TEST_ROOT/machine1 --all \
- | grep builder-build-remote-input-1.sh \
- | grep -v builder-build-remote-input-2.sh \
- | grep -v builder-build-remote-input-3.sh
+output=$(nix path-info --store $TEST_ROOT/machine1 --all)
+echo "$output" | grepQuiet builder-build-remote-input-1.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-2.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-3.sh
+unset output
# Ensure that input2 was built on store2 due to the required feature.
-nix path-info --store $TEST_ROOT/machine2 --all \
- | grep -v builder-build-remote-input-1.sh \
- | grep builder-build-remote-input-2.sh \
- | grep -v builder-build-remote-input-3.sh
+output=$(nix path-info --store $TEST_ROOT/machine2 --all)
+echo "$output" | grepQuietInverse builder-build-remote-input-1.sh
+echo "$output" | grepQuiet builder-build-remote-input-2.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-3.sh
+unset output
# Ensure that input3 was built on store3 due to the required feature.
-nix path-info --store $TEST_ROOT/machine3 --all \
- | grep -v builder-build-remote-input-1.sh \
- | grep -v builder-build-remote-input-2.sh \
- | grep builder-build-remote-input-3.sh
+output=$(nix path-info --store $TEST_ROOT/machine3 --all)
+echo "$output" | grepQuietInverse builder-build-remote-input-1.sh
+echo "$output" | grepQuietInverse builder-build-remote-input-2.sh
+echo "$output" | grepQuiet builder-build-remote-input-3.sh
+unset output
for i in input1 input3; do
diff --git a/tests/build.sh b/tests/build.sh
index 2dfd43b65..b579fc374 100644
--- a/tests/build.sh
+++ b/tests/build.sh
@@ -2,8 +2,6 @@ source common.sh
clearStore
-set -o pipefail
-
# Make sure that 'nix build' returns all outputs by default.
nix build -f multiple-outputs.nix --json a b --no-link | jq --exit-status '
(.[0] |
diff --git a/tests/ca/build.sh b/tests/ca/build.sh
index 8783525e7..98e1c5125 100644
--- a/tests/ca/build.sh
+++ b/tests/ca/build.sh
@@ -19,7 +19,7 @@ testRemoteCache () {
local outPath=$(buildAttr dependentNonCA 1)
nix copy --to file://$cacheDir $outPath
clearStore
- buildAttr dependentNonCA 1 --option substituters file://$cacheDir --no-require-sigs |& (! grep "building dependent-non-ca")
+ buildAttr dependentNonCA 1 --option substituters file://$cacheDir --no-require-sigs |& grepQuietInverse "building dependent-non-ca"
}
testDeterministicCA () {
diff --git a/tests/check-refs.sh b/tests/check-refs.sh
index 65a72552a..2778e491d 100644
--- a/tests/check-refs.sh
+++ b/tests/check-refs.sh
@@ -8,14 +8,14 @@ dep=$(nix-build -o $RESULT check-refs.nix -A dep)
# test1 references dep, not itself.
test1=$(nix-build -o $RESULT check-refs.nix -A test1)
-(! nix-store -q --references $test1 | grep -q $test1)
-nix-store -q --references $test1 | grep -q $dep
+nix-store -q --references $test1 | grepQuietInverse $test1
+nix-store -q --references $test1 | grepQuiet $dep
# test2 references src, not itself nor dep.
test2=$(nix-build -o $RESULT check-refs.nix -A test2)
-(! nix-store -q --references $test2 | grep -q $test2)
-(! nix-store -q --references $test2 | grep -q $dep)
-nix-store -q --references $test2 | grep -q aux-ref
+nix-store -q --references $test2 | grepQuietInverse $test2
+nix-store -q --references $test2 | grepQuietInverse $dep
+nix-store -q --references $test2 | grepQuiet aux-ref
# test3 should fail (unallowed ref).
(! nix-build -o $RESULT check-refs.nix -A test3)
diff --git a/tests/check-reqs.sh b/tests/check-reqs.sh
index e9f65fc2a..856c94cec 100644
--- a/tests/check-reqs.sh
+++ b/tests/check-reqs.sh
@@ -8,8 +8,8 @@ nix-build -o $RESULT check-reqs.nix -A test1
(! nix-build -o $RESULT check-reqs.nix -A test2)
(! nix-build -o $RESULT check-reqs.nix -A test3)
-(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grep -q 'check-reqs-dep1'
-(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grep -q 'check-reqs-dep2'
+(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep1'
+(! nix-build -o $RESULT check-reqs.nix -A test4) 2>&1 | grepQuiet 'check-reqs-dep2'
(! nix-build -o $RESULT check-reqs.nix -A test5)
(! nix-build -o $RESULT check-reqs.nix -A test6)
diff --git a/tests/check.sh b/tests/check.sh
index e77c0405d..645b90222 100644
--- a/tests/check.sh
+++ b/tests/check.sh
@@ -37,7 +37,7 @@ checkBuildTempDirRemoved $TEST_ROOT/log
nix-build check.nix -A deterministic --argstr checkBuildId $checkBuildId \
--no-out-link --check --keep-failed 2> $TEST_ROOT/log
-if grep -q 'may not be deterministic' $TEST_ROOT/log; then false; fi
+if grepQuiet 'may not be deterministic' $TEST_ROOT/log; then false; fi
checkBuildTempDirRemoved $TEST_ROOT/log
nix-build check.nix -A nondeterministic --argstr checkBuildId $checkBuildId \
diff --git a/tests/common.sh b/tests/common.sh
index 68b90a85f..8941671d6 100644
--- a/tests/common.sh
+++ b/tests/common.sh
@@ -1,4 +1,4 @@
-set -e
+set -eu -o pipefail
if [[ -z "${COMMON_SH_SOURCED-}" ]]; then
diff --git a/tests/common/vars-and-functions.sh.in b/tests/common/vars-and-functions.sh.in
index 0deef4c1c..e4a773f34 100644
--- a/tests/common/vars-and-functions.sh.in
+++ b/tests/common/vars-and-functions.sh.in
@@ -1,4 +1,4 @@
-set -e
+set -eu -o pipefail
if [[ -z "${COMMON_VARS_AND_FUNCTIONS_SH_SOURCED-}" ]]; then
@@ -157,7 +157,7 @@ requireDaemonNewerThan () {
}
canUseSandbox() {
- if [[ ! $_canUseSandbox ]]; then
+ if [[ ! ${_canUseSandbox-} ]]; then
echo "Sandboxing not supported, skipping this test..."
return 1
fi
@@ -170,13 +170,38 @@ fail() {
exit 1
}
+# Run a command failing if it didn't exit with the expected exit code.
+#
+# Has two advantages over the built-in `!`:
+#
+# 1. `!` conflates all non-0 codes. `expect` allows testing for an exact
+# code.
+#
+# 2. `!` unexpectedly negates `set -e`, and cannot be used on individual
+# pipeline stages with `set -o pipefail`. It only works on the entire
+# pipeline, which is useless if we want, say, `nix ...` invocation to
+# *fail*, but a grep on the error message it outputs to *succeed*.
expect() {
local expected res
expected="$1"
shift
- "$@" || res="$?"
+ "$@" && res=0 || res="$?"
if [[ $res -ne $expected ]]; then
- echo "Expected '$expected' but got '$res' while running '$*'"
+ echo "Expected '$expected' but got '$res' while running '${*@Q}'" >&2
+ return 1
+ fi
+ return 0
+}
+
+# Better than just doing `expect ... >&2` because the "Expected..."
+# message below will *not* be redirected.
+expectStderr() {
+ local expected res
+ expected="$1"
+ shift
+ "$@" 2>&1 && res=0 || res="$?"
+ if [[ $res -ne $expected ]]; then
+ echo "Expected '$expected' but got '$res' while running '${*@Q}'" >&2
return 1
fi
return 0
@@ -191,7 +216,7 @@ needLocalStore() {
# Just to make it easy to find which tests should be fixed
buggyNeedLocalStore() {
- needLocalStore
+ needLocalStore "$1"
}
enableFeatures() {
@@ -210,6 +235,35 @@ onError() {
done
}
+# `grep -v` doesn't work well for exit codes. We want `!(exist line l. l
+# matches)`. It gives us `exist line l. !(l matches)`.
+#
+# `!` normally doesn't work well with `set -e`, but when we wrap in a
+# function it *does*.
+grepInverse() {
+ ! grep "$@"
+}
+
+# A shorthand, `> /dev/null` is a bit noisy.
+#
+# `grep -q` would seem to do this, no function necessary, but it is a
+# bad fit with pipes and `set -o pipefail`: `-q` will exit after the
+# first match, and then subsequent writes will result in broken pipes.
+#
+# Note that reproducing the above is a bit tricky as it depends on
+# non-deterministic properties such as the timing between the match and
+# the closing of the pipe, the buffering of the pipe, and the speed of
+# the producer into the pipe. But rest assured we've seen it happen in
+# CI reliably.
+grepQuiet() {
+ grep "$@" > /dev/null
+}
+
+# The previous two, combined
+grepQuietInverse() {
+ ! grep "$@" > /dev/null
+}
+
trap onError ERR
fi # COMMON_VARS_AND_FUNCTIONS_SH_SOURCED
diff --git a/tests/compute-levels.sh b/tests/compute-levels.sh
index e4322dfa1..de3da2ebd 100644
--- a/tests/compute-levels.sh
+++ b/tests/compute-levels.sh
@@ -3,5 +3,5 @@ source common.sh
if [[ $(uname -ms) = "Linux x86_64" ]]; then
# x86_64 CPUs must always support the baseline
# microarchitecture level.
- nix -vv --version | grep -q "x86_64-v1-linux"
+ nix -vv --version | grepQuiet "x86_64-v1-linux"
fi
diff --git a/tests/db-migration.sh b/tests/db-migration.sh
index 92dd4f3ba..7d243eefb 100644
--- a/tests/db-migration.sh
+++ b/tests/db-migration.sh
@@ -2,7 +2,7 @@
# Only run this if we have an older Nix available
# XXX: This assumes that the `daemon` package is older than the `client` one
-if [[ -z "$NIX_DAEMON_PACKAGE" ]]; then
+if [[ -z "${NIX_DAEMON_PACKAGE-}" ]]; then
exit 99
fi
@@ -12,7 +12,7 @@ killDaemon
# Fill the db using the older Nix
PATH_WITH_NEW_NIX="$PATH"
-export PATH="$NIX_DAEMON_PACKAGE/bin:$PATH"
+export PATH="${NIX_DAEMON_PACKAGE}/bin:$PATH"
clearStore
nix-build simple.nix --no-out-link
nix-store --generate-binary-cache-key cache1.example.org $TEST_ROOT/sk1 $TEST_ROOT/pk1
diff --git a/tests/dependencies.sh b/tests/dependencies.sh
index 092950aa7..f9da0c6bc 100644
--- a/tests/dependencies.sh
+++ b/tests/dependencies.sh
@@ -36,10 +36,10 @@ deps=$(nix-store -quR "$drvPath")
echo "output closure contains $deps"
# The output path should be in the closure.
-echo "$deps" | grep -q "$outPath"
+echo "$deps" | grepQuiet "$outPath"
# Input-1 is not retained.
-if echo "$deps" | grep -q "dependencies-input-1"; then exit 1; fi
+if echo "$deps" | grepQuiet "dependencies-input-1"; then exit 1; fi
# Input-2 is retained.
input2OutPath=$(echo "$deps" | grep "dependencies-input-2")
@@ -49,4 +49,4 @@ nix-store -q --referrers-closure "$input2OutPath" | grep "$outPath"
# Check that the derivers are set properly.
test $(nix-store -q --deriver "$outPath") = "$drvPath"
-nix-store -q --deriver "$input2OutPath" | grep -q -- "-input-2.drv"
+nix-store -q --deriver "$input2OutPath" | grepQuiet -- "-input-2.drv"
diff --git a/tests/eval-store.sh b/tests/eval-store.sh
index 679da5741..8fc859730 100644
--- a/tests/eval-store.sh
+++ b/tests/eval-store.sh
@@ -2,7 +2,7 @@ source common.sh
# Using `--eval-store` with the daemon will eventually copy everything
# to the build store, invalidating most of the tests here
-needLocalStore
+needLocalStore "“--eval-store” doesn't achieve much with the daemon"
eval_store=$TEST_ROOT/eval-store
diff --git a/tests/export-graph.sh b/tests/export-graph.sh
index 4954a6cbc..1f6232a40 100644
--- a/tests/export-graph.sh
+++ b/tests/export-graph.sh
@@ -4,7 +4,7 @@ clearStore
clearProfiles
checkRef() {
- nix-store -q --references $TEST_ROOT/result | grep -q "$1"'$' || fail "missing reference $1"
+ nix-store -q --references $TEST_ROOT/result | grepQuiet "$1"'$' || fail "missing reference $1"
}
# Test the export of the runtime dependency graph.
diff --git a/tests/fetchClosure.sh b/tests/fetchClosure.sh
index d88c55c3c..a207f647c 100644
--- a/tests/fetchClosure.sh
+++ b/tests/fetchClosure.sh
@@ -42,13 +42,13 @@ if [[ "$NIX_REMOTE" != "daemon" ]]; then
fi
# 'toPath' set to empty string should fail but print the expected path.
-nix eval -v --json --expr "
+expectStderr 1 nix eval -v --json --expr "
builtins.fetchClosure {
fromStore = \"file://$cacheDir\";
fromPath = $nonCaPath;
toPath = \"\";
}
-" 2>&1 | grep "error: rewriting.*$nonCaPath.*yielded.*$caPath"
+" | grep "error: rewriting.*$nonCaPath.*yielded.*$caPath"
# If fromPath is CA, then toPath isn't needed.
nix copy --to file://$cacheDir $caPath
diff --git a/tests/fetchGitRefs.sh b/tests/fetchGitRefs.sh
index 52926040b..a0d86ca5e 100644
--- a/tests/fetchGitRefs.sh
+++ b/tests/fetchGitRefs.sh
@@ -56,7 +56,7 @@ invalid_ref() {
else
(! git check-ref-format --branch "$1" >/dev/null 2>&1)
fi
- nix --debug eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath" 2>&1 | grep 'invalid Git branch/tag name' >/dev/null
+ expect 1 nix --debug eval --raw --impure --expr "(builtins.fetchGit { url = $repo; ref = ''$1''; }).outPath" 2>&1 | grep 'invalid Git branch/tag name' >/dev/null
}
diff --git a/tests/fetchTree-file.sh b/tests/fetchTree-file.sh
index f0c530466..fe569cfb8 100644
--- a/tests/fetchTree-file.sh
+++ b/tests/fetchTree-file.sh
@@ -79,7 +79,7 @@ EOF
EOF
popd
- [[ -z "${NIX_DAEMON_PACKAGE}" ]] && return 0
+ [[ -z "${NIX_DAEMON_PACKAGE-}" ]] && return 0
# Ensure that a lockfile generated by the current Nix for tarball inputs
# can still be read by an older Nix
@@ -91,7 +91,7 @@ EOF
flake = false;
};
outputs = { self, tarball }: {
- foo = builtins.readFile "${tarball}/test_input_file";
+ foo = builtins.readFile "\${tarball}/test_input_file";
};
}
nix flake update
diff --git a/tests/fetchurl.sh b/tests/fetchurl.sh
index b41d8c4b7..8cd40c09f 100644
--- a/tests/fetchurl.sh
+++ b/tests/fetchurl.sh
@@ -62,7 +62,7 @@ hash=$(nix-hash --flat --type sha256 $nar)
outPath=$(nix-build -vvvvv --expr 'import <nix/fetchurl.nix>' --argstr url file://$nar --argstr sha256 $hash \
--arg unpack true --argstr name xyzzy --no-out-link)
-echo $outPath | grep -q 'xyzzy'
+echo $outPath | grepQuiet 'xyzzy'
test -x $outPath/fetchurl.sh
test -L $outPath/symlink
diff --git a/tests/flakes/build-paths.sh b/tests/flakes/build-paths.sh
index 08b4d1763..b399a066e 100644
--- a/tests/flakes/build-paths.sh
+++ b/tests/flakes/build-paths.sh
@@ -35,7 +35,7 @@ cat > $flake1Dir/flake.nix <<EOF
a6 = flake2.outPath;
# FIXME
- a7 = "${flake2}/config.nix";
+ a7 = "\${flake2}/config.nix";
# This is only allowed in impure mode.
a8 = builtins.storePath $dep;
diff --git a/tests/flakes/check.sh b/tests/flakes/check.sh
index 278ac7fa4..865ca61b4 100644
--- a/tests/flakes/check.sh
+++ b/tests/flakes/check.sh
@@ -73,5 +73,5 @@ cat > $flakeDir/flake.nix <<EOF
EOF
checkRes=$(nix flake check --keep-going $flakeDir 2>&1 && fail "nix flake check should have failed" || true)
-echo "$checkRes" | grep -q "packages.system-1.default"
-echo "$checkRes" | grep -q "packages.system-2.default"
+echo "$checkRes" | grepQuiet "packages.system-1.default"
+echo "$checkRes" | grepQuiet "packages.system-2.default"
diff --git a/tests/flakes/common.sh b/tests/flakes/common.sh
index 9d79080cd..58616ac4c 100644
--- a/tests/flakes/common.sh
+++ b/tests/flakes/common.sh
@@ -66,7 +66,7 @@ EOF
createGitRepo() {
local repo="$1"
- local extraArgs="$2"
+ local extraArgs="${2-}"
rm -rf $repo $repo.tmp
mkdir -p $repo
diff --git a/tests/flakes/flakes.sh b/tests/flakes/flakes.sh
index 07f1e6698..5c922d7c5 100644
--- a/tests/flakes/flakes.sh
+++ b/tests/flakes/flakes.sh
@@ -76,17 +76,17 @@ nix registry add --registry $registry nixpkgs flake1
# Test 'nix registry list'.
[[ $(nix registry list | wc -l) == 5 ]]
-nix registry list | grep -q '^global'
-nix registry list | grep -q -v '^user' # nothing in user registry
+nix registry list | grep '^global'
+nix registry list | grepInverse '^user' # nothing in user registry
# Test 'nix flake metadata'.
nix flake metadata flake1
-nix flake metadata flake1 | grep -q 'Locked URL:.*flake1.*'
+nix flake metadata flake1 | grepQuiet 'Locked URL:.*flake1.*'
# Test 'nix flake metadata' on a local flake.
-(cd $flake1Dir && nix flake metadata) | grep -q 'URL:.*flake1.*'
-(cd $flake1Dir && nix flake metadata .) | grep -q 'URL:.*flake1.*'
-nix flake metadata $flake1Dir | grep -q 'URL:.*flake1.*'
+(cd $flake1Dir && nix flake metadata) | grepQuiet 'URL:.*flake1.*'
+(cd $flake1Dir && nix flake metadata .) | grepQuiet 'URL:.*flake1.*'
+nix flake metadata $flake1Dir | grepQuiet 'URL:.*flake1.*'
# Test 'nix flake metadata --json'.
json=$(nix flake metadata flake1 --json | jq .)
@@ -134,11 +134,11 @@ nix build -o $TEST_ROOT/result flake2#bar --impure --no-write-lock-file
nix eval --expr "builtins.getFlake \"$flake2Dir\"" --impure
# Building a local flake with an unlocked dependency should fail with --no-update-lock-file.
-nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
+expect 1 nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
# But it should succeed without that flag.
nix build -o $TEST_ROOT/result $flake2Dir#bar --no-write-lock-file
-nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
+expect 1 nix build -o $TEST_ROOT/result $flake2Dir#bar --no-update-lock-file 2>&1 | grep 'requires lock file changes'
nix build -o $TEST_ROOT/result $flake2Dir#bar --commit-lock-file
[[ -e $flake2Dir/flake.lock ]]
[[ -z $(git -C $flake2Dir diff main || echo failed) ]]
@@ -196,10 +196,10 @@ git -C $flake3Dir add flake.lock
git -C $flake3Dir commit -m 'Add lockfile'
# Test whether registry caching works.
-nix registry list --flake-registry file://$registry | grep -q flake3
+nix registry list --flake-registry file://$registry | grepQuiet flake3
mv $registry $registry.tmp
nix store gc
-nix registry list --flake-registry file://$registry --refresh | grep -q flake3
+nix registry list --flake-registry file://$registry --refresh | grepQuiet flake3
mv $registry.tmp $registry
# Test whether flakes are registered as GC roots for offline use.
@@ -346,8 +346,8 @@ nix registry remove flake1
nix registry add user-flake1 git+file://$flake1Dir
nix registry add user-flake2 git+file://$flake2Dir
[[ $(nix --flake-registry "" registry list | wc -l) == 2 ]]
-nix --flake-registry "" registry list | grep -q -v '^global' # nothing in global registry
-nix --flake-registry "" registry list | grep -q '^user'
+nix --flake-registry "" registry list | grepQuietInverse '^global' # nothing in global registry
+nix --flake-registry "" registry list | grepQuiet '^user'
nix registry remove user-flake1
nix registry remove user-flake2
[[ $(nix registry list | wc -l) == 5 ]]
@@ -454,7 +454,7 @@ url=$(nix flake metadata --json file://$TEST_ROOT/flake.tar.gz | jq -r .url)
nix build -o $TEST_ROOT/result $url
# Building with an incorrect SRI hash should fail.
-nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" 2>&1 | grep 'NAR hash mismatch'
+expectStderr 102 nix build -o $TEST_ROOT/result "file://$TEST_ROOT/flake.tar.gz?narHash=sha256-qQ2Zz4DNHViCUrp6gTS7EE4+RMqFQtUfWF2UNUtJKS0=" | grep 'NAR hash mismatch'
# Test --override-input.
git -C $flake3Dir reset --hard
diff --git a/tests/flakes/follow-paths.sh b/tests/flakes/follow-paths.sh
index 19cc1bafa..fe9b51c65 100644
--- a/tests/flakes/follow-paths.sh
+++ b/tests/flakes/follow-paths.sh
@@ -128,7 +128,7 @@ EOF
git -C $flakeFollowsA add flake.nix
-nix flake lock $flakeFollowsA 2>&1 | grep 'points outside'
+expect 1 nix flake lock $flakeFollowsA 2>&1 | grep 'points outside'
# Non-existant follows should print a warning.
cat >$flakeFollowsA/flake.nix <<EOF
diff --git a/tests/fmt.sh b/tests/fmt.sh
index 254681ca2..3c1bd9989 100644
--- a/tests/fmt.sh
+++ b/tests/fmt.sh
@@ -1,7 +1,5 @@
source common.sh
-set -o pipefail
-
clearStore
rm -rf $TEST_HOME/.cache $TEST_HOME/.config $TEST_HOME/.local
diff --git a/tests/function-trace.sh b/tests/function-trace.sh
index b0d6c9d59..bd804bf18 100755
--- a/tests/function-trace.sh
+++ b/tests/function-trace.sh
@@ -10,17 +10,15 @@ expect_trace() {
--trace-function-calls \
--expr "$expr" 2>&1 \
| grep "function-trace" \
- | sed -e 's/ [0-9]*$//'
+ | sed -e 's/ [0-9]*$//' \
+ || true
)
echo -n "Tracing expression '$expr'"
- set +e
msg=$(diff -swB \
<(echo "$expect") \
<(echo "$actual")
- );
- result=$?
- set -e
+ ) && result=0 || result=$?
if [ $result -eq 0 ]; then
echo " ok."
else
@@ -67,5 +65,3 @@ expect_trace '1 2' "
function-trace entered «string»:1:1 at
function-trace exited «string»:1:1 at
"
-
-set -e
diff --git a/tests/gc.sh b/tests/gc.sh
index ad09a8b39..98d6cb032 100644
--- a/tests/gc.sh
+++ b/tests/gc.sh
@@ -50,3 +50,20 @@ if test -e $outPath/foobar; then false; fi
# Check that the store is empty.
rmdir $NIX_STORE_DIR/.links
rmdir $NIX_STORE_DIR
+
+## Test `nix-collect-garbage -d`
+# `nix-env` doesn't work with CA derivations, so let's ignore that bit if we're
+# using them
+if [[ -z "${NIX_TESTS_CA_BY_DEFAULT:-}" ]]; then
+ clearProfiles
+ # Run two `nix-env` commands, should create two generations of
+ # the profile
+ nix-env -f ./user-envs.nix -i foo-1.0
+ nix-env -f ./user-envs.nix -i foo-2.0pre1
+ [[ $(nix-env --list-generations | wc -l) -eq 2 ]]
+
+ # Clear the profile history. There should be only one generation
+ # left
+ nix-collect-garbage -d
+ [[ $(nix-env --list-generations | wc -l) -eq 1 ]]
+fi
diff --git a/tests/hash.sh b/tests/hash.sh
index e5f75e2cf..7a99aec9b 100644
--- a/tests/hash.sh
+++ b/tests/hash.sh
@@ -2,7 +2,7 @@ source common.sh
try () {
printf "%s" "$2" > $TEST_ROOT/vector
- hash=$(nix hash file --base16 $EXTRA --type "$1" $TEST_ROOT/vector)
+ hash=$(nix hash file --base16 ${EXTRA-} --type "$1" $TEST_ROOT/vector)
if test "$hash" != "$3"; then
echo "hash $1, expected $3, got $hash"
exit 1
diff --git a/tests/impure-derivations.sh b/tests/impure-derivations.sh
index 23a193833..7595fdd35 100644
--- a/tests/impure-derivations.sh
+++ b/tests/impure-derivations.sh
@@ -5,8 +5,6 @@ requireDaemonNewerThan "2.8pre20220311"
enableFeatures "ca-derivations impure-derivations"
restartDaemon
-set -o pipefail
-
clearStore
# Basic test of impure derivations: building one a second time should not use the previous result.
diff --git a/tests/init.sh b/tests/init.sh
index fea659516..c420e8c9f 100755
--- a/tests/init.sh
+++ b/tests/init.sh
@@ -1,5 +1,3 @@
-set -eu -o pipefail
-
# Don't start the daemon
source common/vars-and-functions.sh
diff --git a/tests/install-darwin.sh b/tests/install-darwin.sh
index 7e44e54c4..ea2b75323 100755
--- a/tests/install-darwin.sh
+++ b/tests/install-darwin.sh
@@ -4,7 +4,7 @@ set -eux
cleanup() {
PLIST="/Library/LaunchDaemons/org.nixos.nix-daemon.plist"
- if sudo launchctl list | grep -q nix-daemon; then
+ if sudo launchctl list | grepQuiet nix-daemon; then
sudo launchctl unload "$PLIST"
fi
diff --git a/tests/lang.sh b/tests/lang.sh
index 95e795e2e..cdb4174eb 100644
--- a/tests/lang.sh
+++ b/tests/lang.sh
@@ -4,12 +4,12 @@ export TEST_VAR=foo # for eval-okay-getenv.nix
export NIX_REMOTE=dummy://
export NIX_STORE_DIR=/nix/store
-nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grep -q Hello
+nix-instantiate --eval -E 'builtins.trace "Hello" 123' 2>&1 | grepQuiet Hello
nix-instantiate --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1
-nix-instantiate --trace-verbose --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grep -q Hello
-(! nix-instantiate --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grep -q Hello)
-(! nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grep -q Hello)
-nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' 2>&1 | grep -q Hello
+nix-instantiate --trace-verbose --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grepQuiet Hello
+nix-instantiate --eval -E 'builtins.traceVerbose "Hello" 123' 2>&1 | grepQuietInverse Hello
+nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" 123' 2>&1 | grepQuietInverse Hello
+expectStderr 1 nix-instantiate --show-trace --eval -E 'builtins.addErrorContext "Hello" (throw "Foo")' | grepQuiet Hello
set +x
diff --git a/tests/linux-sandbox.sh b/tests/linux-sandbox.sh
index e62039567..5667000d9 100644
--- a/tests/linux-sandbox.sh
+++ b/tests/linux-sandbox.sh
@@ -35,8 +35,8 @@ nix-build dependencies.nix --no-out-link --check --sandbox-paths /nix/store
nix-build check.nix -A nondeterministic --sandbox-paths /nix/store --no-out-link
(! nix-build check.nix -A nondeterministic --sandbox-paths /nix/store --no-out-link --check -K 2> $TEST_ROOT/log)
-if grep -q 'error: renaming' $TEST_ROOT/log; then false; fi
-grep -q 'may not be deterministic' $TEST_ROOT/log
+if grepQuiet 'error: renaming' $TEST_ROOT/log; then false; fi
+grepQuiet 'may not be deterministic' $TEST_ROOT/log
# Test that sandboxed builds cannot write to /etc easily
(! nix-build -E 'with import ./config.nix; mkDerivation { name = "etc-write"; buildCommand = "echo > /etc/test"; }' --no-out-link --sandbox-paths /nix/store)
diff --git a/tests/local.mk b/tests/local.mk
index 4a620f18b..e6edbf67e 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -1,4 +1,5 @@
nix_tests = \
+ test-infra.sh \
init.sh \
flakes/flakes.sh \
flakes/run.sh \
@@ -132,7 +133,7 @@ install-tests += $(foreach x, $(nix_tests), tests/$(x))
clean-files += $(d)/tests/common/vars-and-functions.sh $(d)/config.nix $(d)/ca/config.nix
-test-deps += tests/common/vars-and-functions.sh tests/config.nix tests/ca/config.nix tests/plugins/libplugintest.$(SO_EXT)
+test-deps += tests/common/vars-and-functions.sh tests/config.nix tests/ca/config.nix
ifeq ($(BUILD_SHARED_LIBS), 1)
test-deps += tests/plugins/libplugintest.$(SO_EXT)
diff --git a/tests/misc.sh b/tests/misc.sh
index 2830856ae..60d58310e 100644
--- a/tests/misc.sh
+++ b/tests/misc.sh
@@ -3,17 +3,17 @@ source common.sh
# Tests miscellaneous commands.
# Do all commands have help?
-#nix-env --help | grep -q install
-#nix-store --help | grep -q realise
-#nix-instantiate --help | grep -q eval
-#nix-hash --help | grep -q base32
+#nix-env --help | grepQuiet install
+#nix-store --help | grepQuiet realise
+#nix-instantiate --help | grepQuiet eval
+#nix-hash --help | grepQuiet base32
# Can we ask for the version number?
nix-env --version | grep "$version"
# Usage errors.
-nix-env --foo 2>&1 | grep "no operation"
-nix-env -q --foo 2>&1 | grep "unknown flag"
+expect 1 nix-env --foo 2>&1 | grep "no operation"
+expect 1 nix-env -q --foo 2>&1 | grep "unknown flag"
# Eval Errors.
eval_arg_res=$(nix-instantiate --eval -E 'let a = {} // a; in a.foo' 2>&1 || true)
diff --git a/tests/multiple-outputs.sh b/tests/multiple-outputs.sh
index 66be6fa64..330600d08 100644
--- a/tests/multiple-outputs.sh
+++ b/tests/multiple-outputs.sh
@@ -19,8 +19,8 @@ echo "evaluating c..."
# outputs.
drvPath=$(nix-instantiate multiple-outputs.nix -A c)
#[ "$drvPath" = "$drvPath2" ]
-grep -q 'multiple-outputs-a.drv",\["first","second"\]' $drvPath
-grep -q 'multiple-outputs-b.drv",\["out"\]' $drvPath
+grepQuiet 'multiple-outputs-a.drv",\["first","second"\]' $drvPath
+grepQuiet 'multiple-outputs-b.drv",\["out"\]' $drvPath
# While we're at it, test the ‘unsafeDiscardOutputDependency’ primop.
outPath=$(nix-build multiple-outputs.nix -A d --no-out-link)
@@ -84,5 +84,5 @@ nix-store --gc --print-roots
rm -rf $NIX_STORE_DIR/.links
rmdir $NIX_STORE_DIR
-nix build -f multiple-outputs.nix invalid-output-name-1 2>&1 | grep 'contains illegal character'
-nix build -f multiple-outputs.nix invalid-output-name-2 2>&1 | grep 'contains illegal character'
+expect 1 nix build -f multiple-outputs.nix invalid-output-name-1 2>&1 | grep 'contains illegal character'
+expect 1 nix build -f multiple-outputs.nix invalid-output-name-2 2>&1 | grep 'contains illegal character'
diff --git a/tests/nar-access.sh b/tests/nar-access.sh
index dcc2e8a36..d487d58d2 100644
--- a/tests/nar-access.sh
+++ b/tests/nar-access.sh
@@ -46,8 +46,8 @@ diff -u \
<(echo '{"type":"regular","size":0}' | jq -S)
# Test missing files.
-nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
-nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
+expect 1 nix store ls --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
+expect 1 nix store ls $storePath/xyzzy 2>&1 | grep 'does not exist'
# Test failure to dump.
if nix-store --dump $storePath >/dev/full ; then
diff --git a/tests/nix-channel.sh b/tests/nix-channel.sh
index b64283f48..dbb3114f1 100644
--- a/tests/nix-channel.sh
+++ b/tests/nix-channel.sh
@@ -6,7 +6,7 @@ rm -f $TEST_HOME/.nix-channels $TEST_HOME/.nix-profile
# Test add/list/remove.
nix-channel --add http://foo/bar xyzzy
-nix-channel --list | grep -q http://foo/bar
+nix-channel --list | grepQuiet http://foo/bar
nix-channel --remove xyzzy
[ -e $TEST_HOME/.nix-channels ]
@@ -17,7 +17,7 @@ nix-channel --remove xyzzy
export NIX_CONFIG="use-xdg-base-directories = true"
nix-channel --add http://foo/bar xyzzy
-nix-channel --list | grep -q http://foo/bar
+nix-channel --list | grepQuiet http://foo/bar
nix-channel --remove xyzzy
unset NIX_CONFIG
@@ -41,8 +41,8 @@ nix-channel --update
# Do a query.
nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml
-grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
-grep -q 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
+grepQuiet 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
+grepQuiet 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
# Do an install.
nix-env -i dependencies-top
@@ -54,9 +54,9 @@ nix-channel --update
# Do a query.
nix-env -qa \* --meta --xml --out-path > $TEST_ROOT/meta.xml
-grep -q 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
-grep -q 'item.*attrPath="bar".*name="dependencies-top"' $TEST_ROOT/meta.xml
-grep -q 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
+grepQuiet 'meta.*description.*Random test package' $TEST_ROOT/meta.xml
+grepQuiet 'item.*attrPath="bar".*name="dependencies-top"' $TEST_ROOT/meta.xml
+grepQuiet 'item.*attrPath="foo".*name="dependencies-top"' $TEST_ROOT/meta.xml
# Do an install.
nix-env -i dependencies-top
diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh
index f291c6f79..a6e32ed54 100644
--- a/tests/nix-shell.sh
+++ b/tests/nix-shell.sh
@@ -88,14 +88,16 @@ output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.rb abc ruby)
nix develop -f "$shellDotNix" shellDrv -c bash -c '[[ -n $stdenv ]]'
# Ensure `nix develop -c` preserves stdin
-echo foo | nix develop -f "$shellDotNix" shellDrv -c cat | grep -q foo
+echo foo | nix develop -f "$shellDotNix" shellDrv -c cat | grepQuiet foo
# Ensure `nix develop -c` actually executes the command if stdout isn't a terminal
-nix develop -f "$shellDotNix" shellDrv -c echo foo |& grep -q foo
+nix develop -f "$shellDotNix" shellDrv -c echo foo |& grepQuiet foo
# Test 'nix print-dev-env'.
[[ $(nix print-dev-env -f "$shellDotNix" shellDrv --json | jq -r .variables.arr1.value[2]) = '3 4' ]]
+set +u # FIXME: Make print-dev-env `set -u` compliant (issue #7951)
+
source <(nix print-dev-env -f "$shellDotNix" shellDrv)
[[ -n $stdenv ]]
[[ ${arr1[2]} = "3 4" ]]
diff --git a/tests/plugins.sh b/tests/plugins.sh
index 6e278ad9d..805f49f01 100644
--- a/tests/plugins.sh
+++ b/tests/plugins.sh
@@ -1,7 +1,5 @@
source common.sh
-set -o pipefail
-
if [[ $BUILD_SHARED_LIBS != 1 ]]; then
echo "plugins are not supported"
exit 99
diff --git a/tests/pure-eval.sh b/tests/pure-eval.sh
index b83ab8afe..5334bf28e 100644
--- a/tests/pure-eval.sh
+++ b/tests/pure-eval.sh
@@ -8,7 +8,7 @@ nix eval --expr 'assert 1 + 2 == 3; true'
missingImpureErrorMsg=$(! nix eval --expr 'builtins.readFile ./pure-eval.sh' 2>&1)
-echo "$missingImpureErrorMsg" | grep -q -- --impure || \
+echo "$missingImpureErrorMsg" | grepQuiet -- --impure || \
fail "The error message should mention the “--impure” flag to unblock users"
[[ $(nix eval --expr 'builtins.pathExists ./pure-eval.sh') == false ]] || \
diff --git a/tests/repl.sh b/tests/repl.sh
index c555560cc..be8adb742 100644
--- a/tests/repl.sh
+++ b/tests/repl.sh
@@ -33,14 +33,14 @@ testRepl () {
nix repl "${nixArgs[@]}" <<< "$replCmds" || fail "nix repl does not work twice with the same inputs"
# simple.nix prints a PATH during build
- echo "$replOutput" | grep -qs 'PATH=' || fail "nix repl :log doesn't output logs"
+ echo "$replOutput" | grepQuiet -s 'PATH=' || fail "nix repl :log doesn't output logs"
local replOutput="$(nix repl "${nixArgs[@]}" <<< "$replFailingCmds" 2>&1)"
echo "$replOutput"
- echo "$replOutput" | grep -qs 'This should fail' \
+ echo "$replOutput" | grepQuiet -s 'This should fail' \
|| fail "nix repl :log doesn't output logs for a failed derivation"
local replOutput="$(nix repl --show-trace "${nixArgs[@]}" <<< "$replUndefinedVariable" 2>&1)"
echo "$replOutput"
- echo "$replOutput" | grep -qs "while evaluating the file" \
+ echo "$replOutput" | grepQuiet -s "while evaluating the file" \
|| fail "nix repl --show-trace doesn't show the trace"
nix repl "${nixArgs[@]}" --option pure-eval true 2>&1 <<< "builtins.currentSystem" \
@@ -58,7 +58,7 @@ testReplResponse () {
local commands="$1"; shift
local expectedResponse="$1"; shift
local response="$(nix repl "$@" <<< "$commands")"
- echo "$response" | grep -qs "$expectedResponse" \
+ echo "$response" | grepQuiet -s "$expectedResponse" \
|| fail "repl command set:
$commands
@@ -121,5 +121,5 @@ sed -i 's/beforeChange/afterChange/' flake/flake.nix
echo ":reload"
echo "changingThing"
) | nix repl ./flake --experimental-features 'flakes repl-flake')
-echo "$replResult" | grep -qs beforeChange
-echo "$replResult" | grep -qs afterChange
+echo "$replResult" | grepQuiet -s beforeChange
+echo "$replResult" | grepQuiet -s afterChange
diff --git a/tests/restricted.sh b/tests/restricted.sh
index 9bd16cf51..776893a56 100644
--- a/tests/restricted.sh
+++ b/tests/restricted.sh
@@ -48,4 +48,4 @@ output="$(nix eval --raw --restrict-eval -I "$traverseDir" \
--expr "builtins.readFile \"$traverseDir/$goUp$(pwd)/restricted-innocent\"" \
2>&1 || :)"
echo "$output" | grep "is forbidden"
-! echo "$output" | grep -F restricted-secret
+echo "$output" | grepInverse -F restricted-secret
diff --git a/tests/search.sh b/tests/search.sh
index 1a98f5b49..8742f8736 100644
--- a/tests/search.sh
+++ b/tests/search.sh
@@ -20,9 +20,9 @@ clearCache
## Search expressions
# Check that empty search string matches all
-nix search -f search.nix '' |grep -q foo
-nix search -f search.nix '' |grep -q bar
-nix search -f search.nix '' |grep -q hello
+nix search -f search.nix '' |grepQuiet foo
+nix search -f search.nix '' |grepQuiet bar
+nix search -f search.nix '' |grepQuiet hello
## Tests for multiple regex/match highlighting
diff --git a/tests/tarball.sh b/tests/tarball.sh
index d5cab879c..5f39658c9 100644
--- a/tests/tarball.sh
+++ b/tests/tarball.sh
@@ -19,7 +19,7 @@ test_tarball() {
tarball=$TEST_ROOT/tarball.tar$ext
(cd $TEST_ROOT && tar cf - tarball) | $compressor > $tarball
- nix-env -f file://$tarball -qa --out-path | grep -q dependencies
+ nix-env -f file://$tarball -qa --out-path | grepQuiet dependencies
nix-build -o $TEST_ROOT/result file://$tarball
@@ -34,7 +34,7 @@ test_tarball() {
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })"
# Do not re-fetch paths already present
nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file:///does-not-exist/must-remain-unused/$tarball; narHash = \"$hash\"; })"
- nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" 2>&1 | grep 'NAR hash mismatch in input'
+ expectStderr 102 nix-build -o $TEST_ROOT/result -E "import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"sha256-xdKv2pq/IiwLSnBBJXW8hNowI4MrdZfW+SYqDQs7Tzc=\"; })" | grep 'NAR hash mismatch in input'
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" >&2
nix-instantiate --strict --eval -E "!((import (fetchTree { type = \"tarball\"; url = file://$tarball; narHash = \"$hash\"; })) ? submodules)" 2>&1 | grep 'true'
diff --git a/tests/test-infra.sh b/tests/test-infra.sh
new file mode 100644
index 000000000..54ae120e7
--- /dev/null
+++ b/tests/test-infra.sh
@@ -0,0 +1,85 @@
+# Test the functions for testing themselves!
+# Also test some assumptions on how bash works that they rely on.
+source common.sh
+
+# `true` should exit with 0
+expect 0 true
+
+# `false` should exit with 1
+expect 1 false
+
+# `expect` will fail when we get it wrong
+expect 1 expect 0 false
+
+noisyTrue () {
+ echo YAY! >&2
+ true
+}
+
+noisyFalse () {
+ echo NAY! >&2
+ false
+}
+
+# These should redirect standard error to standard output
+expectStderr 0 noisyTrue | grepQuiet YAY
+expectStderr 1 noisyFalse | grepQuiet NAY
+
+# `set -o pipefile` is enabled
+
+pipefailure () {
+ # shellcheck disable=SC2216
+ true | false | true
+}
+expect 1 pipefailure
+unset pipefailure
+
+pipefailure () {
+ # shellcheck disable=SC2216
+ false | true | true
+}
+expect 1 pipefailure
+unset pipefailure
+
+commandSubstitutionPipeFailure () {
+ # shellcheck disable=SC2216
+ res=$(set -eu -o pipefail; false | true | echo 0)
+}
+expect 1 commandSubstitutionPipeFailure
+
+# `set -u` is enabled
+
+# note (...), making function use subshell, as unbound variable errors
+# in the outer shell are *rightly* not recoverable.
+useUnbound () (
+ set -eu
+ # shellcheck disable=SC2154
+ echo "$thisVariableIsNotBound"
+)
+expect 1 useUnbound
+
+# ! alone unfortunately negates `set -e`, but it works in functions:
+# shellcheck disable=SC2251
+! true
+funBang () {
+ ! true
+}
+expect 1 funBang
+unset funBang
+
+# `grep -v -q` is not what we want for exit codes, but `grepInverse` is
+# Avoid `grep -v -q`. The following line proves the point, and if it fails,
+# we'll know that `grep` had a breaking change or `-v -q` may not be portable.
+{ echo foo; echo bar; } | grep -v -q foo
+{ echo foo; echo bar; } | expect 1 grepInverse foo
+
+# `grepQuiet` is quiet
+res=$(set -eu -o pipefail; echo foo | grepQuiet foo | wc -c)
+(( res == 0 ))
+unset res
+
+# `greqQietInverse` is both
+{ echo foo; echo bar; } | expect 1 grepQuietInverse foo
+res=$(set -eu -o pipefail; echo foo | expect 1 grepQuietInverse foo | wc -c)
+(( res == 0 ))
+unset res
diff --git a/tests/timeout.sh b/tests/timeout.sh
index e3fb3ebcc..b179b79a2 100644
--- a/tests/timeout.sh
+++ b/tests/timeout.sh
@@ -5,17 +5,14 @@ source common.sh
# XXX: This shouldn’t be, but #4813 cause this test to fail
needLocalStore "see #4813"
-set +e
-messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1)
-status=$?
-set -e
+messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1) && status=0 || status=$?
if [ $status -ne 101 ]; then
echo "error: 'nix-store' exited with '$status'; should have exited 101"
exit 1
fi
-if ! echo "$messages" | grep -q "timed out"; then
+if echo "$messages" | grepQuietInvert "timed out"; then
echo "error: build may have failed for reasons other than timeout; output:"
echo "$messages" >&2
exit 1
diff --git a/tests/user-envs.sh b/tests/user-envs.sh
index d63fe780a..d1260ba04 100644
--- a/tests/user-envs.sh
+++ b/tests/user-envs.sh
@@ -1,6 +1,6 @@
source common.sh
-if [ -z "$storeCleared" ]; then
+if [ -z "${storeCleared-}" ]; then
clearStore
fi
@@ -28,13 +28,13 @@ nix-env -f ./user-envs.nix -qa --json --out-path | jq -e '.[] | select(.name ==
] | all'
# Query descriptions.
-nix-env -f ./user-envs.nix -qa '*' --description | grep -q silly
+nix-env -f ./user-envs.nix -qa '*' --description | grepQuiet silly
rm -rf $HOME/.nix-defexpr
ln -s $(pwd)/user-envs.nix $HOME/.nix-defexpr
-nix-env -qa '*' --description | grep -q silly
+nix-env -qa '*' --description | grepQuiet silly
# Query the system.
-nix-env -qa '*' --system | grep -q $system
+nix-env -qa '*' --system | grepQuiet $system
# Install "foo-1.0".
nix-env -i foo-1.0
@@ -42,19 +42,19 @@ nix-env -i foo-1.0
# Query installed: should contain foo-1.0 now (which should be
# executable).
test "$(nix-env -q '*' | wc -l)" -eq 1
-nix-env -q '*' | grep -q foo-1.0
+nix-env -q '*' | grepQuiet foo-1.0
test "$($profiles/test/bin/foo)" = "foo-1.0"
# Test nix-env -qc to compare installed against available packages, and vice versa.
-nix-env -qc '*' | grep -q '< 2.0'
-nix-env -qac '*' | grep -q '> 1.0'
+nix-env -qc '*' | grepQuiet '< 2.0'
+nix-env -qac '*' | grepQuiet '> 1.0'
# Test the -b flag to filter out source-only packages.
[ "$(nix-env -qab | wc -l)" -eq 1 ]
# Test the -s flag to get package status.
-nix-env -qas | grep -q 'IP- foo-1.0'
-nix-env -qas | grep -q -- '--- bar-0.1'
+nix-env -qas | grepQuiet 'IP- foo-1.0'
+nix-env -qas | grepQuiet -- '--- bar-0.1'
# Disable foo.
nix-env --set-flag active false foo
@@ -74,15 +74,15 @@ nix-env -i foo-2.0pre1
# Query installed: should contain foo-2.0pre1 now.
test "$(nix-env -q '*' | wc -l)" -eq 1
-nix-env -q '*' | grep -q foo-2.0pre1
+nix-env -q '*' | grepQuiet foo-2.0pre1
test "$($profiles/test/bin/foo)" = "foo-2.0pre1"
# Upgrade "foo": should install foo-2.0.
-NIX_PATH=nixpkgs=./user-envs.nix:$NIX_PATH nix-env -f '<nixpkgs>' -u foo
+NIX_PATH=nixpkgs=./user-envs.nix:${NIX_PATH-} nix-env -f '<nixpkgs>' -u foo
# Query installed: should contain foo-2.0 now.
test "$(nix-env -q '*' | wc -l)" -eq 1
-nix-env -q '*' | grep -q foo-2.0
+nix-env -q '*' | grepQuiet foo-2.0
test "$($profiles/test/bin/foo)" = "foo-2.0"
# Store the path of foo-2.0.
@@ -94,20 +94,20 @@ nix-env -i bar-0.1
nix-env -e foo
# Query installed: should only contain bar-0.1 now.
-if nix-env -q '*' | grep -q foo; then false; fi
-nix-env -q '*' | grep -q bar
+if nix-env -q '*' | grepQuiet foo; then false; fi
+nix-env -q '*' | grepQuiet bar
# Rollback: should bring "foo" back.
oldGen="$(nix-store -q --resolve $profiles/test)"
nix-env --rollback
[ "$(nix-store -q --resolve $profiles/test)" != "$oldGen" ]
-nix-env -q '*' | grep -q foo-2.0
-nix-env -q '*' | grep -q bar
+nix-env -q '*' | grepQuiet foo-2.0
+nix-env -q '*' | grepQuiet bar
# Rollback again: should remove "bar".
nix-env --rollback
-nix-env -q '*' | grep -q foo-2.0
-if nix-env -q '*' | grep -q bar; then false; fi
+nix-env -q '*' | grepQuiet foo-2.0
+if nix-env -q '*' | grepQuiet bar; then false; fi
# Count generations.
nix-env --list-generations
@@ -129,7 +129,7 @@ nix-env --switch-generation 7
# Install foo-1.0, now using its store path.
nix-env -i "$outPath10"
-nix-env -q '*' | grep -q foo-1.0
+nix-env -q '*' | grepQuiet foo-1.0
nix-store -qR $profiles/test | grep "$outPath10"
nix-store -q --referrers-closure $profiles/test | grep "$(nix-store -q --resolve $profiles/test)"
[ "$(nix-store -q --deriver "$outPath10")" = $drvPath10 ]
@@ -137,12 +137,12 @@ nix-store -q --referrers-closure $profiles/test | grep "$(nix-store -q --resolve
# Uninstall foo-1.0, using a symlink to its store path.
ln -sfn $outPath10/bin/foo $TEST_ROOT/symlink
nix-env -e $TEST_ROOT/symlink
-if nix-env -q '*' | grep -q foo; then false; fi
-(! nix-store -qR $profiles/test | grep "$outPath10")
+if nix-env -q '*' | grepQuiet foo; then false; fi
+nix-store -qR $profiles/test | grepInverse "$outPath10"
# Install foo-1.0, now using a symlink to its store path.
nix-env -i $TEST_ROOT/symlink
-nix-env -q '*' | grep -q foo
+nix-env -q '*' | grepQuiet foo
# Delete all old generations.
nix-env --delete-generations old
@@ -160,7 +160,7 @@ test "$(nix-env -q '*' | wc -l)" -eq 0
# Installing "foo" should only install the newest foo.
nix-env -i foo
test "$(nix-env -q '*' | grep foo- | wc -l)" -eq 1
-nix-env -q '*' | grep -q foo-2.0
+nix-env -q '*' | grepQuiet foo-2.0
# On the other hand, this should install both (and should fail due to
# a collision).
@@ -171,8 +171,8 @@ nix-env -e '*'
nix-env -e '*'
nix-env -i '*'
test "$(nix-env -q '*' | wc -l)" -eq 2
-nix-env -q '*' | grep -q foo-2.0
-nix-env -q '*' | grep -q bar-0.1.1
+nix-env -q '*' | grepQuiet foo-2.0
+nix-env -q '*' | grepQuiet bar-0.1.1
# Test priorities: foo-0.1 has a lower priority than foo-1.0, so it
# should be possible to install both without a collision. Also test
diff --git a/tests/why-depends.sh b/tests/why-depends.sh
index a04d529b5..b35a0d1cf 100644
--- a/tests/why-depends.sh
+++ b/tests/why-depends.sh
@@ -16,9 +16,9 @@ FAST_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep)
PRECISE_WHY_DEPENDS_OUTPUT=$(nix why-depends ./toplevel ./dep --precise)
# Both outputs should show that `input-2` is in the dependency chain
-echo "$FAST_WHY_DEPENDS_OUTPUT" | grep -q input-2
-echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grep -q input-2
+echo "$FAST_WHY_DEPENDS_OUTPUT" | grepQuiet input-2
+echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grepQuiet input-2
-# But only the “precise” one should refere to `reference-to-input-2`
-echo "$FAST_WHY_DEPENDS_OUTPUT" | (! grep -q reference-to-input-2)
-echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grep -q reference-to-input-2
+# But only the “precise” one should refer to `reference-to-input-2`
+echo "$FAST_WHY_DEPENDS_OUTPUT" | grepQuietInverse reference-to-input-2
+echo "$PRECISE_WHY_DEPENDS_OUTPUT" | grepQuiet reference-to-input-2