mirror of
https://github.com/NixOS/nix
synced 2025-07-07 01:51:47 +02:00
Merge remote-tracking branch 'origin/master' into coerce-string
This commit is contained in:
commit
3f9f6ae127
69 changed files with 910 additions and 650 deletions
|
@ -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},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -10,6 +10,8 @@ class Bindings;
|
|||
|
||||
struct MixEvalArgs : virtual Args
|
||||
{
|
||||
static constexpr auto category = "Common evaluation options";
|
||||
|
||||
MixEvalArgs();
|
||||
|
||||
Bindings * getAutoArgs(EvalState & state);
|
||||
|
|
|
@ -242,7 +242,11 @@ void NixRepl::mainLoop()
|
|||
|
||||
// Allow nix-repl specific settings in .inputrc
|
||||
rl_readline_name = "nix-repl";
|
||||
createDirs(dirOf(historyFile));
|
||||
try {
|
||||
createDirs(dirOf(historyFile));
|
||||
} catch (SysError & e) {
|
||||
logWarning(e.info());
|
||||
}
|
||||
#ifndef READLINE
|
||||
el_hist_size = 1000;
|
||||
#endif
|
||||
|
@ -1046,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");
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
, executable ? false
|
||||
, unpack ? false
|
||||
, name ? baseNameOf (toString url)
|
||||
, impure ? false
|
||||
}:
|
||||
|
||||
derivation {
|
||||
derivation ({
|
||||
builder = "builtin:fetchurl";
|
||||
|
||||
# New-style output content requirements.
|
||||
inherit outputHashAlgo outputHash;
|
||||
outputHashMode = if unpack || executable then "recursive" else "flat";
|
||||
|
||||
inherit name url executable unpack;
|
||||
|
@ -38,4 +38,6 @@ derivation {
|
|||
|
||||
# To make "nix-prefetch-url" work.
|
||||
urls = [ url ];
|
||||
}
|
||||
} // (if impure
|
||||
then { __impure = true; }
|
||||
else { inherit outputHashAlgo outputHash; }))
|
||||
|
|
|
@ -68,7 +68,7 @@ void ConfigFile::apply()
|
|||
}
|
||||
}
|
||||
if (!trusted) {
|
||||
warn("ignoring untrusted flake configuration setting '%s'", name);
|
||||
warn("ignoring untrusted flake configuration setting '%s'.\nPass '%s' to trust it", name, "--accept-flake-config");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -483,12 +483,12 @@ LockedFlake lockFlake(
|
|||
} else if (auto follows = std::get_if<1>(&i.second)) {
|
||||
if (! trustLock) {
|
||||
// It is possible that the flake has changed,
|
||||
// so we must confirm all the follows that are in the lockfile are also in the flake.
|
||||
// so we must confirm all the follows that are in the lock file are also in the flake.
|
||||
auto overridePath(inputPath);
|
||||
overridePath.push_back(i.first);
|
||||
auto o = overrides.find(overridePath);
|
||||
// If the override disappeared, we have to refetch the flake,
|
||||
// since some of the inputs may not be present in the lockfile.
|
||||
// since some of the inputs may not be present in the lock file.
|
||||
if (o == overrides.end()) {
|
||||
mustRefetch = true;
|
||||
// There's no point populating the rest of the fake inputs,
|
||||
|
|
|
@ -36,7 +36,7 @@ LockedNode::LockedNode(const nlohmann::json & json)
|
|||
, isFlake(json.find("flake") != json.end() ? (bool) json["flake"] : true)
|
||||
{
|
||||
if (!lockedRef.input.isLocked())
|
||||
throw Error("lockfile contains mutable lock '%s'",
|
||||
throw Error("lock file contains mutable lock '%s'",
|
||||
fetchers::attrsToJSON(lockedRef.input.toAttrs()));
|
||||
}
|
||||
|
||||
|
|
|
@ -2423,8 +2423,8 @@ static RegisterPrimOp primop_intersectAttrs({
|
|||
.name = "__intersectAttrs",
|
||||
.args = {"e1", "e2"},
|
||||
.doc = R"(
|
||||
Return a set consisting of the attributes in the set *e2* that also
|
||||
exist in the set *e1*.
|
||||
Return a set consisting of the attributes in the set *e2* which have the
|
||||
same name as some attribute in *e1*.
|
||||
)",
|
||||
.fun = prim_intersectAttrs,
|
||||
});
|
||||
|
@ -3818,8 +3818,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"; }`.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -503,7 +503,7 @@ public:
|
|||
return s[0];
|
||||
}
|
||||
|
||||
virtual void setPrintBuildLogs(bool printBuildLogs)
|
||||
void setPrintBuildLogs(bool printBuildLogs) override
|
||||
{
|
||||
this->printBuildLogs = printBuildLogs;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "gc-store.hh"
|
||||
#include "util.hh"
|
||||
#include "loggers.hh"
|
||||
#include "progress-bar.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
@ -422,6 +423,8 @@ RunPager::RunPager()
|
|||
if (!pager) pager = getenv("PAGER");
|
||||
if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return;
|
||||
|
||||
stopProgressBar();
|
||||
|
||||
Pipe toPager;
|
||||
toPager.create();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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?
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,6 +239,8 @@ struct ClientSettings
|
|||
else if (trusted
|
||||
|| name == settings.buildTimeout.name
|
||||
|| name == settings.buildRepeat.name
|
||||
|| name == settings.maxSilentTime.name
|
||||
|| name == settings.pollInterval.name
|
||||
|| name == "connect-timeout"
|
||||
|| (name == "builders" && value == ""))
|
||||
settings.set(name, value);
|
||||
|
|
|
@ -322,7 +322,6 @@ struct curlFileTransfer : public FileTransfer
|
|||
}
|
||||
|
||||
if (request.verifyTLS) {
|
||||
debug("verify TLS: Nix CA file = '%s'", settings.caFile);
|
||||
if (settings.caFile != "")
|
||||
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
|
||||
} else {
|
||||
|
|
|
@ -619,6 +619,17 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
|
|||
Path path = storeDir + "/" + std::string(baseName);
|
||||
Path realPath = realStoreDir + "/" + std::string(baseName);
|
||||
|
||||
/* There may be temp directories in the store that are still in use
|
||||
by another process. We need to be sure that we can acquire an
|
||||
exclusive lock before deleting them. */
|
||||
if (baseName.find("tmp-", 0) == 0) {
|
||||
AutoCloseFD tmpDirFd = open(realPath.c_str(), O_RDONLY | O_DIRECTORY);
|
||||
if (tmpDirFd.get() == -1 || !lockFile(tmpDirFd.get(), ltWrite, false)) {
|
||||
debug("skipping locked tempdir '%s'", realPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printInfo("deleting '%1%'", path);
|
||||
|
||||
results.paths.insert(path);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -560,9 +560,15 @@ public:
|
|||
R"(
|
||||
If set to `true` (the default), any non-content-addressed path added
|
||||
or copied to the Nix store (e.g. when substituting from a binary
|
||||
cache) must have a valid signature, that is, be signed using one of
|
||||
the keys listed in `trusted-public-keys` or `secret-key-files`. Set
|
||||
to `false` to disable signature checking.
|
||||
cache) must have a signature by a trusted key. A trusted key is one
|
||||
listed in `trusted-public-keys`, or a public key counterpart to a
|
||||
private key stored in a file listed in `secret-key-files`.
|
||||
|
||||
Set to `false` to disable signature checking and trust all
|
||||
non-content-addressed paths unconditionally.
|
||||
|
||||
(Content-addressed paths are inherently trustworthy and thus
|
||||
unaffected by this configuration option.)
|
||||
)"};
|
||||
|
||||
Setting<StringSet> extraPlatforms{
|
||||
|
@ -613,6 +619,14 @@ public:
|
|||
are tried based on their Priority value, which each substituter can set
|
||||
independently. Lower value means higher priority.
|
||||
The default is `https://cache.nixos.org`, with a Priority of 40.
|
||||
|
||||
Nix will copy a store path from a remote store only if one
|
||||
of the following is true:
|
||||
|
||||
- the store object is signed by one of the [`trusted-public-keys`](#conf-trusted-public-keys)
|
||||
- the substituter is in the [`trusted-substituters`](#conf-trusted-substituters) list
|
||||
- the [`require-sigs`](#conf-require-sigs) option has been set to `false`
|
||||
- the store object is [output-addressed](glossary.md#gloss-output-addressed-store-object)
|
||||
)",
|
||||
{"binary-caches"}};
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd)
|
|||
txn.commit();
|
||||
}
|
||||
|
||||
writeFile(schemaPath, fmt("%d", nixCASchemaVersion));
|
||||
writeFile(schemaPath, fmt("%d", nixCASchemaVersion), 0666, true);
|
||||
lockFile(lockFd.get(), ltRead, true);
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ LocalStore::LocalStore(const Params & params)
|
|||
else if (curSchema == 0) { /* new store */
|
||||
curSchema = nixSchemaVersion;
|
||||
openDB(*state, true);
|
||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
|
||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
|
||||
}
|
||||
|
||||
else if (curSchema < nixSchemaVersion) {
|
||||
|
@ -329,7 +329,7 @@ LocalStore::LocalStore(const Params & params)
|
|||
txn.commit();
|
||||
}
|
||||
|
||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str());
|
||||
writeFile(schemaPath, (format("%1%") % nixSchemaVersion).str(), 0666, true);
|
||||
|
||||
lockFile(globalLock.get(), ltRead, true);
|
||||
}
|
||||
|
@ -751,7 +751,7 @@ void LocalStore::registerDrvOutput(const Realisation & info, CheckSigsFlag check
|
|||
if (checkSigs == NoCheckSigs || !realisationIsUntrusted(info))
|
||||
registerDrvOutput(info);
|
||||
else
|
||||
throw Error("cannot register realisation '%s' because it lacks a valid signature", info.outPath.to_string());
|
||||
throw Error("cannot register realisation '%s' because it lacks a signature by a trusted key", info.outPath.to_string());
|
||||
}
|
||||
|
||||
void LocalStore::registerDrvOutput(const Realisation & info)
|
||||
|
@ -1266,7 +1266,7 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source,
|
|||
RepairFlag repair, CheckSigsFlag checkSigs)
|
||||
{
|
||||
if (checkSigs && pathInfoIsUntrusted(info))
|
||||
throw Error("cannot add path '%s' because it lacks a valid signature", printStorePath(info.path));
|
||||
throw Error("cannot add path '%s' because it lacks a signature by a trusted key", printStorePath(info.path));
|
||||
|
||||
addTempRoot(info.path);
|
||||
|
||||
|
@ -1382,13 +1382,15 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name
|
|||
|
||||
std::unique_ptr<AutoDelete> delTempDir;
|
||||
Path tempPath;
|
||||
Path tempDir;
|
||||
AutoCloseFD tempDirFd;
|
||||
|
||||
if (!inMemory) {
|
||||
/* Drain what we pulled so far, and then keep on pulling */
|
||||
StringSource dumpSource { dump };
|
||||
ChainSource bothSource { dumpSource, source };
|
||||
|
||||
auto tempDir = createTempDir(realStoreDir, "add");
|
||||
std::tie(tempDir, tempDirFd) = createTempDirInStore();
|
||||
delTempDir = std::make_unique<AutoDelete>(tempDir);
|
||||
tempPath = tempDir + "/x";
|
||||
|
||||
|
@ -1507,18 +1509,24 @@ StorePath LocalStore::addTextToStore(
|
|||
|
||||
|
||||
/* Create a temporary directory in the store that won't be
|
||||
garbage-collected. */
|
||||
Path LocalStore::createTempDirInStore()
|
||||
garbage-collected until the returned FD is closed. */
|
||||
std::pair<Path, AutoCloseFD> LocalStore::createTempDirInStore()
|
||||
{
|
||||
Path tmpDir;
|
||||
Path tmpDirFn;
|
||||
AutoCloseFD tmpDirFd;
|
||||
bool lockedByUs = false;
|
||||
do {
|
||||
/* There is a slight possibility that `tmpDir' gets deleted by
|
||||
the GC between createTempDir() and addTempRoot(), so repeat
|
||||
until `tmpDir' exists. */
|
||||
tmpDir = createTempDir(realStoreDir);
|
||||
addTempRoot(parseStorePath(tmpDir));
|
||||
} while (!pathExists(tmpDir));
|
||||
return tmpDir;
|
||||
the GC between createTempDir() and when we acquire a lock on it.
|
||||
We'll repeat until 'tmpDir' exists and we've locked it. */
|
||||
tmpDirFn = createTempDir(realStoreDir, "tmp");
|
||||
tmpDirFd = open(tmpDirFn.c_str(), O_RDONLY | O_DIRECTORY);
|
||||
if (tmpDirFd.get() < 0) {
|
||||
continue;
|
||||
}
|
||||
lockedByUs = lockFile(tmpDirFd.get(), ltWrite, true);
|
||||
} while (!pathExists(tmpDirFn) || !lockedByUs);
|
||||
return {tmpDirFn, std::move(tmpDirFd)};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -256,7 +256,7 @@ private:
|
|||
|
||||
void findRuntimeRoots(Roots & roots, bool censor);
|
||||
|
||||
Path createTempDirInStore();
|
||||
std::pair<Path, AutoCloseFD> createTempDirInStore();
|
||||
|
||||
void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);
|
||||
|
||||
|
|
|
@ -75,6 +75,9 @@ struct NarAccessor : public FSAccessor
|
|||
createMember(path, {FSAccessor::Type::tRegular, false, 0, 0});
|
||||
}
|
||||
|
||||
void closeRegularFile() override
|
||||
{ }
|
||||
|
||||
void isExecutable() override
|
||||
{
|
||||
parents.top()->isExecutable = true;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -234,6 +234,7 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
|
|||
|
||||
else if (s == "contents" && type == tpRegular) {
|
||||
parseContents(sink, source, path);
|
||||
sink.closeRegularFile();
|
||||
}
|
||||
|
||||
else if (s == "executable" && type == tpRegular) {
|
||||
|
@ -324,6 +325,12 @@ struct RestoreSink : ParseSink
|
|||
if (!fd) throw SysError("creating file '%1%'", p);
|
||||
}
|
||||
|
||||
void closeRegularFile() override
|
||||
{
|
||||
/* Call close explicitly to make sure the error is checked */
|
||||
fd.close();
|
||||
}
|
||||
|
||||
void isExecutable() override
|
||||
{
|
||||
struct stat st;
|
||||
|
|
|
@ -60,6 +60,7 @@ struct ParseSink
|
|||
virtual void createDirectory(const Path & path) { };
|
||||
|
||||
virtual void createRegularFile(const Path & path) { };
|
||||
virtual void closeRegularFile() { };
|
||||
virtual void isExecutable() { };
|
||||
virtual void preallocateContents(uint64_t size) { };
|
||||
virtual void receiveContents(std::string_view data) { };
|
||||
|
|
|
@ -216,7 +216,7 @@ nlohmann::json Args::toJSON()
|
|||
if (flag->shortName)
|
||||
j["shortName"] = std::string(1, flag->shortName);
|
||||
if (flag->description != "")
|
||||
j["description"] = flag->description;
|
||||
j["description"] = trim(flag->description);
|
||||
j["category"] = flag->category;
|
||||
if (flag->handler.arity != ArityAny)
|
||||
j["arity"] = flag->handler.arity;
|
||||
|
@ -237,7 +237,7 @@ nlohmann::json Args::toJSON()
|
|||
}
|
||||
|
||||
auto res = nlohmann::json::object();
|
||||
res["description"] = description();
|
||||
res["description"] = trim(description());
|
||||
res["flags"] = std::move(flags);
|
||||
res["args"] = std::move(args);
|
||||
auto s = doc();
|
||||
|
@ -379,7 +379,7 @@ nlohmann::json MultiCommand::toJSON()
|
|||
auto j = command->toJSON();
|
||||
auto cat = nlohmann::json::object();
|
||||
cat["id"] = command->category();
|
||||
cat["description"] = categories[command->category()];
|
||||
cat["description"] = trim(categories[command->category()]);
|
||||
j["category"] = std::move(cat);
|
||||
cmds[name] = std::move(j);
|
||||
}
|
||||
|
|
|
@ -353,7 +353,7 @@ void readFile(const Path & path, Sink & sink)
|
|||
}
|
||||
|
||||
|
||||
void writeFile(const Path & path, std::string_view s, mode_t mode)
|
||||
void writeFile(const Path & path, std::string_view s, mode_t mode, bool sync)
|
||||
{
|
||||
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
||||
if (!fd)
|
||||
|
@ -364,10 +364,16 @@ void writeFile(const Path & path, std::string_view s, mode_t mode)
|
|||
e.addTrace({}, "writing file '%1%'", path);
|
||||
throw;
|
||||
}
|
||||
if (sync)
|
||||
fd.fsync();
|
||||
// Explicitly close to make sure exceptions are propagated.
|
||||
fd.close();
|
||||
if (sync)
|
||||
syncParent(path);
|
||||
}
|
||||
|
||||
|
||||
void writeFile(const Path & path, Source & source, mode_t mode)
|
||||
void writeFile(const Path & path, Source & source, mode_t mode, bool sync)
|
||||
{
|
||||
AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode);
|
||||
if (!fd)
|
||||
|
@ -386,6 +392,20 @@ void writeFile(const Path & path, Source & source, mode_t mode)
|
|||
e.addTrace({}, "writing file '%1%'", path);
|
||||
throw;
|
||||
}
|
||||
if (sync)
|
||||
fd.fsync();
|
||||
// Explicitly close to make sure exceptions are propagated.
|
||||
fd.close();
|
||||
if (sync)
|
||||
syncParent(path);
|
||||
}
|
||||
|
||||
void syncParent(const Path & path)
|
||||
{
|
||||
AutoCloseFD fd = open(dirOf(path).c_str(), O_RDONLY, 0);
|
||||
if (!fd)
|
||||
throw SysError("opening file '%1%'", path);
|
||||
fd.fsync();
|
||||
}
|
||||
|
||||
std::string readLine(int fd)
|
||||
|
@ -841,6 +861,20 @@ void AutoCloseFD::close()
|
|||
}
|
||||
}
|
||||
|
||||
void AutoCloseFD::fsync()
|
||||
{
|
||||
if (fd != -1) {
|
||||
int result;
|
||||
#if __APPLE__
|
||||
result = ::fcntl(fd, F_FULLFSYNC);
|
||||
#else
|
||||
result = ::fsync(fd);
|
||||
#endif
|
||||
if (result == -1)
|
||||
throw SysError("fsync file descriptor %1%", fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AutoCloseFD::operator bool() const
|
||||
{
|
||||
|
|
|
@ -115,9 +115,12 @@ std::string readFile(const Path & path);
|
|||
void readFile(const Path & path, Sink & sink);
|
||||
|
||||
/* Write a string to a file. */
|
||||
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666);
|
||||
void writeFile(const Path & path, std::string_view s, mode_t mode = 0666, bool sync = false);
|
||||
|
||||
void writeFile(const Path & path, Source & source, mode_t mode = 0666);
|
||||
void writeFile(const Path & path, Source & source, mode_t mode = 0666, bool sync = false);
|
||||
|
||||
/* Flush a file's parent directory to disk */
|
||||
void syncParent(const Path & path);
|
||||
|
||||
/* Read a line from a file descriptor. */
|
||||
std::string readLine(int fd);
|
||||
|
@ -231,6 +234,7 @@ public:
|
|||
explicit operator bool() const;
|
||||
int release();
|
||||
void close();
|
||||
void fsync();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||
Strings attrPaths;
|
||||
Strings left;
|
||||
RepairFlag repair = NoRepair;
|
||||
Path gcRoot;
|
||||
BuildMode buildMode = bmNormal;
|
||||
bool readStdin = false;
|
||||
|
||||
|
@ -167,9 +166,6 @@ static void main_nix_build(int argc, char * * argv)
|
|||
else if (*arg == "--out-link" || *arg == "-o")
|
||||
outLink = getArg(*arg, arg, end);
|
||||
|
||||
else if (*arg == "--add-root")
|
||||
gcRoot = getArg(*arg, arg, end);
|
||||
|
||||
else if (*arg == "--dry-run")
|
||||
dryRun = true;
|
||||
|
||||
|
|
|
@ -246,6 +246,7 @@ struct Common : InstallableCommand, MixProfile
|
|||
"NIX_LOG_FD",
|
||||
"NIX_REMOTE",
|
||||
"PPID",
|
||||
"SHELL",
|
||||
"SHELLOPTS",
|
||||
"SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt
|
||||
"TEMP",
|
||||
|
|
|
@ -66,6 +66,12 @@ R""(
|
|||
`nixpkgs#glibc` in `~/my-glibc` and want to compile another package
|
||||
against it.
|
||||
|
||||
* Run a series of script commands:
|
||||
|
||||
```console
|
||||
# nix develop --command bash -c "mkdir build && cmake .. && make"
|
||||
```
|
||||
|
||||
# Description
|
||||
|
||||
`nix develop` starts a `bash` shell that provides an interactive build
|
||||
|
|
|
@ -74,6 +74,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
addFlag({
|
||||
.longName = "help",
|
||||
.description = "Show usage information.",
|
||||
.category = miscCategory,
|
||||
.handler = {[&]() { throw HelpRequested(); }},
|
||||
});
|
||||
|
||||
|
@ -88,6 +89,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
|||
addFlag({
|
||||
.longName = "version",
|
||||
.description = "Show version information.",
|
||||
.category = miscCategory,
|
||||
.handler = {[&]() { showVersion = true; }},
|
||||
});
|
||||
|
||||
|
@ -95,12 +97,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 +191,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);
|
||||
|
@ -325,7 +329,7 @@ void mainWrapped(int argc, char * * argv)
|
|||
std::cout << "attrs\n"; break;
|
||||
}
|
||||
for (auto & s : *completions)
|
||||
std::cout << s.completion << "\t" << s.description << "\n";
|
||||
std::cout << s.completion << "\t" << trim(s.description) << "\n";
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ R""(
|
|||
|
||||
```console
|
||||
# nix copy --to /tmp/nix --trusted-public-keys '' nixpkgs#hello
|
||||
cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a valid signature
|
||||
cannot add path '/nix/store/zy9wbxwcygrwnh8n2w9qbbcr6zk87m26-libunistring-0.9.10' because it lacks a signature by a trusted key
|
||||
```
|
||||
|
||||
* Create a content-addressed representation of the current NixOS
|
||||
|
|
|
@ -23,6 +23,12 @@ R""(
|
|||
Hi everybody!
|
||||
```
|
||||
|
||||
* Run multiple commands in a shell environment:
|
||||
|
||||
```console
|
||||
# nix shell nixpkgs#gnumake -c sh -c "cd src && make"
|
||||
```
|
||||
|
||||
* Run GNU Hello in a chroot store:
|
||||
|
||||
```console
|
||||
|
|
|
@ -41,7 +41,7 @@ struct CmdVerify : StorePathsCommand
|
|||
addFlag({
|
||||
.longName = "sigs-needed",
|
||||
.shortName = 'n',
|
||||
.description = "Require that each path has at least *n* valid signatures.",
|
||||
.description = "Require that each path is signed by at least *n* different keys.",
|
||||
.labels = {"n"},
|
||||
.handler = {&sigsNeeded}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue