aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build-remote/build-remote.cc4
-rw-r--r--src/libcmd/command.cc5
-rw-r--r--src/libcmd/common-eval-args.cc2
-rw-r--r--src/libcmd/common-eval-args.hh2
-rw-r--r--src/libcmd/repl.cc2
-rw-r--r--src/libexpr/eval.cc6
-rw-r--r--src/libexpr/flake/call-flake.nix2
-rw-r--r--src/libexpr/primops.cc4
-rw-r--r--src/libfetchers/git.cc4
-rw-r--r--src/libfetchers/github.cc19
-rw-r--r--src/libmain/common-args.cc1
-rw-r--r--src/libmain/common-args.hh1
-rw-r--r--src/libmain/progress-bar.cc2
-rw-r--r--src/libmain/shared.cc1
-rw-r--r--src/libmain/shared.hh20
-rw-r--r--src/libmain/stack.cc12
-rw-r--r--src/libstore/binary-cache-store.cc11
-rw-r--r--src/libstore/binary-cache-store.hh3
-rw-r--r--src/libstore/build/hook-instance.cc2
-rw-r--r--src/libstore/build/local-derivation-goal.cc15
-rw-r--r--src/libstore/globals.cc10
-rw-r--r--src/libstore/ssh.cc2
-rw-r--r--src/libstore/store-api.cc4
-rw-r--r--src/libutil/tarfile.cc8
-rw-r--r--src/nix/app.cc4
-rw-r--r--src/nix/daemon.md2
-rw-r--r--src/nix/main.cc9
-rw-r--r--src/nix/path-from-hash-part.cc39
-rw-r--r--src/nix/path-from-hash-part.md20
-rw-r--r--src/nix/repl.md2
30 files changed, 167 insertions, 51 deletions
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index ff8ba2724..6b81ecc49 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -186,12 +186,12 @@ static int main_build_remote(int argc, char * * argv)
// build the hint template.
std::string errorText =
"Failed to find a machine for remote build!\n"
- "derivation: %s\nrequired (system, features): (%s, %s)";
+ "derivation: %s\nrequired (system, features): (%s, [%s])";
errorText += "\n%s available machines:";
errorText += "\n(systems, maxjobs, supportedFeatures, mandatoryFeatures)";
for (unsigned int i = 0; i < machines.size(); ++i)
- errorText += "\n(%s, %s, %s, %s)";
+ errorText += "\n([%s], %s, [%s], [%s])";
// add the template values.
std::string drvstr;
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 14bb27936..0740ea960 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -88,7 +88,8 @@ EvalCommand::EvalCommand()
{
addFlag({
.longName = "debugger",
- .description = "start an interactive environment if evaluation fails",
+ .description = "Start an interactive environment if evaluation fails.",
+ .category = MixEvalArgs::category,
.handler = {&startReplOnEvalErrors, true},
});
}
@@ -225,7 +226,7 @@ MixProfile::MixProfile()
{
addFlag({
.longName = "profile",
- .description = "The profile to update.",
+ .description = "The profile to operate on.",
.labels = {"path"},
.handler = {&profile},
.completer = completePath
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 5b6e82388..140ed3b88 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -13,8 +13,6 @@ namespace nix {
MixEvalArgs::MixEvalArgs()
{
- auto category = "Common evaluation options";
-
addFlag({
.longName = "arg",
.description = "Pass the value *expr* as the argument *name* to Nix functions.",
diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh
index 03fa226aa..1ec800613 100644
--- a/src/libcmd/common-eval-args.hh
+++ b/src/libcmd/common-eval-args.hh
@@ -10,6 +10,8 @@ class Bindings;
struct MixEvalArgs : virtual Args
{
+ static constexpr auto category = "Common evaluation options";
+
MixEvalArgs();
Bindings * getAutoArgs(EvalState & state);
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index 61c05050f..df8932087 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -1050,7 +1050,7 @@ struct CmdRepl : InstallablesCommand
evalSettings.pureEval = false;
}
- void prepare()
+ void prepare() override
{
if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
warn("future versions of Nix will require using `--file` to load a file");
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index e3716f217..563f24e48 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -904,7 +904,7 @@ void EvalState::throwEvalError(const char * s, const std::string & s2,
const std::string & s3)
{
debugThrowLastTrace(EvalError({
- .msg = hintfmt(s, s2),
+ .msg = hintfmt(s, s2, s3),
.errPos = positions[noPos]
}));
}
@@ -913,7 +913,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri
const std::string & s3)
{
debugThrowLastTrace(EvalError({
- .msg = hintfmt(s, s2),
+ .msg = hintfmt(s, s2, s3),
.errPos = positions[pos]
}));
}
@@ -922,7 +922,7 @@ void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::stri
const std::string & s3, Env & env, Expr & expr)
{
debugThrow(EvalError({
- .msg = hintfmt(s, s2),
+ .msg = hintfmt(s, s2, s3),
.errPos = positions[pos]
}), env, expr);
}
diff --git a/src/libexpr/flake/call-flake.nix b/src/libexpr/flake/call-flake.nix
index 932ac5e90..8061db3df 100644
--- a/src/libexpr/flake/call-flake.nix
+++ b/src/libexpr/flake/call-flake.nix
@@ -43,7 +43,7 @@ let
outputs = flake.outputs (inputs // { self = result; });
- result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; };
+ result = outputs // sourceInfo // { inherit inputs; inherit outputs; inherit sourceInfo; _type = "flake"; };
in
if node.flake or true then
assert builtins.isFunction flake.outputs;
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index ff620ca63..22f6ad3cc 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -3826,8 +3826,8 @@ static RegisterPrimOp primop_parseDrvName({
.args = {"s"},
.doc = R"(
Split the string *s* into a package name and version. The package
- name is everything up to but not including the first dash followed
- by a digit, and the version is everything following that dash. The
+ name is everything up to but not including the first dash not followed
+ by a letter, and the version is everything following that dash. The
result is returned in a set `{ name, version }`. Thus,
`builtins.parseDrvName "nix-0.12pre12876"` returns `{ name =
"nix"; version = "0.12pre12876"; }`.
diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc
index c1a21e764..7b7a1be35 100644
--- a/src/libfetchers/git.cc
+++ b/src/libfetchers/git.cc
@@ -485,6 +485,10 @@ struct GitInputScheme : InputScheme
}
input.attrs.insert_or_assign("ref", *head);
unlockedAttrs.insert_or_assign("ref", *head);
+ } else {
+ if (!input.getRev()) {
+ unlockedAttrs.insert_or_assign("ref", input.getRef().value());
+ }
}
if (auto res = getCache()->lookup(store, unlockedAttrs)) {
diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc
index a491d82a6..2115ce2f5 100644
--- a/src/libfetchers/github.cc
+++ b/src/libfetchers/github.cc
@@ -262,17 +262,20 @@ struct GitHubInputScheme : GitArchiveInputScheme
DownloadUrl getDownloadUrl(const Input & input) const override
{
- // FIXME: use regular /archive URLs instead? api.github.com
- // might have stricter rate limits.
auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com");
- auto url = fmt(
- host == "github.com"
- ? "https://api.%s/repos/%s/%s/tarball/%s"
- : "https://%s/api/v3/repos/%s/%s/tarball/%s",
- host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
+ Headers headers = makeHeadersWithAuthTokens(host);
+ // If we have no auth headers then we default to the public archive
+ // urls so we do not run into rate limits.
+ const auto urlFmt =
+ host != "github.com"
+ ? "https://%s/api/v3/repos/%s/%s/tarball/%s"
+ : headers.empty()
+ ? "https://%s/%s/%s/archive/%s.tar.gz"
+ : "https://api.%s/repos/%s/%s/tarball/%s";
+
+ const auto url = fmt(urlFmt, host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"),
input.getRev()->to_string(Base16, false));
- Headers headers = makeHeadersWithAuthTokens(host);
return DownloadUrl { url, headers };
}
diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc
index 12f5403ea..f92920d18 100644
--- a/src/libmain/common-args.cc
+++ b/src/libmain/common-args.cc
@@ -32,6 +32,7 @@ MixCommonArgs::MixCommonArgs(const std::string & programName)
addFlag({
.longName = "option",
.description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).",
+ .category = miscCategory,
.labels = {"name", "value"},
.handler = {[](std::string name, std::string value) {
try {
diff --git a/src/libmain/common-args.hh b/src/libmain/common-args.hh
index 25453b8c6..f180d83ce 100644
--- a/src/libmain/common-args.hh
+++ b/src/libmain/common-args.hh
@@ -6,6 +6,7 @@ namespace nix {
//static constexpr auto commonArgsCategory = "Miscellaneous common options";
static constexpr auto loggingCategory = "Logging-related options";
+static constexpr auto miscCategory = "Miscellaneous global options";
class MixCommonArgs : public virtual Args
{
diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc
index 0bbeaff8d..961f4e18a 100644
--- a/src/libmain/progress-bar.cc
+++ b/src/libmain/progress-bar.cc
@@ -503,7 +503,7 @@ public:
return s[0];
}
- virtual void setPrintBuildLogs(bool printBuildLogs)
+ void setPrintBuildLogs(bool printBuildLogs) override
{
this->printBuildLogs = printBuildLogs;
}
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index c1cf38565..a58428762 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -33,6 +33,7 @@
namespace nix {
+char * * savedArgv;
static bool gcWarning = true;
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index 0cc56d47d..3c37fd627 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -113,5 +113,25 @@ struct PrintFreed
/* Install a SIGSEGV handler to detect stack overflows. */
void detectStackOverflow();
+/* Pluggable behavior to run in case of a stack overflow.
+
+ Default value: defaultStackOverflowHandler.
+
+ This is called by the handler installed by detectStackOverflow().
+
+ This gives Nix library consumers a limit opportunity to report the error
+ condition. The handler should exit the process.
+ See defaultStackOverflowHandler() for a reference implementation.
+
+ NOTE: Use with diligence, because this runs in the signal handler, with very
+ limited stack space and a potentially a corrupted heap, all while the failed
+ thread is blocked indefinitely. All functions called must be reentrant. */
+extern std::function<void(siginfo_t * info, void * ctx)> stackOverflowHandler;
+
+/* The default, robust implementation of stackOverflowHandler.
+
+ Prints an error message directly to stderr using a syscall instead of the
+ logger. Exits the process immediately after. */
+void defaultStackOverflowHandler(siginfo_t * info, void * ctx);
}
diff --git a/src/libmain/stack.cc b/src/libmain/stack.cc
index b0a4a4c5d..10f71c1dc 100644
--- a/src/libmain/stack.cc
+++ b/src/libmain/stack.cc
@@ -1,4 +1,5 @@
#include "error.hh"
+#include "shared.hh"
#include <cstring>
#include <cstddef>
@@ -29,9 +30,7 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx)
ptrdiff_t diff = (char *) info->si_addr - sp;
if (diff < 0) diff = -diff;
if (diff < 4096) {
- char msg[] = "error: stack overflow (possible infinite recursion)\n";
- [[gnu::unused]] auto res = write(2, msg, strlen(msg));
- _exit(1); // maybe abort instead?
+ nix::stackOverflowHandler(info, ctx);
}
}
@@ -67,5 +66,12 @@ void detectStackOverflow()
#endif
}
+std::function<void(siginfo_t * info, void * ctx)> stackOverflowHandler(defaultStackOverflowHandler);
+
+void defaultStackOverflowHandler(siginfo_t * info, void * ctx) {
+ char msg[] = "error: stack overflow (possible infinite recursion)\n";
+ [[gnu::unused]] auto res = write(2, msg, strlen(msg));
+ _exit(1); // maybe abort instead?
+}
}
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 9226c4e19..a26770c79 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -331,6 +331,17 @@ bool BinaryCacheStore::isValidPathUncached(const StorePath & storePath)
return fileExists(narInfoFileFor(storePath));
}
+std::optional<StorePath> BinaryCacheStore::queryPathFromHashPart(const std::string & hashPart)
+{
+ auto pseudoPath = StorePath(hashPart + "-" + MissingName);
+ try {
+ auto info = queryPathInfo(pseudoPath);
+ return info->path;
+ } catch (InvalidPath &) {
+ return std::nullopt;
+ }
+}
+
void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink)
{
auto info = queryPathInfo(storePath).cast<const NarInfo>();
diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh
index ca538b3cb..8c82e2387 100644
--- a/src/libstore/binary-cache-store.hh
+++ b/src/libstore/binary-cache-store.hh
@@ -95,8 +95,7 @@ public:
void queryPathInfoUncached(const StorePath & path,
Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;
- std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override
- { unsupported("queryPathFromHashPart"); }
+ std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;
void addToStore(const ValidPathInfo & info, Source & narSource,
RepairFlag repair, CheckSigsFlag checkSigs) override;
diff --git a/src/libstore/build/hook-instance.cc b/src/libstore/build/hook-instance.cc
index 1f19ddccc..cb58a1f02 100644
--- a/src/libstore/build/hook-instance.cc
+++ b/src/libstore/build/hook-instance.cc
@@ -16,11 +16,11 @@ HookInstance::HookInstance()
buildHookArgs.pop_front();
Strings args;
+ args.push_back(std::string(baseNameOf(buildHook)));
for (auto & arg : buildHookArgs)
args.push_back(arg);
- args.push_back(std::string(baseNameOf(settings.buildHook.get())));
args.push_back(std::to_string(verbosity));
/* Create a pipe to get the output of the child. */
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 18b682e13..5cea3b590 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -1594,6 +1594,8 @@ void LocalDerivationGoal::runChild()
/* Warning: in the child we should absolutely not make any SQLite
calls! */
+ bool sendException = true;
+
try { /* child */
commonChildInit(builderOut);
@@ -2050,6 +2052,8 @@ void LocalDerivationGoal::runChild()
/* Indicate that we managed to set up the build environment. */
writeFull(STDERR_FILENO, std::string("\2\n"));
+ sendException = false;
+
/* Execute the program. This should not return. */
if (drv->isBuiltin()) {
try {
@@ -2103,10 +2107,13 @@ void LocalDerivationGoal::runChild()
throw SysError("executing '%1%'", drv->builder);
} catch (Error & e) {
- writeFull(STDERR_FILENO, "\1\n");
- FdSink sink(STDERR_FILENO);
- sink << e;
- sink.flush();
+ if (sendException) {
+ writeFull(STDERR_FILENO, "\1\n");
+ FdSink sink(STDERR_FILENO);
+ sink << e;
+ sink.flush();
+ } else
+ std::cerr << e.msg();
_exit(1);
}
}
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index d724897bb..ff658c428 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -154,13 +154,9 @@ StringSet Settings::getDefaultExtraPlatforms()
// machines. Note that we can’t force processes from executing
// x86_64 in aarch64 environments or vice versa since they can
// always exec with their own binary preferences.
- if (pathExists("/Library/Apple/System/Library/LaunchDaemons/com.apple.oahd.plist") ||
- pathExists("/System/Library/LaunchDaemons/com.apple.oahd.plist")) {
- if (std::string{SYSTEM} == "x86_64-darwin")
- extraPlatforms.insert("aarch64-darwin");
- else if (std::string{SYSTEM} == "aarch64-darwin")
- extraPlatforms.insert("x86_64-darwin");
- }
+ if (std::string{SYSTEM} == "aarch64-darwin" &&
+ runProgram(RunOptions {.program = "arch", .args = {"-arch", "x86_64", "/usr/bin/true"}, .mergeStderrToStdout = true}).first == 0)
+ extraPlatforms.insert("x86_64-darwin");
#endif
return extraPlatforms;
diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc
index 1bbad71f2..69bfe3418 100644
--- a/src/libstore/ssh.cc
+++ b/src/libstore/ssh.cc
@@ -67,7 +67,7 @@ std::unique_ptr<SSHMaster::Connection> SSHMaster::startCommand(const std::string
if (fakeSSH) {
args = { "bash", "-c" };
} else {
- args = { "ssh", host.c_str(), "-x", "-a" };
+ args = { "ssh", host.c_str(), "-x" };
addCommonSSHOpts(args);
if (socketPath != "")
args.insert(args.end(), {"-S", socketPath});
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 86b12257a..06a9758fc 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -1363,9 +1363,9 @@ std::shared_ptr<Store> openFromNonUri(const std::string & uri, const Store::Para
} catch (Error & e) {
return std::make_shared<LocalStore>(params);
}
- warn("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
+ warn("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
} else
- debug("'/nix' does not exist, so Nix will use '%s' as a chroot store", chrootStore);
+ debug("'%s' does not exist, so Nix will use '%s' as a chroot store", stateDir, chrootStore);
Store::Params params2;
params2["root"] = chrootStore;
return std::make_shared<LocalStore>(params2);
diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc
index a7db58559..238d0a7a6 100644
--- a/src/libutil/tarfile.cc
+++ b/src/libutil/tarfile.cc
@@ -77,9 +77,7 @@ TarArchive::~TarArchive()
static void extract_archive(TarArchive & archive, const Path & destDir)
{
- int flags = ARCHIVE_EXTRACT_FFLAGS
- | ARCHIVE_EXTRACT_PERM
- | ARCHIVE_EXTRACT_TIME
+ int flags = ARCHIVE_EXTRACT_TIME
| ARCHIVE_EXTRACT_SECURE_SYMLINKS
| ARCHIVE_EXTRACT_SECURE_NODOTDOT;
@@ -98,6 +96,10 @@ static void extract_archive(TarArchive & archive, const Path & destDir)
archive_entry_copy_pathname(entry,
(destDir + "/" + name).c_str());
+ // sources can and do contain dirs with no rx bits
+ if (archive_entry_filetype(entry) == AE_IFDIR && (archive_entry_mode(entry) & 0500) != 0500)
+ archive_entry_set_mode(entry, archive_entry_mode(entry) | 0500);
+
// Patch hardlink path
const char *original_hardlink = archive_entry_hardlink(entry);
if (original_hardlink) {
diff --git a/src/nix/app.cc b/src/nix/app.cc
index 821964f86..48de8fb82 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -66,7 +66,9 @@ UnresolvedApp Installable::toApp(EvalState & state)
auto type = cursor->getAttr("type")->getString();
- std::string expected = !attrPath.empty() && state.symbols[attrPath[0]] == "apps" ? "app" : "derivation";
+ std::string expected = !attrPath.empty() &&
+ (state.symbols[attrPath[0]] == "apps" || state.symbols[attrPath[0]] == "defaultApp")
+ ? "app" : "derivation";
if (type != expected)
throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected);
diff --git a/src/nix/daemon.md b/src/nix/daemon.md
index e97016a94..d5cdadf08 100644
--- a/src/nix/daemon.md
+++ b/src/nix/daemon.md
@@ -11,7 +11,7 @@ R""(
# Description
This command runs the Nix daemon, which is a required component in
-multi-user Nix installations. It performs build actions and other
+multi-user Nix installations. It runs build tasks and other
operations on the Nix store on behalf of non-root users. Usually you
don't run the daemon directly; instead it's managed by a service
management framework such as `systemd`.
diff --git a/src/nix/main.cc b/src/nix/main.cc
index e0155cd5d..2c6309c81 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -53,7 +53,6 @@ static bool haveInternet()
}
std::string programPath;
-char * * savedArgv;
struct HelpRequested { };
@@ -74,6 +73,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
addFlag({
.longName = "help",
.description = "Show usage information.",
+ .category = miscCategory,
.handler = {[&]() { throw HelpRequested(); }},
});
@@ -88,6 +88,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
addFlag({
.longName = "version",
.description = "Show version information.",
+ .category = miscCategory,
.handler = {[&]() { showVersion = true; }},
});
@@ -95,12 +96,14 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
.longName = "offline",
.aliases = {"no-net"}, // FIXME: remove
.description = "Disable substituters and consider all previously downloaded files up-to-date.",
+ .category = miscCategory,
.handler = {[&]() { useNet = false; }},
});
addFlag({
.longName = "refresh",
.description = "Consider all previously downloaded files out-of-date.",
+ .category = miscCategory,
.handler = {[&]() { refresh = true; }},
});
}
@@ -187,7 +190,7 @@ static void showHelp(std::vector<std::string> subcommand, MultiCommand & topleve
*vUtils);
auto attrs = state.buildBindings(16);
- attrs.alloc("command").mkString(toplevel.toJSON().dump());
+ attrs.alloc("toplevel").mkString(toplevel.toJSON().dump());
auto vRes = state.allocValue();
state.callFunction(*vGenerateManpage, state.allocValue()->mkAttrs(attrs), *vRes, noPos);
@@ -266,7 +269,7 @@ void mainWrapped(int argc, char * * argv)
programPath = argv[0];
auto programName = std::string(baseNameOf(programPath));
- if (argc > 0 && std::string_view(argv[0]) == "__build-remote") {
+ if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
programName = "build-remote";
argv++; argc--;
}
diff --git a/src/nix/path-from-hash-part.cc b/src/nix/path-from-hash-part.cc
new file mode 100644
index 000000000..7f7cda8d3
--- /dev/null
+++ b/src/nix/path-from-hash-part.cc
@@ -0,0 +1,39 @@
+#include "command.hh"
+#include "store-api.hh"
+
+using namespace nix;
+
+struct CmdPathFromHashPart : StoreCommand
+{
+ std::string hashPart;
+
+ CmdPathFromHashPart()
+ {
+ expectArgs({
+ .label = "hash-part",
+ .handler = {&hashPart},
+ });
+ }
+
+ std::string description() override
+ {
+ return "get a store path from its hash part";
+ }
+
+ std::string doc() override
+ {
+ return
+ #include "path-from-hash-part.md"
+ ;
+ }
+
+ void run(ref<Store> store) override
+ {
+ if (auto storePath = store->queryPathFromHashPart(hashPart))
+ logger->cout(store->printStorePath(*storePath));
+ else
+ throw Error("there is no store path corresponding to '%s'", hashPart);
+ }
+};
+
+static auto rCmdPathFromHashPart = registerCommand2<CmdPathFromHashPart>({"store", "path-from-hash-part"});
diff --git a/src/nix/path-from-hash-part.md b/src/nix/path-from-hash-part.md
new file mode 100644
index 000000000..788e13ab6
--- /dev/null
+++ b/src/nix/path-from-hash-part.md
@@ -0,0 +1,20 @@
+R""(
+
+# Examples
+
+* Return the full store path with the given hash part:
+
+ ```console
+ # nix store path-from-hash-part --store https://cache.nixos.org/ 0i2jd68mp5g6h2sa5k9c85rb80sn8hi9
+ /nix/store/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9-hello-2.10
+ ```
+
+# Description
+
+Given the hash part of a store path (that is, the 32 characters
+following `/nix/store/`), return the full store path. This is
+primarily useful in the implementation of binary caches, where a
+request for a `.narinfo` file only supplies the hash part
+(e.g. `https://cache.nixos.org/0i2jd68mp5g6h2sa5k9c85rb80sn8hi9.narinfo`).
+
+)""
diff --git a/src/nix/repl.md b/src/nix/repl.md
index 23ef0f4e6..c5113be61 100644
--- a/src/nix/repl.md
+++ b/src/nix/repl.md
@@ -36,7 +36,7 @@ R""(
Loading Installable ''...
Added 1 variables.
- # nix repl --extra_experimental_features 'flakes repl-flake' nixpkgs
+ # nix repl --extra-experimental-features 'flakes repl-flake' nixpkgs
Loading Installable 'flake:nixpkgs#'...
Added 5 variables.