mirror of
https://github.com/NixOS/nix
synced 2025-07-07 10:11:47 +02:00
Merge branch 'master' into paths-from-stdin
This commit is contained in:
commit
1f394d2107
47 changed files with 322 additions and 119 deletions
|
@ -31,27 +31,24 @@ InstallableDerivedPath InstallableDerivedPath::parse(
|
|||
ExtendedOutputsSpec extendedOutputsSpec)
|
||||
{
|
||||
auto derivedPath = std::visit(overloaded {
|
||||
// If the user did not use ^, we treat the output more liberally.
|
||||
// If the user did not use ^, we treat the output more
|
||||
// liberally: we accept a symlink chain or an actual
|
||||
// store path.
|
||||
[&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
|
||||
// First, we accept a symlink chain or an actual store path.
|
||||
auto storePath = store->followLinksToStorePath(prefix);
|
||||
// Second, we see if the store path ends in `.drv` to decide what sort
|
||||
// of derived path they want.
|
||||
//
|
||||
// This handling predates the `^` syntax. The `^*` in
|
||||
// `/nix/store/hash-foo.drv^*` unambiguously means "do the
|
||||
// `DerivedPath::Built` case", so plain `/nix/store/hash-foo.drv` could
|
||||
// also unambiguously mean "do the DerivedPath::Opaque` case".
|
||||
//
|
||||
// Issue #7261 tracks reconsidering this `.drv` dispatching.
|
||||
return storePath.isDerivation()
|
||||
? (DerivedPath) DerivedPath::Built {
|
||||
.drvPath = std::move(storePath),
|
||||
.outputs = OutputsSpec::All {},
|
||||
}
|
||||
: (DerivedPath) DerivedPath::Opaque {
|
||||
.path = std::move(storePath),
|
||||
// Remove this prior to stabilizing the new CLI.
|
||||
if (storePath.isDerivation()) {
|
||||
auto oldDerivedPath = DerivedPath::Built {
|
||||
.drvPath = storePath,
|
||||
.outputs = OutputsSpec::All { },
|
||||
};
|
||||
warn(
|
||||
"The interpretation of store paths arguments ending in `.drv` recently changed. If this command is now failing try again with '%s'",
|
||||
oldDerivedPath.to_string(*store));
|
||||
};
|
||||
return DerivedPath::Opaque {
|
||||
.path = std::move(storePath),
|
||||
};
|
||||
},
|
||||
// If the user did use ^, we just do exactly what is written.
|
||||
[&](const ExtendedOutputsSpec::Explicit & outputSpec) -> DerivedPath {
|
||||
|
|
|
@ -677,9 +677,12 @@ StorePathSet Installable::toDerivations(
|
|||
for (const auto & b : i->toDerivedPaths())
|
||||
std::visit(overloaded {
|
||||
[&](const DerivedPath::Opaque & bo) {
|
||||
if (!useDeriver)
|
||||
throw Error("argument '%s' did not evaluate to a derivation", i->what());
|
||||
drvPaths.insert(getDeriver(store, *i, bo.path));
|
||||
drvPaths.insert(
|
||||
bo.path.isDerivation()
|
||||
? bo.path
|
||||
: useDeriver
|
||||
? getDeriver(store, *i, bo.path)
|
||||
: throw Error("argument '%s' did not evaluate to a derivation", i->what()));
|
||||
},
|
||||
[&](const DerivedPath::Built & bfd) {
|
||||
drvPaths.insert(bfd.drvPath);
|
||||
|
|
|
@ -63,6 +63,11 @@ public:
|
|||
one that contains a commit hash or content hash. */
|
||||
bool isLocked() const { return locked; }
|
||||
|
||||
/* Check whether the input carries all necessary info required
|
||||
for cache insertion and substitution.
|
||||
These fields are used to uniquely identify cached trees
|
||||
within the "tarball TTL" window without necessarily
|
||||
indicating that the input's origin is unchanged. */
|
||||
bool hasAllInfo() const;
|
||||
|
||||
bool operator ==(const Input & other) const;
|
||||
|
|
|
@ -92,13 +92,11 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir,
|
|||
if (S_ISLNK(dstSt.st_mode)) {
|
||||
auto prevPriority = state.priorities[dstFile];
|
||||
if (prevPriority == priority)
|
||||
throw Error(
|
||||
"files '%1%' and '%2%' have the same priority %3%; "
|
||||
"use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' "
|
||||
"or type 'nix profile install --help' if using 'nix profile' to find out how "
|
||||
"to change the priority of one of the conflicting packages"
|
||||
" (0 being the highest priority)",
|
||||
srcFile, readLink(dstFile), priority);
|
||||
throw BuildEnvFileConflictError(
|
||||
readLink(dstFile),
|
||||
srcFile,
|
||||
priority
|
||||
);
|
||||
if (prevPriority < priority)
|
||||
continue;
|
||||
if (unlink(dstFile.c_str()) == -1)
|
||||
|
|
|
@ -12,6 +12,32 @@ struct Package {
|
|||
Package(const Path & path, bool active, int priority) : path{path}, active{active}, priority{priority} {}
|
||||
};
|
||||
|
||||
class BuildEnvFileConflictError : public Error
|
||||
{
|
||||
public:
|
||||
const Path fileA;
|
||||
const Path fileB;
|
||||
int priority;
|
||||
|
||||
BuildEnvFileConflictError(
|
||||
const Path fileA,
|
||||
const Path fileB,
|
||||
int priority
|
||||
)
|
||||
: Error(
|
||||
"Unable to build profile. There is a conflict for the following files:\n"
|
||||
"\n"
|
||||
" %1%\n"
|
||||
" %2%",
|
||||
fileA,
|
||||
fileB
|
||||
)
|
||||
, fileA(fileA)
|
||||
, fileB(fileB)
|
||||
, priority(priority)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::vector<Package> Packages;
|
||||
|
||||
void buildProfile(const Path & out, Packages && pkgs);
|
||||
|
|
|
@ -88,6 +88,10 @@ struct curlFileTransfer : public FileTransfer
|
|||
{request.uri}, request.parentAct)
|
||||
, callback(std::move(callback))
|
||||
, finalSink([this](std::string_view data) {
|
||||
if (errorSink) {
|
||||
(*errorSink)(data);
|
||||
}
|
||||
|
||||
if (this->request.dataCallback) {
|
||||
auto httpStatus = getHTTPStatus();
|
||||
|
||||
|
@ -163,8 +167,6 @@ struct curlFileTransfer : public FileTransfer
|
|||
}
|
||||
}
|
||||
|
||||
if (errorSink)
|
||||
(*errorSink)({(char *) contents, realSize});
|
||||
(*decompressionSink)({(char *) contents, realSize});
|
||||
|
||||
return realSize;
|
||||
|
|
|
@ -38,8 +38,6 @@ class RemoteStore : public virtual RemoteStoreConfig,
|
|||
{
|
||||
public:
|
||||
|
||||
virtual bool sameMachine() = 0;
|
||||
|
||||
RemoteStore(const Params & params);
|
||||
|
||||
/* Implementations of abstract store API methods. */
|
||||
|
|
|
@ -49,9 +49,6 @@ public:
|
|||
return *uriSchemes().begin() + "://" + host;
|
||||
}
|
||||
|
||||
bool sameMachine() override
|
||||
{ return false; }
|
||||
|
||||
// FIXME extend daemon protocol, move implementation to RemoteStore
|
||||
std::optional<std::string> getBuildLogExact(const StorePath & path) override
|
||||
{ unsupported("getBuildLogExact"); }
|
||||
|
|
|
@ -855,6 +855,7 @@ json Store::pathInfoToJSON(const StorePathSet & storePaths,
|
|||
auto info = queryPathInfo(storePath);
|
||||
|
||||
jsonPath["path"] = printStorePath(info->path);
|
||||
jsonPath["valid"] = true;
|
||||
jsonPath["narHash"] = info->narHash.to_string(hashBase, true);
|
||||
jsonPath["narSize"] = info->narSize;
|
||||
|
||||
|
|
|
@ -29,9 +29,6 @@ public:
|
|||
static std::set<std::string> uriSchemes()
|
||||
{ return {"unix"}; }
|
||||
|
||||
bool sameMachine() override
|
||||
{ return true; }
|
||||
|
||||
ref<FSAccessor> getFSAccessor() override
|
||||
{ return LocalFSStore::getFSAccessor(); }
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ void Logger::warn(const std::string & msg)
|
|||
|
||||
void Logger::writeToStdout(std::string_view s)
|
||||
{
|
||||
std::cout << s << "\n";
|
||||
writeFull(STDOUT_FILENO, s);
|
||||
writeFull(STDOUT_FILENO, "\n");
|
||||
}
|
||||
|
||||
class SimpleLogger : public Logger
|
||||
|
@ -84,7 +85,7 @@ public:
|
|||
|
||||
void startActivity(ActivityId act, Verbosity lvl, ActivityType type,
|
||||
const std::string & s, const Fields & fields, ActivityId parent)
|
||||
override
|
||||
override
|
||||
{
|
||||
if (lvl <= verbosity && !s.empty())
|
||||
log(lvl, s + "...");
|
||||
|
|
|
@ -102,11 +102,9 @@ public:
|
|||
virtual void writeToStdout(std::string_view s);
|
||||
|
||||
template<typename... Args>
|
||||
inline void cout(const std::string & fs, const Args & ... args)
|
||||
inline void cout(const Args & ... args)
|
||||
{
|
||||
boost::format f(fs);
|
||||
formatHelper(f, args...);
|
||||
writeToStdout(f.str());
|
||||
writeToStdout(fmt(args...));
|
||||
}
|
||||
|
||||
virtual std::optional<char> ask(std::string_view s)
|
||||
|
|
|
@ -139,11 +139,11 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile
|
|||
for (auto & buildable : buildables) {
|
||||
std::visit(overloaded {
|
||||
[&](const BuiltPath::Opaque & bo) {
|
||||
std::cout << store->printStorePath(bo.path) << std::endl;
|
||||
logger->cout(store->printStorePath(bo.path));
|
||||
},
|
||||
[&](const BuiltPath::Built & bfd) {
|
||||
for (auto & output : bfd.outputs) {
|
||||
std::cout << store->printStorePath(output.second) << std::endl;
|
||||
logger->cout(store->printStorePath(output.second));
|
||||
}
|
||||
},
|
||||
}, buildable.path.raw());
|
||||
|
|
|
@ -17,7 +17,7 @@ struct MixCat : virtual Args
|
|||
if (st.type != FSAccessor::Type::tRegular)
|
||||
throw Error("path '%1%' is not a regular file", path);
|
||||
|
||||
std::cout << accessor->readFile(path);
|
||||
writeFull(STDOUT_FILENO, accessor->readFile(path));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ struct CmdDescribeStores : Command, MixJSON
|
|||
res[storeName] = storeConfig->toJSON();
|
||||
}
|
||||
if (json) {
|
||||
std::cout << res;
|
||||
logger->cout("%s", res);
|
||||
} else {
|
||||
for (auto & [storeName, storeConfig] : res.items()) {
|
||||
std::cout << "## " << storeName << std::endl << std::endl;
|
||||
|
|
|
@ -97,7 +97,7 @@ void printClosureDiff(
|
|||
items.push_back(fmt("%s → %s", showVersions(removed), showVersions(added)));
|
||||
if (showDelta)
|
||||
items.push_back(fmt("%s%+.1f KiB" ANSI_NORMAL, sizeDelta > 0 ? ANSI_RED : ANSI_GREEN, sizeDelta / 1024.0));
|
||||
std::cout << fmt("%s%s: %s\n", indent, name, concatStringsSep(", ", items));
|
||||
logger->cout("%s%s: %s", indent, name, concatStringsSep(", ", items));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,11 +112,11 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
|
|||
|
||||
else if (raw) {
|
||||
stopProgressBar();
|
||||
std::cout << *state->coerceToString(noPos, *v, context, "while generating the eval command output");
|
||||
writeFull(STDOUT_FILENO, *state->coerceToString(noPos, *v, context, "while generating the eval command output"));
|
||||
}
|
||||
|
||||
else if (json) {
|
||||
std::cout << printValueAsJSON(*state, true, *v, pos, context, false).dump() << std::endl;
|
||||
logger->cout("%s", printValueAsJSON(*state, true, *v, pos, context, false));
|
||||
}
|
||||
|
||||
else {
|
||||
|
|
|
@ -952,7 +952,7 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
|
|||
{"path", store->printStorePath(flake.flake.sourceInfo->storePath)},
|
||||
{"inputs", traverse(*flake.lockFile.root)},
|
||||
};
|
||||
std::cout << jsonRoot.dump() << std::endl;
|
||||
logger->cout("%s", jsonRoot);
|
||||
} else {
|
||||
traverse(*flake.lockFile.root);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ struct CmdLog : InstallableCommand
|
|||
if (!log) continue;
|
||||
stopProgressBar();
|
||||
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
|
||||
std::cout << *log;
|
||||
writeFull(STDOUT_FILENO, *log);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ struct MixLs : virtual Args, MixJSON
|
|||
if (json) {
|
||||
if (showDirectory)
|
||||
throw UsageError("'--directory' is useless with '--json'");
|
||||
std::cout << listNar(accessor, path, recursive);
|
||||
logger->cout("%s", listNar(accessor, path, recursive));
|
||||
} else
|
||||
listText(accessor);
|
||||
}
|
||||
|
|
|
@ -292,7 +292,7 @@ void mainWrapped(int argc, char * * argv)
|
|||
NixArgs args;
|
||||
|
||||
if (argc == 2 && std::string(argv[1]) == "__dump-args") {
|
||||
std::cout << args.toJSON().dump() << "\n";
|
||||
logger->cout("%s", args.toJSON());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,7 @@ void mainWrapped(int argc, char * * argv)
|
|||
b["doc"] = trim(stripIndentation(primOp->doc));
|
||||
res[state.symbols[builtin.name]] = std::move(b);
|
||||
}
|
||||
std::cout << res.dump() << "\n";
|
||||
logger->cout("%s", res);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -321,14 +321,14 @@ void mainWrapped(int argc, char * * argv)
|
|||
if (completions) {
|
||||
switch (completionType) {
|
||||
case ctNormal:
|
||||
std::cout << "normal\n"; break;
|
||||
logger->cout("normal"); break;
|
||||
case ctFilenames:
|
||||
std::cout << "filenames\n"; break;
|
||||
logger->cout("filenames"); break;
|
||||
case ctAttrs:
|
||||
std::cout << "attrs\n"; break;
|
||||
logger->cout("attrs"); break;
|
||||
}
|
||||
for (auto & s : *completions)
|
||||
std::cout << s.completion << "\t" << trim(s.description) << "\n";
|
||||
logger->cout(s.completion + "\t" + trim(s.description));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
|
|||
}
|
||||
auto json = json::object();
|
||||
json["rewrites"] = jsonRewrites;
|
||||
std::cout << json.dump();
|
||||
logger->cout("%s", json);
|
||||
} else {
|
||||
for (auto & path : storePaths) {
|
||||
auto i = remappings.find(path);
|
||||
|
|
|
@ -234,9 +234,9 @@ static int main_nix_prefetch_url(int argc, char * * argv)
|
|||
if (!printPath)
|
||||
printInfo("path is '%s'", store->printStorePath(storePath));
|
||||
|
||||
std::cout << printHash16or32(hash) << std::endl;
|
||||
logger->cout(printHash16or32(hash));
|
||||
if (printPath)
|
||||
std::cout << store->printStorePath(storePath) << std::endl;
|
||||
logger->cout(store->printStorePath(storePath));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -228,12 +228,12 @@ struct ProfileManifest
|
|||
|
||||
while (i != prevElems.end() || j != curElems.end()) {
|
||||
if (j != curElems.end() && (i == prevElems.end() || i->describe() > j->describe())) {
|
||||
std::cout << fmt("%s%s: ∅ -> %s\n", indent, j->describe(), j->versions());
|
||||
logger->cout("%s%s: ∅ -> %s", indent, j->describe(), j->versions());
|
||||
changes = true;
|
||||
++j;
|
||||
}
|
||||
else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) {
|
||||
std::cout << fmt("%s%s: %s -> ∅\n", indent, i->describe(), i->versions());
|
||||
logger->cout("%s%s: %s -> ∅", indent, i->describe(), i->versions());
|
||||
changes = true;
|
||||
++i;
|
||||
}
|
||||
|
@ -241,7 +241,7 @@ struct ProfileManifest
|
|||
auto v1 = i->versions();
|
||||
auto v2 = j->versions();
|
||||
if (v1 != v2) {
|
||||
std::cout << fmt("%s%s: %s -> %s\n", indent, i->describe(), v1, v2);
|
||||
logger->cout("%s%s: %s -> %s", indent, i->describe(), v1, v2);
|
||||
changes = true;
|
||||
}
|
||||
++i;
|
||||
|
@ -250,7 +250,7 @@ struct ProfileManifest
|
|||
}
|
||||
|
||||
if (!changes)
|
||||
std::cout << fmt("%sNo changes.\n", indent);
|
||||
logger->cout("%sNo changes.", indent);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -330,7 +330,63 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
|
|||
manifest.elements.push_back(std::move(element));
|
||||
}
|
||||
|
||||
updateProfile(manifest.build(store));
|
||||
try {
|
||||
updateProfile(manifest.build(store));
|
||||
} catch (BuildEnvFileConflictError & conflictError) {
|
||||
// FIXME use C++20 std::ranges once macOS has it
|
||||
// See https://github.com/NixOS/nix/compare/3efa476c5439f8f6c1968a6ba20a31d1239c2f04..1fe5d172ece51a619e879c4b86f603d9495cc102
|
||||
auto findRefByFilePath = [&]<typename Iterator>(Iterator begin, Iterator end) {
|
||||
for (auto it = begin; it != end; it++) {
|
||||
auto profileElement = *it;
|
||||
for (auto & storePath : profileElement.storePaths) {
|
||||
if (conflictError.fileA.starts_with(store->printStorePath(storePath))) {
|
||||
return std::pair(conflictError.fileA, profileElement.source->originalRef);
|
||||
}
|
||||
if (conflictError.fileB.starts_with(store->printStorePath(storePath))) {
|
||||
return std::pair(conflictError.fileB, profileElement.source->originalRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw conflictError;
|
||||
};
|
||||
// There are 2 conflicting files. We need to find out which one is from the already installed package and
|
||||
// which one is the package that is the new package that is being installed.
|
||||
// The first matching package is the one that was already installed (original).
|
||||
auto [originalConflictingFilePath, originalConflictingRef] = findRefByFilePath(manifest.elements.begin(), manifest.elements.end());
|
||||
// The last matching package is the one that was going to be installed (new).
|
||||
auto [newConflictingFilePath, newConflictingRef] = findRefByFilePath(manifest.elements.rbegin(), manifest.elements.rend());
|
||||
|
||||
throw Error(
|
||||
"An existing package already provides the following file:\n"
|
||||
"\n"
|
||||
" %1%\n"
|
||||
"\n"
|
||||
"This is the conflicting file from the new package:\n"
|
||||
"\n"
|
||||
" %2%\n"
|
||||
"\n"
|
||||
"To remove the existing package:\n"
|
||||
"\n"
|
||||
" nix profile remove %3%\n"
|
||||
"\n"
|
||||
"The new package can also be installed next to the existing one by assigning a different priority.\n"
|
||||
"The conflicting packages have a priority of %5%.\n"
|
||||
"To prioritise the new package:\n"
|
||||
"\n"
|
||||
" nix profile install %4% --priority %6%\n"
|
||||
"\n"
|
||||
"To prioritise the existing package:\n"
|
||||
"\n"
|
||||
" nix profile install %4% --priority %7%\n",
|
||||
originalConflictingFilePath,
|
||||
newConflictingFilePath,
|
||||
originalConflictingRef.to_string(),
|
||||
newConflictingRef.to_string(),
|
||||
conflictError.priority,
|
||||
conflictError.priority - 1,
|
||||
conflictError.priority + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -584,9 +640,9 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile
|
|||
|
||||
for (auto & gen : gens) {
|
||||
if (prevGen) {
|
||||
if (!first) std::cout << "\n";
|
||||
if (!first) logger->cout("");
|
||||
first = false;
|
||||
std::cout << fmt("Version %d -> %d:\n", prevGen->number, gen.number);
|
||||
logger->cout("Version %d -> %d:", prevGen->number, gen.number);
|
||||
printClosureDiff(store,
|
||||
store->followLinksToStorePath(prevGen->path),
|
||||
store->followLinksToStorePath(gen.path),
|
||||
|
@ -622,10 +678,10 @@ struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile
|
|||
for (auto & gen : gens) {
|
||||
ProfileManifest manifest(*getEvalState(), gen.path);
|
||||
|
||||
if (!first) std::cout << "\n";
|
||||
if (!first) logger->cout("");
|
||||
first = false;
|
||||
|
||||
std::cout << fmt("Version %s%d" ANSI_NORMAL " (%s)%s:\n",
|
||||
logger->cout("Version %s%d" ANSI_NORMAL " (%s)%s:",
|
||||
gen.number == curGen ? ANSI_GREEN : ANSI_BOLD,
|
||||
gen.number,
|
||||
std::put_time(std::gmtime(&gen.creationTime), "%Y-%m-%d"),
|
||||
|
|
|
@ -65,18 +65,16 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON
|
|||
|
||||
res.push_back(currentPath);
|
||||
}
|
||||
std::cout << res.dump();
|
||||
logger->cout("%s", res);
|
||||
}
|
||||
else {
|
||||
for (auto & path : realisations) {
|
||||
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
|
||||
std::cout <<
|
||||
realisation->id.to_string() << " " <<
|
||||
store->printStorePath(realisation->outPath);
|
||||
logger->cout("%s %s",
|
||||
realisation->id.to_string(),
|
||||
store->printStorePath(realisation->outPath));
|
||||
} else
|
||||
std::cout << store->printStorePath(path.path());
|
||||
|
||||
std::cout << std::endl;
|
||||
logger->cout("%s", store->printStorePath(path.path()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,9 +196,8 @@ struct CmdSearch : InstallableCommand, MixJSON
|
|||
for (auto & cursor : installable->getCursors(*state))
|
||||
visit(*cursor, cursor->getAttrPath(), true);
|
||||
|
||||
if (json) {
|
||||
std::cout << jsonOut->dump() << std::endl;
|
||||
}
|
||||
if (json)
|
||||
logger->cout("%s", *jsonOut);
|
||||
|
||||
if (!json && !results)
|
||||
throw Error("no results for the given search term(s)!");
|
||||
|
|
|
@ -57,7 +57,7 @@ struct CmdShowDerivation : InstallablesCommand
|
|||
jsonRoot[store->printStorePath(drvPath)] =
|
||||
store->readDerivation(drvPath).toJSON(*store);
|
||||
}
|
||||
std::cout << jsonRoot.dump(2) << std::endl;
|
||||
logger->cout(jsonRoot.dump(2));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ struct CmdKeyGenerateSecret : Command
|
|||
if (!keyName)
|
||||
throw UsageError("required argument '--key-name' is missing");
|
||||
|
||||
std::cout << SecretKey::generate(*keyName).to_string();
|
||||
writeFull(STDOUT_FILENO, SecretKey::generate(*keyName).to_string());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -194,7 +194,7 @@ struct CmdKeyConvertSecretToPublic : Command
|
|||
void run() override
|
||||
{
|
||||
SecretKey secretKey(drainFD(STDIN_FILENO));
|
||||
std::cout << secretKey.toPublicKey().to_string();
|
||||
writeFull(STDOUT_FILENO, secretKey.toPublicKey().to_string());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue