aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/install-nix-from-closure.sh8
-rw-r--r--src/libexpr/eval.cc21
-rw-r--r--src/libexpr/flake/flake.cc2
-rw-r--r--src/libexpr/nixexpr.hh1
-rw-r--r--src/libfetchers/github.cc20
-rw-r--r--src/libstore/local-store.cc2
-rw-r--r--src/libstore/nar-info-disk-cache.cc6
-rw-r--r--src/libutil/error.cc2
-rw-r--r--src/libutil/error.hh2
-rw-r--r--src/libutil/url-parts.hh2
-rwxr-xr-xsrc/nix-build/nix-build.cc4
-rw-r--r--src/nix/build.cc6
-rw-r--r--src/nix/installables.cc2
-rw-r--r--src/nix/main.cc5
-rw-r--r--src/nix/ping-store.md3
-rw-r--r--src/nix/profile.cc24
-rw-r--r--tests/nix-shell.sh18
-rw-r--r--tests/shell.nix2
18 files changed, 104 insertions, 26 deletions
diff --git a/scripts/install-nix-from-closure.sh b/scripts/install-nix-from-closure.sh
index 6352a8fac..0ee7ce5af 100644
--- a/scripts/install-nix-from-closure.sh
+++ b/scripts/install-nix-from-closure.sh
@@ -166,9 +166,15 @@ fi
mkdir -p $dest/store
printf "copying Nix to %s..." "${dest}/store" >&2
+# Insert a newline if no progress is shown.
+if [ ! -t 0 ]; then
+ echo ""
+fi
for i in $(cd "$self/store" >/dev/null && echo ./*); do
- printf "." >&2
+ if [ -t 0 ]; then
+ printf "." >&2
+ fi
i_tmp="$dest/store/$i.$$"
if [ -e "$i_tmp" ]; then
rm -rf "$i_tmp"
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index ead5bf8c7..f3471aac7 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -657,11 +657,6 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s))
});
}
-LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1))
-{
- throw TypeError(s, s1);
-}
-
LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const ExprLambda & fun, const Symbol & s2))
{
throw TypeError({
@@ -686,6 +681,14 @@ LocalNoInlineNoReturn(void throwUndefinedVarError(const Pos & pos, const char *
});
}
+LocalNoInlineNoReturn(void throwMissingArgumentError(const Pos & pos, const char * s, const string & s1))
+{
+ throw MissingArgumentError({
+ .hint = hintfmt(s, s1),
+ .errPos = pos
+ });
+}
+
LocalNoInline(void addErrorTrace(Error & e, const char * s, const string & s2))
{
e.addTrace(std::nullopt, s, s2);
@@ -1376,7 +1379,13 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
if (j != args.end()) {
actualArgs->attrs->push_back(*j);
} else if (!i.def) {
- throwTypeError("cannot auto-call a function that has an argument without a default value ('%1%')", i.name);
+ throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%')
+
+nix attempted to evaluate a function as a top level expression; in this case it must have its
+arguments supplied either by default values, or passed explicitly with --arg or --argstr.
+
+https://nixos.org/manual/nix/stable/#ss-functions)", i.name);
+
}
}
}
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 61aeae543..0786fef3d 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -128,7 +128,7 @@ static FlakeInput parseFlakeInput(EvalState & state,
attrs.emplace(attr.name, Explicit<bool> { attr.value->boolean });
break;
case nInt:
- attrs.emplace(attr.name, attr.value->integer);
+ attrs.emplace(attr.name, (long unsigned int)attr.value->integer);
break;
default:
throw TypeError("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index b80a7de4e..530202ff6 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -17,6 +17,7 @@ MakeError(ThrownError, AssertionError);
MakeError(Abort, EvalError);
MakeError(TypeError, EvalError);
MakeError(UndefinedVarError, Error);
+MakeError(MissingArgumentError, Error);
MakeError(RestrictedPathError, Error);
diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc
index db1ced5d6..8352ef02d 100644
--- a/src/libfetchers/github.cc
+++ b/src/libfetchers/github.cc
@@ -37,15 +37,29 @@ struct GitArchiveInputScheme : InputScheme
std::optional<std::string> ref;
std::optional<std::string> host_url;
- if (path.size() == 2) {
- } else if (path.size() == 3) {
+ auto size = path.size();
+ if (size == 3) {
if (std::regex_match(path[2], revRegex))
rev = Hash::parseAny(path[2], htSHA1);
else if (std::regex_match(path[2], refRegex))
ref = path[2];
else
throw BadURL("in URL '%s', '%s' is not a commit hash or branch/tag name", url.url, path[2]);
- } else
+ } else if (size > 3) {
+ std::string rs;
+ for (auto i = std::next(path.begin(), 2); i != path.end(); i++) {
+ rs += *i;
+ if (std::next(i) != path.end()) {
+ rs += "/";
+ }
+ }
+
+ if (std::regex_match(rs, refRegex)) {
+ ref = rs;
+ } else {
+ throw BadURL("in URL '%s', '%s' is not a branch/tag name", url.url, rs);
+ }
+ } else if (size < 2)
throw BadURL("URL '%s' is invalid", url.url);
for (auto &[name, value] : url.query) {
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index d6d74a0b0..71e61cfe3 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -914,7 +914,7 @@ LocalStore::queryDerivationOutputMapNoResolve(const StorePath& path_)
if (realisation)
outputs.insert_or_assign(outputName, realisation->outPath);
else
- outputs.insert_or_assign(outputName, std::nullopt);
+ outputs.insert({outputName, std::nullopt});
}
return outputs;
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index 8541cc51f..1d8d2d57e 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -109,8 +109,10 @@ public:
SQLiteStmt(state->db,
"delete from NARs where ((present = 0 and timestamp < ?) or (present = 1 and timestamp < ?))")
.use()
- (now - settings.ttlNegativeNarInfoCache)
- (now - settings.ttlPositiveNarInfoCache)
+ // Use a minimum TTL to prevent --refresh from
+ // nuking the entire disk cache.
+ (now - std::max(settings.ttlNegativeNarInfoCache.get(), 3600U))
+ (now - std::max(settings.ttlPositiveNarInfoCache.get(), 30 * 24 * 3600U))
.exec();
debug("deleted %d entries from the NAR info disk cache", sqlite3_changes(state->db));
diff --git a/src/libutil/error.cc b/src/libutil/error.cc
index e7dc3f1d3..2a67a730a 100644
--- a/src/libutil/error.cc
+++ b/src/libutil/error.cc
@@ -61,6 +61,8 @@ std::optional<LinesOfCode> getCodeLines(const ErrPos & errPos)
if (errPos.origin == foFile) {
LinesOfCode loc;
try {
+ // FIXME: when running as the daemon, make sure we don't
+ // open a file to which the client doesn't have access.
AutoCloseFD fd = open(errPos.file.c_str(), O_RDONLY | O_CLOEXEC);
if (!fd) return {};
diff --git a/src/libutil/error.hh b/src/libutil/error.hh
index aa4fadfcc..1e0bde7ea 100644
--- a/src/libutil/error.hh
+++ b/src/libutil/error.hh
@@ -38,7 +38,7 @@ namespace nix {
ErrorInfo structs are sent to the logger as part of an exception, or directly with the
logError or logWarning macros.
- See the error-demo.cc program for usage examples.
+ See libutil/tests/logging.cc for usage examples.
*/
diff --git a/src/libutil/url-parts.hh b/src/libutil/url-parts.hh
index 5d21b8d1a..862d9fa6e 100644
--- a/src/libutil/url-parts.hh
+++ b/src/libutil/url-parts.hh
@@ -23,7 +23,7 @@ const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
// A Git ref (i.e. branch or tag name).
-const static std::string refRegexS = "[a-zA-Z0-9][a-zA-Z0-9_.-]*"; // FIXME: check
+const static std::string refRegexS = "[a-zA-Z0-9][a-zA-Z0-9_.\\/-]*"; // FIXME: check
extern std::regex refRegex;
// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc
index 74fafd426..38048da52 100755
--- a/src/nix-build/nix-build.cc
+++ b/src/nix-build/nix-build.cc
@@ -217,9 +217,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(\"%3%\")' -- %4%") % execArgs % interpreter % script % joined.str()).str();
+ envCommand = (format("exec %1% %2% -e 'load(ARGV.shift)' -- %3% %4%") % execArgs % interpreter % shellEscape(script) % joined.str()).str();
} else {
- envCommand = (format("exec %1% %2% %3% %4%") % execArgs % interpreter % script % joined.str()).str();
+ envCommand = (format("exec %1% %2% %3% %4%") % execArgs % interpreter % shellEscape(script) % joined.str()).str();
}
}
diff --git a/src/nix/build.cc b/src/nix/build.cc
index 4cb8ade08..724ce9d79 100644
--- a/src/nix/build.cc
+++ b/src/nix/build.cc
@@ -58,7 +58,8 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
if (outLink != "")
if (auto store2 = store.dynamic_pointer_cast<LocalFSStore>())
- for (size_t i = 0; i < buildables.size(); ++i)
+ for (const auto & [_i, buildable] : enumerate(buildables)) {
+ auto i = _i;
std::visit(overloaded {
[&](BuildableOpaque bo) {
std::string symlink = outLink;
@@ -74,7 +75,8 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
store2->addPermRoot(output.second, absPath(symlink));
}
},
- }, buildables[i]);
+ }, buildable);
+ }
updateProfile(buildables);
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index 50e3b29c4..34ee238bf 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -501,7 +501,7 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
auto drvInfo = DerivationInfo{
std::move(drvPath),
- state->store->parseStorePath(attr->getAttr(state->sOutPath)->getString()),
+ state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()),
attr->getAttr(state->sOutputName)->getString()
};
diff --git a/src/nix/main.cc b/src/nix/main.cc
index 418396280..80422bd24 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -330,8 +330,11 @@ void mainWrapped(int argc, char * * argv)
fileTransferSettings.connectTimeout = 1;
}
- if (args.refresh)
+ if (args.refresh) {
settings.tarballTtl = 0;
+ settings.ttlNegativeNarInfoCache = 0;
+ settings.ttlPositiveNarInfoCache = 0;
+ }
args.command->second->prepare();
args.command->second->run();
diff --git a/src/nix/ping-store.md b/src/nix/ping-store.md
index 322093091..8c846791b 100644
--- a/src/nix/ping-store.md
+++ b/src/nix/ping-store.md
@@ -27,4 +27,7 @@ argument `--store` *url*) can be accessed. What this means is
dependent on the type of the store. For instance, for an SSH store it
means that Nix can connect to the specified machine.
+If the command succeeds, Nix returns a exit code of 0 and does not
+print any output.
+
)""
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index ca95817d0..765d6866e 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -252,8 +252,28 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
pathsToBuild.push_back({drv.drvPath, StringSet{"out"}}); // FIXME
manifest.elements.emplace_back(std::move(element));
- } else
- throw UnimplementedError("'nix profile install' does not support argument '%s'", installable->what());
+ } else {
+ auto buildables = build(store, Realise::Outputs, {installable}, bmNormal);
+
+ for (auto & buildable : buildables) {
+ ProfileElement element;
+
+ std::visit(overloaded {
+ [&](BuildableOpaque bo) {
+ pathsToBuild.push_back({bo.path, {}});
+ element.storePaths.insert(bo.path);
+ },
+ [&](BuildableFromDrv bfd) {
+ for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
+ pathsToBuild.push_back({bfd.drvPath, {output.first}});
+ element.storePaths.insert(output.second);
+ }
+ },
+ }, buildable);
+
+ manifest.elements.emplace_back(std::move(element));
+ }
+ }
}
store->buildPaths(pathsToBuild);
diff --git a/tests/nix-shell.sh b/tests/nix-shell.sh
index 7b2be650a..4775bafb9 100644
--- a/tests/nix-shell.sh
+++ b/tests/nix-shell.sh
@@ -47,6 +47,14 @@ chmod a+rx $TEST_ROOT/shell.shebang.sh
output=$($TEST_ROOT/shell.shebang.sh abc def)
[ "$output" = "foo bar abc def" ]
+# Test nix-shell shebang mode again with metacharacters in the filename.
+# First word of filename is chosen to not match any file in the test root.
+sed -e "s|@ENV_PROG@|$(type -p env)|" shell.shebang.sh > $TEST_ROOT/spaced\ \\\'\"shell.shebang.sh
+chmod a+rx $TEST_ROOT/spaced\ \\\'\"shell.shebang.sh
+
+output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.sh abc def)
+[ "$output" = "foo bar abc def" ]
+
# Test nix-shell shebang mode for ruby
# This uses a fake interpreter that returns the arguments passed
# This, in turn, verifies the `rc` script is valid and the `load()` script (given using `-e`) is as expected.
@@ -54,7 +62,15 @@ sed -e "s|@SHELL_PROG@|$(type -p nix-shell)|" shell.shebang.rb > $TEST_ROOT/shel
chmod a+rx $TEST_ROOT/shell.shebang.rb
output=$($TEST_ROOT/shell.shebang.rb abc ruby)
-[ "$output" = '-e load("'"$TEST_ROOT"'/shell.shebang.rb") -- abc ruby' ]
+[ "$output" = '-e load(ARGV.shift) -- '"$TEST_ROOT"'/shell.shebang.rb abc ruby' ]
+
+# Test nix-shell shebang mode for ruby again with metacharacters in the filename.
+# Note: fake interpreter only space-separates args without adding escapes to its output.
+sed -e "s|@SHELL_PROG@|$(type -p nix-shell)|" shell.shebang.rb > $TEST_ROOT/spaced\ \\\'\"shell.shebang.rb
+chmod a+rx $TEST_ROOT/spaced\ \\\'\"shell.shebang.rb
+
+output=$($TEST_ROOT/spaced\ \\\'\"shell.shebang.rb abc ruby)
+[ "$output" = '-e load(ARGV.shift) -- '"$TEST_ROOT"'/spaced \'\''"shell.shebang.rb abc ruby' ]
# Test 'nix develop'.
nix develop -f shell.nix shellDrv -c bash -c '[[ -n $stdenv ]]'
diff --git a/tests/shell.nix b/tests/shell.nix
index 6ce59b416..24ebcc04c 100644
--- a/tests/shell.nix
+++ b/tests/shell.nix
@@ -50,7 +50,7 @@ let pkgs = rec {
# ruby "interpreter" that outputs "$@"
ruby = runCommand "ruby" {} ''
mkdir -p $out/bin
- echo 'printf -- "$*"' > $out/bin/ruby
+ echo 'printf %s "$*"' > $out/bin/ruby
chmod a+rx $out/bin/ruby
'';