diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index ff8ba2724147..0409370c8ce3 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -24,8 +24,7 @@ using namespace nix; using std::cin; -static void handleAlarm(int sig) { -} +static void handleAlarm(int sig) {} std::string escapeUri(std::string uri) { @@ -40,13 +39,15 @@ static AutoCloseFD openSlotLock(const Machine & m, uint64_t slot) return openLockFile(fmt("%s/%s-%d", currentLoad, escapeUri(m.storeUri), slot), true); } -static bool allSupportedLocally(Store & store, const std::set& requiredFeatures) { +static bool allSupportedLocally(Store & store, const std::set & requiredFeatures) +{ for (auto & feature : requiredFeatures) - if (!store.systemFeatures.get().count(feature)) return false; + if (!store.systemFeatures.get().count(feature)) + return false; return true; } -static int main_build_remote(int argc, char * * argv) +static int main_build_remote(int argc, char ** argv) { { logger = makeJSONLogger(*logger); @@ -82,7 +83,7 @@ static int main_build_remote(int argc, char * * argv) that gets cleared on reboot, but it wouldn't work on macOS. */ auto currentLoadName = "/current-load"; if (auto localStore = store.dynamic_pointer_cast()) - currentLoad = std::string { localStore->stateDir } + currentLoadName; + currentLoad = std::string{localStore->stateDir} + currentLoadName; else currentLoad = settings.nixStateDir + currentLoadName; @@ -104,18 +105,21 @@ static int main_build_remote(int argc, char * * argv) try { auto s = readString(source); - if (s != "try") return 0; - } catch (EndOfFile &) { return 0; } + if (s != "try") + return 0; + } catch (EndOfFile &) { + return 0; + } auto amWilling = readInt(source); auto neededSystem = readString(source); drvPath = store->parseStorePath(readString(source)); auto requiredFeatures = readStrings>(source); - auto canBuildLocally = amWilling - && ( neededSystem == settings.thisSystem - || settings.extraPlatforms.get().count(neededSystem) > 0) - && allSupportedLocally(*store, requiredFeatures); + auto canBuildLocally = + amWilling + && (neededSystem == settings.thisSystem || settings.extraPlatforms.get().count(neededSystem) > 0) + && allSupportedLocally(*store, requiredFeatures); /* Error ignored here, will be caught later */ mkdir(currentLoad.c_str(), 0777); @@ -134,12 +138,9 @@ static int main_build_remote(int argc, char * * argv) if (m.enabled && (neededSystem == "builtin" - || std::find(m.systemTypes.begin(), - m.systemTypes.end(), - neededSystem) != m.systemTypes.end()) && - m.allSupported(requiredFeatures) && - m.mandatoryMet(requiredFeatures)) - { + || std::find(m.systemTypes.begin(), m.systemTypes.end(), neededSystem) + != m.systemTypes.end()) + && m.allSupported(requiredFeatures) && m.mandatoryMet(requiredFeatures)) { rightType = true; AutoCloseFD free; uint64_t load = 0; @@ -181,8 +182,7 @@ static int main_build_remote(int argc, char * * argv) if (!bestSlotLock) { if (rightType && !canBuildLocally) std::cerr << "# postpone\n"; - else - { + else { // build the hint template. std::string errorText = "Failed to find a machine for remote build!\n" @@ -201,16 +201,11 @@ static int main_build_remote(int argc, char * * argv) drvstr = ""; auto error = hintformat(errorText); - error - % drvstr - % neededSystem - % concatStringsSep(", ", requiredFeatures) + error % drvstr % neededSystem % concatStringsSep(", ", requiredFeatures) % machines.size(); for (auto & m : machines) - error - % concatStringsSep>(", ", m.systemTypes) - % m.maxJobs + error % concatStringsSep>(", ", m.systemTypes) % m.maxJobs % concatStringsSep(", ", m.supportedFeatures) % concatStringsSep(", ", m.mandatoryFeatures); @@ -239,9 +234,8 @@ static int main_build_remote(int argc, char * * argv) } catch (std::exception & e) { auto msg = chomp(drainFD(5, false)); - printError("cannot build on '%s': %s%s", - bestMachine->storeUri, e.what(), - msg.empty() ? "" : ": " + msg); + printError( + "cannot build on '%s': %s%s", bestMachine->storeUri, e.what(), msg.empty() ? "" : ": " + msg); bestMachine->enabled = false; continue; } @@ -250,7 +244,7 @@ static int main_build_remote(int argc, char * * argv) } } -connected: + connected: close(5); std::cerr << "# accept\n" << storeUri << "\n"; @@ -303,7 +297,7 @@ static int main_build_remote(int argc, char * * argv) if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) && !drv.type().hasKnownOutputPaths()) { for (auto & outputName : wantedOutputs) { auto thisOutputHash = outputHashes.at(outputName); - auto thisOutputId = DrvOutput{ thisOutputHash, outputName }; + auto thisOutputId = DrvOutput{thisOutputHash, outputName}; if (!store->queryRealisation(thisOutputId)) { debug("missing output %s", outputName); assert(result.builtOutputs.count(thisOutputId)); diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index 7f8072d75fcb..af7849723cea 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -7,7 +7,7 @@ #include -extern char * * environ __attribute__((weak)); +extern char ** environ __attribute__((weak)); namespace nix { @@ -20,7 +20,8 @@ nix::Commands RegisterCommand::getCommandsFor(const std::vector & p if (name.size() == prefix.size() + 1) { bool equal = true; for (size_t i = 0; i < prefix.size(); ++i) - if (name[i] != prefix[i]) equal = false; + if (name[i] != prefix[i]) + equal = false; if (equal) res.insert_or_assign(name[prefix.size()], command); } @@ -33,9 +34,7 @@ nlohmann::json NixMultiCommand::toJSON() return MultiCommand::toJSON(); } -StoreCommand::StoreCommand() -{ -} +StoreCommand::StoreCommand() {} ref StoreCommand::getStore() { @@ -110,17 +109,15 @@ ref EvalCommand::getEvalState() { if (!evalState) { evalState = - #if HAVE_BOEHMGC - std::allocate_shared(traceable_allocator(), - searchPath, getEvalStore(), getStore()) - #else - std::make_shared( - searchPath, getEvalStore(), getStore()) - #endif +#if HAVE_BOEHMGC + std::allocate_shared(traceable_allocator(), searchPath, getEvalStore(), getStore()) +#else + std::make_shared(searchPath, getEvalStore(), getStore()) +#endif ; if (startReplOnEvalErrors) { - evalState->debugRepl = &runRepl; + evalState->debugRepl = &runRepl; }; } return ref(evalState); @@ -183,8 +180,7 @@ void BuiltPathsCommand::run(ref store) StorePathsCommand::StorePathsCommand(bool recursive) : BuiltPathsCommand(recursive) -{ -} +{} void StorePathsCommand::run(ref store, BuiltPaths && paths) { @@ -211,11 +207,9 @@ Strings editorFor(const Path & file, uint32_t line) { auto editor = getEnv("EDITOR").value_or("cat"); auto args = tokenizeString(editor); - if (line > 0 && ( - editor.find("emacs") != std::string::npos || - editor.find("nano") != std::string::npos || - editor.find("vim") != std::string::npos || - editor.find("kak") != std::string::npos)) + if (line > 0 + && (editor.find("emacs") != std::string::npos || editor.find("nano") != std::string::npos + || editor.find("vim") != std::string::npos || editor.find("kak") != std::string::npos)) args.push_back(fmt("+%d", line)); args.push_back(file); return args; @@ -223,48 +217,48 @@ Strings editorFor(const Path & file, uint32_t line) MixProfile::MixProfile() { - addFlag({ - .longName = "profile", - .description = "The profile to update.", - .labels = {"path"}, - .handler = {&profile}, - .completer = completePath - }); + addFlag( + {.longName = "profile", + .description = "The profile to update.", + .labels = {"path"}, + .handler = {&profile}, + .completer = completePath}); } void MixProfile::updateProfile(const StorePath & storePath) { - if (!profile) return; + if (!profile) + return; auto store = getStore().dynamic_pointer_cast(); - if (!store) throw Error("'--profile' is not supported for this Nix store"); + if (!store) + throw Error("'--profile' is not supported for this Nix store"); auto profile2 = absPath(*profile); - switchLink(profile2, - createGeneration( - ref(store), - profile2, storePath)); + switchLink(profile2, createGeneration(ref(store), profile2, storePath)); } void MixProfile::updateProfile(const BuiltPaths & buildables) { - if (!profile) return; + if (!profile) + return; std::vector result; for (auto & buildable : buildables) { - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - result.push_back(bo.path); + std::visit( + overloaded{ + [&](const BuiltPath::Opaque & bo) { result.push_back(bo.path); }, + [&](const BuiltPath::Built & bfd) { + for (auto & output : bfd.outputs) { + result.push_back(output.second); + } + }, }, - [&](const BuiltPath::Built & bfd) { - for (auto & output : bfd.outputs) { - result.push_back(output.second); - } - }, - }, buildable.raw()); + buildable.raw()); } if (result.size() != 1) - throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size()); + throw UsageError( + "'--profile' requires that the arguments produce a single store path, but there are %d", result.size()); updateProfile(result[0]); } @@ -274,7 +268,8 @@ MixDefaultProfile::MixDefaultProfile() profile = getDefaultProfile(); } -MixEnvironment::MixEnvironment() : ignoreEnvironment(false) +MixEnvironment::MixEnvironment() + : ignoreEnvironment(false) { addFlag({ .longName = "ignore-environment", @@ -300,14 +295,16 @@ MixEnvironment::MixEnvironment() : ignoreEnvironment(false) }); } -void MixEnvironment::setEnviron() { +void MixEnvironment::setEnviron() +{ if (ignoreEnvironment) { if (!unset.empty()) throw UsageError("--unset does not make sense with --ignore-environment"); for (const auto & var : keep) { auto val = getenv(var.c_str()); - if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val)); + if (val) + stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val)); } vectorEnv = stringsToCharPtrs(stringsEnv); diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 8982f21d0864..6854b501a7b2 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -12,7 +12,7 @@ namespace nix { extern std::string programPath; -extern char * * savedArgv; +extern char ** savedArgv; class EvalState; struct Pos; @@ -80,7 +80,9 @@ struct MixFlakeOptions : virtual Args, EvalCommand MixFlakeOptions(); virtual std::optional getFlakeRefForCompletion() - { return {}; } + { + return {}; + } }; struct SourceExprCommand : virtual Args, MixFlakeOptions @@ -94,11 +96,9 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions SourceExprCommand(bool supportReadOnlyMode = false); - std::vector> parseInstallables( - ref store, std::vector ss); + std::vector> parseInstallables(ref store, std::vector ss); - std::shared_ptr parseInstallable( - ref store, const std::string & installable); + std::shared_ptr parseInstallable(ref store, const std::string & installable); virtual Strings getDefaultFlakeAttrPaths(); @@ -117,7 +117,10 @@ struct InstallablesCommand : virtual Args, SourceExprCommand void prepare() override; - virtual bool useDefaultInstallables() { return true; } + virtual bool useDefaultInstallables() + { + return true; + } std::optional getFlakeRefForCompletion() override; @@ -167,7 +170,10 @@ public: void run(ref store) override; - bool useDefaultInstallables() override { return !all; } + bool useDefaultInstallables() override + { + return !all; + } }; struct StorePathsCommand : public BuiltPathsCommand @@ -197,10 +203,10 @@ struct RegisterCommand typedef std::map, std::function()>> Commands; static Commands * commands; - RegisterCommand(std::vector && name, - std::function()> command) + RegisterCommand(std::vector && name, std::function()> command) { - if (!commands) commands = new Commands; + if (!commands) + commands = new Commands; commands->emplace(name, command); } @@ -210,13 +216,13 @@ struct RegisterCommand template static RegisterCommand registerCommand(const std::string & name) { - return RegisterCommand({name}, [](){ return make_ref(); }); + return RegisterCommand({name}, []() { return make_ref(); }); } template static RegisterCommand registerCommand2(std::vector && name) { - return RegisterCommand(std::move(name), [](){ return make_ref(); }); + return RegisterCommand(std::move(name), []() { return make_ref(); }); } /* Helper function to generate args that invoke $EDITOR on @@ -242,16 +248,18 @@ struct MixDefaultProfile : MixProfile MixDefaultProfile(); }; -struct MixEnvironment : virtual Args { +struct MixEnvironment : virtual Args +{ StringSet keep, unset; Strings stringsEnv; - std::vector vectorEnv; + std::vector vectorEnv; bool ignoreEnvironment; MixEnvironment(); - /* Modify global environ based on ignoreEnvironment, keep, and unset. It's expected that exec will be called before this class goes out of scope, otherwise environ will become invalid. */ + /* Modify global environ based on ignoreEnvironment, keep, and unset. It's expected that exec will be called before + * this class goes out of scope, otherwise environ will become invalid. */ void setEnviron(); }; @@ -267,13 +275,7 @@ void completeFlakeRefWithFragment( std::string showVersions(const std::set & versions); void printClosureDiff( - ref store, - const StorePath & beforePath, - const StorePath & afterPath, - std::string_view indent); + ref store, const StorePath & beforePath, const StorePath & afterPath, std::string_view indent); - -void runRepl( - ref evalState, - const ValMap & extraEnv); +void runRepl(ref evalState, const ValMap & extraEnv); } diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 5b6e82388218..f45b7f3da390 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -15,13 +15,12 @@ MixEvalArgs::MixEvalArgs() { auto category = "Common evaluation options"; - addFlag({ - .longName = "arg", - .description = "Pass the value *expr* as the argument *name* to Nix functions.", - .category = category, - .labels = {"name", "expr"}, - .handler = {[&](std::string name, std::string expr) { autoArgs[name] = 'E' + expr; }} - }); + addFlag( + {.longName = "arg", + .description = "Pass the value *expr* as the argument *name* to Nix functions.", + .category = category, + .labels = {"name", "expr"}, + .handler = {[&](std::string name, std::string expr) { autoArgs[name] = 'E' + expr; }}}); addFlag({ .longName = "argstr", @@ -31,40 +30,35 @@ MixEvalArgs::MixEvalArgs() .handler = {[&](std::string name, std::string s) { autoArgs[name] = 'S' + s; }}, }); - addFlag({ - .longName = "include", - .shortName = 'I', - .description = "Add *path* to the list of locations used to look up `<...>` file names.", - .category = category, - .labels = {"path"}, - .handler = {[&](std::string s) { searchPath.push_back(s); }} - }); + addFlag( + {.longName = "include", + .shortName = 'I', + .description = "Add *path* to the list of locations used to look up `<...>` file names.", + .category = category, + .labels = {"path"}, + .handler = {[&](std::string s) { searchPath.push_back(s); }}}); addFlag({ .longName = "impure", .description = "Allow access to mutable paths and repositories.", .category = category, - .handler = {[&]() { - evalSettings.pureEval = false; - }}, + .handler = {[&]() { evalSettings.pureEval = false; }}, }); - addFlag({ - .longName = "override-flake", - .description = "Override the flake registries, redirecting *original-ref* to *resolved-ref*.", - .category = category, - .labels = {"original-ref", "resolved-ref"}, - .handler = {[&](std::string _from, std::string _to) { - auto from = parseFlakeRef(_from, absPath(".")); - auto to = parseFlakeRef(_to, absPath(".")); - fetchers::Attrs extraAttrs; - if (to.subdir != "") extraAttrs["dir"] = to.subdir; - fetchers::overrideRegistry(from.input, to.input, extraAttrs); - }}, - .completer = {[&](size_t, std::string_view prefix) { - completeFlakeRef(openStore(), prefix); - }} - }); + addFlag( + {.longName = "override-flake", + .description = "Override the flake registries, redirecting *original-ref* to *resolved-ref*.", + .category = category, + .labels = {"original-ref", "resolved-ref"}, + .handler = {[&](std::string _from, std::string _to) { + auto from = parseFlakeRef(_from, absPath(".")); + auto to = parseFlakeRef(_to, absPath(".")); + fetchers::Attrs extraAttrs; + if (to.subdir != "") + extraAttrs["dir"] = to.subdir; + fetchers::overrideRegistry(from.input, to.input, extraAttrs); + }}, + .completer = {[&](size_t, std::string_view prefix) { completeFlakeRef(openStore(), prefix); }}}); addFlag({ .longName = "eval-store", @@ -93,8 +87,7 @@ Path lookupFileArg(EvalState & state, std::string_view s) { if (isUri(s)) { return state.store->toRealPath( - fetchers::downloadTarball( - state.store, resolveUri(s), "source", false).first.storePath); + fetchers::downloadTarball(state.store, resolveUri(s), "source", false).first.storePath); } else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { Path p(s.substr(1, s.size() - 2)); return state.findFile(p); diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index ffc25135eb61..c0725d889fd1 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -23,10 +23,7 @@ namespace nix { -void completeFlakeInputPath( - ref evalState, - const FlakeRef & flakeRef, - std::string_view prefix) +void completeFlakeInputPath(ref evalState, const FlakeRef & flakeRef, std::string_view prefix) { auto flake = flake::getFlake(*evalState, flakeRef, true); for (auto & input : flake.inputs) @@ -38,129 +35,110 @@ MixFlakeOptions::MixFlakeOptions() { auto category = "Common flake-related options"; - addFlag({ - .longName = "recreate-lock-file", - .description = "Recreate the flake's lock file from scratch.", - .category = category, - .handler = {&lockFlags.recreateLockFile, true} - }); - - addFlag({ - .longName = "no-update-lock-file", - .description = "Do not allow any updates to the flake's lock file.", - .category = category, - .handler = {&lockFlags.updateLockFile, false} - }); - - addFlag({ - .longName = "no-write-lock-file", - .description = "Do not write the flake's newly generated lock file.", - .category = category, - .handler = {&lockFlags.writeLockFile, false} - }); - - addFlag({ - .longName = "no-registries", - .description = - "Don't allow lookups in the flake registries. This option is deprecated; use `--no-use-registries`.", - .category = category, - .handler = {[&]() { - lockFlags.useRegistries = false; - warn("'--no-registries' is deprecated; use '--no-use-registries'"); - }} - }); - - addFlag({ - .longName = "commit-lock-file", - .description = "Commit changes to the flake's lock file.", - .category = category, - .handler = {&lockFlags.commitLockFile, true} - }); - - addFlag({ - .longName = "update-input", - .description = "Update a specific flake input (ignoring its previous entry in the lock file).", - .category = category, - .labels = {"input-path"}, - .handler = {[&](std::string s) { - lockFlags.inputUpdates.insert(flake::parseInputPath(s)); - }}, - .completer = {[&](size_t, std::string_view prefix) { - if (auto flakeRef = getFlakeRefForCompletion()) - completeFlakeInputPath(getEvalState(), *flakeRef, prefix); - }} - }); - - addFlag({ - .longName = "override-input", - .description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.", - .category = category, - .labels = {"input-path", "flake-url"}, - .handler = {[&](std::string inputPath, std::string flakeRef) { - lockFlags.writeLockFile = false; - lockFlags.inputOverrides.insert_or_assign( - flake::parseInputPath(inputPath), - parseFlakeRef(flakeRef, absPath("."), true)); - }}, - .completer = {[&](size_t n, std::string_view prefix) { - if (n == 0) { - if (auto flakeRef = getFlakeRefForCompletion()) - completeFlakeInputPath(getEvalState(), *flakeRef, prefix); - } else if (n == 1) { - completeFlakeRef(getEvalState()->store, prefix); - } - }} - }); - - addFlag({ - .longName = "inputs-from", - .description = "Use the inputs of the specified flake as registry entries.", - .category = category, - .labels = {"flake-url"}, - .handler = {[&](std::string flakeRef) { - auto evalState = getEvalState(); - auto flake = flake::lockFlake( - *evalState, - parseFlakeRef(flakeRef, absPath(".")), - { .writeLockFile = false }); - for (auto & [inputName, input] : flake.lockFile.root->inputs) { - auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes - if (auto input3 = std::dynamic_pointer_cast(input2)) { - overrideRegistry( - fetchers::Input::fromAttrs({{"type","indirect"}, {"id", inputName}}), - input3->lockedRef.input, - {}); - } - } - }}, - .completer = {[&](size_t, std::string_view prefix) { - completeFlakeRef(getEvalState()->store, prefix); - }} - }); + addFlag( + {.longName = "recreate-lock-file", + .description = "Recreate the flake's lock file from scratch.", + .category = category, + .handler = {&lockFlags.recreateLockFile, true}}); + + addFlag( + {.longName = "no-update-lock-file", + .description = "Do not allow any updates to the flake's lock file.", + .category = category, + .handler = {&lockFlags.updateLockFile, false}}); + + addFlag( + {.longName = "no-write-lock-file", + .description = "Do not write the flake's newly generated lock file.", + .category = category, + .handler = {&lockFlags.writeLockFile, false}}); + + addFlag( + {.longName = "no-registries", + .description = + "Don't allow lookups in the flake registries. This option is deprecated; use `--no-use-registries`.", + .category = category, + .handler = {[&]() { + lockFlags.useRegistries = false; + warn("'--no-registries' is deprecated; use '--no-use-registries'"); + }}}); + + addFlag( + {.longName = "commit-lock-file", + .description = "Commit changes to the flake's lock file.", + .category = category, + .handler = {&lockFlags.commitLockFile, true}}); + + addFlag( + {.longName = "update-input", + .description = "Update a specific flake input (ignoring its previous entry in the lock file).", + .category = category, + .labels = {"input-path"}, + .handler = {[&](std::string s) { lockFlags.inputUpdates.insert(flake::parseInputPath(s)); }}, + .completer = {[&](size_t, std::string_view prefix) { + if (auto flakeRef = getFlakeRefForCompletion()) + completeFlakeInputPath(getEvalState(), *flakeRef, prefix); + }}}); + + addFlag( + {.longName = "override-input", + .description = + "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.", + .category = category, + .labels = {"input-path", "flake-url"}, + .handler = {[&](std::string inputPath, std::string flakeRef) { + lockFlags.writeLockFile = false; + lockFlags.inputOverrides.insert_or_assign( + flake::parseInputPath(inputPath), parseFlakeRef(flakeRef, absPath("."), true)); + }}, + .completer = {[&](size_t n, std::string_view prefix) { + if (n == 0) { + if (auto flakeRef = getFlakeRefForCompletion()) + completeFlakeInputPath(getEvalState(), *flakeRef, prefix); + } else if (n == 1) { + completeFlakeRef(getEvalState()->store, prefix); + } + }}}); + + addFlag( + {.longName = "inputs-from", + .description = "Use the inputs of the specified flake as registry entries.", + .category = category, + .labels = {"flake-url"}, + .handler = {[&](std::string flakeRef) { + auto evalState = getEvalState(); + auto flake = flake::lockFlake(*evalState, parseFlakeRef(flakeRef, absPath(".")), {.writeLockFile = false}); + for (auto & [inputName, input] : flake.lockFile.root->inputs) { + auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes + if (auto input3 = std::dynamic_pointer_cast(input2)) { + overrideRegistry( + fetchers::Input::fromAttrs({{"type", "indirect"}, {"id", inputName}}), input3->lockedRef.input, + {}); + } + } + }}, + .completer = {[&](size_t, std::string_view prefix) { completeFlakeRef(getEvalState()->store, prefix); }}}); } SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode) { - addFlag({ - .longName = "file", - .shortName = 'f', - .description = - "Interpret 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, - .labels = {"file"}, - .handler = {&file}, - .completer = completePath - }); - - addFlag({ - .longName = "expr", - .description = "Interpret installables as attribute paths relative to the Nix expression *expr*.", - .category = installablesCategory, - .labels = {"expr"}, - .handler = {&expr} - }); + addFlag( + {.longName = "file", + .shortName = 'f', + .description = "Interpret 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, + .labels = {"file"}, + .handler = {&file}, + .completer = completePath}); + + addFlag( + {.longName = "expr", + .description = "Interpret installables as attribute paths relative to the Nix expression *expr*.", + .category = installablesCategory, + .labels = {"expr"}, + .handler = {&expr}}); addFlag({ .longName = "derivation", @@ -172,10 +150,9 @@ SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode) if (supportReadOnlyMode) { addFlag({ .longName = "read-only", - .description = - "Do not instantiate each evaluated derivation. " - "This improves performance, but can cause errors when accessing " - "store paths of derivations during evaluation.", + .description = "Do not instantiate each evaluated derivation. " + "This improves performance, but can cause errors when accessing " + "store paths of derivations during evaluation.", .handler = {&readOnlyMode, true}, }); } @@ -183,22 +160,17 @@ SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode) Strings SourceExprCommand::getDefaultFlakeAttrPaths() { - return { - "packages." + settings.thisSystem.get() + ".default", - "defaultPackage." + settings.thisSystem.get() - }; + return {"packages." + settings.thisSystem.get() + ".default", "defaultPackage." + settings.thisSystem.get()}; } Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() { - return { - // As a convenience, look for the attribute in - // 'outputs.packages'. - "packages." + settings.thisSystem.get() + ".", - // As a temporary hack until Nixpkgs is properly converted - // to provide a clean 'packages' set, look in 'legacyPackages'. - "legacyPackages." + settings.thisSystem.get() + "." - }; + return {// As a convenience, look for the attribute in + // 'outputs.packages'. + "packages." + settings.thisSystem.get() + ".", + // As a temporary hack until Nixpkgs is properly converted + // to provide a clean 'packages' set, look in 'legacyPackages'. + "legacyPackages." + settings.thisSystem.get() + "."}; } void SourceExprCommand::completeInstallable(std::string_view prefix) @@ -208,9 +180,7 @@ void SourceExprCommand::completeInstallable(std::string_view prefix) evalSettings.pureEval = false; auto state = getEvalState(); - Expr *e = state->parseExprFromFile( - resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file))) - ); + Expr * e = state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))); Value root; state->eval(e, root); @@ -229,7 +199,7 @@ void SourceExprCommand::completeInstallable(std::string_view prefix) } auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root); - Value &v1(*v); + Value & v1(*v); state->forceValue(v1, pos); Value v2; state->autoCallFunction(*autoArgs, v1, v2); @@ -247,11 +217,7 @@ void SourceExprCommand::completeInstallable(std::string_view prefix) } } else { completeFlakeRefWithFragment( - getEvalState(), - lockFlags, - getDefaultFlakeAttrPathPrefixes(), - getDefaultFlakeAttrPaths(), - prefix); + getEvalState(), lockFlags, getDefaultFlakeAttrPathPrefixes(), getDefaultFlakeAttrPaths(), prefix); } } @@ -275,8 +241,8 @@ void completeFlakeRefWithFragment( auto flakeRefS = std::string(prefix.substr(0, hash)); auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath(".")); - auto evalCache = openEvalCache(*evalState, - std::make_shared(lockFlake(*evalState, flakeRef, lockFlags))); + auto evalCache = openEvalCache( + *evalState, std::make_shared(lockFlake(*evalState, flakeRef, lockFlags))); auto root = evalCache->getRoot(); @@ -297,14 +263,16 @@ void completeFlakeRefWithFragment( } auto attr = root->findAlongAttrPath(attrPath); - if (!attr) continue; + if (!attr) + continue; for (auto & attr2 : (*attr)->getAttrs()) { if (hasPrefix(evalState->symbols[attr2], lastAttr)) { auto attrPath2 = (*attr)->getAttrPath(attr2); /* Strip the attrpath prefix. */ attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size()); - completions->add(flakeRefS + "#" + concatStringsSep(".", evalState->symbols.resolve(attrPath2))); + completions->add( + flakeRefS + "#" + concatStringsSep(".", evalState->symbols.resolve(attrPath2))); } } } @@ -314,7 +282,8 @@ void completeFlakeRefWithFragment( if (fragment.empty()) { for (auto & attrPath : defaultFlakeAttrPaths) { auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath)); - if (!attr) continue; + if (!attr) + continue; completions->add(flakeRefS + "#"); } } @@ -354,21 +323,19 @@ DerivedPath Installable::toDerivedPath() { auto buildables = toDerivedPaths(); if (buildables.size() != 1) - throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size()); + throw Error( + "installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size()); return std::move(buildables[0]); } -std::vector> -Installable::getCursors(EvalState & state) +std::vector> Installable::getCursors(EvalState & state) { auto evalCache = - std::make_shared(std::nullopt, state, - [&]() { return toValue(state).first; }); + std::make_shared(std::nullopt, state, [&]() { return toValue(state).first; }); return {evalCache->getRoot()}; } -ref -Installable::getCursor(EvalState & state) +ref Installable::getCursor(EvalState & state) { auto cursors = getCursors(state); if (cursors.empty()) @@ -376,10 +343,7 @@ Installable::getCursor(EvalState & state) return cursors[0]; } -static StorePath getDeriver( - ref store, - const Installable & i, - const StorePath & drvPath) +static StorePath getDeriver(ref store, const Installable & i, const StorePath & drvPath) { auto derivers = store->queryValidDerivers(drvPath); if (derivers.empty()) @@ -394,26 +358,27 @@ struct InstallableStorePath : Installable StorePath storePath; InstallableStorePath(ref store, StorePath && storePath) - : store(store), storePath(std::move(storePath)) { } + : store(store) + , storePath(std::move(storePath)) + {} - std::string what() const override { return store->printStorePath(storePath); } + std::string what() const override + { + return store->printStorePath(storePath); + } DerivedPaths toDerivedPaths() override { if (storePath.isDerivation()) { auto drv = store->readDerivation(storePath); - return { - DerivedPath::Built { - .drvPath = storePath, - .outputs = drv.outputNames(), - } - }; + return {DerivedPath::Built{ + .drvPath = storePath, + .outputs = drv.outputNames(), + }}; } else { - return { - DerivedPath::Opaque { - .path = storePath, - } - }; + return {DerivedPath::Opaque{ + .path = storePath, + }}; } } @@ -447,7 +412,7 @@ DerivedPaths InstallableValue::toDerivedPaths() } for (auto & i : drvsToOutputs) - res.push_back(DerivedPath::Built { i.first, i.second }); + res.push_back(DerivedPath::Built{i.first, i.second}); return res; } @@ -468,19 +433,18 @@ struct InstallableAttrPath : InstallableValue OutputsSpec outputsSpec; InstallableAttrPath( - ref state, - SourceExprCommand & cmd, - Value * v, - const std::string & attrPath, - OutputsSpec outputsSpec) + ref state, SourceExprCommand & cmd, Value * v, const std::string & attrPath, OutputsSpec outputsSpec) : InstallableValue(state) , cmd(cmd) , v(allocRootValue(v)) , attrPath(attrPath) , outputsSpec(std::move(outputsSpec)) - { } + {} - std::string what() const override { return attrPath; } + std::string what() const override + { + return attrPath; + } std::pair toValue(EvalState & state) override { @@ -515,10 +479,7 @@ std::vector InstallableAttrPath::toDerivations for (auto & output : drvInfo.queryOutputs(false, std::get_if(&outputsSpec))) outputsToInstall.insert(output.first); - res.push_back(DerivationInfo { - .drvPath = *drvPath, - .outputsToInstall = std::move(outputsToInstall) - }); + res.push_back(DerivationInfo{.drvPath = *drvPath, .outputsToInstall = std::move(outputsToInstall)}); } return res; @@ -551,18 +512,12 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Locked return aOutputs->value; } -ref openEvalCache( - EvalState & state, - std::shared_ptr lockedFlake) +ref openEvalCache(EvalState & state, std::shared_ptr lockedFlake) { auto fingerprint = lockedFlake->getFingerprint(); return make_ref( - evalSettings.useEvalCache && evalSettings.pureEval - ? std::optional { std::cref(fingerprint) } - : std::nullopt, - state, - [&state, lockedFlake]() - { + evalSettings.useEvalCache && evalSettings.pureEval ? std::optional{std::cref(fingerprint)} : std::nullopt, + state, [&state, lockedFlake]() { /* For testing whether the evaluation cache is complete. */ if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0") @@ -584,8 +539,11 @@ static std::string showAttrPaths(const std::vector & paths) { std::string s; for (const auto & [n, i] : enumerate(paths)) { - if (n > 0) s += n + 1 == paths.size() ? " or " : ", "; - s += '\''; s += i; s += '\''; + if (n > 0) + s += n + 1 == paths.size() ? " or " : ", "; + s += '\''; + s += i; + s += '\''; } return s; } @@ -599,12 +557,12 @@ InstallableFlake::InstallableFlake( Strings attrPaths, Strings prefixes, const flake::LockFlags & lockFlags) - : InstallableValue(state), - flakeRef(flakeRef), - attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}), - prefixes(fragment == "" ? Strings{} : prefixes), - outputsSpec(std::move(outputsSpec)), - lockFlags(lockFlags) + : InstallableValue(state) + , flakeRef(flakeRef) + , attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}) + , prefixes(fragment == "" ? Strings{} : prefixes) + , outputsSpec(std::move(outputsSpec)) + , lockFlags(lockFlags) { if (cmd && cmd->getAutoArgs(*state)->size()) throw UsageError("'--arg' and '--argstr' are incompatible with flakes"); @@ -627,7 +585,7 @@ std::tuple InstallableF if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) { if (aOutputSpecified->getBool()) { if (auto aOutputName = attr->maybeGetAttr("outputName")) - outputsToInstall = { aOutputName->getString() }; + outputsToInstall = {aOutputName->getString()}; } } @@ -652,7 +610,7 @@ std::tuple InstallableF if (auto outputNames = std::get_if(&outputsSpec)) outputsToInstall = *outputNames; - auto drvInfo = DerivationInfo { + auto drvInfo = DerivationInfo{ .drvPath = std::move(drvPath), .outputsToInstall = std::move(outputsToInstall), .priority = priority, @@ -673,11 +631,9 @@ std::pair InstallableFlake::toValue(EvalState & state) return {&getCursor(state)->forceValue(), noPos}; } -std::vector> -InstallableFlake::getCursors(EvalState & state) +std::vector> InstallableFlake::getCursors(EvalState & state) { - auto evalCache = openEvalCache(state, - std::make_shared(lockFlake(state, flakeRef, lockFlags))); + auto evalCache = openEvalCache(state, std::make_shared(lockFlake(state, flakeRef, lockFlags))); auto root = evalCache->getRoot(); @@ -685,7 +641,8 @@ InstallableFlake::getCursors(EvalState & state) for (auto & attrPath : getActualAttrPaths()) { auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath)); - if (attr) res.push_back(ref(*attr)); + if (attr) + res.push_back(ref(*attr)); } return res; @@ -705,10 +662,7 @@ ref InstallableFlake::getCursor(EvalState & state) for (auto & attrPath : attrPaths) { debug("trying flake output attribute '%s'", attrPath); - auto attrOrSuggestions = root->findAlongAttrPath( - parseAttrPath(state, attrPath), - true - ); + auto attrOrSuggestions = root->findAlongAttrPath(parseAttrPath(state, attrPath), true); if (!attrOrSuggestions) { suggestions += attrOrSuggestions.getSuggestions(); @@ -718,11 +672,7 @@ ref InstallableFlake::getCursor(EvalState & state) return *attrOrSuggestions; } - throw Error( - suggestions, - "flake '%s' does not provide attribute %s", - flakeRef, - showAttrPaths(attrPaths)); + throw Error(suggestions, "flake '%s' does not provide attribute %s", flakeRef, showAttrPaths(attrPaths)); } std::shared_ptr InstallableFlake::getLockedFlake() const @@ -749,8 +699,8 @@ FlakeRef InstallableFlake::nixpkgsFlakeRef() const return Installable::nixpkgsFlakeRef(); } -std::vector> SourceExprCommand::parseInstallables( - ref store, std::vector ss) +std::vector> +SourceExprCommand::parseInstallables(ref store, std::vector ss) { std::vector> result; @@ -763,7 +713,8 @@ std::vector> SourceExprCommand::parseInstallables( throw UsageError("'--file' and '--expr' are exclusive"); // FIXME: backward compatibility hack - if (file) evalSettings.pureEval = false; + if (file) + evalSettings.pureEval = false; auto state = getEvalState(); auto vFile = state->allocValue(); @@ -781,10 +732,7 @@ std::vector> SourceExprCommand::parseInstallables( for (auto & s : ss) { auto [prefix, outputsSpec] = parseOutputsSpec(s); result.push_back( - std::make_shared( - state, *this, vFile, - prefix == "." ? "" : prefix, - outputsSpec)); + std::make_shared(state, *this, vFile, prefix == "." ? "" : prefix, outputsSpec)); } } else { @@ -806,14 +754,8 @@ std::vector> SourceExprCommand::parseInstallables( try { auto [flakeRef, fragment, outputsSpec] = parseFlakeRefWithFragmentAndOutputsSpec(s, absPath(".")); result.push_back(std::make_shared( - this, - getEvalState(), - std::move(flakeRef), - fragment, - outputsSpec, - getDefaultFlakeAttrPaths(), - getDefaultFlakeAttrPathPrefixes(), - lockFlags)); + this, getEvalState(), std::move(flakeRef), fragment, outputsSpec, getDefaultFlakeAttrPaths(), + getDefaultFlakeAttrPathPrefixes(), lockFlags)); continue; } catch (...) { ex = std::current_exception(); @@ -826,8 +768,7 @@ std::vector> SourceExprCommand::parseInstallables( return result; } -std::shared_ptr SourceExprCommand::parseInstallable( - ref store, const std::string & installable) +std::shared_ptr SourceExprCommand::parseInstallable(ref store, const std::string & installable) { auto installables = parseInstallables(store, {installable}); assert(installables.size() == 1); @@ -877,43 +818,44 @@ std::vector, BuiltPath>> Installable::bui for (auto & path : pathsToBuild) { for (auto & installable : backmap[path]) { - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - OutputPathMap outputs; - auto drv = evalStore->readDerivation(bfd.drvPath); - auto outputHashes = staticOutputHashes(*evalStore, drv); // FIXME: expensive - auto drvOutputs = drv.outputsAndOptPaths(*store); - for (auto & output : bfd.outputs) { - auto outputHash = get(outputHashes, output); - if (!outputHash) - throw Error( - "the derivation '%s' doesn't have an output named '%s'", - store->printStorePath(bfd.drvPath), output); - if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { - DrvOutput outputId { *outputHash, output }; - auto realisation = store->queryRealisation(outputId); - if (!realisation) + std::visit( + overloaded{ + [&](const DerivedPath::Built & bfd) { + OutputPathMap outputs; + auto drv = evalStore->readDerivation(bfd.drvPath); + auto outputHashes = staticOutputHashes(*evalStore, drv); // FIXME: expensive + auto drvOutputs = drv.outputsAndOptPaths(*store); + for (auto & output : bfd.outputs) { + auto outputHash = get(outputHashes, output); + if (!outputHash) throw Error( - "cannot operate on an output of the " - "unbuilt derivation '%s'", - outputId.to_string()); - outputs.insert_or_assign(output, realisation->outPath); - } else { - // If ca-derivations isn't enabled, assume that - // the output path is statically known. - auto drvOutput = get(drvOutputs, output); - assert(drvOutput); - assert(drvOutput->second); - outputs.insert_or_assign( - output, *drvOutput->second); + "the derivation '%s' doesn't have an output named '%s'", + store->printStorePath(bfd.drvPath), output); + if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { + DrvOutput outputId{*outputHash, output}; + auto realisation = store->queryRealisation(outputId); + if (!realisation) + throw Error( + "cannot operate on an output of the " + "unbuilt derivation '%s'", + outputId.to_string()); + outputs.insert_or_assign(output, realisation->outPath); + } else { + // If ca-derivations isn't enabled, assume that + // the output path is statically known. + auto drvOutput = get(drvOutputs, output); + assert(drvOutput); + assert(drvOutput->second); + outputs.insert_or_assign(output, *drvOutput->second); + } } - } - res.push_back({installable, BuiltPath::Built { bfd.drvPath, outputs }}); + res.push_back({installable, BuiltPath::Built{bfd.drvPath, outputs}}); + }, + [&](const DerivedPath::Opaque & bo) { + res.push_back({installable, BuiltPath::Opaque{bo.path}}); + }, }, - [&](const DerivedPath::Opaque & bo) { - res.push_back({installable, BuiltPath::Opaque { bo.path }}); - }, - }, path.raw()); + path.raw()); } } @@ -921,24 +863,26 @@ std::vector, BuiltPath>> Installable::bui case Realise::Outputs: { if (settings.printMissing) - printMissing(store, pathsToBuild, lvlInfo); + printMissing(store, pathsToBuild, lvlInfo); for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) { if (!buildResult.success()) buildResult.rethrow(); for (auto & installable : backmap[buildResult.path]) { - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - std::map outputs; - for (auto & path : buildResult.builtOutputs) - outputs.emplace(path.first.outputName, path.second.outPath); - res.push_back({installable, BuiltPath::Built { bfd.drvPath, outputs }}); - }, - [&](const DerivedPath::Opaque & bo) { - res.push_back({installable, BuiltPath::Opaque { bo.path }}); + std::visit( + overloaded{ + [&](const DerivedPath::Built & bfd) { + std::map outputs; + for (auto & path : buildResult.builtOutputs) + outputs.emplace(path.first.outputName, path.second.outPath); + res.push_back({installable, BuiltPath::Built{bfd.drvPath, outputs}}); + }, + [&](const DerivedPath::Opaque & bo) { + res.push_back({installable, BuiltPath::Opaque{bo.path}}); + }, }, - }, buildResult.path.raw()); + buildResult.path.raw()); } } @@ -975,7 +919,8 @@ BuiltPaths Installable::toBuiltPaths( StorePathSet Installable::toStorePaths( ref evalStore, ref store, - Realise mode, OperateOn operateOn, + Realise mode, + OperateOn operateOn, const std::vector> & installables) { StorePathSet outPaths; @@ -987,10 +932,7 @@ StorePathSet Installable::toStorePaths( } StorePath Installable::toStorePath( - ref evalStore, - ref store, - Realise mode, OperateOn operateOn, - std::shared_ptr installable) + ref evalStore, ref store, Realise mode, OperateOn operateOn, std::shared_ptr installable) { auto paths = toStorePaths(evalStore, store, mode, operateOn, {installable}); @@ -1001,37 +943,32 @@ StorePath Installable::toStorePath( } StorePathSet Installable::toDerivations( - ref store, - const std::vector> & installables, - bool useDeriver) + ref store, const std::vector> & installables, bool useDeriver) { StorePathSet drvPaths; for (const auto & i : installables) 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)); - }, - [&](const DerivedPath::Built & bfd) { - drvPaths.insert(bfd.drvPath); + 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)); + }, + [&](const DerivedPath::Built & bfd) { drvPaths.insert(bfd.drvPath); }, }, - }, b.raw()); + b.raw()); return drvPaths; } InstallablesCommand::InstallablesCommand() { - expectArgs({ - .label = "installables", - .handler = {&_installables}, - .completer = {[&](size_t, std::string_view prefix) { - completeInstallable(prefix); - }} - }); + expectArgs( + {.label = "installables", .handler = {&_installables}, .completer = {[&](size_t, std::string_view prefix) { + completeInstallable(prefix); + }}}); } void InstallablesCommand::prepare() @@ -1056,14 +993,11 @@ std::optional InstallablesCommand::getFlakeRefForCompletion() InstallableCommand::InstallableCommand(bool supportReadOnlyMode) : SourceExprCommand(supportReadOnlyMode) { - expectArgs({ - .label = "installable", - .optional = true, - .handler = {&_installable}, - .completer = {[&](size_t, std::string_view prefix) { - completeInstallable(prefix); - }} - }); + expectArgs( + {.label = "installable", + .optional = true, + .handler = {&_installable}, + .completer = {[&](size_t, std::string_view prefix) { completeInstallable(prefix); }}}); } void InstallableCommand::prepare() diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh index 5d715210e92f..19a4a7d375c1 100644 --- a/src/libcmd/installables.hh +++ b/src/libcmd/installables.hh @@ -15,7 +15,10 @@ namespace nix { struct DrvInfo; struct SourceExprCommand; -namespace eval_cache { class EvalCache; class AttrCursor; } +namespace eval_cache { +class EvalCache; +class AttrCursor; +} struct App { @@ -53,7 +56,7 @@ enum class OperateOn { struct Installable { - virtual ~Installable() { } + virtual ~Installable() {} virtual std::string what() const = 0; @@ -80,15 +83,13 @@ struct Installable return {}; } - virtual std::vector> - getCursors(EvalState & state); + virtual std::vector> getCursors(EvalState & state); - virtual ref - getCursor(EvalState & state); + virtual ref getCursor(EvalState & state); virtual FlakeRef nixpkgsFlakeRef() const { - return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}}); + return FlakeRef::fromAttrs({{"type", "indirect"}, {"id", "nixpkgs"}}); } static BuiltPaths build( @@ -120,9 +121,7 @@ struct Installable std::shared_ptr installable); static std::set toDerivations( - ref store, - const std::vector> & installables, - bool useDeriver = false); + ref store, const std::vector> & installables, bool useDeriver = false); static BuiltPaths toBuiltPaths( ref evalStore, @@ -136,7 +135,9 @@ struct InstallableValue : Installable { ref state; - InstallableValue(ref state) : state(state) {} + InstallableValue(ref state) + : state(state) + {} struct DerivationInfo { @@ -171,7 +172,10 @@ struct InstallableFlake : InstallableValue Strings prefixes, const flake::LockFlags & lockFlags); - std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); } + std::string what() const override + { + return flakeRef.to_string() + "#" + *attrPaths.begin(); + } std::vector getActualAttrPaths(); @@ -185,8 +189,7 @@ struct InstallableFlake : InstallableValue /* Get a cursor to every attrpath in getActualAttrPaths() that exists. */ - std::vector> - getCursors(EvalState & state) override; + std::vector> getCursors(EvalState & state) override; /* Get a cursor to the first attrpath in getActualAttrPaths() that exists, or throw an exception with suggestions if none exists. */ @@ -197,8 +200,6 @@ struct InstallableFlake : InstallableValue FlakeRef nixpkgsFlakeRef() const override; }; -ref openEvalCache( - EvalState & state, - std::shared_ptr lockedFlake); +ref openEvalCache(EvalState & state, std::shared_ptr lockedFlake); } diff --git a/src/libcmd/legacy.hh b/src/libcmd/legacy.hh index f503b0da3e1a..ef86a755dec2 100644 --- a/src/libcmd/legacy.hh +++ b/src/libcmd/legacy.hh @@ -6,7 +6,7 @@ namespace nix { -typedef std::function MainFunction; +typedef std::function MainFunction; struct RegisterLegacyCommand { @@ -15,7 +15,8 @@ struct RegisterLegacyCommand RegisterLegacyCommand(const std::string & name, MainFunction fun) { - if (!commands) commands = new Commands; + if (!commands) + commands = new Commands; (*commands)[name] = fun; } }; diff --git a/src/libcmd/markdown.cc b/src/libcmd/markdown.cc index 71f9c8dff7f2..19ff6cc7695c 100644 --- a/src/libcmd/markdown.cc +++ b/src/libcmd/markdown.cc @@ -11,14 +11,10 @@ std::string renderMarkdownToTerminal(std::string_view markdown) { int windowWidth = getWindowSize().second; - struct lowdown_opts opts { - .type = LOWDOWN_TERM, - .maxdepth = 20, - .cols = (size_t) std::max(windowWidth - 5, 60), - .hmargin = 0, - .vmargin = 0, - .feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES, - .oflags = 0, + struct lowdown_opts opts + { + .type = LOWDOWN_TERM, .maxdepth = 20, .cols = (size_t) std::max(windowWidth - 5, 60), .hmargin = 0, + .vmargin = 0, .feat = LOWDOWN_COMMONMARK | LOWDOWN_FENCED | LOWDOWN_DEFLIST | LOWDOWN_TABLES, .oflags = 0, }; auto doc = lowdown_doc_new(&opts); diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 3c89a8ea36cc..740fe9d41d1e 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -43,9 +43,9 @@ extern "C" { namespace nix { struct NixRepl - #if HAVE_BOEHMGC +#if HAVE_BOEHMGC : gc - #endif +#endif { std::string curDir; ref state; @@ -86,16 +86,15 @@ struct NixRepl std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); }; - std::string removeWhitespace(std::string s) { s = chomp(s); size_t n = s.find_first_not_of(" \n\r\t"); - if (n != std::string::npos) s = std::string(s, n); + if (n != std::string::npos) + s = std::string(s, n); return s; } - NixRepl::NixRepl(ref state) : state(state) , debugTraceIndex(0) @@ -105,20 +104,18 @@ NixRepl::NixRepl(ref state) curDir = absPath("."); } - NixRepl::~NixRepl() { write_history(historyFile.c_str()); } -std::string runNix(Path program, const Strings & args, - const std::optional & input = {}) +std::string runNix(Path program, const Strings & args, const std::optional & input = {}) { auto subprocessEnv = getEnv(); subprocessEnv["NIX_CONFIG"] = globalConfig.toKeyValue(); - auto res = runProgram(RunOptions { - .program = settings.nixBinDir+ "/" + program, + auto res = runProgram(RunOptions{ + .program = settings.nixBinDir + "/" + program, .args = args, .environment = subprocessEnv, .input = input, @@ -132,75 +129,81 @@ std::string runNix(Path program, const Strings & args, static NixRepl * curRepl; // ugly -static char * completionCallback(char * s, int *match) { - auto possible = curRepl->completePrefix(s); - if (possible.size() == 1) { - *match = 1; - auto *res = strdup(possible.begin()->c_str() + strlen(s)); - if (!res) throw Error("allocation failure"); - return res; - } else if (possible.size() > 1) { - auto checkAllHaveSameAt = [&](size_t pos) { - auto &first = *possible.begin(); - for (auto &p : possible) { - if (p.size() <= pos || p[pos] != first[pos]) - return false; - } - return true; - }; - size_t start = strlen(s); - size_t len = 0; - while (checkAllHaveSameAt(start + len)) ++len; - if (len > 0) { - *match = 1; - auto *res = strdup(std::string(*possible.begin(), start, len).c_str()); - if (!res) throw Error("allocation failure"); - return res; +static char * completionCallback(char * s, int * match) +{ + auto possible = curRepl->completePrefix(s); + if (possible.size() == 1) { + *match = 1; + auto * res = strdup(possible.begin()->c_str() + strlen(s)); + if (!res) + throw Error("allocation failure"); + return res; + } else if (possible.size() > 1) { + auto checkAllHaveSameAt = [&](size_t pos) { + auto & first = *possible.begin(); + for (auto & p : possible) { + if (p.size() <= pos || p[pos] != first[pos]) + return false; + } + return true; + }; + size_t start = strlen(s); + size_t len = 0; + while (checkAllHaveSameAt(start + len)) + ++len; + if (len > 0) { + *match = 1; + auto * res = strdup(std::string(*possible.begin(), start, len).c_str()); + if (!res) + throw Error("allocation failure"); + return res; + } } - } - *match = 0; - return nullptr; + *match = 0; + return nullptr; } -static int listPossibleCallback(char *s, char ***avp) { - auto possible = curRepl->completePrefix(s); +static int listPossibleCallback(char * s, char *** avp) +{ + auto possible = curRepl->completePrefix(s); - if (possible.size() > (INT_MAX / sizeof(char*))) - throw Error("too many completions"); + if (possible.size() > (INT_MAX / sizeof(char *))) + throw Error("too many completions"); - int ac = 0; - char **vp = nullptr; + int ac = 0; + char ** vp = nullptr; - auto check = [&](auto *p) { - if (!p) { - if (vp) { - while (--ac >= 0) - free(vp[ac]); - free(vp); - } - throw Error("allocation failure"); - } - return p; - }; + auto check = [&](auto * p) { + if (!p) { + if (vp) { + while (--ac >= 0) + free(vp[ac]); + free(vp); + } + throw Error("allocation failure"); + } + return p; + }; - vp = check((char **)malloc(possible.size() * sizeof(char*))); + vp = check((char **) malloc(possible.size() * sizeof(char *))); - for (auto & p : possible) - vp[ac++] = check(strdup(p.c_str())); + for (auto & p : possible) + vp[ac++] = check(strdup(p.c_str())); - *avp = vp; + *avp = vp; - return ac; + return ac; } namespace { - // Used to communicate to NixRepl::getLine whether a signal occurred in ::readline. - volatile sig_atomic_t g_signal_received = 0; +// Used to communicate to NixRepl::getLine whether a signal occurred in ::readline. +volatile sig_atomic_t g_signal_received = 0; - void sigintHandler(int signo) { - g_signal_received = signo; - } +void sigintHandler(int signo) +{ + g_signal_received = signo; +} } static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positions, const DebugTrace & dt) @@ -210,9 +213,7 @@ static std::ostream & showDebugTrace(std::ostream & out, const PosTable & positi out << dt.hint.str() << "\n"; // prefer direct pos, but if noPos then try the expr. - auto pos = *dt.pos - ? *dt.pos - : positions[dt.expr.getPos() ? dt.expr.getPos() : noPos]; + auto pos = *dt.pos ? *dt.pos : positions[dt.expr.getPos() ? dt.expr.getPos() : noPos]; if (pos) { printAtPos(pos, out); @@ -239,7 +240,8 @@ void NixRepl::mainLoop(const std::vector & files) } loadFiles(); - if (!loadedFiles.empty()) notice(""); + if (!loadedFiles.empty()) + notice(""); // Allow nix-repl specific settings in .inputrc rl_readline_name = "nix-repl"; @@ -266,14 +268,15 @@ void NixRepl::mainLoop(const std::vector & files) break; } try { - if (!removeWhitespace(input).empty() && !processLine(input)) return; + if (!removeWhitespace(input).empty() && !processLine(input)) + return; } catch (ParseError & e) { if (e.msg().find("unexpected end of file") != std::string::npos) { // For parse errors on incomplete input, we continue waiting for the next line of // input without clearing the input so far. continue; } else { - printMsg(lvlError, e.msg()); + printMsg(lvlError, e.msg()); } } catch (EvalError & e) { // in debugger mode, an EvalError should trigger another repl session. @@ -296,7 +299,6 @@ void NixRepl::mainLoop(const std::vector & files) } } - bool NixRepl::getLine(std::string & input, const std::string & prompt) { struct sigaction act, old; @@ -335,13 +337,12 @@ bool NixRepl::getLine(std::string & input, const std::string & prompt) } if (!s) - return false; + return false; input += s; input += '\n'; return true; } - StringSet NixRepl::completePrefix(const std::string & prefix) { StringSet completions; @@ -372,7 +373,8 @@ StringSet NixRepl::completePrefix(const std::string & prefix) /* This is a variable name; look it up in the current scope. */ StringSet::iterator i = varNames.lower_bound(cur); while (i != varNames.end()) { - if (i->substr(0, cur.size()) != cur) break; + if (i->substr(0, cur.size()) != cur) + break; completions.insert(prev + *i); i++; } @@ -391,7 +393,8 @@ StringSet NixRepl::completePrefix(const std::string & prefix) for (auto & i : *v.attrs) { std::string_view name = state->symbols[i.name]; - if (name.substr(0, cur2.size()) != cur2) continue; + if (name.substr(0, cur2.size()) != cur2) + continue; completions.insert(concatStrings(prev, expr, ".", name)); } @@ -409,23 +412,22 @@ StringSet NixRepl::completePrefix(const std::string & prefix) return completions; } - static bool isVarName(std::string_view s) { - if (s.size() == 0) return false; + if (s.size() == 0) + return false; char c = s[0]; - if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false; + if ((c >= '0' && c <= '9') || c == '-' || c == '\'') + return false; for (auto & i : s) - if (!((i >= 'a' && i <= 'z') || - (i >= 'A' && i <= 'Z') || - (i >= '0' && i <= '9') || - i == '_' || i == '-' || i == '\'')) + if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || i == '_' || i == '-' + || i == '\'')) return false; return true; } - -StorePath NixRepl::getDerivationPath(Value & v) { +StorePath NixRepl::getDerivationPath(Value & v) +{ auto drvInfo = getDerivation(*state, v, false); if (!drvInfo) throw Error("expression does not evaluate to a derivation, so I can't build it"); @@ -454,7 +456,8 @@ void NixRepl::loadDebugTraceEnv(DebugTrace & dt) bool NixRepl::processLine(std::string line) { line = trim(line); - if (line == "") return true; + if (line == "") + return true; _isInterrupted = false; @@ -463,46 +466,43 @@ bool NixRepl::processLine(std::string line) if (line[0] == ':') { size_t p = line.find_first_of(" \n\r\t"); command = line.substr(0, p); - if (p != std::string::npos) arg = removeWhitespace(line.substr(p)); + if (p != std::string::npos) + arg = removeWhitespace(line.substr(p)); } else { arg = line; } if (command == ":?" || command == ":help") { // FIXME: convert to Markdown, include in the 'nix repl' manpage. - std::cout - << "The following commands are available:\n" - << "\n" - << " Evaluate and print expression\n" - << " = Bind expression to variable\n" - << " :a Add attributes from resulting set to scope\n" - << " :b Build a derivation\n" - << " :bl Build a derivation, creating GC roots in the working directory\n" - << " :e Open package or function in $EDITOR\n" - << " :i Build derivation, then install result into current profile\n" - << " :l Load Nix expression and add it to scope\n" - << " :lf Load Nix flake and add it to scope\n" - << " :p Evaluate and print expression recursively\n" - << " :q Exit nix-repl\n" - << " :r Reload all files\n" - << " :sh Build dependencies of derivation, then start nix-shell\n" - << " :t Describe result of evaluation\n" - << " :u Build derivation, then start nix-shell\n" - << " :doc Show documentation of a builtin function\n" - << " :log Show logs for a derivation\n" - << " :te [bool] Enable, disable or toggle showing traces for errors\n" - ; + std::cout << "The following commands are available:\n" + << "\n" + << " Evaluate and print expression\n" + << " = Bind expression to variable\n" + << " :a Add attributes from resulting set to scope\n" + << " :b Build a derivation\n" + << " :bl Build a derivation, creating GC roots in the working directory\n" + << " :e Open package or function in $EDITOR\n" + << " :i Build derivation, then install result into current profile\n" + << " :l Load Nix expression and add it to scope\n" + << " :lf Load Nix flake and add it to scope\n" + << " :p Evaluate and print expression recursively\n" + << " :q Exit nix-repl\n" + << " :r Reload all files\n" + << " :sh Build dependencies of derivation, then start nix-shell\n" + << " :t Describe result of evaluation\n" + << " :u Build derivation, then start nix-shell\n" + << " :doc Show documentation of a builtin function\n" + << " :log Show logs for a derivation\n" + << " :te [bool] Enable, disable or toggle showing traces for errors\n"; if (state->debugRepl) { - std::cout - << "\n" - << " Debug mode commands\n" - << " :env Show env stack\n" - << " :bt Show trace stack\n" - << " :st Show current trace\n" - << " :st Change to another trace in the stack\n" - << " :c Go until end of program, exception, or builtins.break\n" - << " :s Go one step\n" - ; + std::cout << "\n" + << " Debug mode commands\n" + << " :env Show env stack\n" + << " :bt Show trace stack\n" + << " :st Show current trace\n" + << " :st Change to another trace in the stack\n" + << " :c Go until end of program, exception, or builtins.break\n" + << " :s Go one step\n"; } } @@ -527,17 +527,18 @@ bool NixRepl::processLine(std::string line) try { // change the DebugTrace index. debugTraceIndex = stoi(arg); - } catch (...) { } + } catch (...) { + } for (const auto & [idx, i] : enumerate(state->debugTraces)) { - if (idx == debugTraceIndex) { - std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; - showDebugTrace(std::cout, state->positions, i); - std::cout << std::endl; - printEnvBindings(*state, i.expr, i.env); - loadDebugTraceEnv(i); - break; - } + if (idx == debugTraceIndex) { + std::cout << "\n" << ANSI_BLUE << idx << ANSI_NORMAL << ": "; + showDebugTrace(std::cout, state->positions, i); + std::cout << std::endl; + printEnvBindings(*state, i.expr, i.env); + loadDebugTraceEnv(i); + break; + } } } @@ -577,7 +578,7 @@ bool NixRepl::processLine(std::string line) Value v; evalString(arg, v); - const auto [file, line] = [&] () -> std::pair { + const auto [file, line] = [&]() -> std::pair { if (v.type() == nPath || v.type() == nString) { PathSet context; auto filename = state->coerceToString(noPos, v, context).toOwned(); @@ -599,7 +600,7 @@ bool NixRepl::processLine(std::string line) // runProgram redirects stdout to a StringSink, // using runProgram2 to allow editors to display their UI - runProgram2(RunOptions { .program = editor, .searchPath = true, .args = args }); + runProgram2(RunOptions{.program = editor, .searchPath = true, .args = args}); // Reload right after exiting the editor state->resetFileCache(); @@ -646,9 +647,7 @@ bool NixRepl::processLine(std::string line) runNix("nix-env", {"-i", drvPathRaw}); } else if (command == ":log") { settings.readOnlyMode = true; - Finally roModeReset([&]() { - settings.readOnlyMode = false; - }); + Finally roModeReset([&]() { settings.readOnlyMode = false; }); auto subs = getDefaultSubstituters(); subs.push_front(state->store); @@ -671,7 +670,8 @@ bool NixRepl::processLine(std::string line) break; } } - if (!foundLog) throw Error("build log of '%s' is not available", drvPathRaw); + if (!foundLog) + throw Error("build log of '%s' is not available", drvPathRaw); } else { runNix("nix-shell", {drvPathRaw}); } @@ -700,9 +700,8 @@ bool NixRepl::processLine(std::string line) for (auto & arg : args) arg = "*" + arg + "*"; - markdown += - "**Synopsis:** `builtins." + (std::string) (*doc->name) + "` " - + concatStringsSep(" ", args) + "\n\n"; + markdown += "**Synopsis:** `builtins." + (std::string)(*doc->name) + "` " + concatStringsSep(" ", args) + + "\n\n"; } markdown += stripIndentation(doc->doc); @@ -730,11 +729,8 @@ bool NixRepl::processLine(std::string line) else { size_t p = line.find('='); std::string name; - if (p != std::string::npos && - p < line.size() && - line[p + 1] != '=' && - isVarName(name = removeWhitespace(line.substr(0, p)))) - { + if (p != std::string::npos && p < line.size() && line[p + 1] != '=' + && isVarName(name = removeWhitespace(line.substr(0, p)))) { Expr * e = parseString(line.substr(p + 1)); Value & v(*state->allocValue()); v.mkThunk(env, e); @@ -749,7 +745,6 @@ bool NixRepl::processLine(std::string line) return true; } - void NixRepl::loadFile(const Path & path) { loadedFiles.remove(path); @@ -771,18 +766,19 @@ void NixRepl::loadFlake(const std::string & flakeRefS) Value v; - flake::callFlake(*state, - flake::lockFlake(*state, flakeRef, - flake::LockFlags { + flake::callFlake( + *state, + flake::lockFlake( + *state, flakeRef, + flake::LockFlags{ .updateLockFile = false, .useRegistries = !evalSettings.pureEval, - .allowMutable = !evalSettings.pureEval, + .allowMutable = !evalSettings.pureEval, }), v); addAttrsToScope(v); } - void NixRepl::initEnv() { env = &state->allocEnv(envSize); @@ -795,7 +791,6 @@ void NixRepl::initEnv() varNames.emplace(state->symbols[i.first]); } - void NixRepl::reloadFiles() { initEnv(); @@ -803,7 +798,6 @@ void NixRepl::reloadFiles() loadFiles(); } - void NixRepl::loadFiles() { Strings old = loadedFiles; @@ -811,14 +805,14 @@ void NixRepl::loadFiles() bool first = true; for (auto & i : old) { - if (!first) notice(""); + if (!first) + notice(""); first = false; notice("Loading '%1%'...", i); loadFile(i); } } - void NixRepl::addAttrsToScope(Value & attrs) { state->forceAttrs(attrs, [&]() { return attrs.determinePos(noPos); }); @@ -835,7 +829,6 @@ void NixRepl::addAttrsToScope(Value & attrs) notice("Added %1% variables.", attrs.attrs->size()); } - void NixRepl::addVarToScope(const Symbol name, Value & v) { if (displ >= envSize) @@ -848,14 +841,12 @@ void NixRepl::addVarToScope(const Symbol name, Value & v) varNames.emplace(state->symbols[name]); } - Expr * NixRepl::parseString(std::string s) { Expr * e = state->parseExprFromString(std::move(s), curDir, staticEnv); return e; } - void NixRepl::evalString(std::string s, Value & v) { Expr * e = parseString(s); @@ -863,27 +854,30 @@ void NixRepl::evalString(std::string s, Value & v) state->forceValue(v, [&]() { return v.determinePos(noPos); }); } - std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) { ValuesSeen seen; return printValue(str, v, maxDepth, seen); } - -std::ostream & printStringValue(std::ostream & str, const char * string) { +std::ostream & printStringValue(std::ostream & str, const char * string) +{ str << "\""; for (const char * i = string; *i; i++) - if (*i == '\"' || *i == '\\') str << "\\" << *i; - else if (*i == '\n') str << "\\n"; - else if (*i == '\r') str << "\\r"; - else if (*i == '\t') str << "\\t"; - else str << *i; + if (*i == '\"' || *i == '\\') + str << "\\" << *i; + else if (*i == '\n') + str << "\\n"; + else if (*i == '\r') + str << "\\r"; + else if (*i == '\t') + str << "\\t"; + else + str << *i; str << "\""; return str; } - // FIXME: lot of cut&paste from Nix's eval.cc. std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen) { @@ -1011,9 +1005,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m return str; } -void runRepl( - refevalState, - const ValMap & extraEnv) +void runRepl(ref evalState, const ValMap & extraEnv) { auto repl = std::make_unique(evalState); @@ -1032,11 +1024,7 @@ struct CmdRepl : StoreCommand, MixEvalArgs CmdRepl() { - expectArgs({ - .label = "files", - .handler = {&files}, - .completer = completePath - }); + expectArgs({.label = "files", .handler = {&files}, .completer = completePath}); } bool forceImpureByDefault() override @@ -1052,8 +1040,8 @@ struct CmdRepl : StoreCommand, MixEvalArgs std::string doc() override { return - #include "repl.md" - ; +#include "repl.md" + ; } void run(ref store) override diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 94ab60f9ac82..3d069bb09e0e 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -2,10 +2,8 @@ #include "eval-inline.hh" #include "util.hh" - namespace nix { - static Strings parseAttrPath(std::string_view s) { Strings res; @@ -20,18 +18,19 @@ static Strings parseAttrPath(std::string_view s) while (1) { if (i == s.end()) throw ParseError("missing closing quote in selection path '%1%'", s); - if (*i == '"') break; + if (*i == '"') + break; cur.push_back(*i++); } } else cur.push_back(*i); ++i; } - if (!cur.empty()) res.push_back(cur); + if (!cur.empty()) + res.push_back(cur); return res; } - std::vector parseAttrPath(EvalState & state, std::string_view s) { std::vector res; @@ -40,9 +39,8 @@ std::vector parseAttrPath(EvalState & state, std::string_view s) return res; } - -std::pair findAlongAttrPath(EvalState & state, const std::string & attrPath, - Bindings & autoArgs, Value & vIn) +std::pair +findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & autoArgs, Value & vIn) { Strings tokens = parseAttrPath(attrPath); @@ -67,8 +65,7 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin if (v->type() != nAttrs) throw TypeError( - "the expression selected by the selection path '%1%' should be a set but is %2%", - attrPath, + "the expression selected by the selection path '%1%' should be a set but is %2%", attrPath, showType(*v)); if (attr.empty()) throw Error("empty attribute name in selection path '%1%'", attrPath); @@ -80,7 +77,8 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin attrNames.insert(state.symbols[attr.name]); auto suggestions = Suggestions::bestMatches(attrNames, attr); - throw AttrPathNotFound(suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath); + throw AttrPathNotFound( + suggestions, "attribute '%1%' in selection path '%2%' not found", attr, attrPath); } v = &*a->value; pos = a->pos; @@ -90,8 +88,7 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin if (!v->isList()) throw TypeError( - "the expression selected by the selection path '%1%' should be a list but is %2%", - attrPath, + "the expression selected by the selection path '%1%' should be a list but is %2%", attrPath, showType(*v)); if (*attrIndex >= v->listSize()) throw AttrPathNotFound("list index %1% in selection path '%2%' is out of range", *attrIndex, attrPath); @@ -99,13 +96,11 @@ std::pair findAlongAttrPath(EvalState & state, const std::strin v = v->listElems()[*attrIndex]; pos = noPos; } - } return {v, pos}; } - std::pair findPackageFilename(EvalState & state, Value & v, std::string what) { Value * v2; @@ -132,8 +127,7 @@ std::pair findPackageFilename(EvalState & state, Value & throw ParseError("cannot parse line number '%s'", pos); } - return { std::move(filename), lineno }; + return {std::move(filename), lineno}; } - } diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh index 117e0051bb8e..f97f72e8becf 100644 --- a/src/libexpr/attr-path.hh +++ b/src/libexpr/attr-path.hh @@ -10,11 +10,8 @@ namespace nix { MakeError(AttrPathNotFound, Error); MakeError(NoPositionInfo, Error); -std::pair findAlongAttrPath( - EvalState & state, - const std::string & attrPath, - Bindings & autoArgs, - Value & vIn); +std::pair +findAlongAttrPath(EvalState & state, const std::string & attrPath, Bindings & autoArgs, Value & vIn); /* Heuristic to find the filename and lineno or a nix value. */ std::pair findPackageFilename(EvalState & state, Value & v, std::string what); diff --git a/src/libexpr/attr-set.cc b/src/libexpr/attr-set.cc index 877116f1f9c5..978d67a024d9 100644 --- a/src/libexpr/attr-set.cc +++ b/src/libexpr/attr-set.cc @@ -3,11 +3,8 @@ #include - namespace nix { - - /* Allocate a new array of attributes for an attribute set with a specific capacity. The space is implicitly reserved after the Bindings structure. */ @@ -22,7 +19,6 @@ Bindings * EvalState::allocBindings(size_t capacity) return new (allocBytes(sizeof(Bindings) + sizeof(Attr) * capacity)) Bindings((Bindings::size_t) capacity); } - /* Create a new attribute named 'name' on an existing attribute set stored in 'vAttrs' and return the newly allocated Value which is associated with this attribute. */ @@ -33,13 +29,11 @@ Value * EvalState::allocAttr(Value & vAttrs, Symbol name) return v; } - Value * EvalState::allocAttr(Value & vAttrs, std::string_view name) { return allocAttr(vAttrs, symbols.create(name)); } - Value & BindingsBuilder::alloc(Symbol name, PosIdx pos) { auto value = state.allocValue(); @@ -47,24 +41,21 @@ Value & BindingsBuilder::alloc(Symbol name, PosIdx pos) return *value; } - Value & BindingsBuilder::alloc(std::string_view name, PosIdx pos) { return alloc(state.symbols.create(name), pos); } - void Bindings::sort() { - if (size_) std::sort(begin(), end()); + if (size_) + std::sort(begin(), end()); } - Value & Value::mkAttrs(BindingsBuilder & bindings) { mkAttrs(bindings.finish()); return *this; } - } diff --git a/src/libexpr/attr-set.hh b/src/libexpr/attr-set.hh index dcc73b506917..1b877ef6aa63 100644 --- a/src/libexpr/attr-set.hh +++ b/src/libexpr/attr-set.hh @@ -8,7 +8,6 @@ namespace nix { - class EvalState; struct Value; @@ -23,15 +22,18 @@ struct Attr PosIdx pos; Value * value; Attr(Symbol name, Value * value, PosIdx pos = noPos) - : name(name), pos(pos), value(value) { }; - Attr() { }; - bool operator < (const Attr & a) const + : name(name) + , pos(pos) + , value(value){}; + Attr(){}; + bool operator<(const Attr & a) const { return name < a.name; } }; -static_assert(sizeof(Attr) == 2 * sizeof(uint32_t) + sizeof(Value *), +static_assert( + sizeof(Attr) == 2 * sizeof(uint32_t) + sizeof(Value *), "performance of the evaluator is highly sensitive to the size of Attr. " "avoid introducing any padding into Attr if at all possible, and do not " "introduce new fields that need not be present for almost every instance."); @@ -50,13 +52,22 @@ private: size_t size_, capacity_; Attr attrs[0]; - Bindings(size_t capacity) : size_(0), capacity_(capacity) { } + Bindings(size_t capacity) + : size_(0) + , capacity_(capacity) + {} Bindings(const Bindings & bindings) = delete; public: - size_t size() const { return size_; } + size_t size() const + { + return size_; + } - bool empty() const { return !size_; } + bool empty() const + { + return !size_; + } typedef Attr * iterator; @@ -70,7 +81,8 @@ public: { Attr key(name, 0); iterator i = std::lower_bound(begin(), end(), key); - if (i != end() && i->name == name) return i; + if (i != end() && i->name == name) + return i; return end(); } @@ -78,12 +90,19 @@ public: { Attr key(name, 0); iterator i = std::lower_bound(begin(), end(), key); - if (i != end() && i->name == name) return &*i; + if (i != end() && i->name == name) + return &*i; return nullptr; } - iterator begin() { return &attrs[0]; } - iterator end() { return &attrs[size_]; } + iterator begin() + { + return &attrs[0]; + } + iterator end() + { + return &attrs[size_]; + } Attr & operator[](size_t pos) { @@ -92,7 +111,10 @@ public: void sort(); - size_t capacity() { return capacity_; } + size_t capacity() + { + return capacity_; + } /* Returns the attributes in lexicographically sorted order. */ std::vector lexicographicOrder(const SymbolTable & symbols) const @@ -125,8 +147,9 @@ public: EvalState & state; BindingsBuilder(EvalState & state, Bindings * bindings) - : bindings(bindings), state(state) - { } + : bindings(bindings) + , state(state) + {} void insert(Symbol name, Value * value, PosIdx pos = noPos) { diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index dbfd8e70be59..155470222555 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -37,10 +37,7 @@ struct AttrDb SymbolTable & symbols; - AttrDb( - const Store & cfg, - const Hash & fingerprint, - SymbolTable & symbols) + AttrDb(const Store & cfg, const Hash & fingerprint, SymbolTable & symbols) : cfg(cfg) , _state(std::make_unique>()) , symbols(symbols) @@ -56,17 +53,16 @@ struct AttrDb state->db.isCache(); state->db.exec(schema); - state->insertAttribute.create(state->db, - "insert or replace into Attributes(parent, name, type, value) values (?, ?, ?, ?)"); + state->insertAttribute.create( + state->db, "insert or replace into Attributes(parent, name, type, value) values (?, ?, ?, ?)"); - state->insertAttributeWithContext.create(state->db, - "insert or replace into Attributes(parent, name, type, value, context) values (?, ?, ?, ?, ?)"); + state->insertAttributeWithContext.create( + state->db, "insert or replace into Attributes(parent, name, type, value, context) values (?, ?, ?, ?, ?)"); - state->queryAttribute.create(state->db, - "select rowid, type, value, context from Attributes where parent = ? and name = ?"); + state->queryAttribute.create( + state->db, "select rowid, type, value, context from Attributes where parent = ? and name = ?"); - state->queryAttributes.create(state->db, - "select name from Attributes where parent = ?"); + state->queryAttributes.create(state->db, "select name from Attributes where parent = ?"); state->txn = std::make_unique(state->db); } @@ -86,7 +82,8 @@ struct AttrDb template AttrId doSQLite(F && fun) { - if (failed) return 0; + if (failed) + return 0; try { return fun(); } catch (SQLiteError &) { @@ -96,116 +93,75 @@ struct AttrDb } } - AttrId setAttrs( - AttrKey key, - const std::vector & attrs) + AttrId setAttrs(AttrKey key, const std::vector & attrs) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::FullAttrs) - (0, false).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::FullAttrs)(0, false).exec(); AttrId rowId = state->db.getLastInsertedRowId(); assert(rowId); for (auto & attr : attrs) - state->insertAttribute.use() - (rowId) - (symbols[attr]) - (AttrType::Placeholder) - (0, false).exec(); + state->insertAttribute.use()(rowId)(symbols[attr])(AttrType::Placeholder)(0, false).exec(); return rowId; }); } - AttrId setString( - AttrKey key, - std::string_view s, - const char * * context = nullptr) + AttrId setString(AttrKey key, std::string_view s, const char ** context = nullptr) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); if (context) { std::string ctx; - for (const char * * p = context; *p; ++p) { - if (p != context) ctx.push_back(' '); + for (const char ** p = context; *p; ++p) { + if (p != context) + ctx.push_back(' '); ctx.append(*p); } - state->insertAttributeWithContext.use() - (key.first) - (symbols[key.second]) - (AttrType::String) - (s) - (ctx).exec(); + state->insertAttributeWithContext.use()(key.first)(symbols[key.second])(AttrType::String)(s) (ctx) + .exec(); } else { - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::String) - (s).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::String)(s).exec(); } return state->db.getLastInsertedRowId(); }); } - AttrId setBool( - AttrKey key, - bool b) + AttrId setBool(AttrKey key, bool b) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::Bool) - (b ? 1 : 0).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Bool)(b ? 1 : 0).exec(); return state->db.getLastInsertedRowId(); }); } - AttrId setInt( - AttrKey key, - int n) + AttrId setInt(AttrKey key, int n) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::Int) - (n).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Int)(n).exec(); return state->db.getLastInsertedRowId(); }); } - AttrId setListOfStrings( - AttrKey key, - const std::vector & l) + AttrId setListOfStrings(AttrKey key, const std::vector & l) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::ListOfStrings) - (concatStringsSep("\t", l)).exec(); + state->insertAttribute + .use()(key.first)(symbols[key.second])(AttrType::ListOfStrings)(concatStringsSep("\t", l)) + .exec(); return state->db.getLastInsertedRowId(); }); @@ -213,15 +169,10 @@ struct AttrDb AttrId setPlaceholder(AttrKey key) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::Placeholder) - (0, false).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Placeholder)(0, false).exec(); return state->db.getLastInsertedRowId(); }); @@ -229,15 +180,10 @@ struct AttrDb AttrId setMissing(AttrKey key) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::Missing) - (0, false).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Missing)(0, false).exec(); return state->db.getLastInsertedRowId(); }); @@ -245,15 +191,10 @@ struct AttrDb AttrId setMisc(AttrKey key) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::Misc) - (0, false).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Misc)(0, false).exec(); return state->db.getLastInsertedRowId(); }); @@ -261,15 +202,10 @@ struct AttrDb AttrId setFailed(AttrKey key) { - return doSQLite([&]() - { + return doSQLite([&]() { auto state(_state->lock()); - state->insertAttribute.use() - (key.first) - (symbols[key.second]) - (AttrType::Failed) - (0, false).exec(); + state->insertAttribute.use()(key.first)(symbols[key.second])(AttrType::Failed)(0, false).exec(); return state->db.getLastInsertedRowId(); }); @@ -280,51 +216,49 @@ struct AttrDb auto state(_state->lock()); auto queryAttribute(state->queryAttribute.use()(key.first)(symbols[key.second])); - if (!queryAttribute.next()) return {}; + if (!queryAttribute.next()) + return {}; auto rowId = (AttrId) queryAttribute.getInt(0); auto type = (AttrType) queryAttribute.getInt(1); switch (type) { - case AttrType::Placeholder: - return {{rowId, placeholder_t()}}; - case AttrType::FullAttrs: { - // FIXME: expensive, should separate this out. - std::vector attrs; - auto queryAttributes(state->queryAttributes.use()(rowId)); - while (queryAttributes.next()) - attrs.emplace_back(symbols.create(queryAttributes.getStr(0))); - return {{rowId, attrs}}; - } - case AttrType::String: { - NixStringContext context; - if (!queryAttribute.isNull(3)) - for (auto & s : tokenizeString>(queryAttribute.getStr(3), ";")) - context.push_back(decodeContext(cfg, s)); - return {{rowId, string_t{queryAttribute.getStr(2), context}}}; - } - case AttrType::Bool: - return {{rowId, queryAttribute.getInt(2) != 0}}; - case AttrType::Int: - return {{rowId, int_t{queryAttribute.getInt(2)}}}; - case AttrType::ListOfStrings: - return {{rowId, tokenizeString>(queryAttribute.getStr(2), "\t")}}; - case AttrType::Missing: - return {{rowId, missing_t()}}; - case AttrType::Misc: - return {{rowId, misc_t()}}; - case AttrType::Failed: - return {{rowId, failed_t()}}; - default: - throw Error("unexpected type in evaluation cache"); + case AttrType::Placeholder: + return {{rowId, placeholder_t()}}; + case AttrType::FullAttrs: { + // FIXME: expensive, should separate this out. + std::vector attrs; + auto queryAttributes(state->queryAttributes.use()(rowId)); + while (queryAttributes.next()) + attrs.emplace_back(symbols.create(queryAttributes.getStr(0))); + return {{rowId, attrs}}; + } + case AttrType::String: { + NixStringContext context; + if (!queryAttribute.isNull(3)) + for (auto & s : tokenizeString>(queryAttribute.getStr(3), ";")) + context.push_back(decodeContext(cfg, s)); + return {{rowId, string_t{queryAttribute.getStr(2), context}}}; + } + case AttrType::Bool: + return {{rowId, queryAttribute.getInt(2) != 0}}; + case AttrType::Int: + return {{rowId, int_t{queryAttribute.getInt(2)}}}; + case AttrType::ListOfStrings: + return {{rowId, tokenizeString>(queryAttribute.getStr(2), "\t")}}; + case AttrType::Missing: + return {{rowId, missing_t()}}; + case AttrType::Misc: + return {{rowId, misc_t()}}; + case AttrType::Failed: + return {{rowId, failed_t()}}; + default: + throw Error("unexpected type in evaluation cache"); } } }; -static std::shared_ptr makeAttrDb( - const Store & cfg, - const Hash & fingerprint, - SymbolTable & symbols) +static std::shared_ptr makeAttrDb(const Store & cfg, const Hash & fingerprint, SymbolTable & symbols) { try { return std::make_shared(cfg, fingerprint, symbols); @@ -335,14 +269,11 @@ static std::shared_ptr makeAttrDb( } EvalCache::EvalCache( - std::optional> useCache, - EvalState & state, - RootLoader rootLoader) + std::optional> useCache, EvalState & state, RootLoader rootLoader) : db(useCache ? makeAttrDb(*state.store, *useCache, state.symbols) : nullptr) , state(state) , rootLoader(rootLoader) -{ -} +{} Value * EvalCache::getRootValue() { @@ -359,11 +290,10 @@ ref EvalCache::getRoot() } AttrCursor::AttrCursor( - ref root, - Parent parent, - Value * value, - std::optional> && cachedValue) - : root(root), parent(parent), cachedValue(std::move(cachedValue)) + ref root, Parent parent, Value * value, std::optional> && cachedValue) + : root(root) + , parent(parent) + , cachedValue(std::move(cachedValue)) { if (value) _value = allocRootValue(value); @@ -440,8 +370,7 @@ Value & AttrCursor::forceValue() if (root->db && (!cachedValue || std::get_if(&cachedValue->second))) { if (v.type() == nString) - cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), - string_t{v.string.s, {}}}; + cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), string_t{v.string.s, {}}}; else if (v.type() == nPath) cachedValue = {root->db->setString(getKey(), v.path), string_t{v.path, {}}}; else if (v.type() == nBool) @@ -490,14 +419,14 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro else throw CachedEvalError("cached failure of attribute '%s'", getAttrPathStr(name)); } else - return std::make_shared(root, - std::make_pair(shared_from_this(), name), nullptr, std::move(attr)); + return std::make_shared( + root, std::make_pair(shared_from_this(), name), nullptr, std::move(attr)); } // Incomplete attrset, so need to fall thru and // evaluate to see whether 'name' exists } else return nullptr; - //throw TypeError("'%s' is not an attribute set", getAttrPathStr()); + // throw TypeError("'%s' is not an attribute set", getAttrPathStr()); } } @@ -505,7 +434,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro if (v.type() != nAttrs) return nullptr; - //throw TypeError("'%s' is not an attribute set", getAttrPathStr()); + // throw TypeError("'%s' is not an attribute set", getAttrPathStr()); for (auto & attr : *v.attrs) { if (root->db) @@ -530,8 +459,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro cachedValue2 = {root->db->setPlaceholder({cachedValue->first, name}), placeholder_t()}; } - return make_ref( - root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2)); + return make_ref(root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2)); } std::shared_ptr AttrCursor::maybeGetAttr(std::string_view name) @@ -746,8 +674,8 @@ StorePath AttrCursor::forceDerivation() been garbage-collected. So force it to be regenerated. */ aDrvPath->forceValue(); if (!root->state.store->isValidPath(drvPath)) - throw Error("don't know how to recreate store derivation '%s'!", - root->state.store->printStorePath(drvPath)); + throw Error( + "don't know how to recreate store derivation '%s'!", root->state.store->printStorePath(drvPath)); } return drvPath; } diff --git a/src/libexpr/eval-cache.hh b/src/libexpr/eval-cache.hh index c93e55b93d01..066789a889f3 100644 --- a/src/libexpr/eval-cache.hh +++ b/src/libexpr/eval-cache.hh @@ -28,10 +28,7 @@ class EvalCache : public std::enable_shared_from_this public: - EvalCache( - std::optional> useCache, - EvalState & state, - RootLoader rootLoader); + EvalCache(std::optional> useCache, EvalState & state, RootLoader rootLoader); ref getRoot(); }; @@ -48,11 +45,18 @@ enum AttrType { Int = 8, }; -struct placeholder_t {}; -struct missing_t {}; -struct misc_t {}; -struct failed_t {}; -struct int_t { NixInt x; }; +struct placeholder_t +{}; +struct missing_t +{}; +struct misc_t +{}; +struct failed_t +{}; +struct int_t +{ + NixInt x; +}; typedef uint64_t AttrId; typedef std::pair AttrKey; typedef std::pair string_t; @@ -66,8 +70,8 @@ typedef std::variant< failed_t, bool, int_t, - std::vector - > AttrValue; + std::vector> + AttrValue; class AttrCursor : public std::enable_shared_from_this { diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index f2f4ba725b61..95159685cf0f 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -5,8 +5,7 @@ namespace nix { /* Note: Various places expect the allocated memory to be zeroed. */ -[[gnu::always_inline]] -inline void * allocBytes(size_t n) +[[gnu::always_inline]] inline void * allocBytes(size_t n) { void * p; #if HAVE_BOEHMGC @@ -14,13 +13,12 @@ inline void * allocBytes(size_t n) #else p = calloc(n, 1); #endif - if (!p) throw std::bad_alloc(); + if (!p) + throw std::bad_alloc(); return p; } - -[[gnu::always_inline]] -Value * EvalState::allocValue() +[[gnu::always_inline]] Value * EvalState::allocValue() { #if HAVE_BOEHMGC /* We use the boehm batch allocator to speed up allocations of Values (of which there are many). @@ -29,7 +27,8 @@ Value * EvalState::allocValue() have to explicitly clear the first word of every object we take. */ if (!*valueAllocCache) { *valueAllocCache = GC_malloc_many(sizeof(Value)); - if (!*valueAllocCache) throw std::bad_alloc(); + if (!*valueAllocCache) + throw std::bad_alloc(); } /* GC_NEXT is a convenience macro for accessing the first word of an object. @@ -45,9 +44,7 @@ Value * EvalState::allocValue() return (Value *) p; } - -[[gnu::always_inline]] -Env & EvalState::allocEnv(size_t size) +[[gnu::always_inline]] Env & EvalState::allocEnv(size_t size) { nrEnvs++; nrValuesInEnvs += size; @@ -59,7 +56,8 @@ Env & EvalState::allocEnv(size_t size) /* see allocValue for explanations. */ if (!*env1AllocCache) { *env1AllocCache = GC_malloc_many(sizeof(Env) + sizeof(Value *)); - if (!*env1AllocCache) throw std::bad_alloc(); + if (!*env1AllocCache) + throw std::bad_alloc(); } void * p = *env1AllocCache; @@ -77,14 +75,11 @@ Env & EvalState::allocEnv(size_t size) return *env; } - -[[gnu::always_inline]] -void EvalState::forceValue(Value & v, const PosIdx pos) +[[gnu::always_inline]] void EvalState::forceValue(Value & v, const PosIdx pos) { forceValue(v, [&]() { return pos; }); } - template void EvalState::forceValue(Value & v, Callable getPos) { @@ -93,44 +88,36 @@ void EvalState::forceValue(Value & v, Callable getPos) Expr * expr = v.thunk.expr; try { v.mkBlackhole(); - //checkInterrupt(); + // checkInterrupt(); expr->eval(*this, *env, v); } catch (...) { v.mkThunk(env, expr); throw; } - } - else if (v.isApp()) + } else if (v.isApp()) callFunction(*v.app.left, *v.app.right, v, noPos); else if (v.isBlackhole()) throwEvalError(getPos(), "infinite recursion encountered"); } - -[[gnu::always_inline]] -inline void EvalState::forceAttrs(Value & v, const PosIdx pos) +[[gnu::always_inline]] inline void EvalState::forceAttrs(Value & v, const PosIdx pos) { forceAttrs(v, [&]() { return pos; }); } - -template -[[gnu::always_inline]] -inline void EvalState::forceAttrs(Value & v, Callable getPos) +template +[[gnu::always_inline]] inline void EvalState::forceAttrs(Value & v, Callable getPos) { forceValue(v, getPos); if (v.type() != nAttrs) throwTypeError(getPos(), "value is %1% while a set was expected", v); } - -[[gnu::always_inline]] -inline void EvalState::forceList(Value & v, const PosIdx pos) +[[gnu::always_inline]] inline void EvalState::forceList(Value & v, const PosIdx pos) { forceValue(v, pos); if (!v.isList()) throwTypeError(pos, "value is %1% while a list was expected", v); } - } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 40462afdfc68..24a085cf9e59 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -45,11 +45,11 @@ static char * allocString(size_t size) #else t = malloc(size); #endif - if (!t) throw std::bad_alloc(); + if (!t) + throw std::bad_alloc(); return t; } - static char * dupString(const char * s) { char * t; @@ -58,11 +58,11 @@ static char * dupString(const char * s) #else t = strdup(s); #endif - if (!t) throw std::bad_alloc(); + if (!t) + throw std::bad_alloc(); return t; } - // When there's no need to write to the string, we can optimize away empty // string allocations. // This function handles makeImmutableStringWithLen(null, 0) by returning the @@ -77,15 +77,16 @@ static const char * makeImmutableStringWithLen(const char * s, size_t size) #else t = strndup(s, size); #endif - if (!t) throw std::bad_alloc(); + if (!t) + throw std::bad_alloc(); return t; } -static inline const char * makeImmutableString(std::string_view s) { +static inline const char * makeImmutableString(std::string_view s) +{ return makeImmutableStringWithLen(s.data(), s.size()); } - RootValue allocRootValue(Value * v) { #if HAVE_BOEHMGC @@ -95,9 +96,7 @@ RootValue allocRootValue(Value * v) #endif } - -void Value::print(const SymbolTable & symbols, std::ostream & str, - std::set * seen) const +void Value::print(const SymbolTable & symbols, std::ostream & str, std::set * seen) const { checkInterrupt(); @@ -111,12 +110,18 @@ void Value::print(const SymbolTable & symbols, std::ostream & str, case tString: str << "\""; for (const char * i = string.s; *i; i++) - if (*i == '\"' || *i == '\\') str << "\\" << *i; - else if (*i == '\n') str << "\\n"; - else if (*i == '\r') str << "\\r"; - else if (*i == '\t') str << "\\t"; - else if (*i == '$' && *(i+1) == '{') str << "\\" << *i; - else str << *i; + if (*i == '\"' || *i == '\\') + str << "\\" << *i; + else if (*i == '\n') + str << "\\n"; + else if (*i == '\r') + str << "\\r"; + else if (*i == '\t') + str << "\\t"; + else if (*i == '$' && *(i + 1) == '{') + str << "\\" << *i; + else + str << *i; str << "\""; break; case tPath: @@ -180,7 +185,6 @@ void Value::print(const SymbolTable & symbols, std::ostream & str, } } - void Value::print(const SymbolTable & symbols, std::ostream & str, bool showRepeated) const { std::set seen; @@ -188,7 +192,8 @@ void Value::print(const SymbolTable & symbols, std::ostream & str, bool showRepe } // Pretty print types for assertion errors -std::ostream & operator << (std::ostream & os, const ValueType t) { +std::ostream & operator<<(std::ostream & os, const ValueType t) +{ os << showType(t); return os; } @@ -200,8 +205,8 @@ std::string printValue(const EvalState & state, const Value & v) return out.str(); } - -const Value * getPrimOp(const Value &v) { +const Value * getPrimOp(const Value & v) +{ const Value * primOp = &v; while (primOp->isPrimOpApp()) { primOp = primOp->primOpApp.left; @@ -213,34 +218,49 @@ const Value * getPrimOp(const Value &v) { std::string_view showType(ValueType type) { switch (type) { - case nInt: return "an integer"; - case nBool: return "a Boolean"; - case nString: return "a string"; - case nPath: return "a path"; - case nNull: return "null"; - case nAttrs: return "a set"; - case nList: return "a list"; - case nFunction: return "a function"; - case nExternal: return "an external value"; - case nFloat: return "a float"; - case nThunk: return "a thunk"; + case nInt: + return "an integer"; + case nBool: + return "a Boolean"; + case nString: + return "a string"; + case nPath: + return "a path"; + case nNull: + return "null"; + case nAttrs: + return "a set"; + case nList: + return "a list"; + case nFunction: + return "a function"; + case nExternal: + return "an external value"; + case nFloat: + return "a float"; + case nThunk: + return "a thunk"; } abort(); } - std::string showType(const Value & v) { switch (v.internalType) { - case tString: return v.string.context ? "a string with context" : "a string"; - case tPrimOp: - return fmt("the built-in function '%s'", std::string(v.primOp->name)); - case tPrimOpApp: - return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name)); - case tExternal: return v.external->showType(); - case tThunk: return "a thunk"; - case tApp: return "a function application"; - case tBlackhole: return "a black hole"; + case tString: + return v.string.context ? "a string with context" : "a string"; + case tPrimOp: + return fmt("the built-in function '%s'", std::string(v.primOp->name)); + case tPrimOpApp: + return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name)); + case tExternal: + return v.external->showType(); + case tThunk: + return "a thunk"; + case tApp: + return "a function application"; + case tBlackhole: + return "a black hole"; default: return std::string(showType(v.type())); } @@ -249,26 +269,25 @@ std::string showType(const Value & v) PosIdx Value::determinePos(const PosIdx pos) const { switch (internalType) { - case tAttrs: return attrs->pos; - case tLambda: return lambda.fun->pos; - case tApp: return app.left->determinePos(pos); - default: return pos; + case tAttrs: + return attrs->pos; + case tLambda: + return lambda.fun->pos; + case tApp: + return app.left->determinePos(pos); + default: + return pos; } } bool Value::isTrivial() const { - return - internalType != tApp - && internalType != tPrimOpApp - && (internalType != tThunk - || (dynamic_cast(thunk.expr) - && ((ExprAttrs *) thunk.expr)->dynamicAttrs.empty()) - || dynamic_cast(thunk.expr) - || dynamic_cast(thunk.expr)); + return internalType != tApp && internalType != tPrimOpApp + && (internalType != tThunk + || (dynamic_cast(thunk.expr) && ((ExprAttrs *) thunk.expr)->dynamicAttrs.empty()) + || dynamic_cast(thunk.expr) || dynamic_cast(thunk.expr)); } - #if HAVE_BOEHMGC /* Called when the Boehm GC runs out of memory. */ static void * oomHandler(size_t requested) @@ -277,23 +296,25 @@ static void * oomHandler(size_t requested) throw std::bad_alloc(); } -class BoehmGCStackAllocator : public StackAllocator { - boost::coroutines2::protected_fixedsize_stack stack { +class BoehmGCStackAllocator : public StackAllocator +{ + boost::coroutines2::protected_fixedsize_stack stack{ // We allocate 8 MB, the default max stack size on NixOS. // A smaller stack might be quicker to allocate but reduces the stack // depth available for source filter expressions etc. - std::max(boost::context::stack_traits::default_size(), static_cast(8 * 1024 * 1024)) - }; + std::max(boost::context::stack_traits::default_size(), static_cast(8 * 1024 * 1024))}; // This is specific to boost::coroutines2::protected_fixedsize_stack. // The stack protection page is included in sctx.size, so we have to // subtract one page size from the stack size. - std::size_t pfss_usable_stack_size(boost::context::stack_context &sctx) { + std::size_t pfss_usable_stack_size(boost::context::stack_context & sctx) + { return sctx.size - boost::context::stack_traits::page_size(); } - public: - boost::context::stack_context allocate() override { +public: + boost::context::stack_context allocate() override + { auto sctx = stack.allocate(); // Stacks generally start at a high address and grow to lower addresses. @@ -304,18 +325,17 @@ class BoehmGCStackAllocator : public StackAllocator { return sctx; } - void deallocate(boost::context::stack_context sctx) override { + void deallocate(boost::context::stack_context sctx) override + { GC_remove_roots(static_cast(sctx.sp) - pfss_usable_stack_size(sctx), sctx.sp); stack.deallocate(sctx); } - }; static BoehmGCStackAllocator boehmGCStackAllocator; #endif - static Symbol getName(const AttrName & name, EvalState & state, Env & env) { if (name.symbol) { @@ -328,12 +348,12 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env) } } - static bool gcInitialised = false; void initGC() { - if (gcInitialised) return; + if (gcInitialised) + return; #if HAVE_BOEHMGC /* Initialise the Boehm garbage collector. */ @@ -369,7 +389,8 @@ void initGC() long pages = sysconf(_SC_PHYS_PAGES); if (pageSize != -1) size = (pageSize * pages) / 4; // 25% of RAM - if (size > maxSize) size = maxSize; + if (size > maxSize) + size = maxSize; #endif debug(format("setting initial heap size to %1% bytes") % size); GC_expand_hp(size); @@ -380,7 +401,6 @@ void initGC() gcInitialised = true; } - /* Very hacky way to parse $NIX_PATH, which is colon-separated, but can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */ static Strings parseNixPath(const std::string & s) @@ -394,22 +414,26 @@ static Strings parseNixPath(const std::string & s) auto start2 = p; while (p != s.end() && *p != ':') { - if (*p == '=') start2 = p + 1; + if (*p == '=') + start2 = p + 1; ++p; } if (p == s.end()) { - if (p != start) res.push_back(std::string(start, p)); + if (p != start) + res.push_back(std::string(start, p)); break; } if (*p == ':') { if (isUri(std::string(start2, s.end()))) { ++p; - while (p != s.end() && *p != ':') ++p; + while (p != s.end() && *p != ':') + ++p; } res.push_back(std::string(start, p)); - if (p == s.end()) break; + if (p == s.end()) + break; } ++p; @@ -418,11 +442,7 @@ static Strings parseNixPath(const std::string & s) return res; } - -EvalState::EvalState( - const Strings & _searchPath, - ref store, - std::shared_ptr buildStore) +EvalState::EvalState(const Strings & _searchPath, ref store, std::shared_ptr buildStore) : sWith(symbols.create("")) , sOutPath(symbols.create("outPath")) , sDrvPath(symbols.create("drvPath")) @@ -486,8 +506,10 @@ EvalState::EvalState( /* Initialise the Nix expression search path. */ if (!evalSettings.pureEval) { - for (auto & i : _searchPath) addToSearchPath(i); - for (auto & i : evalSettings.nixPath.get()) addToSearchPath(i); + for (auto & i : _searchPath) + addToSearchPath(i); + for (auto & i : evalSettings.nixPath.get()) + addToSearchPath(i); } if (evalSettings.restrictEval || evalSettings.pureEval) { @@ -495,7 +517,8 @@ EvalState::EvalState( for (auto & i : searchPath) { auto r = resolveSearchPathElem(i); - if (!r.first) continue; + if (!r.first) + continue; auto path = r.second; @@ -516,11 +539,7 @@ EvalState::EvalState( createBaseEnv(); } - -EvalState::~EvalState() -{ -} - +EvalState::~EvalState() {} void EvalState::allowPath(const Path & path) { @@ -544,7 +563,8 @@ void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & Path EvalState::checkSourcePath(const Path & path_) { - if (!allowedPaths) return path_; + if (!allowedPaths) + return path_; auto i = resolvedPaths.find(path_); if (i != resolvedPaths.end()) @@ -558,7 +578,8 @@ Path EvalState::checkSourcePath(const Path & path_) */ Path abspath = canonPath(path_); - if (hasPrefix(abspath, corepkgsPrefix)) return abspath; + if (hasPrefix(abspath, corepkgsPrefix)) + return abspath; for (auto & i : *allowedPaths) { if (isDirOrInDir(abspath, i)) { @@ -568,9 +589,8 @@ Path EvalState::checkSourcePath(const Path & path_) } if (!found) { - auto modeInformation = evalSettings.pureEval - ? "in pure eval mode (use '--impure' to override)" - : "in restricted mode"; + auto modeInformation = + evalSettings.pureEval ? "in pure eval mode (use '--impure' to override)" : "in restricted mode"; throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", abspath, modeInformation); } @@ -588,21 +608,19 @@ Path EvalState::checkSourcePath(const Path & path_) throw RestrictedPathError("access to canonical path '%1%' is forbidden in restricted mode", path); } - void EvalState::checkURI(const std::string & uri) { - if (!evalSettings.restrictEval) return; + if (!evalSettings.restrictEval) + return; /* 'uri' should be equal to a prefix, or in a subdirectory of a prefix. Thus, the prefix https://github.co does not permit access to https://github.com. Note: this allows 'http://' and 'https://' as prefixes for any http/https URI. */ for (auto & prefix : evalSettings.allowedUris.get()) - if (uri == prefix || - (uri.size() > prefix.size() - && prefix.size() > 0 - && hasPrefix(uri, prefix) - && (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/'))) + if (uri == prefix + || (uri.size() > prefix.size() && prefix.size() > 0 && hasPrefix(uri, prefix) + && (prefix[prefix.size() - 1] == '/' || uri[prefix.size()] == '/'))) return; /* If the URI is a path, then check it against allowedPaths as @@ -620,17 +638,12 @@ void EvalState::checkURI(const std::string & uri) throw RestrictedPathError("access to URI '%s' is forbidden in restricted mode", uri); } - Path EvalState::toRealPath(const Path & path, const PathSet & context) { // FIXME: check whether 'path' is in 'context'. - return - !context.empty() && store->isInStore(path) - ? store->toRealPath(path) - : path; + return !context.empty() && store->isInStore(path) ? store->toRealPath(path) : path; } - Value * EvalState::addConstant(const std::string & name, Value & v) { Value * v2 = allocValue(); @@ -639,7 +652,6 @@ Value * EvalState::addConstant(const std::string & name, Value & v) return v2; } - void EvalState::addConstant(const std::string & name, Value * v) { staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl); @@ -648,9 +660,7 @@ void EvalState::addConstant(const std::string & name, Value * v) baseEnv.values[0]->attrs->push_back(Attr(symbols.create(name2), v)); } - -Value * EvalState::addPrimOp(const std::string & name, - size_t arity, PrimOpFun primOp) +Value * EvalState::addPrimOp(const std::string & name, size_t arity, PrimOpFun primOp) { auto name2 = name.substr(0, 2) == "__" ? name.substr(2) : name; auto sym = symbols.create(name2); @@ -659,21 +669,20 @@ Value * EvalState::addPrimOp(const std::string & name, the primop to a dummy value. */ if (arity == 0) { auto vPrimOp = allocValue(); - vPrimOp->mkPrimOp(new PrimOp { .fun = primOp, .arity = 1, .name = name2 }); + vPrimOp->mkPrimOp(new PrimOp{.fun = primOp, .arity = 1, .name = name2}); Value v; v.mkApp(vPrimOp, vPrimOp); return addConstant(name, v); } Value * v = allocValue(); - v->mkPrimOp(new PrimOp { .fun = primOp, .arity = arity, .name = name2 }); + v->mkPrimOp(new PrimOp{.fun = primOp, .arity = arity, .name = name2}); staticBaseEnv->vars.emplace_back(symbols.create(name), baseEnvDispl); baseEnv.values[baseEnvDispl++] = v; baseEnv.values[0]->attrs->push_back(Attr(sym, v)); return v; } - Value * EvalState::addPrimOp(PrimOp && primOp) { /* Hack to make constants lazy: turn them into a application of @@ -699,19 +708,17 @@ Value * EvalState::addPrimOp(PrimOp && primOp) return v; } - Value & EvalState::getBuiltin(const std::string & name) { return *baseEnv.values[0]->attrs->find(symbols.create(name))->value; } - std::optional EvalState::getDoc(Value & v) { if (v.isPrimOp()) { auto v2 = &v; if (v2->primOp->doc) - return Doc { + return Doc{ .pos = {}, .name = v2->primOp->name, .arity = v2->primOp->arity, @@ -722,7 +729,6 @@ std::optional EvalState::getDoc(Value & v) return {}; } - // just for the current level of StaticEnv, not the whole chain. void printStaticEnvBindings(const SymbolTable & st, const StaticEnv & se) { @@ -768,13 +774,12 @@ void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & std::cout << st[i.first] << " "; std::cout << ANSI_NORMAL; std::cout << std::endl; - printWithBindings(st, env); // probably nothing there for the top level. + printWithBindings(st, env); // probably nothing there for the top level. std::cout << std::endl; - } } -void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env) +void printEnvBindings(const EvalState & es, const Expr & expr, const Env & env) { // just print the names for now auto se = es.getStaticEnv(expr); @@ -818,21 +823,21 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & if (!debugRepl) return; - auto dts = - error && expr.getPos() - ? std::make_unique( - *this, - DebugTrace { - .pos = error->info().errPos ? *error->info().errPos : positions[expr.getPos()], - .expr = expr, - .env = env, - .hint = error->info().msg, - .isError = true - }) - : nullptr; + auto dts = error && expr.getPos() ? std::make_unique( + *this, + DebugTrace{ + .pos = error->info().errPos ? *error->info().errPos : positions[expr.getPos()], + .expr = expr, + .env = env, + .hint = error->info().msg, + .isError = true}) + : nullptr; if (error) - printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what()); + printError( + "%s\n\n" ANSI_BOLD + "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, + error->what()); auto se = getStaticEnv(expr); if (se) { @@ -847,18 +852,12 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr & exceptions. */ void EvalState::throwEvalError(const PosIdx pos, const char * s, Env & env, Expr & expr) { - debugThrow(EvalError({ - .msg = hintfmt(s), - .errPos = positions[pos] - }), env, expr); + debugThrow(EvalError({.msg = hintfmt(s), .errPos = positions[pos]}), env, expr); } void EvalState::throwEvalError(const PosIdx pos, const char * s) { - debugThrowLastTrace(EvalError({ - .msg = hintfmt(s), - .errPos = positions[pos] - })); + debugThrowLastTrace(EvalError({.msg = hintfmt(s), .errPos = positions[pos]})); } void EvalState::throwEvalError(const char * s, const std::string & s2) @@ -866,141 +865,115 @@ void EvalState::throwEvalError(const char * s, const std::string & s2) debugThrowLastTrace(EvalError(s, s2)); } -void EvalState::throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const std::string & s2, Env & env, Expr & expr) +void EvalState::throwEvalError( + const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, Env & env, Expr & expr) { - debugThrow(EvalError(ErrorInfo{ - .msg = hintfmt(s, s2), - .errPos = positions[pos], - .suggestions = suggestions, - }), env, expr); + debugThrow( + EvalError(ErrorInfo{ + .msg = hintfmt(s, s2), + .errPos = positions[pos], + .suggestions = suggestions, + }), + env, expr); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2) { - debugThrowLastTrace(EvalError({ - .msg = hintfmt(s, s2), - .errPos = positions[pos] - })); + debugThrowLastTrace(EvalError({.msg = hintfmt(s, s2), .errPos = positions[pos]})); } void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr) { - debugThrow(EvalError({ - .msg = hintfmt(s, s2), - .errPos = positions[pos] - }), env, expr); + debugThrow(EvalError({.msg = hintfmt(s, s2), .errPos = positions[pos]}), env, expr); } -void EvalState::throwEvalError(const char * s, const std::string & s2, - const std::string & s3) +void EvalState::throwEvalError(const char * s, const std::string & s2, const std::string & s3) { - debugThrowLastTrace(EvalError({ - .msg = hintfmt(s, s2), - .errPos = positions[noPos] - })); + debugThrowLastTrace(EvalError({.msg = hintfmt(s, s2), .errPos = positions[noPos]})); } -void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - const std::string & s3) +void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3) { - debugThrowLastTrace(EvalError({ - .msg = hintfmt(s, s2), - .errPos = positions[pos] - })); + debugThrowLastTrace(EvalError({.msg = hintfmt(s, s2), .errPos = positions[pos]})); } -void EvalState::throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - const std::string & s3, Env & env, Expr & expr) +void EvalState::throwEvalError( + const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, Env & env, Expr & expr) { - debugThrow(EvalError({ - .msg = hintfmt(s, s2), - .errPos = positions[pos] - }), env, expr); + debugThrow(EvalError({.msg = hintfmt(s, s2), .errPos = positions[pos]}), env, expr); } -void EvalState::throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) +void EvalState::throwEvalError( + const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr) { // p1 is where the error occurred; p2 is a position mentioned in the message. - debugThrow(EvalError({ - .msg = hintfmt(s, symbols[sym], positions[p2]), - .errPos = positions[p1] - }), env, expr); + debugThrow(EvalError({.msg = hintfmt(s, symbols[sym], positions[p2]), .errPos = positions[p1]}), env, expr); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v) { - debugThrowLastTrace(TypeError({ - .msg = hintfmt(s, showType(v)), - .errPos = positions[pos] - })); + debugThrowLastTrace(TypeError({.msg = hintfmt(s, showType(v)), .errPos = positions[pos]})); } void EvalState::throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr) { - debugThrow(TypeError({ - .msg = hintfmt(s, showType(v)), - .errPos = positions[pos] - }), env, expr); + debugThrow(TypeError({.msg = hintfmt(s, showType(v)), .errPos = positions[pos]}), env, expr); } void EvalState::throwTypeError(const PosIdx pos, const char * s) { - debugThrowLastTrace(TypeError({ - .msg = hintfmt(s), - .errPos = positions[pos] - })); + debugThrowLastTrace(TypeError({.msg = hintfmt(s), .errPos = positions[pos]})); } -void EvalState::throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, - const Symbol s2, Env & env, Expr &expr) +void EvalState::throwTypeError( + const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, Env & env, Expr & expr) { - debugThrow(TypeError({ - .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), - .errPos = positions[pos] - }), env, expr); + debugThrow( + TypeError({.msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), .errPos = positions[pos]}), env, expr); } -void EvalState::throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, - const ExprLambda & fun, const Symbol s2, Env & env, Expr &expr) +void EvalState::throwTypeError( + const PosIdx pos, + const Suggestions & suggestions, + const char * s, + const ExprLambda & fun, + const Symbol s2, + Env & env, + Expr & expr) { - debugThrow(TypeError(ErrorInfo { - .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), - .errPos = positions[pos], - .suggestions = suggestions, - }), env, expr); + debugThrow( + TypeError(ErrorInfo{ + .msg = hintfmt(s, fun.showNamePos(*this), symbols[s2]), + .errPos = positions[pos], + .suggestions = suggestions, + }), + env, expr); } -void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr &expr) +void EvalState::throwTypeError(const char * s, const Value & v, Env & env, Expr & expr) { - debugThrow(TypeError({ - .msg = hintfmt(s, showType(v)), - .errPos = positions[expr.getPos()], - }), env, expr); + debugThrow( + TypeError({ + .msg = hintfmt(s, showType(v)), + .errPos = positions[expr.getPos()], + }), + env, expr); } -void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) +void EvalState::throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr & expr) { - debugThrow(AssertionError({ - .msg = hintfmt(s, s1), - .errPos = positions[pos] - }), env, expr); + debugThrow(AssertionError({.msg = hintfmt(s, s1), .errPos = positions[pos]}), env, expr); } -void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) +void EvalState::throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr & expr) { - debugThrow(UndefinedVarError({ - .msg = hintfmt(s, s1), - .errPos = positions[pos] - }), env, expr); + debugThrow(UndefinedVarError({.msg = hintfmt(s, s1), .errPos = positions[pos]}), env, expr); } -void EvalState::throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr &expr) +void EvalState::throwMissingArgumentError( + const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr & expr) { - debugThrow(MissingArgumentError({ - .msg = hintfmt(s, s1), - .errPos = positions[pos] - }), env, expr); + debugThrow(MissingArgumentError({.msg = hintfmt(s, s1), .errPos = positions[pos]}), env, expr); } void EvalState::addErrorTrace(Error & e, const char * s, const std::string & s2) const @@ -1014,21 +987,10 @@ void EvalState::addErrorTrace(Error & e, const PosIdx pos, const char * s, const } static std::unique_ptr makeDebugTraceStacker( - EvalState & state, - Expr & expr, - Env & env, - std::optional pos, - const char * s, - const std::string & s2) + EvalState & state, Expr & expr, Env & env, std::optional pos, const char * s, const std::string & s2) { - return std::make_unique(state, - DebugTrace { - .pos = pos, - .expr = expr, - .env = env, - .hint = hintfmt(s, s2), - .isError = false - }); + return std::make_unique( + state, DebugTrace{.pos = pos, .expr = expr, .env = env, .hint = hintfmt(s, s2), .isError = false}); } DebugTraceStacker::DebugTraceStacker(EvalState & evalState, DebugTrace t) @@ -1045,13 +1007,11 @@ void Value::mkString(std::string_view s) mkString(makeImmutableString(s)); } - static void copyContextToValue(Value & v, const PathSet & context) { if (!context.empty()) { size_t n = 0; - v.string.context = (const char * *) - allocBytes((context.size() + 1) * sizeof(char *)); + v.string.context = (const char **) allocBytes((context.size() + 1) * sizeof(char *)); for (auto & i : context) v.string.context[n++] = dupString(i.c_str()); v.string.context[n] = 0; @@ -1070,22 +1030,23 @@ void Value::mkStringMove(const char * s, const PathSet & context) copyContextToValue(*this, context); } - void Value::mkPath(std::string_view s) { mkPath(makeImmutableString(s)); } - inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) { - for (auto l = var.level; l; --l, env = env->up) ; + for (auto l = var.level; l; --l, env = env->up) + ; - if (!var.fromWith) return env->values[var.displ]; + if (!var.fromWith) + return env->values[var.displ]; while (1) { if (env->type == Env::HasWithExpr) { - if (noEval) return 0; + if (noEval) + return 0; Value * v = allocValue(); evalAttrs(*env->up, (Expr *) env->values[0], *v); env->values[0] = v; @@ -1093,12 +1054,15 @@ inline Value * EvalState::lookupVar(Env * env, const ExprVar & var, bool noEval) } Bindings::iterator j = env->values[0]->attrs->find(var.name); if (j != env->values[0]->attrs->end()) { - if (countCalls) attrSelects[j->pos]++; + if (countCalls) + attrSelects[j->pos]++; return j->value; } if (!env->prevWith) - throwUndefinedVarError(var.pos, "undefined variable '%1%'", symbols[var.name], *env, const_cast(var)); - for (size_t l = env->prevWith; l; --l, env = env->up) ; + throwUndefinedVarError( + var.pos, "undefined variable '%1%'", symbols[var.name], *env, const_cast(var)); + for (size_t l = env->prevWith; l; --l, env = env->up) + ; } } @@ -1106,11 +1070,10 @@ void EvalState::mkList(Value & v, size_t size) { v.mkList(size); if (size > 2) - v.bigList.elems = (Value * *) allocBytes(size * sizeof(Value *)); + v.bigList.elems = (Value **) allocBytes(size * sizeof(Value *)); nrListElems += size; } - unsigned long nrThunks = 0; static inline void mkThunk(Value & v, Env & env, Expr * expr) @@ -1119,13 +1082,11 @@ static inline void mkThunk(Value & v, Env & env, Expr * expr) nrThunks++; } - void EvalState::mkThunk_(Value & v, Expr * expr) { mkThunk(v, baseEnv, expr); } - void EvalState::mkPos(Value & v, PosIdx p) { auto pos = positions[p]; @@ -1139,7 +1100,6 @@ void EvalState::mkPos(Value & v, PosIdx p) v.mkNull(); } - /* Create a thunk for the delayed computation of the given expression in the given environment. But if the expression is a variable, then look it up right away. This significantly reduces the number @@ -1151,17 +1111,18 @@ Value * Expr::maybeThunk(EvalState & state, Env & env) return v; } - Value * ExprVar::maybeThunk(EvalState & state, Env & env) { Value * v = state.lookupVar(&env, *this, true); /* The value might not be initialised in the environment yet. In that case, ignore it. */ - if (v) { state.nrAvoided++; return v; } + if (v) { + state.nrAvoided++; + return v; + } return Expr::maybeThunk(state, env); } - Value * ExprString::maybeThunk(EvalState & state, Env & env) { state.nrAvoided++; @@ -1186,7 +1147,6 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env) return &v; } - void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial) { auto path = checkSourcePath(path_); @@ -1216,37 +1176,26 @@ void EvalState::evalFile(const Path & path_, Value & v, bool mustBeTrivial) cacheFile(path, resolvedPath, e, v, mustBeTrivial); } - void EvalState::resetFileCache() { fileEvalCache.clear(); fileParseCache.clear(); } - -void EvalState::cacheFile( - const Path & path, - const Path & resolvedPath, - Expr * e, - Value & v, - bool mustBeTrivial) +void EvalState::cacheFile(const Path & path, const Path & resolvedPath, Expr * e, Value & v, bool mustBeTrivial) { fileParseCache[resolvedPath] = e; try { - auto dts = debugRepl - ? makeDebugTraceStacker( - *this, - *e, - this->baseEnv, - e->getPos() ? std::optional(ErrPos(positions[e->getPos()])) : std::nullopt, + auto dts = + debugRepl ? makeDebugTraceStacker( + *this, *e, this->baseEnv, e->getPos() ? std::optional(ErrPos(positions[e->getPos()])) : std::nullopt, "while evaluating the file '%1%':", resolvedPath) - : nullptr; + : nullptr; // Enforce that 'flake.nix' is a direct attrset, not a // computation. - if (mustBeTrivial && - !(dynamic_cast(e))) + if (mustBeTrivial && !(dynamic_cast(e))) throw EvalError("file '%s' must be an attribute set", path); eval(e, v); } catch (Error & e) { @@ -1255,16 +1204,15 @@ void EvalState::cacheFile( } fileEvalCache[resolvedPath] = v; - if (path != resolvedPath) fileEvalCache[path] = v; + if (path != resolvedPath) + fileEvalCache[path] = v; } - void EvalState::eval(Expr * e, Value & v) { e->eval(*this, baseEnv, v); } - inline bool EvalState::evalBool(Env & env, Expr * e) { Value v; @@ -1274,7 +1222,6 @@ inline bool EvalState::evalBool(Env & env, Expr * e) return v.boolean; } - inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos) { Value v; @@ -1284,7 +1231,6 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const PosIdx pos) return v.boolean; } - inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); @@ -1292,19 +1238,16 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) throwTypeError(noPos, "value is %1% while a set was expected", v, env, *e); } - void Expr::eval(EvalState & state, Env & env, Value & v) { abort(); } - void ExprInt::eval(EvalState & state, Env & env, Value & v) { v = this->v; } - void ExprFloat::eval(EvalState & state, Env & env, Value & v) { v = this->v; @@ -1315,13 +1258,11 @@ void ExprString::eval(EvalState & state, Env & env, Value & v) v = this->v; } - void ExprPath::eval(EvalState & state, Env & env, Value & v) { v = this->v; } - void ExprAttrs::eval(EvalState & state, Env & env, Value & v) { v.mkAttrs(state.buildBindings(attrs.size() + dynamicAttrs.size()).finish()); @@ -1405,7 +1346,6 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) v.attrs->pos = pos; } - void ExprLet::eval(EvalState & state, Env & env, Value & v) { /* Create a new environment that contains the attributes in this @@ -1423,15 +1363,13 @@ void ExprLet::eval(EvalState & state, Env & env, Value & v) body->eval(state, env2, v); } - void ExprList::eval(EvalState & state, Env & env, Value & v) { state.mkList(v, elems.size()); for (auto [n, v2] : enumerate(v.listItems())) - const_cast(v2) = elems[n]->maybeThunk(state, env); + const_cast(v2) = elems[n]->maybeThunk(state, env); } - void ExprVar::eval(EvalState & state, Env & env, Value & v) { Value * v2 = state.lookupVar(&env, *this, false); @@ -1439,13 +1377,15 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v) v = *v2; } - static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & attrPath) { std::ostringstream out; bool first = true; for (auto & i : attrPath) { - if (!first) out << '.'; else first = false; + if (!first) + out << '.'; + else + first = false; try { out << state.symbols[getName(i, state, env)]; } catch (Error & e) { @@ -1458,7 +1398,6 @@ static std::string showAttrPath(EvalState & state, Env & env, const AttrPath & a return out.str(); } - void ExprSelect::eval(EvalState & state, Env & env, Value & v) { Value vTmp; @@ -1468,15 +1407,10 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) e->eval(state, env, vTmp); try { - auto dts = state.debugRepl - ? makeDebugTraceStacker( - state, - *this, - env, - state.positions[pos2], - "while evaluating the attribute '%1%'", - showAttrPath(state, env, attrPath)) - : nullptr; + auto dts = state.debugRepl ? makeDebugTraceStacker( + state, *this, env, state.positions[pos2], "while evaluating the attribute '%1%'", + showAttrPath(state, env, attrPath)) + : nullptr; for (auto & i : attrPath) { state.nrLookups++; @@ -1484,9 +1418,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) auto name = getName(i, state, env); if (def) { state.forceValue(*vAttrs, pos); - if (vAttrs->type() != nAttrs || - (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - { + if (vAttrs->type() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { def->eval(state, env, v); return; } @@ -1497,30 +1429,28 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) for (auto & attr : *vAttrs->attrs) allAttrNames.insert(state.symbols[attr.name]); state.throwEvalError( - pos, - Suggestions::bestMatches(allAttrNames, state.symbols[name]), - "attribute '%1%' missing", state.symbols[name], env, *this); + pos, Suggestions::bestMatches(allAttrNames, state.symbols[name]), "attribute '%1%' missing", + state.symbols[name], env, *this); } } vAttrs = j->value; pos2 = j->pos; - if (state.countCalls) state.attrSelects[pos2]++; + if (state.countCalls) + state.attrSelects[pos2]++; } - state.forceValue(*vAttrs, (pos2 ? pos2 : this->pos ) ); + state.forceValue(*vAttrs, (pos2 ? pos2 : this->pos)); } catch (Error & e) { auto pos2r = state.positions[pos2]; if (pos2 && pos2r.file != state.derivationNixPath) - state.addErrorTrace(e, pos2, "while evaluating the attribute '%1%'", - showAttrPath(state, env, attrPath)); + state.addErrorTrace(e, pos2, "while evaluating the attribute '%1%'", showAttrPath(state, env, attrPath)); throw; } v = *vAttrs; } - void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) { Value vTmp; @@ -1532,9 +1462,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) state.forceValue(*vAttrs, noPos); Bindings::iterator j; auto name = getName(i, state, env); - if (vAttrs->type() != nAttrs || - (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) - { + if (vAttrs->type() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { v.mkBool(false); return; } else { @@ -1545,25 +1473,20 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) v.mkBool(true); } - void ExprLambda::eval(EvalState & state, Env & env, Value & v) { v.mkLambda(&env, this); } - -void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos) +void EvalState::callFunction(Value & fun, size_t nrArgs, Value ** args, Value & vRes, const PosIdx pos) { - auto trace = evalSettings.traceFunctionCalls - ? std::make_unique(positions[pos]) - : nullptr; + auto trace = evalSettings.traceFunctionCalls ? std::make_unique(positions[pos]) : nullptr; forceValue(fun, pos); Value vCur(fun); - auto makeAppChain = [&]() - { + auto makeAppChain = [&]() { vRes = vCur; for (size_t i = 0; i < nrArgs; ++i) { auto fun2 = allocValue(); @@ -1580,9 +1503,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & ExprLambda & lambda(*vCur.lambda.fun); - auto size = - (!lambda.arg ? 0 : 1) + - (lambda.hasFormals() ? lambda.formals->formals.size() : 0); + auto size = (!lambda.arg ? 0 : 1) + (lambda.hasFormals() ? lambda.formals->formals.size() : 0); Env & env2(allocEnv(size)); env2.up = vCur.lambda.env; @@ -1603,8 +1524,10 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & for (auto & i : lambda.formals->formals) { auto j = args[0]->attrs->get(i.name); if (!j) { - if (!i.def) throwTypeError(pos, "%1% called without required argument '%2%'", - lambda, i.name, *fun.lambda.env, lambda); + if (!i.def) + throwTypeError( + pos, "%1% called without required argument '%2%'", lambda, i.name, *fun.lambda.env, + lambda); env2.values[displ++] = i.def->maybeThunk(*this, env2); } else { attrsUsed++; @@ -1623,36 +1546,30 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & for (auto & formal : lambda.formals->formals) formalNames.insert(symbols[formal.name]); throwTypeError( - pos, - Suggestions::bestMatches(formalNames, symbols[i.name]), - "%1% called with unexpected argument '%2%'", - lambda, i.name, *fun.lambda.env, lambda); + pos, Suggestions::bestMatches(formalNames, symbols[i.name]), + "%1% called with unexpected argument '%2%'", lambda, i.name, *fun.lambda.env, lambda); } abort(); // can't happen } } nrFunctionCalls++; - if (countCalls) incrFunctionCall(&lambda); + if (countCalls) + incrFunctionCall(&lambda); /* Evaluate the body. */ try { - auto dts = debugRepl - ? makeDebugTraceStacker( - *this, *lambda.body, env2, positions[lambda.pos], - "while evaluating %s", - lambda.name - ? concatStrings("'", symbols[lambda.name], "'") - : "anonymous lambda") - : nullptr; + auto dts = debugRepl ? makeDebugTraceStacker( + *this, *lambda.body, env2, positions[lambda.pos], "while evaluating %s", + lambda.name ? concatStrings("'", symbols[lambda.name], "'") : "anonymous lambda") + : nullptr; lambda.body->eval(*this, env2, vCur); } catch (Error & e) { if (loggerSettings.showTrace.get()) { - addErrorTrace(e, lambda.pos, "while evaluating %s", - (lambda.name - ? concatStrings("'", symbols[lambda.name], "'") - : "anonymous lambda")); + addErrorTrace( + e, lambda.pos, "while evaluating %s", + (lambda.name ? concatStrings("'", symbols[lambda.name], "'") : "anonymous lambda")); addErrorTrace(e, pos, "from call site%s", ""); } throw; @@ -1673,7 +1590,8 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & } else { /* We have all the arguments, so call the primop. */ nrPrimOpCalls++; - if (countCalls) primOpCalls[vCur.primOp->name]++; + if (countCalls) + primOpCalls[vCur.primOp->name]++; vCur.primOp->fun(*this, pos, args, vCur); nrArgs -= argsLeft; @@ -1710,7 +1628,8 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vArgs[argsDone + i] = args[i]; nrPrimOpCalls++; - if (countCalls) primOpCalls[primOp->primOp->name]++; + if (countCalls) + primOpCalls[primOp->primOp->name]++; primOp->primOp->fun(*this, pos, vArgs, vCur); nrArgs -= argsLeft; @@ -1737,7 +1656,6 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes = vCur; } - void ExprCall::eval(EvalState & state, Env & env, Value & v) { Value vFun; @@ -1750,7 +1668,6 @@ void ExprCall::eval(EvalState & state, Env & env, Value & v) state.callFunction(vFun, args.size(), vArgs, v, pos); } - // Lifted out of callFunction() because it creates a temporary that // prevents tail-call optimisation. void EvalState::incrFunctionCall(ExprLambda * fun) @@ -1758,7 +1675,6 @@ void EvalState::incrFunctionCall(ExprLambda * fun) functionCalls[fun]++; } - void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) { auto pos = fun.determinePos(noPos); @@ -1795,13 +1711,14 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) if (j != args.end()) { attrs.insert(*j); } else if (!i.def) { - throwMissingArgumentError(i.pos, R"(cannot evaluate a function that has an argument without a value ('%1%') + 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'. See -https://nixos.org/manual/nix/stable/expressions/language-constructs.html#functions.)", symbols[i.name], - *fun.lambda.env, *fun.lambda.fun); +https://nixos.org/manual/nix/stable/expressions/language-constructs.html#functions.)", + symbols[i.name], *fun.lambda.env, *fun.lambda.fun); } } } @@ -1809,7 +1726,6 @@ values, or passed explicitly with '--arg' or '--argstr'. See callFunction(fun, allocValue()->mkAttrs(attrs), res, noPos); } - void ExprWith::eval(EvalState & state, Env & env, Value & v) { Env & env2(state.allocEnv(1)); @@ -1821,13 +1737,11 @@ void ExprWith::eval(EvalState & state, Env & env, Value & v) body->eval(state, env2, v); } - void ExprIf::eval(EvalState & state, Env & env, Value & v) { (state.evalBool(env, cond, pos) ? then : else_)->eval(state, env, v); } - void ExprAssert::eval(EvalState & state, Env & env, Value & v) { if (!state.evalBool(env, cond, pos)) { @@ -1838,47 +1752,44 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v) body->eval(state, env, v); } - void ExprOpNot::eval(EvalState & state, Env & env, Value & v) { v.mkBool(!state.evalBool(env, e)); } - void ExprOpEq::eval(EvalState & state, Env & env, Value & v) { - Value v1; e1->eval(state, env, v1); - Value v2; e2->eval(state, env, v2); + Value v1; + e1->eval(state, env, v1); + Value v2; + e2->eval(state, env, v2); v.mkBool(state.eqValues(v1, v2)); } - void ExprOpNEq::eval(EvalState & state, Env & env, Value & v) { - Value v1; e1->eval(state, env, v1); - Value v2; e2->eval(state, env, v2); + Value v1; + e1->eval(state, env, v1); + Value v2; + e2->eval(state, env, v2); v.mkBool(!state.eqValues(v1, v2)); } - void ExprOpAnd::eval(EvalState & state, Env & env, Value & v) { v.mkBool(state.evalBool(env, e1, pos) && state.evalBool(env, e2, pos)); } - void ExprOpOr::eval(EvalState & state, Env & env, Value & v) { v.mkBool(state.evalBool(env, e1, pos) || state.evalBool(env, e2, pos)); } - void ExprOpImpl::eval(EvalState & state, Env & env, Value & v) { v.mkBool(!state.evalBool(env, e1, pos) || state.evalBool(env, e2, pos)); } - void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) { Value v1, v2; @@ -1887,8 +1798,14 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) state.nrOpUpdates++; - if (v1.attrs->size() == 0) { v = v2; return; } - if (v2.attrs->size() == 0) { v = v1; return; } + if (v1.attrs->size() == 0) { + v = v2; + return; + } + if (v2.attrs->size() == 0) { + v = v1; + return; + } auto attrs = state.buildBindings(v1.attrs->size() + v2.attrs->size()); @@ -1900,33 +1817,35 @@ void ExprOpUpdate::eval(EvalState & state, Env & env, Value & v) while (i != v1.attrs->end() && j != v2.attrs->end()) { if (i->name == j->name) { attrs.insert(*j); - ++i; ++j; - } - else if (i->name < j->name) + ++i; + ++j; + } else if (i->name < j->name) attrs.insert(*i++); else attrs.insert(*j++); } - while (i != v1.attrs->end()) attrs.insert(*i++); - while (j != v2.attrs->end()) attrs.insert(*j++); + while (i != v1.attrs->end()) + attrs.insert(*i++); + while (j != v2.attrs->end()) + attrs.insert(*j++); v.mkAttrs(attrs.alreadySorted()); state.nrOpUpdateValuesCopied += v.attrs->size(); } - void ExprOpConcatLists::eval(EvalState & state, Env & env, Value & v) { - Value v1; e1->eval(state, env, v1); - Value v2; e2->eval(state, env, v2); - Value * lists[2] = { &v1, &v2 }; + Value v1; + e1->eval(state, env, v1); + Value v2; + e2->eval(state, env, v2); + Value * lists[2] = {&v1, &v2}; state.concatLists(v, 2, lists, pos); } - -void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos) +void EvalState::concatLists(Value & v, size_t nrLists, Value ** lists, const PosIdx pos) { nrListConcats++; @@ -1936,7 +1855,8 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po forceList(*lists[n], pos); auto l = lists[n]->listSize(); len += l; - if (l) nonEmpty = lists[n]; + if (l) + nonEmpty = lists[n]; } if (nonEmpty && len == nonEmpty->listSize()) { @@ -1954,7 +1874,6 @@ void EvalState::concatLists(Value & v, size_t nrLists, Value * * lists, const Po } } - void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) { PathSet context; @@ -1969,7 +1888,8 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) const auto str = [&] { std::string result; result.reserve(sSize); - for (const auto & part : s) result += *part; + for (const auto & part : s) + result += *part; return result; }; /* c_str() is not str().c_str() because we want to create a string @@ -2019,7 +1939,8 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else state.throwEvalError(i_pos, "cannot add %1% to a float", showType(vTmp), env, *this); } else { - if (s.empty()) s.reserve(es->size()); + if (s.empty()) + s.reserve(es->size()); /* skip canonization of first path, which would only be not canonized in the first place if it's coming from a ./${foo} type path */ @@ -2043,13 +1964,11 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) v.mkStringMove(c_str(), context); } - void ExprPos::eval(EvalState & state, Env & env, Value & v) { state.mkPos(v, pos); } - void EvalState::forceValueDeep(Value & v) { std::set seen; @@ -2057,7 +1976,8 @@ void EvalState::forceValueDeep(Value & v) std::function recurse; recurse = [&](Value & v) { - if (!seen.insert(&v).second) return; + if (!seen.insert(&v).second) + return; forceValue(v, [&]() { return v.determinePos(noPos); }); @@ -2065,10 +1985,10 @@ void EvalState::forceValueDeep(Value & v) for (auto & i : *v.attrs) try { // If the value is a thunk, we're evaling. Otherwise no trace necessary. - auto dts = debugRepl && i.value->isThunk() - ? makeDebugTraceStacker(*this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos], - "while evaluating the attribute '%1%'", symbols[i.name]) - : nullptr; + auto dts = debugRepl && i.value->isThunk() ? makeDebugTraceStacker( + *this, *i.value->thunk.expr, *i.value->thunk.env, positions[i.pos], + "while evaluating the attribute '%1%'", symbols[i.name]) + : nullptr; recurse(*i.value); } catch (Error & e) { @@ -2086,7 +2006,6 @@ void EvalState::forceValueDeep(Value & v) recurse(v); } - NixInt EvalState::forceInt(Value & v, const PosIdx pos) { forceValue(v, pos); @@ -2096,7 +2015,6 @@ NixInt EvalState::forceInt(Value & v, const PosIdx pos) return v.integer; } - NixFloat EvalState::forceFloat(Value & v, const PosIdx pos) { forceValue(v, pos); @@ -2107,7 +2025,6 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos) return v.fpoint; } - bool EvalState::forceBool(Value & v, const PosIdx pos) { forceValue(v, pos); @@ -2116,13 +2033,11 @@ bool EvalState::forceBool(Value & v, const PosIdx pos) return v.boolean; } - bool EvalState::isFunctor(Value & fun) { return fun.type() == nAttrs && fun.attrs->find(sFunctor) != fun.attrs->end(); } - void EvalState::forceFunction(Value & v, const PosIdx pos) { forceValue(v, pos); @@ -2130,7 +2045,6 @@ void EvalState::forceFunction(Value & v, const PosIdx pos) throwTypeError(pos, "value is %1% while a function was expected", v); } - std::string_view EvalState::forceString(Value & v, const PosIdx pos) { forceValue(v, pos); @@ -2140,7 +2054,6 @@ std::string_view EvalState::forceString(Value & v, const PosIdx pos) return v.string.s; } - /* Decode a context string ‘!!’ into a pair . */ NixStringContextElem decodeContext(const Store & store, std::string_view s) @@ -2153,34 +2066,28 @@ NixStringContextElem decodeContext(const Store & store, std::string_view s) }; } else return { - store.parseStorePath( - s.at(0) == '/' - ? s - : s.substr(1)), + store.parseStorePath(s.at(0) == '/' ? s : s.substr(1)), "", }; } - void copyContext(const Value & v, PathSet & context) { if (v.string.context) - for (const char * * p = v.string.context; *p; ++p) + for (const char ** p = v.string.context; *p; ++p) context.insert(*p); } - NixStringContext Value::getContext(const Store & store) { NixStringContext res; assert(internalType == tString); if (string.context) - for (const char * * p = string.context; *p; ++p) + for (const char ** p = string.context; *p; ++p) res.push_back(decodeContext(store, *p)); return res; } - std::string_view EvalState::forceString(Value & v, PathSet & context, const PosIdx pos) { auto s = forceString(v, pos); @@ -2188,35 +2095,37 @@ std::string_view EvalState::forceString(Value & v, PathSet & context, const PosI return s; } - std::string_view EvalState::forceStringNoCtx(Value & v, const PosIdx pos) { auto s = forceString(v, pos); if (v.string.context) { if (pos) - throwEvalError(pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0]); + throwEvalError( + pos, "the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, + v.string.context[0]); else - throwEvalError("the string '%1%' is not allowed to refer to a store path (such as '%2%')", - v.string.s, v.string.context[0]); + throwEvalError( + "the string '%1%' is not allowed to refer to a store path (such as '%2%')", v.string.s, + v.string.context[0]); } return s; } - bool EvalState::isDerivation(Value & v) { - if (v.type() != nAttrs) return false; + if (v.type() != nAttrs) + return false; Bindings::iterator i = v.attrs->find(sType); - if (i == v.attrs->end()) return false; + if (i == v.attrs->end()) + return false; forceValue(*i->value, i->pos); - if (i->value->type() != nString) return false; + if (i->value->type() != nString) + return false; return strcmp(i->value->string.s, "derivation") == 0; } - -std::optional EvalState::tryAttrsToString(const PosIdx pos, Value & v, - PathSet & context, bool coerceMore, bool copyToStore) +std::optional +EvalState::tryAttrsToString(const PosIdx pos, Value & v, PathSet & context, bool coerceMore, bool copyToStore) { auto i = v.attrs->find(sToString); if (i != v.attrs->end()) { @@ -2228,8 +2137,8 @@ std::optional EvalState::tryAttrsToString(const PosIdx pos, Value & return {}; } -BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet & context, - bool coerceMore, bool copyToStore, bool canonicalizePath) +BackedStringView EvalState::coerceToString( + const PosIdx pos, Value & v, PathSet & context, bool coerceMore, bool copyToStore, bool canonicalizePath) { forceValue(v, pos); @@ -2263,11 +2172,16 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet if (coerceMore) { /* Note that `false' is represented as an empty string for shell scripting convenience, just like `null'. */ - if (v.type() == nBool && v.boolean) return "1"; - if (v.type() == nBool && !v.boolean) return ""; - if (v.type() == nInt) return std::to_string(v.integer); - if (v.type() == nFloat) return std::to_string(v.fpoint); - if (v.type() == nNull) return ""; + if (v.type() == nBool && v.boolean) + return "1"; + if (v.type() == nBool && !v.boolean) + return ""; + if (v.type() == nInt) + return std::to_string(v.integer); + if (v.type() == nFloat) + return std::to_string(v.fpoint); + if (v.type() == nNull) + return ""; if (v.isList()) { std::string result; @@ -2285,7 +2199,6 @@ BackedStringView EvalState::coerceToString(const PosIdx pos, Value & v, PathSet throwTypeError(pos, "cannot coerce %1% to a string", v); } - std::string EvalState::copyPathToStore(PathSet & context, const Path & path) { if (nix::isDerivation(path)) @@ -2297,8 +2210,10 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path) dstPath = store->printStorePath(i->second); else { auto p = settings.readOnlyMode - ? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first - : store->addToStore(std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, repair); + ? store->computeStorePathForPath(std::string(baseNameOf(path)), checkSourcePath(path)).first + : store->addToStore( + std::string(baseNameOf(path)), checkSourcePath(path), FileIngestionMethod::Recursive, htSHA256, + defaultPathFilter, repair); dstPath = store->printStorePath(p); allowPath(p); srcToStore.insert_or_assign(path, std::move(p)); @@ -2309,7 +2224,6 @@ std::string EvalState::copyPathToStore(PathSet & context, const Path & path) return dstPath; } - Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context) { auto path = coerceToString(pos, v, context, false, false).toOwned(); @@ -2318,19 +2232,14 @@ Path EvalState::coerceToPath(const PosIdx pos, Value & v, PathSet & context) return path; } - StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, PathSet & context) { auto path = coerceToString(pos, v, context, false, false).toOwned(); if (auto storePath = store->maybeParseStorePath(path)) return *storePath; - throw EvalError({ - .msg = hintfmt("path '%1%' is not in the Nix store", path), - .errPos = positions[pos] - }); + throw EvalError({.msg = hintfmt("path '%1%' is not in the Nix store", path), .errPos = positions[pos]}); } - bool EvalState::eqValues(Value & v1, Value & v2) { forceValue(v1, noPos); @@ -2339,7 +2248,8 @@ bool EvalState::eqValues(Value & v1, Value & v2) /* !!! Hack to support some old broken code that relies on pointer equality tests between sets. (Specifically, builderDefs calls uniqList on a list of sets.) Will remove this eventually. */ - if (&v1 == &v2) return true; + if (&v1 == &v2) + return true; // Special case type-compatibility between float and int if (v1.type() == nInt && v2.type() == nFloat) @@ -2348,66 +2258,68 @@ bool EvalState::eqValues(Value & v1, Value & v2) return v1.fpoint == v2.integer; // All other types are not compatible with each other. - if (v1.type() != v2.type()) return false; + if (v1.type() != v2.type()) + return false; switch (v1.type()) { - case nInt: - return v1.integer == v2.integer; + case nInt: + return v1.integer == v2.integer; - case nBool: - return v1.boolean == v2.boolean; + case nBool: + return v1.boolean == v2.boolean; - case nString: - return strcmp(v1.string.s, v2.string.s) == 0; + case nString: + return strcmp(v1.string.s, v2.string.s) == 0; - case nPath: - return strcmp(v1.path, v2.path) == 0; + case nPath: + return strcmp(v1.path, v2.path) == 0; - case nNull: - return true; + case nNull: + return true; - case nList: - if (v1.listSize() != v2.listSize()) return false; - for (size_t n = 0; n < v1.listSize(); ++n) - if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false; - return true; + case nList: + if (v1.listSize() != v2.listSize()) + return false; + for (size_t n = 0; n < v1.listSize(); ++n) + if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) + return false; + return true; + + case nAttrs: { + /* If both sets denote a derivation (type = "derivation"), + then compare their outPaths. */ + if (isDerivation(v1) && isDerivation(v2)) { + Bindings::iterator i = v1.attrs->find(sOutPath); + Bindings::iterator j = v2.attrs->find(sOutPath); + if (i != v1.attrs->end() && j != v2.attrs->end()) + return eqValues(*i->value, *j->value); + } - case nAttrs: { - /* If both sets denote a derivation (type = "derivation"), - then compare their outPaths. */ - if (isDerivation(v1) && isDerivation(v2)) { - Bindings::iterator i = v1.attrs->find(sOutPath); - Bindings::iterator j = v2.attrs->find(sOutPath); - if (i != v1.attrs->end() && j != v2.attrs->end()) - return eqValues(*i->value, *j->value); - } + if (v1.attrs->size() != v2.attrs->size()) + return false; - if (v1.attrs->size() != v2.attrs->size()) return false; + /* Otherwise, compare the attributes one by one. */ + Bindings::iterator i, j; + for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j) + if (i->name != j->name || !eqValues(*i->value, *j->value)) + return false; - /* Otherwise, compare the attributes one by one. */ - Bindings::iterator i, j; - for (i = v1.attrs->begin(), j = v2.attrs->begin(); i != v1.attrs->end(); ++i, ++j) - if (i->name != j->name || !eqValues(*i->value, *j->value)) - return false; + return true; + } - return true; - } + /* Functions are incomparable. */ + case nFunction: + return false; - /* Functions are incomparable. */ - case nFunction: - return false; + case nExternal: + return *v1.external == *v2.external; - case nExternal: - return *v1.external == *v2.external; + case nFloat: + return v1.fpoint == v2.fpoint; - case nFloat: - return v1.fpoint == v2.fpoint; - - default: - throwEvalError("cannot compare %1% with %2%", - showType(v1), - showType(v2)); + default: + throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2)); } } @@ -2434,7 +2346,7 @@ void EvalState::printStats() if (outPath != "-") fs.open(outPath, std::fstream::out); JSONObject topObj(outPath == "-" ? std::cerr : fs, true); - topObj.attr("cpuTime",cpuTime); + topObj.attr("cpuTime", cpuTime); { auto envs = topObj.object("envs"); envs.attr("number", nrEnvs); @@ -2528,31 +2440,26 @@ void EvalState::printStats() } } - std::string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const { - throw TypeError({ - .msg = hintfmt("cannot coerce %1% to a string", showType()), - .errPos = pos - }); + throw TypeError({.msg = hintfmt("cannot coerce %1% to a string", showType()), .errPos = pos}); } - bool ExternalValueBase::operator==(const ExternalValueBase & b) const { return false; } - -std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) { +std::ostream & operator<<(std::ostream & str, const ExternalValueBase & v) +{ return v.print(str); } - EvalSettings::EvalSettings() { auto var = getEnv("NIX_PATH"); - if (var) nixPath = parseNixPath(*var); + if (var) + nixPath = parseNixPath(*var); } Strings EvalSettings::getDefaultNixPath() @@ -2581,5 +2488,4 @@ EvalSettings evalSettings; static GlobalConfig::Register rEvalSettings(&evalSettings); - } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 4eaa3c9b03e6..140f5bf087e7 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -15,14 +15,12 @@ namespace nix { - class Store; class EvalState; class StorePath; enum RepairFlag : bool; - -typedef void (* PrimOpFun) (EvalState & state, const PosIdx pos, Value * * args, Value & v); +typedef void (*PrimOpFun)(EvalState & state, const PosIdx pos, Value ** args, Value & v); struct PrimOp { @@ -34,9 +32,11 @@ struct PrimOp }; #if HAVE_BOEHMGC - typedef std::map, traceable_allocator > > ValMap; +typedef std:: + map, traceable_allocator>> + ValMap; #else - typedef std::map ValMap; +typedef std::map ValMap; #endif struct Env @@ -47,37 +47,33 @@ struct Env Value * values[0]; }; -void printEnvBindings(const EvalState &es, const Expr & expr, const Env & env); +void printEnvBindings(const EvalState & es, const Expr & expr, const Env & env); void printEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env, int lvl = 0); std::unique_ptr mapStaticEnvBindings(const SymbolTable & st, const StaticEnv & se, const Env & env); void copyContext(const Value & v, PathSet & context); - /* Cache for calls to addToStore(); maps source paths to the store paths. */ typedef std::map SrcToStore; - std::ostream & printValue(const EvalState & state, std::ostream & str, const Value & v); std::string printValue(const EvalState & state, const Value & v); -std::ostream & operator << (std::ostream & os, const ValueType t); - +std::ostream & operator<<(std::ostream & os, const ValueType t); typedef std::pair SearchPathElem; typedef std::list SearchPath; - /* Initialise the Boehm GC, if applicable. */ void initGC(); - struct RegexCache; std::shared_ptr makeRegexCache(); -struct DebugTrace { +struct DebugTrace +{ std::optional pos; const Expr & expr; const Env & env; @@ -95,16 +91,10 @@ public: static inline std::string derivationNixPath = "//builtin/derivation.nix"; - const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, - sSystem, sOverrides, sOutputs, sOutputName, sIgnoreNulls, - sFile, sLine, sColumn, sFunctor, sToString, - sRight, sWrong, sStructuredAttrs, sBuilder, sArgs, - sContentAddressed, sImpure, - sOutputHash, sOutputHashAlgo, sOutputHashMode, - sRecurseForDerivations, - sDescription, sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, - sPrefix, - sOutputSpecified; + const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sValue, sSystem, sOverrides, sOutputs, sOutputName, + sIgnoreNulls, sFile, sLine, sColumn, sFunctor, sToString, sRight, sWrong, sStructuredAttrs, sBuilder, sArgs, + sContentAddressed, sImpure, sOutputHash, sOutputHashAlgo, sOutputHashMode, sRecurseForDerivations, sDescription, + sSelf, sEpsilon, sStartSet, sOperator, sKey, sPath, sPrefix, sOutputSpecified; Symbol sDerivationNix; /* If set, force copying files to the Nix store even if they @@ -127,25 +117,25 @@ public: RootValue vImportedDrvToDerivation = nullptr; /* Debugger */ - void (* debugRepl)(ref es, const ValMap & extraEnv); + void (*debugRepl)(ref es, const ValMap & extraEnv); bool debugStop; bool debugQuit; std::list debugTraces; - std::map> exprEnvs; + std::map> exprEnvs; const std::shared_ptr getStaticEnv(const Expr & expr) const { auto i = exprEnvs.find(&expr); if (i != exprEnvs.end()) return i->second; else - return std::shared_ptr();; + return std::shared_ptr(); + ; } void runDebugRepl(const Error * error, const Env & env, const Expr & expr); template - [[gnu::noinline, gnu::noreturn]] - void debugThrow(E && error, const Env & env, const Expr & expr) + [[gnu::noinline, gnu::noreturn]] void debugThrow(E && error, const Env & env, const Expr & expr) { if (debugRepl) runDebugRepl(&error, env, expr); @@ -154,8 +144,7 @@ public: } template - [[gnu::noinline, gnu::noreturn]] - void debugThrowLastTrace(E && e) + [[gnu::noinline, gnu::noreturn]] void debugThrowLastTrace(E && e) { // Call this in the situation where Expr and Env are inaccessible. // The debugger will start in the last context that's in the @@ -208,15 +197,15 @@ private: public: - EvalState( - const Strings & _searchPath, - ref store, - std::shared_ptr buildStore = nullptr); + EvalState(const Strings & _searchPath, ref store, std::shared_ptr buildStore = nullptr); ~EvalState(); void addToSearchPath(const std::string & s); - SearchPath getSearchPath() { return searchPath; } + SearchPath getSearchPath() + { + return searchPath; + } /* Allow access to a path. */ void allowPath(const Path & path); @@ -259,12 +248,7 @@ public: void evalFile(const Path & path, Value & v, bool mustBeTrivial = false); /* Like `evalFile`, but with an already parsed expression. */ - void cacheFile( - const Path & path, - const Path & resolvedPath, - Expr * e, - Value & v, - bool mustBeTrivial = false); + void cacheFile(const Path & path, const Path & resolvedPath, Expr * e, Value & v, bool mustBeTrivial = false); void resetFileCache(); @@ -291,7 +275,7 @@ public: result. Otherwise, this is a no-op. */ inline void forceValue(Value & v, const PosIdx pos); - template + template inline void forceValue(Value & v, Callable getPos); /* Force a value, then recursively force list elements and @@ -305,7 +289,7 @@ public: void forceAttrs(Value & v, const PosIdx pos); - template + template inline void forceAttrs(Value & v, Callable getPos); inline void forceList(Value & v, const PosIdx pos); @@ -314,89 +298,79 @@ public: std::string_view forceString(Value & v, PathSet & context, const PosIdx pos = noPos); std::string_view forceStringNoCtx(Value & v, const PosIdx pos = noPos); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, const std::string & s2); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2, const std::string & s3, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const char * s, const std::string & s2, const std::string & s3); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx pos, const Suggestions & suggestions, const char * s, const std::string & s2, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, - Env & env, Expr & expr); - - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const Value & v); - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const Value & v, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s); - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const PosIdx pos, const Suggestions & suggestions, const char * s, const ExprLambda & fun, const Symbol s2, - Env & env, Expr & expr); - [[gnu::noinline, gnu::noreturn]] - void throwTypeError(const char * s, const Value & v, - Env & env, Expr & expr); - - [[gnu::noinline, gnu::noreturn]] - void throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, - Env & env, Expr & expr); - - [[gnu::noinline, gnu::noreturn]] - void throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, - Env & env, Expr & expr); - - [[gnu::noinline, gnu::noreturn]] - void throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, - Env & env, Expr & expr); - - [[gnu::noinline]] - void addErrorTrace(Error & e, const char * s, const std::string & s2) const; - [[gnu::noinline]] - void addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2) const; + [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s); + [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void throwEvalError(const char * s, const std::string & s2); + [[gnu::noinline, gnu::noreturn]] void throwEvalError(const PosIdx pos, const char * s, const std::string & s2); + [[gnu::noinline, gnu::noreturn]] void + throwEvalError(const char * s, const std::string & s2, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void + throwEvalError(const PosIdx pos, const char * s, const std::string & s2, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void + throwEvalError(const char * s, const std::string & s2, const std::string & s3, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void throwEvalError( + const PosIdx pos, const char * s, const std::string & s2, const std::string & s3, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void + throwEvalError(const PosIdx pos, const char * s, const std::string & s2, const std::string & s3); + [[gnu::noinline, gnu::noreturn]] void + throwEvalError(const char * s, const std::string & s2, const std::string & s3); + [[gnu::noinline, gnu::noreturn]] void throwEvalError( + const PosIdx pos, + const Suggestions & suggestions, + const char * s, + const std::string & s2, + Env & env, + Expr & expr); + [[gnu::noinline, gnu::noreturn]] void + throwEvalError(const PosIdx p1, const char * s, const Symbol sym, const PosIdx p2, Env & env, Expr & expr); + + [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s, const Value & v); + [[gnu::noinline, gnu::noreturn]] void + throwTypeError(const PosIdx pos, const char * s, const Value & v, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s); + [[gnu::noinline, gnu::noreturn]] void throwTypeError(const PosIdx pos, const char * s, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void + throwTypeError(const PosIdx pos, const char * s, const ExprLambda & fun, const Symbol s2, Env & env, Expr & expr); + [[gnu::noinline, gnu::noreturn]] void throwTypeError( + const PosIdx pos, + const Suggestions & suggestions, + const char * s, + const ExprLambda & fun, + const Symbol s2, + Env & env, + Expr & expr); + [[gnu::noinline, gnu::noreturn]] void throwTypeError(const char * s, const Value & v, Env & env, Expr & expr); + + [[gnu::noinline, gnu::noreturn]] void + throwAssertionError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr & expr); + + [[gnu::noinline, gnu::noreturn]] void + throwUndefinedVarError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr & expr); + + [[gnu::noinline, gnu::noreturn]] void + throwMissingArgumentError(const PosIdx pos, const char * s, const std::string & s1, Env & env, Expr & expr); + + [[gnu::noinline]] void addErrorTrace(Error & e, const char * s, const std::string & s2) const; + [[gnu::noinline]] void addErrorTrace(Error & e, const PosIdx pos, const char * s, const std::string & s2) const; public: /* Return true iff the value `v' denotes a derivation (i.e. a set with attribute `type = "derivation"'). */ bool isDerivation(Value & v); - std::optional tryAttrsToString(const PosIdx pos, Value & v, - PathSet & context, bool coerceMore = false, bool copyToStore = true); + std::optional + tryAttrsToString(const PosIdx pos, Value & v, PathSet & context, bool coerceMore = false, bool copyToStore = true); /* String coercion. Converts strings, paths and derivations to a string. If `coerceMore' is set, also converts nulls, integers, booleans and lists to a string. If `copyToStore' is set, referenced paths are copied to the Nix store as a side effect. */ - BackedStringView coerceToString(const PosIdx pos, Value & v, PathSet & context, - bool coerceMore = false, bool copyToStore = true, + BackedStringView coerceToString( + const PosIdx pos, + Value & v, + PathSet & context, + bool coerceMore = false, + bool copyToStore = true, bool canonicalizePath = true); std::string copyPathToStore(PathSet & context, const Path & path); @@ -428,8 +402,7 @@ private: void addConstant(const std::string & name, Value * v); - Value * addPrimOp(const std::string & name, - size_t arity, PrimOpFun primOp); + Value * addPrimOp(const std::string & name, size_t arity, PrimOpFun primOp); Value * addPrimOp(PrimOp && primOp); @@ -456,8 +429,13 @@ private: friend struct ExprAttrs; friend struct ExprLet; - Expr * parse(char * text, size_t length, FileOrigin origin, const PathView path, - const PathView basePath, std::shared_ptr & staticEnv); + Expr * parse( + char * text, + size_t length, + FileOrigin origin, + const PathView path, + const PathView basePath, + std::shared_ptr & staticEnv); public: @@ -468,7 +446,7 @@ public: bool isFunctor(Value & fun); // FIXME: use std::span - void callFunction(Value & fun, size_t nrArgs, Value * * args, Value & vRes, const PosIdx pos); + void callFunction(Value & fun, size_t nrArgs, Value ** args, Value & vRes, const PosIdx pos); void callFunction(Value & fun, Value & arg, Value & vRes, const PosIdx pos) { @@ -498,7 +476,7 @@ public: void mkThunk_(Value & v, Expr * expr); void mkPos(Value & v, PosIdx pos); - void concatLists(Value & v, size_t nrLists, Value * * lists, const PosIdx pos); + void concatLists(Value & v, size_t nrLists, Value ** lists, const PosIdx pos); /* Print statistics. */ void printStats(); @@ -545,14 +523,15 @@ private: friend struct ExprFloat; friend struct ExprPath; friend struct ExprSelect; - friend void prim_getAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v); - friend void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v); - friend void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v); + friend void prim_getAttr(EvalState & state, const PosIdx pos, Value ** args, Value & v); + friend void prim_match(EvalState & state, const PosIdx pos, Value ** args, Value & v); + friend void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v); friend struct Value; }; -struct DebugTraceStacker { +struct DebugTraceStacker +{ DebugTraceStacker(EvalState & evalState, DebugTrace t); ~DebugTraceStacker() { @@ -579,7 +558,7 @@ struct InvalidPathError : EvalError Path path; InvalidPathError(const Path & path); #ifdef EXCEPTION_NEEDS_THROW_SPEC - ~InvalidPathError() throw () { }; + ~InvalidPathError() throw(){}; #endif }; @@ -589,12 +568,12 @@ struct EvalSettings : Config static Strings getDefaultNixPath(); - Setting enableNativeCode{this, false, "allow-unsafe-native-code-during-evaluation", + Setting enableNativeCode{ + this, false, "allow-unsafe-native-code-during-evaluation", "Whether builtin functions that allow executing native code should be enabled."}; Setting nixPath{ - this, getDefaultNixPath(), "nix-path", - "List of directories to be searched for `<...>` file references."}; + this, getDefaultNixPath(), "nix-path", "List of directories to be searched for `<...>` file references."}; Setting restrictEval{ this, false, "restrict-eval", @@ -605,7 +584,8 @@ struct EvalSettings : Config `allowed-uri`. The default is `false`. )"}; - Setting pureEval{this, false, "pure-eval", + Setting pureEval{ + this, false, "pure-eval", "Whether to restrict file system and network access to files specified by cryptographic hash."}; Setting enableImportFromDerivation{ @@ -618,7 +598,10 @@ struct EvalSettings : Config builds to take place. )"}; - Setting allowedUris{this, {}, "allowed-uris", + Setting allowedUris{ + this, + {}, + "allowed-uris", R"( A list of URI prefixes to which access is allowed in restricted evaluation mode. For example, when set to @@ -626,7 +609,8 @@ struct EvalSettings : Config allowed to access `https://github.com/NixOS/patchelf.git`. )"}; - Setting traceFunctionCalls{this, false, "trace-function-calls", + Setting traceFunctionCalls{ + this, false, "trace-function-calls", R"( If set to `true`, the Nix evaluator will trace every function call. Nix will print a log message at the "vomit" level for every function @@ -644,8 +628,7 @@ struct EvalSettings : Config `flamegraph.pl`. )"}; - Setting useEvalCache{this, true, "eval-cache", - "Whether to use the flake evaluation cache."}; + Setting useEvalCache{this, true, "eval-cache", "Whether to use the flake evaluation cache."}; }; extern EvalSettings evalSettings; diff --git a/src/libexpr/flake/config.cc b/src/libexpr/flake/config.cc index 3e9d264b43ea..245410ce00f7 100644 --- a/src/libexpr/flake/config.cc +++ b/src/libexpr/flake/config.cc @@ -17,7 +17,8 @@ Path trustedListPath() static TrustedList readTrustedList() { auto path = trustedListPath(); - if (!pathExists(path)) return {}; + if (!pathExists(path)) + return {}; auto json = nlohmann::json::parse(readFile(path)); return json; } @@ -39,11 +40,11 @@ void ConfigFile::apply() // FIXME: Move into libutil/config.cc. std::string valueS; - if (auto* s = std::get_if(&value)) + if (auto * s = std::get_if(&value)) valueS = *s; - else if (auto* n = std::get_if(&value)) + else if (auto * n = std::get_if(&value)) valueS = fmt("%d", *n); - else if (auto* b = std::get_if>(&value)) + else if (auto * b = std::get_if>(&value)) valueS = b->t ? "true" : "false"; else if (auto ss = std::get_if>(&value)) valueS = concatStringsSep(" ", *ss); // FIXME: evil @@ -56,13 +57,24 @@ void ConfigFile::apply() auto tlname = get(trustedList, name); if (auto saved = tlname ? get(*tlname, valueS) : nullptr) { trusted = *saved; - warn("Using saved setting for '%s = %s' from ~/.local/share/nix/trusted-settings.json.", name,valueS); + warn("Using saved setting for '%s = %s' from ~/.local/share/nix/trusted-settings.json.", name, valueS); } else { // FIXME: filter ANSI escapes, newlines, \r, etc. - if (std::tolower(logger->ask(fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED "%s" ANSI_NORMAL "' (y/N)?", name, valueS)).value_or('n')) == 'y') { + if (std::tolower(logger + ->ask( + fmt("do you want to allow configuration setting '%s' to be set to '" ANSI_RED + "%s" ANSI_NORMAL "' (y/N)?", + name, valueS)) + .value_or('n')) + == 'y') { trusted = true; } - if (std::tolower(logger->ask(fmt("do you want to permanently mark this value as %s (y/N)?", trusted ? "trusted": "untrusted" )).value_or('n')) == 'y') { + if (std::tolower(logger + ->ask( + fmt("do you want to permanently mark this value as %s (y/N)?", + trusted ? "trusted" : "untrusted")) + .value_or('n')) + == 'y') { trustedList[name][valueS] = trusted; writeTrustedList(trustedList); } diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 920726b73b00..f784919640bf 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -17,15 +17,12 @@ namespace flake { typedef std::pair FetchedFlake; typedef std::vector> FlakeCache; -static std::optional lookupInFlakeCache( - const FlakeCache & flakeCache, - const FlakeRef & flakeRef) +static std::optional lookupInFlakeCache(const FlakeCache & flakeCache, const FlakeRef & flakeRef) { // FIXME: inefficient. for (auto & i : flakeCache) { if (flakeRef == i.first) { - debug("mapping '%s' to previously seen input '%s' -> '%s", - flakeRef, i.first, i.second.second); + debug("mapping '%s' to previously seen input '%s' -> '%s", flakeRef, i.first, i.second.second); return i.second; } } @@ -33,11 +30,8 @@ static std::optional lookupInFlakeCache( return std::nullopt; } -static std::tuple fetchOrSubstituteTree( - EvalState & state, - const FlakeRef & originalRef, - bool allowLookup, - FlakeCache & flakeCache) +static std::tuple +fetchOrSubstituteTree(EvalState & state, const FlakeRef & originalRef, bool allowLookup, FlakeCache & flakeCache) { auto fetched = lookupInFlakeCache(flakeCache, originalRef); FlakeRef resolvedRef = originalRef; @@ -49,11 +43,11 @@ static std::tuple fetchOrSubstituteTree( if (allowLookup) { resolvedRef = originalRef.resolve(state.store); auto fetchedResolved = lookupInFlakeCache(flakeCache, originalRef); - if (!fetchedResolved) fetchedResolved.emplace(resolvedRef.fetchTree(state.store)); + if (!fetchedResolved) + fetchedResolved.emplace(resolvedRef.fetchTree(state.store)); flakeCache.push_back({resolvedRef, *fetchedResolved}); fetched.emplace(*fetchedResolved); - } - else { + } else { throw Error("'%s' is an indirect flake reference, but registry lookups are not allowed", originalRef); } } @@ -62,8 +56,7 @@ static std::tuple fetchOrSubstituteTree( auto [tree, lockedRef] = *fetched; - debug("got tree '%s' from '%s'", - state.store->printStorePath(tree.storePath), lockedRef); + debug("got tree '%s' from '%s'", state.store->printStorePath(tree.storePath), lockedRef); state.allowPath(tree.storePath); @@ -78,23 +71,23 @@ static void forceTrivialValue(EvalState & state, Value & value, const PosIdx pos state.forceValue(value, pos); } - -static void expectType(EvalState & state, ValueType type, - Value & value, const PosIdx pos) +static void expectType(EvalState & state, ValueType type, Value & value, const PosIdx pos) { forceTrivialValue(state, value, pos); if (value.type() != type) - throw Error("expected %s but got %s at %s", - showType(type), showType(value.type()), state.positions[pos]); + throw Error("expected %s but got %s at %s", showType(type), showType(value.type()), state.positions[pos]); } static std::map parseFlakeInputs( - EvalState & state, Value * value, const PosIdx pos, - const std::optional & baseDir, InputPath lockRootPath); + EvalState & state, Value * value, const PosIdx pos, const std::optional & baseDir, InputPath lockRootPath); -static FlakeInput parseFlakeInput(EvalState & state, - const std::string & inputName, Value * value, const PosIdx pos, - const std::optional & baseDir, InputPath lockRootPath) +static FlakeInput parseFlakeInput( + EvalState & state, + const std::string & inputName, + Value * value, + const PosIdx pos, + const std::optional & baseDir, + InputPath lockRootPath) { expectType(state, nAttrs, *value, pos); @@ -126,24 +119,23 @@ static FlakeInput parseFlakeInput(EvalState & state, input.follows = follows; } else { switch (attr.value->type()) { - case nString: - attrs.emplace(state.symbols[attr.name], attr.value->string.s); - break; - case nBool: - attrs.emplace(state.symbols[attr.name], Explicit { attr.value->boolean }); - break; - case nInt: - attrs.emplace(state.symbols[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", - state.symbols[attr.name], showType(*attr.value)); + case nString: + attrs.emplace(state.symbols[attr.name], attr.value->string.s); + break; + case nBool: + attrs.emplace(state.symbols[attr.name], Explicit{attr.value->boolean}); + break; + case nInt: + attrs.emplace(state.symbols[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", + state.symbols[attr.name], showType(*attr.value)); } } } catch (Error & e) { - e.addTrace( - state.positions[attr.pos], - hintfmt("in flake attribute '%s'", state.symbols[attr.name])); + e.addTrace(state.positions[attr.pos], hintfmt("in flake attribute '%s'", state.symbols[attr.name])); throw; } } @@ -170,52 +162,44 @@ static FlakeInput parseFlakeInput(EvalState & state, } static std::map parseFlakeInputs( - EvalState & state, Value * value, const PosIdx pos, - const std::optional & baseDir, InputPath lockRootPath) + EvalState & state, Value * value, const PosIdx pos, const std::optional & baseDir, InputPath lockRootPath) { std::map inputs; expectType(state, nAttrs, *value, pos); for (nix::Attr & inputAttr : *(*value).attrs) { - inputs.emplace(state.symbols[inputAttr.name], - parseFlakeInput(state, - state.symbols[inputAttr.name], - inputAttr.value, - inputAttr.pos, - baseDir, - lockRootPath)); + inputs.emplace( + state.symbols[inputAttr.name], + parseFlakeInput( + state, state.symbols[inputAttr.name], inputAttr.value, inputAttr.pos, baseDir, lockRootPath)); } return inputs; } static Flake getFlake( - EvalState & state, - const FlakeRef & originalRef, - bool allowLookup, - FlakeCache & flakeCache, - InputPath lockRootPath) + EvalState & state, const FlakeRef & originalRef, bool allowLookup, FlakeCache & flakeCache, InputPath lockRootPath) { - auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree( - state, originalRef, allowLookup, flakeCache); + auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree(state, originalRef, allowLookup, flakeCache); // Guard against symlink attacks. auto flakeDir = canonPath(sourceInfo.actualPath + "/" + lockedRef.subdir, true); auto flakeFile = canonPath(flakeDir + "/flake.nix", true); if (!isInDir(flakeFile, sourceInfo.actualPath)) - throw Error("'flake.nix' file of flake '%s' escapes from '%s'", - lockedRef, state.store->printStorePath(sourceInfo.storePath)); + throw Error( + "'flake.nix' file of flake '%s' escapes from '%s'", lockedRef, + state.store->printStorePath(sourceInfo.storePath)); - Flake flake { + Flake flake{ .originalRef = originalRef, .resolvedRef = resolvedRef, .lockedRef = lockedRef, - .sourceInfo = std::make_shared(std::move(sourceInfo)) - }; + .sourceInfo = std::make_shared(std::move(sourceInfo))}; if (!pathExists(flakeFile)) - throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir); + throw Error( + "source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir); Value vInfo; state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack @@ -240,9 +224,8 @@ static Flake getFlake( if (outputs->value->isLambda() && outputs->value->lambda.fun->hasFormals()) { for (auto & formal : outputs->value->lambda.fun->formals->formals) { if (formal.name != state.sSelf) - flake.inputs.emplace(state.symbols[formal.name], FlakeInput { - .ref = parseFlakeRef(state.symbols[formal.name]) - }); + flake.inputs.emplace( + state.symbols[formal.name], FlakeInput{.ref = parseFlakeRef(state.symbols[formal.name])}); } } @@ -258,45 +241,38 @@ static Flake getFlake( forceTrivialValue(state, *setting.value, setting.pos); if (setting.value->type() == nString) flake.config.settings.emplace( - state.symbols[setting.name], - std::string(state.forceStringNoCtx(*setting.value, setting.pos))); + state.symbols[setting.name], std::string(state.forceStringNoCtx(*setting.value, setting.pos))); else if (setting.value->type() == nPath) { PathSet emptyContext = {}; flake.config.settings.emplace( state.symbols[setting.name], - state.coerceToString(setting.pos, *setting.value, emptyContext, false, true, true) .toOwned()); - } - else if (setting.value->type() == nInt) - flake.config.settings.emplace( - state.symbols[setting.name], - state.forceInt(*setting.value, setting.pos)); + state.coerceToString(setting.pos, *setting.value, emptyContext, false, true, true).toOwned()); + } else if (setting.value->type() == nInt) + flake.config.settings.emplace(state.symbols[setting.name], state.forceInt(*setting.value, setting.pos)); else if (setting.value->type() == nBool) flake.config.settings.emplace( - state.symbols[setting.name], - Explicit { state.forceBool(*setting.value, setting.pos) }); + state.symbols[setting.name], Explicit{state.forceBool(*setting.value, setting.pos)}); else if (setting.value->type() == nList) { std::vector ss; for (auto elem : setting.value->listItems()) { if (elem->type() != nString) - throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected", + throw TypeError( + "list element in flake configuration setting '%s' is %s while a string is expected", state.symbols[setting.name], showType(*setting.value)); ss.emplace_back(state.forceStringNoCtx(*elem, setting.pos)); } flake.config.settings.emplace(state.symbols[setting.name], ss); - } - else - throw TypeError("flake configuration setting '%s' is %s", - state.symbols[setting.name], showType(*setting.value)); + } else + throw TypeError( + "flake configuration setting '%s' is %s", state.symbols[setting.name], showType(*setting.value)); } } for (auto & attr : *vInfo.attrs) { - if (attr.name != state.sDescription && - attr.name != sInputs && - attr.name != sOutputs && - attr.name != sNixConfig) - throw Error("flake '%s' has an unsupported attribute '%s', at %s", - lockedRef, state.symbols[attr.name], state.positions[attr.pos]); + if (attr.name != state.sDescription && attr.name != sInputs && attr.name != sOutputs && attr.name != sNixConfig) + throw Error( + "flake '%s' has an unsupported attribute '%s', at %s", lockedRef, state.symbols[attr.name], + state.positions[attr.pos]); } return flake; @@ -315,10 +291,7 @@ Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup /* Compute an in-memory lock file for the specified top-level flake, and optionally write it to file, if the flake is writable. */ -LockedFlake lockFlake( - EvalState & state, - const FlakeRef & topRef, - const LockFlags & lockFlags) +LockedFlake lockFlake(EvalState & state, const FlakeRef & topRef, const LockFlags & lockFlags) { settings.requireExperimentalFeature(Xp::Flakes); @@ -336,8 +309,7 @@ LockedFlake lockFlake( try { // FIXME: symlink attack - auto oldLockFile = LockFile::read( - flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock"); + auto oldLockFile = LockFile::read(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir + "/flake.lock"); debug("old lock file: %s", oldLockFile); @@ -346,31 +318,21 @@ LockedFlake lockFlake( std::set overridesUsed, updatesUsed; for (auto & i : lockFlags.inputOverrides) - overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second }); + overrides.insert_or_assign(i.first, FlakeInput{.ref = i.second}); LockFile newLockFile; std::vector parents; std::function node, - const InputPath & inputPathPrefix, - std::shared_ptr oldNode, - const InputPath & lockRootPath, - const Path & parentPath, + const FlakeInputs & flakeInputs, std::shared_ptr node, const InputPath & inputPathPrefix, + std::shared_ptr oldNode, const InputPath & lockRootPath, const Path & parentPath, bool trustLock)> computeLocks; - computeLocks = [&]( - const FlakeInputs & flakeInputs, - std::shared_ptr node, - const InputPath & inputPathPrefix, - std::shared_ptr oldNode, - const InputPath & lockRootPath, - const Path & parentPath, - bool trustLock) - { + computeLocks = [&](const FlakeInputs & flakeInputs, std::shared_ptr node, + const InputPath & inputPathPrefix, std::shared_ptr oldNode, + const InputPath & lockRootPath, const Path & parentPath, bool trustLock) { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); /* Get the overrides (i.e. attributes of the form @@ -432,17 +394,14 @@ LockedFlake lockFlake( if (auto oldLock3 = std::get_if<0>(&*oldLock2)) oldLock = *oldLock3; - if (oldLock - && oldLock->originalRef == *input.ref - && !hasOverride) - { + if (oldLock && oldLock->originalRef == *input.ref && !hasOverride) { debug("keeping existing input '%s'", inputPathS); /* Copy the input from the old lock since its flakeref didn't change and there is no override from a higher level flake. */ - auto childNode = std::make_shared( - oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake); + auto childNode = + std::make_shared(oldLock->lockedRef, oldLock->originalRef, oldLock->isFlake); node->inputs.insert_or_assign(id, childNode); @@ -451,10 +410,8 @@ LockedFlake lockFlake( update it. */ auto lb = lockFlags.inputUpdates.lower_bound(inputPath); - auto mustRefetch = - lb != lockFlags.inputUpdates.end() - && lb->size() > inputPath.size() - && std::equal(inputPath.begin(), inputPath.end(), lb->begin()); + auto mustRefetch = lb != lockFlags.inputUpdates.end() && lb->size() > inputPath.size() + && std::equal(inputPath.begin(), inputPath.end(), lb->begin()); FlakeInputs fakeInputs; @@ -465,14 +422,16 @@ LockedFlake lockFlake( those. */ for (auto & i : oldLock->inputs) { if (auto lockedNode = std::get_if<0>(&i.second)) { - fakeInputs.emplace(i.first, FlakeInput { - .ref = (*lockedNode)->originalRef, - .isFlake = (*lockedNode)->isFlake, - }); + fakeInputs.emplace( + i.first, FlakeInput{ + .ref = (*lockedNode)->originalRef, + .isFlake = (*lockedNode)->isFlake, + }); } else if (auto follows = std::get_if<1>(&i.second)) { - if (! trustLock) { + 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 lockfile are also in the + // flake. auto overridePath(inputPath); overridePath.push_back(i.first); auto o = overrides.find(overridePath); @@ -487,9 +446,10 @@ LockedFlake lockFlake( } auto absoluteFollows(lockRootPath); absoluteFollows.insert(absoluteFollows.end(), follows->begin(), follows->end()); - fakeInputs.emplace(i.first, FlakeInput { - .follows = absoluteFollows, - }); + fakeInputs.emplace( + i.first, FlakeInput{ + .follows = absoluteFollows, + }); } } } @@ -500,9 +460,8 @@ LockedFlake lockFlake( if ((*input.ref).input.getType() == "path") localPath = absPath(*input.ref->input.getSourcePath(), parentPath); computeLocks( - mustRefetch - ? getFlake(state, oldLock->lockedRef, false, flakeCache, inputPath).inputs - : fakeInputs, + mustRefetch ? getFlake(state, oldLock->lockedRef, false, flakeCache, inputPath).inputs + : fakeInputs, childNode, inputPath, oldLock, lockRootPath, parentPath, !mustRefetch); } else { @@ -550,18 +509,18 @@ LockedFlake lockFlake( own lock file. */ computeLocks( inputFlake.inputs, childNode, inputPath, - oldLock - ? std::dynamic_pointer_cast(oldLock) - : LockFile::read( - inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root, + oldLock ? std::dynamic_pointer_cast(oldLock) + : LockFile::read( + inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + + "/flake.lock") + .root, oldLock ? lockRootPath : inputPath, localPath, false); } else { - auto [sourceInfo, resolvedRef, lockedRef] = fetchOrSubstituteTree( - state, *input.ref, useRegistries, flakeCache); - node->inputs.insert_or_assign(id, - std::make_shared(lockedRef, ref, false)); + auto [sourceInfo, resolvedRef, lockedRef] = + fetchOrSubstituteTree(state, *input.ref, useRegistries, flakeCache); + node->inputs.insert_or_assign(id, std::make_shared(lockedRef, ref, false)); } } @@ -576,13 +535,12 @@ LockedFlake lockFlake( auto parentPath = canonPath(flake.sourceInfo->actualPath + "/" + flake.lockedRef.subdir, true); computeLocks( - flake.inputs, newLockFile.root, {}, - lockFlags.recreateLockFile ? nullptr : oldLockFile.root, {}, parentPath, false); + flake.inputs, newLockFile.root, {}, lockFlags.recreateLockFile ? nullptr : oldLockFile.root, {}, parentPath, + false); for (auto & i : lockFlags.inputOverrides) if (!overridesUsed.count(i.first)) - warn("the flag '--override-input %s %s' does not match any input", - printInputPath(i.first), i.second); + warn("the flag '--override-input %s %s' does not match any input", printInputPath(i.first), i.second); for (auto & i : lockFlags.inputUpdates) if (!updatesUsed.count(i)) @@ -605,7 +563,9 @@ LockedFlake lockFlake( warn("will not write lock file of flake '%s' because it has a mutable input", topRef); } else { if (!lockFlags.updateLockFile) - throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef); + throw Error( + "flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", + topRef); auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock"; @@ -640,8 +600,7 @@ LockedFlake lockFlake( } topRef.input.markChangedFile( - (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock", - commitMessage); + (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock", commitMessage); /* Rewriting the lockfile changed the top-level repo, so we should re-read it. FIXME: we could @@ -650,28 +609,29 @@ LockedFlake lockFlake( FlakeCache dummyCache; flake = getFlake(state, topRef, useRegistries, dummyCache); - if (lockFlags.commitLockFile && - flake.lockedRef.input.getRev() && - prevLockedRef.input.getRev() != flake.lockedRef.input.getRev()) + if (lockFlags.commitLockFile && flake.lockedRef.input.getRev() + && prevLockedRef.input.getRev() != flake.lockedRef.input.getRev()) warn("committed new revision '%s'", flake.lockedRef.input.getRev()->gitRev()); /* Make sure that we picked up the change, i.e. the tree should usually be dirty now. Corner case: we could have reverted from a dirty to a clean tree! */ - if (flake.lockedRef.input == prevLockedRef.input - && !flake.lockedRef.input.isLocked()) - throw Error("'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", flake.originalRef); + if (flake.lockedRef.input == prevLockedRef.input && !flake.lockedRef.input.isLocked()) + throw Error( + "'%s' did not change after I updated its 'flake.lock' file; is 'flake.lock' under version control?", + flake.originalRef); } } else - throw Error("cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef); + throw Error( + "cannot write modified lock file of flake '%s' (use '--no-write-lock-file' to ignore)", topRef); } else { warn("not writing modified lock file of flake '%s':\n%s", topRef, chomp(diff)); flake.forceDirty = true; } } - return LockedFlake { .flake = std::move(flake), .lockFile = std::move(newLockFile) }; + return LockedFlake{.flake = std::move(flake), .lockFile = std::move(newLockFile)}; } catch (Error & e) { e.addTrace({}, "while updating the lock file of flake '%s'", flake.lockedRef.to_string()); @@ -679,9 +639,7 @@ LockedFlake lockFlake( } } -void callFlake(EvalState & state, - const LockedFlake & lockedFlake, - Value & vRes) +void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & vRes) { auto vLocks = state.allocValue(); auto vRootSrc = state.allocValue(); @@ -692,20 +650,18 @@ void callFlake(EvalState & state, vLocks->mkString(lockedFlake.lockFile.to_string()); emitTreeAttrs( - state, - *lockedFlake.flake.sourceInfo, - lockedFlake.flake.lockedRef.input, - *vRootSrc, - false, + state, *lockedFlake.flake.sourceInfo, lockedFlake.flake.lockedRef.input, *vRootSrc, false, lockedFlake.flake.forceDirty); vRootSubdir->mkString(lockedFlake.flake.lockedRef.subdir); if (!state.vCallFlake) { state.vCallFlake = allocRootValue(state.allocValue()); - state.eval(state.parseExprFromString( - #include "call-flake.nix.gen.hh" - , "/"), **state.vCallFlake); + state.eval( + state.parseExprFromString( +#include "call-flake.nix.gen.hh" + , "/"), + **state.vCallFlake); } state.callFunction(**state.vCallFlake, *vLocks, *vTmp1, noPos); @@ -713,26 +669,30 @@ void callFlake(EvalState & state, state.callFunction(*vTmp2, *vRootSubdir, vRes, noPos); } -static void prim_getFlake(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_getFlake(EvalState & state, const PosIdx pos, Value ** args, Value & v) { std::string flakeRefS(state.forceStringNoCtx(*args[0], pos)); auto flakeRef = parseFlakeRef(flakeRefS, {}, true); if (evalSettings.pureEval && !flakeRef.input.isLocked()) - throw Error("cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, state.positions[pos]); + throw Error( + "cannot call 'getFlake' on unlocked flake reference '%s', at %s (use --impure to override)", flakeRefS, + state.positions[pos]); - callFlake(state, - lockFlake(state, flakeRef, - LockFlags { + callFlake( + state, + lockFlake( + state, flakeRef, + LockFlags{ .updateLockFile = false, .writeLockFile = false, .useRegistries = !evalSettings.pureEval && fetchSettings.useRegistries, - .allowMutable = !evalSettings.pureEval, + .allowMutable = !evalSettings.pureEval, }), v); } static RegisterPrimOp r2({ - .name = "__getFlake", + .name = "__getFlake", .args = {"args"}, .doc = R"( Fetch a flake from a flake reference, and return its output attributes and some metadata. For example: @@ -763,15 +723,12 @@ Fingerprint LockedFlake::getFingerprint() const // FIXME: as an optimization, if the flake contains a lock file // and we haven't changed it, then it's sufficient to use // flake.sourceInfo.storePath for the fingerprint. - return hashString(htSHA256, - fmt("%s;%s;%d;%d;%s", - flake.sourceInfo->storePath.to_string(), - flake.lockedRef.subdir, - flake.lockedRef.input.getRevCount().value_or(0), - flake.lockedRef.input.getLastModified().value_or(0), - lockFile)); + return hashString( + htSHA256, fmt("%s;%s;%d;%d;%s", flake.sourceInfo->storePath.to_string(), flake.lockedRef.subdir, + flake.lockedRef.input.getRevCount().value_or(0), + flake.lockedRef.input.getLastModified().value_or(0), lockFile)); } -Flake::~Flake() { } +Flake::~Flake() {} } diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh index 524b18af1756..57372495604b 100644 --- a/src/libexpr/flake/flake.hh +++ b/src/libexpr/flake/flake.hh @@ -9,7 +9,9 @@ namespace nix { class EvalState; -namespace fetchers { struct Tree; } +namespace fetchers { +struct Tree; +} namespace flake { @@ -41,7 +43,7 @@ typedef std::map FlakeInputs; struct FlakeInput { std::optional ref; - bool isFlake = true; // true = process flake to get outputs, false = (fetched) static source path + bool isFlake = true; // true = process flake to get outputs, false = (fetched) static source path std::optional follows; FlakeInputs overrides; }; @@ -58,9 +60,9 @@ struct ConfigFile /* The contents of a flake.nix file. */ struct Flake { - FlakeRef originalRef; // the original flake specification (by the user) - FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake - FlakeRef lockedRef; // the specific local store result of invoking the fetcher + FlakeRef originalRef; // the original flake specification (by the user) + FlakeRef resolvedRef; // registry references and caching resolved to the specific underlying flake + FlakeRef lockedRef; // the specific local store result of invoking the fetcher bool forceDirty = false; // pretend that 'lockedRef' is dirty std::optional description; std::shared_ptr sourceInfo; @@ -125,15 +127,9 @@ struct LockFlags std::set inputUpdates; }; -LockedFlake lockFlake( - EvalState & state, - const FlakeRef & flakeRef, - const LockFlags & lockFlags); +LockedFlake lockFlake(EvalState & state, const FlakeRef & flakeRef, const LockFlags & lockFlags); -void callFlake( - EvalState & state, - const LockedFlake & lockedFlake, - Value & v); +void callFlake(EvalState & state, const LockedFlake & lockedFlake, Value & v); } diff --git a/src/libexpr/flake/flakeref.cc b/src/libexpr/flake/flakeref.cc index eede493f8dd1..1f17b8538243 100644 --- a/src/libexpr/flake/flakeref.cc +++ b/src/libexpr/flake/flakeref.cc @@ -30,13 +30,13 @@ fetchers::Attrs FlakeRef::toAttrs() const return attrs; } -std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef) +std::ostream & operator<<(std::ostream & str, const FlakeRef & flakeRef) { str << flakeRef.to_string(); return str; } -bool FlakeRef::operator ==(const FlakeRef & other) const +bool FlakeRef::operator==(const FlakeRef & other) const { return input == other.input && subdir == other.subdir; } @@ -47,11 +47,7 @@ FlakeRef FlakeRef::resolve(ref store) const return FlakeRef(std::move(input2), fetchers::maybeGetStrAttr(extraAttrs, "dir").value_or(subdir)); } -FlakeRef parseFlakeRef( - const std::string & url, - const std::optional & baseDir, - bool allowMissing, - bool isFlake) +FlakeRef parseFlakeRef(const std::string & url, const std::optional & baseDir, bool allowMissing, bool isFlake) { auto [flakeRef, fragment] = parseFlakeRefWithFragment(url, baseDir, allowMissing, isFlake); if (fragment != "") @@ -59,8 +55,7 @@ FlakeRef parseFlakeRef( return flakeRef; } -std::optional maybeParseFlakeRef( - const std::string & url, const std::optional & baseDir) +std::optional maybeParseFlakeRef(const std::string & url, const std::optional & baseDir) { try { return parseFlakeRef(url, baseDir); @@ -69,25 +64,19 @@ std::optional maybeParseFlakeRef( } } -std::pair parseFlakeRefWithFragment( - const std::string & url, - const std::optional & baseDir, - bool allowMissing, - bool isFlake) +std::pair +parseFlakeRefWithFragment(const std::string & url, const std::optional & baseDir, bool allowMissing, bool isFlake) { using namespace fetchers; static std::string fnRegex = "[0-9a-zA-Z-._~!$&'\"()*+,;=]+"; static std::regex pathUrlRegex( - "(/?" + fnRegex + "(?:/" + fnRegex + ")*/?)" - + "(?:\\?(" + queryRegex + "))?" - + "(?:#(" + queryRegex + "))?", + "(/?" + fnRegex + "(?:/" + fnRegex + ")*/?)" + "(?:\\?(" + queryRegex + "))?" + "(?:#(" + queryRegex + "))?", std::regex::ECMAScript); static std::regex flakeRegex( - "((" + flakeIdRegexS + ")(?:/(?:" + refAndOrRevRegex + "))?)" - + "(?:#(" + queryRegex + "))?", + "((" + flakeIdRegexS + ")(?:/(?:" + refAndOrRevRegex + "))?)" + "(?:#(" + queryRegex + "))?", std::regex::ECMAScript); std::smatch match; @@ -104,9 +93,7 @@ std::pair parseFlakeRefWithFragment( .path = match[1], }; - return std::make_pair( - FlakeRef(Input::fromURL(parsedURL), ""), - percentDecode(match.str(6))); + return std::make_pair(FlakeRef(Input::fromURL(parsedURL), ""), percentDecode(match.str(6))); } else if (std::regex_match(url, match, pathUrlRegex)) { @@ -122,8 +109,8 @@ std::pair parseFlakeRefWithFragment( if (isFlake) { - if (!allowMissing && !pathExists(path + "/flake.nix")){ - notice("path '%s' does not contain a 'flake.nix', searching up",path); + if (!allowMissing && !pathExists(path + "/flake.nix")) { + notice("path '%s' does not contain a 'flake.nix', searching up", path); // Save device to detect filesystem boundary dev_t device = lstat(path).st_dev; @@ -133,10 +120,13 @@ std::pair parseFlakeRefWithFragment( found = true; break; } else if (pathExists(path + "/.git")) - throw Error("path '%s' is not part of a flake (neither it nor its parent directories contain a 'flake.nix' file)", path); + throw Error( + "path '%s' is not part of a flake (neither it nor its parent directories contain a 'flake.nix' file)", + path); else { if (lstat(path).st_dev != device) - throw Error("unable to find a flake before encountering filesystem boundary at '%s'", path); + throw Error( + "unable to find a flake before encountering filesystem boundary at '%s'", path); } path = dirOf(path); } @@ -176,8 +166,7 @@ std::pair parseFlakeRefWithFragment( parsedURL.query.insert_or_assign("shallow", "1"); return std::make_pair( - FlakeRef(Input::fromURL(parsedURL), getOr(parsedURL.query, "dir", "")), - fragment); + FlakeRef(Input::fromURL(parsedURL), getOr(parsedURL.query, "dir", "")), fragment); } subdir = std::string(baseNameOf(flakeRoot)) + (subdir.empty() ? "" : "/" + subdir); @@ -207,14 +196,12 @@ std::pair parseFlakeRefWithFragment( auto input = Input::fromURL(parsedURL); input.parent = baseDir; - return std::make_pair( - FlakeRef(std::move(input), getOr(parsedURL.query, "dir", "")), - fragment); + return std::make_pair(FlakeRef(std::move(input), getOr(parsedURL.query, "dir", "")), fragment); } } -std::optional> maybeParseFlakeRefWithFragment( - const std::string & url, const std::optional & baseDir) +std::optional> +maybeParseFlakeRefWithFragment(const std::string & url, const std::optional & baseDir) { try { return parseFlakeRefWithFragment(url, baseDir); @@ -228,8 +215,7 @@ FlakeRef FlakeRef::fromAttrs(const fetchers::Attrs & attrs) auto attrs2(attrs); attrs2.erase("dir"); return FlakeRef( - fetchers::Input::fromAttrs(std::move(attrs2)), - fetchers::maybeGetStrAttr(attrs, "dir").value_or("")); + fetchers::Input::fromAttrs(std::move(attrs2)), fetchers::maybeGetStrAttr(attrs, "dir").value_or("")); } std::pair FlakeRef::fetchTree(ref store) const @@ -239,10 +225,7 @@ std::pair FlakeRef::fetchTree(ref store) const } std::tuple parseFlakeRefWithFragmentAndOutputsSpec( - const std::string & url, - const std::optional & baseDir, - bool allowMissing, - bool isFlake) + const std::string & url, const std::optional & baseDir, bool allowMissing, bool isFlake) { auto [prefix, outputsSpec] = parseOutputsSpec(url); auto [flakeRef, fragment] = parseFlakeRefWithFragment(prefix, baseDir, allowMissing, isFlake); diff --git a/src/libexpr/flake/flakeref.hh b/src/libexpr/flake/flakeref.hh index a9182f4bfd72..7be26a82268c 100644 --- a/src/libexpr/flake/flakeref.hh +++ b/src/libexpr/flake/flakeref.hh @@ -45,8 +45,9 @@ struct FlakeRef bool operator==(const FlakeRef & other) const; FlakeRef(fetchers::Input && input, const Path & subdir) - : input(std::move(input)), subdir(subdir) - { } + : input(std::move(input)) + , subdir(subdir) + {} // FIXME: change to operator <<. std::string to_string() const; @@ -60,31 +61,20 @@ struct FlakeRef std::pair fetchTree(ref store) const; }; -std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef); +std::ostream & operator<<(std::ostream & str, const FlakeRef & flakeRef); FlakeRef parseFlakeRef( - const std::string & url, - const std::optional & baseDir = {}, - bool allowMissing = false, - bool isFlake = true); + const std::string & url, const std::optional & baseDir = {}, bool allowMissing = false, bool isFlake = true); -std::optional maybeParseFlake( - const std::string & url, const std::optional & baseDir = {}); +std::optional maybeParseFlake(const std::string & url, const std::optional & baseDir = {}); std::pair parseFlakeRefWithFragment( - const std::string & url, - const std::optional & baseDir = {}, - bool allowMissing = false, - bool isFlake = true); + const std::string & url, const std::optional & baseDir = {}, bool allowMissing = false, bool isFlake = true); -std::optional> maybeParseFlakeRefWithFragment( - const std::string & url, const std::optional & baseDir = {}); +std::optional> +maybeParseFlakeRefWithFragment(const std::string & url, const std::optional & baseDir = {}); std::tuple parseFlakeRefWithFragmentAndOutputsSpec( - const std::string & url, - const std::optional & baseDir = {}, - bool allowMissing = false, - bool isFlake = true); - + const std::string & url, const std::optional & baseDir = {}, bool allowMissing = false, bool isFlake = true); } diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc index 60b52d578ee5..44f19c18d446 100644 --- a/src/libexpr/flake/lockfile.cc +++ b/src/libexpr/flake/lockfile.cc @@ -8,10 +8,7 @@ namespace nix::flake { -FlakeRef getFlakeRef( - const nlohmann::json & json, - const char * attr, - const char * info) +FlakeRef getFlakeRef(const nlohmann::json & json, const char * attr, const char * info) { auto i = json.find(attr); if (i != json.end()) { @@ -36,8 +33,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'", - fetchers::attrsToJSON(lockedRef.input.toAttrs())); + throw Error("lockfile contains mutable lock '%s'", fetchers::attrsToJSON(lockedRef.input.toAttrs())); } StorePath LockedNode::computeStorePath(Store & store) const @@ -49,7 +45,8 @@ std::shared_ptr LockFile::findInput(const InputPath & path) { auto pos = root; - if (!pos) return {}; + if (!pos) + return {}; for (auto & elem : path) { if (auto i = get(pos->inputs, elem)) { @@ -57,7 +54,8 @@ std::shared_ptr LockFile::findInput(const InputPath & path) pos = *node; else if (auto follows = std::get_if<1>(&*i)) { pos = findInput(*follows); - if (!pos) return {}; + if (!pos) + return {}; } } else return {}; @@ -76,9 +74,9 @@ LockFile::LockFile(const nlohmann::json & json, const Path & path) std::function getInputs; - getInputs = [&](Node & node, const nlohmann::json & jsonNode) - { - if (jsonNode.find("inputs") == jsonNode.end()) return; + getInputs = [&](Node & node, const nlohmann::json & jsonNode) { + if (jsonNode.find("inputs") == jsonNode.end()) + return; for (auto & i : jsonNode["inputs"].items()) { if (i.value().is_array()) { // FIXME: remove, obsolete InputPath path; @@ -124,14 +122,13 @@ nlohmann::json LockFile::toJSON() const std::function node)> dumpNode; - dumpNode = [&](std::string key, std::shared_ptr node) -> std::string - { + dumpNode = [&](std::string key, std::shared_ptr node) -> std::string { auto k = nodeKeys.find(node); if (k != nodeKeys.end()) return k->second; if (!keys.insert(key).second) { - for (int n = 2; ; ++n) { + for (int n = 2;; ++n) { auto k = fmt("%s_%d", key, n); if (keys.insert(k).second) { key = k; @@ -162,7 +159,8 @@ nlohmann::json LockFile::toJSON() const if (auto lockedNode = std::dynamic_pointer_cast(node)) { n["original"] = fetchers::attrsToJSON(lockedNode->originalRef.toAttrs()); n["locked"] = fetchers::attrsToJSON(lockedNode->lockedRef.toAttrs()); - if (!lockedNode->isFlake) n["flake"] = false; + if (!lockedNode->isFlake) + n["flake"] = false; } nodes[key] = std::move(n); @@ -185,11 +183,12 @@ std::string LockFile::to_string() const LockFile LockFile::read(const Path & path) { - if (!pathExists(path)) return LockFile(); + if (!pathExists(path)) + return LockFile(); return LockFile(nlohmann::json::parse(readFile(path)), path); } -std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile) +std::ostream & operator<<(std::ostream & stream, const LockFile & lockFile) { stream << lockFile.toJSON().dump(2); return stream; @@ -207,9 +206,9 @@ bool LockFile::isImmutable() const std::function node)> visit; - visit = [&](std::shared_ptr node) - { - if (!nodes.insert(node).second) return; + visit = [&](std::shared_ptr node) { + if (!nodes.insert(node).second) + return; for (auto & i : node->inputs) if (auto child = std::get_if<0>(&i.second)) visit(*child); @@ -218,15 +217,17 @@ bool LockFile::isImmutable() const visit(root); for (auto & i : nodes) { - if (i == root) continue; + if (i == root) + continue; auto lockedNode = std::dynamic_pointer_cast(i); - if (lockedNode && !lockedNode->lockedRef.input.isLocked()) return false; + if (lockedNode && !lockedNode->lockedRef.input.isLocked()) + return false; } return true; } -bool LockFile::operator ==(const LockFile & other) const +bool LockFile::operator==(const LockFile & other) const { // FIXME: slow return toJSON() == other.toJSON(); @@ -252,11 +253,11 @@ std::map LockFile::getAllInputs() const std::function node)> recurse; - recurse = [&](const InputPath & prefix, std::shared_ptr node) - { - if (!done.insert(node).second) return; + recurse = [&](const InputPath & prefix, std::shared_ptr node) { + if (!done.insert(node).second) + return; - for (auto &[id, input] : node->inputs) { + for (auto & [id, input] : node->inputs) { auto inputPath(prefix); inputPath.push_back(id); res.emplace(inputPath, input); @@ -280,7 +281,7 @@ static std::string describe(const FlakeRef & flakeRef) return s; } -std::ostream & operator <<(std::ostream & stream, const Node::Edge & edge) +std::ostream & operator<<(std::ostream & stream, const Node::Edge & edge) { if (auto node = std::get_if<0>(&edge)) stream << describe((*node)->lockedRef); @@ -311,18 +312,17 @@ std::string LockFile::diff(const LockFile & oldLocks, const LockFile & newLocks) while (i != oldFlat.end() || j != newFlat.end()) { if (j != newFlat.end() && (i == oldFlat.end() || i->first > j->first)) { - res += fmt("• " ANSI_GREEN "Added input '%s':" ANSI_NORMAL "\n %s\n", - printInputPath(j->first), j->second); + res += + fmt("• " ANSI_GREEN "Added input '%s':" ANSI_NORMAL "\n %s\n", printInputPath(j->first), j->second); ++j; } else if (i != oldFlat.end() && (j == newFlat.end() || i->first < j->first)) { res += fmt("• " ANSI_RED "Removed input '%s'" ANSI_NORMAL "\n", printInputPath(i->first)); ++i; } else { if (!equals(i->second, j->second)) { - res += fmt("• " ANSI_BOLD "Updated input '%s':" ANSI_NORMAL "\n %s\n → %s\n", - printInputPath(i->first), - i->second, - j->second); + res += + fmt("• " ANSI_BOLD "Updated input '%s':" ANSI_NORMAL "\n %s\n → %s\n", printInputPath(i->first), + i->second, j->second); } ++i; ++j; @@ -339,8 +339,8 @@ void LockFile::check() for (auto & [inputPath, input] : inputs) { if (auto follows = std::get_if<1>(&input)) { if (!follows->empty() && !get(inputs, *follows)) - throw Error("input '%s' follows a non-existent input '%s'", - printInputPath(inputPath), + throw Error( + "input '%s' follows a non-existent input '%s'", printInputPath(inputPath), printInputPath(*follows)); } } diff --git a/src/libexpr/flake/lockfile.hh b/src/libexpr/flake/lockfile.hh index 96f1edc76bab..a77ac93265b3 100644 --- a/src/libexpr/flake/lockfile.hh +++ b/src/libexpr/flake/lockfile.hh @@ -24,7 +24,7 @@ struct Node : std::enable_shared_from_this std::map inputs; - virtual ~Node() { } + virtual ~Node() {} }; /* A non-root node in the lock file. */ @@ -33,12 +33,11 @@ struct LockedNode : Node FlakeRef lockedRef, originalRef; bool isFlake = true; - LockedNode( - const FlakeRef & lockedRef, - const FlakeRef & originalRef, - bool isFlake = true) - : lockedRef(lockedRef), originalRef(originalRef), isFlake(isFlake) - { } + LockedNode(const FlakeRef & lockedRef, const FlakeRef & originalRef, bool isFlake = true) + : lockedRef(lockedRef) + , originalRef(originalRef) + , isFlake(isFlake) + {} LockedNode(const nlohmann::json & json); @@ -49,7 +48,7 @@ struct LockFile { std::shared_ptr root = std::make_shared(); - LockFile() {}; + LockFile(){}; LockFile(const nlohmann::json & json, const Path & path); nlohmann::json toJSON() const; @@ -62,7 +61,7 @@ struct LockFile bool isImmutable() const; - bool operator ==(const LockFile & other) const; + bool operator==(const LockFile & other) const; std::shared_ptr findInput(const InputPath & path); @@ -74,7 +73,7 @@ struct LockFile void check(); }; -std::ostream & operator <<(std::ostream & stream, const LockFile & lockFile); +std::ostream & operator<<(std::ostream & stream, const LockFile & lockFile); InputPath parseInputPath(std::string_view s); diff --git a/src/libexpr/function-trace.cc b/src/libexpr/function-trace.cc index c6057b3842f1..661a280b917a 100644 --- a/src/libexpr/function-trace.cc +++ b/src/libexpr/function-trace.cc @@ -3,13 +3,16 @@ namespace nix { -FunctionCallTrace::FunctionCallTrace(const Pos & pos) : pos(pos) { +FunctionCallTrace::FunctionCallTrace(const Pos & pos) + : pos(pos) +{ auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); auto ns = std::chrono::duration_cast(duration); printMsg(lvlInfo, "function-trace entered %1% at %2%", pos, ns.count()); } -FunctionCallTrace::~FunctionCallTrace() { +FunctionCallTrace::~FunctionCallTrace() +{ auto duration = std::chrono::high_resolution_clock::now().time_since_epoch(); auto ns = std::chrono::duration_cast(duration); printMsg(lvlInfo, "function-trace exited %1% at %2%", pos, ns.count()); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 346741dd5460..c9096967c049 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -8,18 +8,18 @@ #include #include - namespace nix { - DrvInfo::DrvInfo(EvalState & state, std::string attrPath, Bindings * attrs) - : state(&state), attrs(attrs), attrPath(std::move(attrPath)) -{ -} - + : state(&state) + , attrs(attrs) + , attrPath(std::move(attrPath)) +{} DrvInfo::DrvInfo(EvalState & state, ref store, const std::string & drvPathWithOutputs) - : state(&state), attrs(nullptr), attrPath("") + : state(&state) + , attrs(nullptr) + , attrPath("") { auto [drvPath, selectedOutputs] = parsePathWithOutputs(*store, drvPathWithOutputs); @@ -32,10 +32,7 @@ DrvInfo::DrvInfo(EvalState & state, ref store, const std::string & drvPat if (selectedOutputs.size() > 1) throw Error("building more than one derivation output is not supported, in '%s'", drvPathWithOutputs); - outputName = - selectedOutputs.empty() - ? getOr(drv.env, "outputName", "out") - : *selectedOutputs.begin(); + outputName = selectedOutputs.empty() ? getOr(drv.env, "outputName", "out") : *selectedOutputs.begin(); auto i = drv.outputs.find(outputName); if (i == drv.outputs.end()) @@ -45,18 +42,17 @@ DrvInfo::DrvInfo(EvalState & state, ref store, const std::string & drvPat outPath = {output.path(*store, drv.name, outputName)}; } - std::string DrvInfo::queryName() const { if (name == "" && attrs) { auto i = attrs->find(state->sName); - if (i == attrs->end()) throw TypeError("derivation name missing"); + if (i == attrs->end()) + throw TypeError("derivation name missing"); name = state->forceStringNoCtx(*i->value); } return name; } - std::string DrvInfo::querySystem() const { if (system == "" && attrs) { @@ -66,7 +62,6 @@ std::string DrvInfo::querySystem() const return system; } - std::optional DrvInfo::queryDrvPath() const { if (!drvPath && attrs) { @@ -80,7 +75,6 @@ std::optional DrvInfo::queryDrvPath() const return drvPath.value_or(std::nullopt); } - StorePath DrvInfo::requireDrvPath() const { if (auto drvPath = queryDrvPath()) @@ -88,7 +82,6 @@ StorePath DrvInfo::requireDrvPath() const throw Error("derivation does not contain a 'drvPath' attribute"); } - StorePath DrvInfo::queryOutPath() const { if (!outPath && attrs) { @@ -102,7 +95,6 @@ StorePath DrvInfo::queryOutPath() const return *outPath; } - DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall) { if (outputs.empty()) { @@ -118,12 +110,14 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall if (withPaths) { /* Evaluate the corresponding set. */ Bindings::iterator out = attrs->find(state->symbols.create(output)); - if (out == attrs->end()) continue; // FIXME: throw error? + if (out == attrs->end()) + continue; // FIXME: throw error? state->forceAttrs(*out->value, i->pos); /* And evaluate its ‘outPath’ attribute. */ Bindings::iterator outPath = out->value->attrs->find(state->sOutPath); - if (outPath == out->value->attrs->end()) continue; // FIXME: throw error? + if (outPath == out->value->attrs->end()) + continue; // FIXME: throw error? PathSet context; outputs.emplace(output, state->coerceToStorePath(outPath->pos, *outPath->value, context)); } else @@ -149,22 +143,25 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool withPaths, bool onlyOutputsToInstall else { /* Check for `meta.outputsToInstall` and return `outputs` reduced to that. */ const Value * outTI = queryMeta("outputsToInstall"); - if (!outTI) return outputs; + if (!outTI) + return outputs; const auto errMsg = Error("this derivation has bad 'meta.outputsToInstall'"); - /* ^ this shows during `nix-env -i` right under the bad derivation */ - if (!outTI->isList()) throw errMsg; + /* ^ this shows during `nix-env -i` right under the bad derivation */ + if (!outTI->isList()) + throw errMsg; Outputs result; for (auto elem : outTI->listItems()) { - if (elem->type() != nString) throw errMsg; + if (elem->type() != nString) + throw errMsg; auto out = outputs.find(elem->string.s); - if (out == outputs.end()) throw errMsg; + if (out == outputs.end()) + throw errMsg; result.insert(*out); } return result; } } - std::string DrvInfo::queryOutputName() const { if (outputName == "" && attrs) { @@ -174,71 +171,75 @@ std::string DrvInfo::queryOutputName() const return outputName; } - Bindings * DrvInfo::getMeta() { - if (meta) return meta; - if (!attrs) return 0; + if (meta) + return meta; + if (!attrs) + return 0; Bindings::iterator a = attrs->find(state->sMeta); - if (a == attrs->end()) return 0; + if (a == attrs->end()) + return 0; state->forceAttrs(*a->value, a->pos); meta = a->value->attrs; return meta; } - StringSet DrvInfo::queryMetaNames() { StringSet res; - if (!getMeta()) return res; + if (!getMeta()) + return res; for (auto & i : *meta) res.emplace(state->symbols[i.name]); return res; } - bool DrvInfo::checkMeta(Value & v) { state->forceValue(v, [&]() { return v.determinePos(noPos); }); if (v.type() == nList) { for (auto elem : v.listItems()) - if (!checkMeta(*elem)) return false; + if (!checkMeta(*elem)) + return false; return true; - } - else if (v.type() == nAttrs) { + } else if (v.type() == nAttrs) { Bindings::iterator i = v.attrs->find(state->sOutPath); - if (i != v.attrs->end()) return false; + if (i != v.attrs->end()) + return false; for (auto & i : *v.attrs) - if (!checkMeta(*i.value)) return false; + if (!checkMeta(*i.value)) + return false; return true; - } - else return v.type() == nInt || v.type() == nBool || v.type() == nString || - v.type() == nFloat; + } else + return v.type() == nInt || v.type() == nBool || v.type() == nString || v.type() == nFloat; } - Value * DrvInfo::queryMeta(const std::string & name) { - if (!getMeta()) return 0; + if (!getMeta()) + return 0; Bindings::iterator a = meta->find(state->symbols.create(name)); - if (a == meta->end() || !checkMeta(*a->value)) return 0; + if (a == meta->end() || !checkMeta(*a->value)) + return 0; return a->value; } - std::string DrvInfo::queryMetaString(const std::string & name) { Value * v = queryMeta(name); - if (!v || v->type() != nString) return ""; + if (!v || v->type() != nString) + return ""; return v->string.s; } - NixInt DrvInfo::queryMetaInt(const std::string & name, NixInt def) { Value * v = queryMeta(name); - if (!v) return def; - if (v->type() == nInt) return v->integer; + if (!v) + return def; + if (v->type() == nInt) + return v->integer; if (v->type() == nString) { /* Backwards compatibility with before we had support for integer meta fields. */ @@ -251,8 +252,10 @@ NixInt DrvInfo::queryMetaInt(const std::string & name, NixInt def) NixFloat DrvInfo::queryMetaFloat(const std::string & name, NixFloat def) { Value * v = queryMeta(name); - if (!v) return def; - if (v->type() == nFloat) return v->fpoint; + if (!v) + return def; + if (v->type() == nFloat) + return v->fpoint; if (v->type() == nString) { /* Backwards compatibility with before we had support for float meta fields. */ @@ -262,22 +265,24 @@ NixFloat DrvInfo::queryMetaFloat(const std::string & name, NixFloat def) return def; } - bool DrvInfo::queryMetaBool(const std::string & name, bool def) { Value * v = queryMeta(name); - if (!v) return def; - if (v->type() == nBool) return v->boolean; + if (!v) + return def; + if (v->type() == nBool) + return v->boolean; if (v->type() == nString) { /* Backwards compatibility with before we had support for Boolean meta fields. */ - if (strcmp(v->string.s, "true") == 0) return true; - if (strcmp(v->string.s, "false") == 0) return false; + if (strcmp(v->string.s, "true") == 0) + return true; + if (strcmp(v->string.s, "false") == 0) + return false; } return def; } - void DrvInfo::setMeta(const std::string & name, Value * v) { getMeta(); @@ -287,30 +292,35 @@ void DrvInfo::setMeta(const std::string & name, Value * v) for (auto i : *meta) if (i.name != sym) attrs.insert(i); - if (v) attrs.insert(sym, v); + if (v) + attrs.insert(sym, v); meta = attrs.finish(); } - /* Cache for already considered attrsets. */ typedef std::set Done; - /* Evaluate value `v'. If it evaluates to a set of type `derivation', then put information about it in `drvs' (unless it's already in `done'). The result boolean indicates whether it makes sense for the caller to recursively search for derivations in `v'. */ -static bool getDerivation(EvalState & state, Value & v, - const std::string & attrPath, DrvInfos & drvs, Done & done, +static bool getDerivation( + EvalState & state, + Value & v, + const std::string & attrPath, + DrvInfos & drvs, + Done & done, bool ignoreAssertionFailures) { try { state.forceValue(v, [&]() { return v.determinePos(noPos); }); - if (!state.isDerivation(v)) return true; + if (!state.isDerivation(v)) + return true; /* Remove spurious duplicates (e.g., a set like `rec { x = derivation {...}; y = x;}'. */ - if (!done.insert(v.attrs).second) return false; + if (!done.insert(v.attrs).second) + return false; DrvInfo drv(state, attrPath, v.attrs); @@ -321,42 +331,44 @@ static bool getDerivation(EvalState & state, Value & v, return false; } catch (AssertionError & e) { - if (ignoreAssertionFailures) return false; + if (ignoreAssertionFailures) + return false; throw; } } - -std::optional getDerivation(EvalState & state, Value & v, - bool ignoreAssertionFailures) +std::optional getDerivation(EvalState & state, Value & v, bool ignoreAssertionFailures) { Done done; DrvInfos drvs; getDerivation(state, v, "", drvs, done, ignoreAssertionFailures); - if (drvs.size() != 1) return {}; + if (drvs.size() != 1) + return {}; return std::move(drvs.front()); } - static std::string addToPath(const std::string & s1, const std::string & s2) { return s1.empty() ? s2 : s1 + "." + s2; } - static std::regex attrRegex("[A-Za-z_][A-Za-z0-9-_+]*"); - -static void getDerivations(EvalState & state, Value & vIn, - const std::string & pathPrefix, Bindings & autoArgs, - DrvInfos & drvs, Done & done, +static void getDerivations( + EvalState & state, + Value & vIn, + const std::string & pathPrefix, + Bindings & autoArgs, + DrvInfos & drvs, + Done & done, bool ignoreAssertionFailures) { Value v; state.autoCallFunction(autoArgs, vIn, v); /* Process the expression. */ - if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ; + if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) + ; else if (v.type() == nAttrs) { @@ -397,16 +409,20 @@ static void getDerivations(EvalState & state, Value & vIn, } } - else throw TypeError("expression does not evaluate to a derivation (or a set or list of those)"); + else + throw TypeError("expression does not evaluate to a derivation (or a set or list of those)"); } - -void getDerivations(EvalState & state, Value & v, const std::string & pathPrefix, - Bindings & autoArgs, DrvInfos & drvs, bool ignoreAssertionFailures) +void getDerivations( + EvalState & state, + Value & v, + const std::string & pathPrefix, + Bindings & autoArgs, + DrvInfos & drvs, + bool ignoreAssertionFailures) { Done done; getDerivations(state, v, pathPrefix, autoArgs, drvs, done, ignoreAssertionFailures); } - } diff --git a/src/libexpr/get-drvs.hh b/src/libexpr/get-drvs.hh index bbd2d3c477b2..35b17cd608b8 100644 --- a/src/libexpr/get-drvs.hh +++ b/src/libexpr/get-drvs.hh @@ -6,10 +6,8 @@ #include #include - namespace nix { - struct DrvInfo { public: @@ -27,7 +25,7 @@ private: bool failed = false; // set if we get an AssertionError - Bindings * attrs = nullptr, * meta = nullptr; + Bindings *attrs = nullptr, *meta = nullptr; Bindings * getMeta(); @@ -36,7 +34,8 @@ private: public: std::string attrPath; /* path towards the derivation */ - DrvInfo(EvalState & state) : state(&state) { }; + DrvInfo(EvalState & state) + : state(&state){}; DrvInfo(EvalState & state, std::string attrPath, Bindings * attrs); DrvInfo(EvalState & state, ref store, const std::string & drvPathWithOutputs); @@ -63,30 +62,45 @@ public: MetaValue queryMetaInfo(EvalState & state, const string & name) const; */ - void setName(const std::string & s) { name = s; } - void setDrvPath(StorePath path) { drvPath = {{std::move(path)}}; } - void setOutPath(StorePath path) { outPath = {{std::move(path)}}; } - - void setFailed() { failed = true; }; - bool hasFailed() { return failed; }; + void setName(const std::string & s) + { + name = s; + } + void setDrvPath(StorePath path) + { + drvPath = {{std::move(path)}}; + } + void setOutPath(StorePath path) + { + outPath = {{std::move(path)}}; + } + + void setFailed() + { + failed = true; + }; + bool hasFailed() + { + return failed; + }; }; - #if HAVE_BOEHMGC typedef std::list> DrvInfos; #else typedef std::list DrvInfos; #endif - /* If value `v' denotes a derivation, return a DrvInfo object describing it. Otherwise return nothing. */ -std::optional getDerivation(EvalState & state, - Value & v, bool ignoreAssertionFailures); - -void getDerivations(EvalState & state, Value & v, const std::string & pathPrefix, - Bindings & autoArgs, DrvInfos & drvs, +std::optional getDerivation(EvalState & state, Value & v, bool ignoreAssertionFailures); + +void getDerivations( + EvalState & state, + Value & v, + const std::string & pathPrefix, + Bindings & autoArgs, + DrvInfos & drvs, bool ignoreAssertionFailures); - } diff --git a/src/libexpr/json-to-value.cc b/src/libexpr/json-to-value.cc index 99a475ff9871..a8bad65ee908 100644 --- a/src/libexpr/json-to-value.cc +++ b/src/libexpr/json-to-value.cc @@ -9,8 +9,10 @@ namespace nix { // for more information, refer to // https://github.com/nlohmann/json/blob/master/include/nlohmann/detail/input/json_sax.hpp -class JSONSax : nlohmann::json_sax { - class JSONState { +class JSONSax : nlohmann::json_sax +{ + class JSONState + { protected: std::unique_ptr parent; RootValue v; @@ -19,8 +21,12 @@ class JSONSax : nlohmann::json_sax { { throw std::logic_error("tried to close toplevel json parser state"); } - explicit JSONState(std::unique_ptr && p) : parent(std::move(p)) {} - explicit JSONState(Value * v) : v(allocRootValue(v)) {} + explicit JSONState(std::unique_ptr && p) + : parent(std::move(p)) + {} + explicit JSONState(Value * v) + : v(allocRootValue(v)) + {} JSONState(JSONState & p) = delete; Value & value(EvalState & state) { @@ -32,7 +38,8 @@ class JSONSax : nlohmann::json_sax { virtual void add() {} }; - class JSONObjectState : public JSONState { + class JSONObjectState : public JSONState + { using JSONState::JSONState; ValueMap attrs; std::unique_ptr resolve(EvalState & state) override @@ -43,7 +50,10 @@ class JSONSax : nlohmann::json_sax { parent->value(state).mkAttrs(attrs2.alreadySorted()); return std::move(parent); } - void add() override { v = nullptr; } + void add() override + { + v = nullptr; + } public: void key(string_t & name, EvalState & state) { @@ -51,7 +61,8 @@ class JSONSax : nlohmann::json_sax { } }; - class JSONListState : public JSONState { + class JSONListState : public JSONState + { ValueVector values; std::unique_ptr resolve(EvalState & state) override { @@ -62,12 +73,14 @@ class JSONSax : nlohmann::json_sax { } return std::move(parent); } - void add() override { + void add() override + { values.push_back(*v); v = nullptr; } public: - JSONListState(std::unique_ptr && p, std::size_t reserve) : JSONState(std::move(p)) + JSONListState(std::unique_ptr && p, std::size_t reserve) + : JSONState(std::move(p)) { values.reserve(reserve); } @@ -77,7 +90,9 @@ class JSONSax : nlohmann::json_sax { std::unique_ptr rs; public: - JSONSax(EvalState & state, Value & v) : state(state), rs(new JSONState(&v)) {}; + JSONSax(EvalState & state, Value & v) + : state(state) + , rs(new JSONState(&v)){}; bool null() { @@ -122,7 +137,7 @@ class JSONSax : nlohmann::json_sax { } #if NLOHMANN_JSON_VERSION_MAJOR >= 3 && NLOHMANN_JSON_VERSION_MINOR >= 8 - bool binary(binary_t&) + bool binary(binary_t &) { // This function ought to be unreachable assert(false); @@ -138,27 +153,30 @@ class JSONSax : nlohmann::json_sax { bool key(string_t & name) { - dynamic_cast(rs.get())->key(name, state); + dynamic_cast(rs.get())->key(name, state); return true; } - bool end_object() { + bool end_object() + { rs = rs->resolve(state); rs->add(); return true; } - bool end_array() { + bool end_array() + { return end_object(); } - bool start_array(size_t len) { - rs = std::make_unique(std::move(rs), - len != std::numeric_limits::max() ? len : 128); + bool start_array(size_t len) + { + rs = std::make_unique(std::move(rs), len != std::numeric_limits::max() ? len : 128); return true; } - bool parse_error(std::size_t, const std::string&, const nlohmann::detail::exception& ex) { + bool parse_error(std::size_t, const std::string &, const nlohmann::detail::exception & ex) + { throw JSONParseError(ex.what()); } }; diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc index 7c623a07deb4..e58ee4ca282e 100644 --- a/src/libexpr/nixexpr.cc +++ b/src/libexpr/nixexpr.cc @@ -14,15 +14,20 @@ static void showString(std::ostream & str, std::string_view s) { str << '"'; for (auto c : s) - if (c == '"' || c == '\\' || c == '$') str << "\\" << c; - else if (c == '\n') str << "\\n"; - else if (c == '\r') str << "\\r"; - else if (c == '\t') str << "\\t"; - else str << c; + if (c == '"' || c == '\\' || c == '$') + str << "\\" << c; + else if (c == '\n') + str << "\\n"; + else if (c == '\r') + str << "\\r"; + else if (c == '\t') + str << "\\t"; + else + str << c; str << '"'; } -std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol) +std::ostream & operator<<(std::ostream & str, const SymbolStr & symbol) { std::string_view s = symbol; @@ -37,10 +42,8 @@ std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol) return str; } for (auto c : s) - if (!((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '_' || c == '\'' || c == '-')) { + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '\'' + || c == '-')) { showString(str, s); return str; } @@ -100,18 +103,21 @@ void ExprOpHasAttr::show(const SymbolTable & symbols, std::ostream & str) const void ExprAttrs::show(const SymbolTable & symbols, std::ostream & str) const { - if (recursive) str << "rec "; + if (recursive) + str << "rec "; str << "{ "; typedef const decltype(attrs)::value_type * Attr; std::vector sorted; - for (auto & i : attrs) sorted.push_back(&i); + for (auto & i : attrs) + sorted.push_back(&i); std::sort(sorted.begin(), sorted.end(), [&](Attr a, Attr b) { std::string_view sa = symbols[a->first], sb = symbols[b->first]; return sa < sb; }); for (auto & i : sorted) { if (i->second.inherited) - str << "inherit " << symbols[i->first] << " " << "; "; + str << "inherit " << symbols[i->first] << " " + << "; "; else { str << symbols[i->first] << " = "; i->second.e->show(symbols, str); @@ -146,7 +152,10 @@ void ExprLambda::show(const SymbolTable & symbols, std::ostream & str) const str << "{ "; bool first = true; for (auto & i : formals->formals) { - if (first) first = false; else str << ", "; + if (first) + first = false; + else + str << ", "; str << symbols[i.name]; if (i.def) { str << " ? "; @@ -154,13 +163,16 @@ void ExprLambda::show(const SymbolTable & symbols, std::ostream & str) const } } if (formals->ellipsis) { - if (!first) str << ", "; + if (!first) + str << ", "; str << "..."; } str << " }"; - if (arg) str << " @ "; + if (arg) + str << " @ "; } - if (arg) str << symbols[arg]; + if (arg) + str << symbols[arg]; str << ": "; body->show(symbols, str); str << ")"; @@ -171,7 +183,7 @@ void ExprCall::show(const SymbolTable & symbols, std::ostream & str) const str << '('; fun->show(symbols, str); for (auto e : args) { - str << ' '; + str << ' '; e->show(symbols, str); } str << ')'; @@ -183,8 +195,7 @@ void ExprLet::show(const SymbolTable & symbols, std::ostream & str) const for (auto & i : attrs->attrs) if (i.second.inherited) { str << "inherit " << symbols[i.first] << "; "; - } - else { + } else { str << symbols[i.first] << " = "; i.second.e->show(symbols, str); str << "; "; @@ -234,7 +245,10 @@ void ExprConcatStrings::show(const SymbolTable & symbols, std::ostream & str) co bool first = true; str << "("; for (auto & i : *es) { - if (first) first = false; else str << " + "; + if (first) + first = false; + else + str << " + "; i.second->show(symbols, str); } str << ")"; @@ -245,24 +259,22 @@ void ExprPos::show(const SymbolTable & symbols, std::ostream & str) const str << "__curPos"; } - -std::ostream & operator << (std::ostream & str, const Pos & pos) +std::ostream & operator<<(std::ostream & str, const Pos & pos) { if (!pos) str << "undefined position"; - else - { + else { auto f = format(ANSI_BOLD "%1%" ANSI_NORMAL ":%2%:%3%"); switch (pos.origin) { - case foFile: - f % (const std::string &) pos.file; - break; - case foStdin: - case foString: - f % "(string)"; - break; - default: - throw Error("unhandled Pos origin!"); + case foFile: + f % (const std::string &) pos.file; + break; + case foStdin: + case foString: + f % "(string)"; + break; + default: + throw Error("unhandled Pos origin!"); } str << (f % pos.line % pos.column).str(); } @@ -270,13 +282,15 @@ std::ostream & operator << (std::ostream & str, const Pos & pos) return str; } - std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath) { std::ostringstream out; bool first = true; for (auto & i : attrPath) { - if (!first) out << '.'; else first = false; + if (!first) + out << '.'; + else + first = false; if (i.symbol) out << symbols[i.symbol]; else { @@ -288,8 +302,6 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath) return out.str(); } - - /* Computing levels/displacements for variables. */ void Expr::bindVars(EvalState & es, const std::shared_ptr & env) @@ -333,7 +345,8 @@ void ExprVar::bindVars(EvalState & es, const std::shared_ptr & int withLevel = -1; for (curEnv = env.get(), level = 0; curEnv; curEnv = curEnv->up, level++) { if (curEnv->isWith) { - if (withLevel == -1) withLevel = level; + if (withLevel == -1) + withLevel = level; } else { auto i = curEnv->find(name); if (i != curEnv->vars.end()) { @@ -349,10 +362,8 @@ void ExprVar::bindVars(EvalState & es, const std::shared_ptr & enclosing `with'. If there is no `with', then we can issue an "undefined variable" error now. */ if (withLevel == -1) - throw UndefinedVarError({ - .msg = hintfmt("undefined variable '%1%'", es.symbols[name]), - .errPos = es.positions[pos] - }); + throw UndefinedVarError( + {.msg = hintfmt("undefined variable '%1%'", es.symbols[name]), .errPos = es.positions[pos]}); fromWith = true; this->level = withLevel; } @@ -363,7 +374,8 @@ void ExprSelect::bindVars(EvalState & es, const std::shared_ptr es.exprEnvs.insert(std::make_pair(this, env)); e->bindVars(es, env); - if (def) def->bindVars(es, env); + if (def) + def->bindVars(es, env); for (auto & i : attrPath) if (!i.symbol) i.expr->bindVars(es, env); @@ -401,8 +413,7 @@ void ExprAttrs::bindVars(EvalState & es, const std::shared_ptr i.nameExpr->bindVars(es, newEnv); i.valueExpr->bindVars(es, newEnv); } - } - else { + } else { for (auto & i : attrs) i.second.e->bindVars(es, env); @@ -427,14 +438,13 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr if (es.debugRepl) es.exprEnvs.insert(std::make_pair(this, env)); - auto newEnv = std::make_shared( - false, env.get(), - (hasFormals() ? formals->formals.size() : 0) + - (!arg ? 0 : 1)); + auto newEnv = + std::make_shared(false, env.get(), (hasFormals() ? formals->formals.size() : 0) + (!arg ? 0 : 1)); Displacement displ = 0; - if (arg) newEnv->vars.emplace_back(arg, displ++); + if (arg) + newEnv->vars.emplace_back(arg, displ++); if (hasFormals()) { for (auto & i : formals->formals) @@ -443,7 +453,8 @@ void ExprLambda::bindVars(EvalState & es, const std::shared_ptr newEnv->sort(); for (auto & i : formals->formals) - if (i.def) i.def->bindVars(es, newEnv); + if (i.def) + i.def->bindVars(es, newEnv); } body->bindVars(es, newEnv); @@ -545,13 +556,9 @@ void ExprPos::bindVars(EvalState & es, const std::shared_ptr & es.exprEnvs.insert(std::make_pair(this, env)); } - /* Storing function names. */ -void Expr::setName(Symbol name) -{ -} - +void Expr::setName(Symbol name) {} void ExprLambda::setName(Symbol name) { @@ -559,23 +566,18 @@ void ExprLambda::setName(Symbol name) body->setName(name); } - std::string ExprLambda::showNamePos(const EvalState & state) const { - std::string id(name - ? concatStrings("'", state.symbols[name], "'") - : "anonymous function"); + std::string id(name ? concatStrings("'", state.symbols[name], "'") : "anonymous function"); return fmt("%1% at %2%", id, state.positions[pos]); } - - /* Symbol table. */ size_t SymbolTable::totalSize() const { size_t n = 0; - dump([&] (const std::string & s) { n += s.size(); }); + dump([&](const std::string & s) { n += s.size(); }); return n; } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index 5eb0227707f3..8385f29cedfa 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -8,10 +8,8 @@ #include "error.hh" #include "chunked-vector.hh" - namespace nix { - MakeError(EvalError, Error); MakeError(ParseError, Error); MakeError(AssertionError, EvalError); @@ -31,29 +29,44 @@ struct Pos uint32_t line; uint32_t column; - explicit operator bool() const { return line > 0; } + explicit operator bool() const + { + return line > 0; + } }; -class PosIdx { +class PosIdx +{ friend class PosTable; private: uint32_t id; - explicit PosIdx(uint32_t id): id(id) {} + explicit PosIdx(uint32_t id) + : id(id) + {} public: - PosIdx() : id(0) {} + PosIdx() + : id(0) + {} - explicit operator bool() const { return id > 0; } + explicit operator bool() const + { + return id > 0; + } - bool operator<(const PosIdx other) const { return id < other.id; } + bool operator<(const PosIdx other) const + { + return id < other.id; + } }; class PosTable { public: - class Origin { + class Origin + { friend PosTable; private: // must always be invalid by default, add() replaces this with the actual value. @@ -61,16 +74,24 @@ public: // current origins.back() can be reused or not. mutable uint32_t idx = std::numeric_limits::max(); - explicit Origin(uint32_t idx): idx(idx), file{}, origin{} {} + explicit Origin(uint32_t idx) + : idx(idx) + , file{} + , origin{} + {} public: const std::string file; const FileOrigin origin; - Origin(std::string file, FileOrigin origin): file(std::move(file)), origin(origin) {} + Origin(std::string file, FileOrigin origin) + : file(std::move(file)) + , origin(origin) + {} }; - struct Offset { + struct Offset + { uint32_t line, column; }; @@ -79,7 +100,8 @@ private: ChunkedVector offsets; public: - PosTable(): offsets(1024) + PosTable() + : offsets(1024) { origins.reserve(1024); } @@ -103,8 +125,7 @@ public: this is guaranteed to never rewind origin.begin because the first key is always 0. */ const auto pastOrigin = std::upper_bound( - origins.begin(), origins.end(), Origin(idx), - [] (const auto & a, const auto & b) { return a.idx < b.idx; }); + origins.begin(), origins.end(), Origin(idx), [](const auto & a, const auto & b) { return a.idx < b.idx; }); const auto origin = *std::prev(pastOrigin); const auto offset = offsets[idx]; return {origin.file, origin.origin, offset.line, offset.column}; @@ -113,40 +134,42 @@ public: inline PosIdx noPos = {}; -std::ostream & operator << (std::ostream & str, const Pos & pos); - +std::ostream & operator<<(std::ostream & str, const Pos & pos); struct Env; struct Value; class EvalState; struct StaticEnv; - /* An attribute path is a sequence of attribute names. */ struct AttrName { Symbol symbol; Expr * expr; - AttrName(Symbol s) : symbol(s) {}; - AttrName(Expr * e) : expr(e) {}; + AttrName(Symbol s) + : symbol(s){}; + AttrName(Expr * e) + : expr(e){}; }; typedef std::vector AttrPath; std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath); - /* Abstract syntax of Nix expressions. */ struct Expr { - virtual ~Expr() { }; + virtual ~Expr(){}; virtual void show(const SymbolTable & symbols, std::ostream & str) const; virtual void bindVars(EvalState & es, const std::shared_ptr & env); virtual void eval(EvalState & state, Env & env, Value & v); virtual Value * maybeThunk(EvalState & state, Env & env); virtual void setName(Symbol name); - virtual PosIdx getPos() const { return noPos; } + virtual PosIdx getPos() const + { + return noPos; + } }; #define COMMON_METHODS \ @@ -158,7 +181,11 @@ struct ExprInt : Expr { NixInt n; Value v; - ExprInt(NixInt n) : n(n) { v.mkInt(n); }; + ExprInt(NixInt n) + : n(n) + { + v.mkInt(n); + }; Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -167,7 +194,11 @@ struct ExprFloat : Expr { NixFloat nf; Value v; - ExprFloat(NixFloat nf) : nf(nf) { v.mkFloat(nf); }; + ExprFloat(NixFloat nf) + : nf(nf) + { + v.mkFloat(nf); + }; Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -176,7 +207,11 @@ struct ExprString : Expr { std::string s; Value v; - ExprString(std::string s) : s(std::move(s)) { v.mkString(this->s.data()); }; + ExprString(std::string s) + : s(std::move(s)) + { + v.mkString(this->s.data()); + }; Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -185,7 +220,11 @@ struct ExprPath : Expr { std::string s; Value v; - ExprPath(std::string s) : s(std::move(s)) { v.mkPath(this->s.c_str()); }; + ExprPath(std::string s) + : s(std::move(s)) + { + v.mkPath(this->s.c_str()); + }; Value * maybeThunk(EvalState & state, Env & env) override; COMMON_METHODS }; @@ -211,21 +250,40 @@ struct ExprVar : Expr Level level; Displacement displ; - ExprVar(Symbol name) : name(name) { }; - ExprVar(const PosIdx & pos, Symbol name) : pos(pos), name(name) { }; + ExprVar(Symbol name) + : name(name){}; + ExprVar(const PosIdx & pos, Symbol name) + : pos(pos) + , name(name){}; Value * maybeThunk(EvalState & state, Env & env) override; - PosIdx getPos() const override { return pos; } + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; struct ExprSelect : Expr { PosIdx pos; - Expr * e, * def; + Expr *e, *def; AttrPath attrPath; - ExprSelect(const PosIdx & pos, Expr * e, const AttrPath & attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(attrPath) { }; - ExprSelect(const PosIdx & pos, Expr * e, Symbol name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); }; - PosIdx getPos() const override { return pos; } + ExprSelect(const PosIdx & pos, Expr * e, const AttrPath & attrPath, Expr * def) + : pos(pos) + , e(e) + , def(def) + , attrPath(attrPath){}; + ExprSelect(const PosIdx & pos, Expr * e, Symbol name) + : pos(pos) + , e(e) + , def(0) + { + attrPath.push_back(AttrName(name)); + }; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; @@ -233,8 +291,13 @@ struct ExprOpHasAttr : Expr { Expr * e; AttrPath attrPath; - ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) { }; - PosIdx getPos() const override { return e->getPos(); } + ExprOpHasAttr(Expr * e, const AttrPath & attrPath) + : e(e) + , attrPath(attrPath){}; + PosIdx getPos() const override + { + return e->getPos(); + } COMMON_METHODS }; @@ -242,35 +305,47 @@ struct ExprAttrs : Expr { bool recursive; PosIdx pos; - struct AttrDef { + struct AttrDef + { bool inherited; Expr * e; PosIdx pos; Displacement displ; // displacement - AttrDef(Expr * e, const PosIdx & pos, bool inherited=false) - : inherited(inherited), e(e), pos(pos) { }; - AttrDef() { }; + AttrDef(Expr * e, const PosIdx & pos, bool inherited = false) + : inherited(inherited) + , e(e) + , pos(pos){}; + AttrDef(){}; }; typedef std::map AttrDefs; AttrDefs attrs; - struct DynamicAttrDef { - Expr * nameExpr, * valueExpr; + struct DynamicAttrDef + { + Expr *nameExpr, *valueExpr; PosIdx pos; DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const PosIdx & pos) - : nameExpr(nameExpr), valueExpr(valueExpr), pos(pos) { }; + : nameExpr(nameExpr) + , valueExpr(valueExpr) + , pos(pos){}; }; typedef std::vector DynamicAttrDefs; DynamicAttrDefs dynamicAttrs; - ExprAttrs(const PosIdx &pos) : recursive(false), pos(pos) { }; - ExprAttrs() : recursive(false) { }; - PosIdx getPos() const override { return pos; } + ExprAttrs(const PosIdx & pos) + : recursive(false) + , pos(pos){}; + ExprAttrs() + : recursive(false){}; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; struct ExprList : Expr { std::vector elems; - ExprList() { }; + ExprList(){}; COMMON_METHODS PosIdx getPos() const override @@ -294,19 +369,18 @@ struct Formals bool has(Symbol arg) const { - auto it = std::lower_bound(formals.begin(), formals.end(), arg, - [] (const Formal & f, const Symbol & sym) { return f.name < sym; }); + auto it = std::lower_bound( + formals.begin(), formals.end(), arg, [](const Formal & f, const Symbol & sym) { return f.name < sym; }); return it != formals.end() && it->name == arg; } std::vector lexicographicOrder(const SymbolTable & symbols) const { std::vector result(formals.begin(), formals.end()); - std::sort(result.begin(), result.end(), - [&] (const Formal & a, const Formal & b) { - std::string_view sa = symbols[a.name], sb = symbols[b.name]; - return sa < sb; - }); + std::sort(result.begin(), result.end(), [&](const Formal & a, const Formal & b) { + std::string_view sa = symbols[a.name], sb = symbols[b.name]; + return sa < sb; + }); return result; } }; @@ -319,17 +393,25 @@ struct ExprLambda : Expr Formals * formals; Expr * body; ExprLambda(PosIdx pos, Symbol arg, Formals * formals, Expr * body) - : pos(pos), arg(arg), formals(formals), body(body) - { - }; + : pos(pos) + , arg(arg) + , formals(formals) + , body(body){}; ExprLambda(PosIdx pos, Formals * formals, Expr * body) - : pos(pos), formals(formals), body(body) - { - } + : pos(pos) + , formals(formals) + , body(body) + {} void setName(Symbol name) override; std::string showNamePos(const EvalState & state) const; - inline bool hasFormals() const { return formals != nullptr; } - PosIdx getPos() const override { return pos; } + inline bool hasFormals() const + { + return formals != nullptr; + } + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; @@ -339,9 +421,14 @@ struct ExprCall : Expr std::vector args; PosIdx pos; ExprCall(const PosIdx & pos, Expr * fun, std::vector && args) - : fun(fun), args(args), pos(pos) - { } - PosIdx getPos() const override { return pos; } + : fun(fun) + , args(args) + , pos(pos) + {} + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; @@ -349,42 +436,64 @@ struct ExprLet : Expr { ExprAttrs * attrs; Expr * body; - ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { }; + ExprLet(ExprAttrs * attrs, Expr * body) + : attrs(attrs) + , body(body){}; COMMON_METHODS }; struct ExprWith : Expr { PosIdx pos; - Expr * attrs, * body; + Expr *attrs, *body; size_t prevWith; - ExprWith(const PosIdx & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { }; - PosIdx getPos() const override { return pos; } + ExprWith(const PosIdx & pos, Expr * attrs, Expr * body) + : pos(pos) + , attrs(attrs) + , body(body){}; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; struct ExprIf : Expr { PosIdx pos; - Expr * cond, * then, * else_; - ExprIf(const PosIdx & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { }; - PosIdx getPos() const override { return pos; } + Expr *cond, *then, *else_; + ExprIf(const PosIdx & pos, Expr * cond, Expr * then, Expr * else_) + : pos(pos) + , cond(cond) + , then(then) + , else_(else_){}; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; struct ExprAssert : Expr { PosIdx pos; - Expr * cond, * body; - ExprAssert(const PosIdx & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { }; - PosIdx getPos() const override { return pos; } + Expr *cond, *body; + ExprAssert(const PosIdx & pos, Expr * cond, Expr * body) + : pos(pos) + , cond(cond) + , body(body){}; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; struct ExprOpNot : Expr { Expr * e; - ExprOpNot(Expr * e) : e(e) { }; + ExprOpNot(Expr * e) + : e(e){}; COMMON_METHODS }; @@ -392,49 +501,65 @@ struct ExprOpNot : Expr struct name : Expr \ { \ PosIdx pos; \ - Expr * e1, * e2; \ - name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \ - name(const PosIdx & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \ + Expr *e1, *e2; \ + name(Expr * e1, Expr * e2) \ + : e1(e1) \ + , e2(e2){}; \ + name(const PosIdx & pos, Expr * e1, Expr * e2) \ + : pos(pos) \ + , e1(e1) \ + , e2(e2){}; \ void show(const SymbolTable & symbols, std::ostream & str) const override \ { \ - str << "("; e1->show(symbols, str); str << " " s " "; e2->show(symbols, str); str << ")"; \ + str << "("; \ + e1->show(symbols, str); \ + str << " " s " "; \ + e2->show(symbols, str); \ + str << ")"; \ } \ void bindVars(EvalState & es, const std::shared_ptr & env) override \ { \ - e1->bindVars(es, env); e2->bindVars(es, env); \ + e1->bindVars(es, env); \ + e2->bindVars(es, env); \ } \ void eval(EvalState & state, Env & env, Value & v) override; \ - PosIdx getPos() const override { return pos; } \ + PosIdx getPos() const override \ + { \ + return pos; \ + } \ }; -MakeBinOp(ExprOpEq, "==") -MakeBinOp(ExprOpNEq, "!=") -MakeBinOp(ExprOpAnd, "&&") -MakeBinOp(ExprOpOr, "||") -MakeBinOp(ExprOpImpl, "->") -MakeBinOp(ExprOpUpdate, "//") -MakeBinOp(ExprOpConcatLists, "++") +MakeBinOp(ExprOpEq, "==") MakeBinOp(ExprOpNEq, "!=") MakeBinOp(ExprOpAnd, "&&") MakeBinOp(ExprOpOr, "||") + MakeBinOp(ExprOpImpl, "->") MakeBinOp(ExprOpUpdate, "//") MakeBinOp(ExprOpConcatLists, "++") -struct ExprConcatStrings : Expr + struct ExprConcatStrings : Expr { PosIdx pos; bool forceString; std::vector> * es; ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector> * es) - : pos(pos), forceString(forceString), es(es) { }; - PosIdx getPos() const override { return pos; } + : pos(pos) + , forceString(forceString) + , es(es){}; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; struct ExprPos : Expr { PosIdx pos; - ExprPos(const PosIdx & pos) : pos(pos) { }; - PosIdx getPos() const override { return pos; } + ExprPos(const PosIdx & pos) + : pos(pos){}; + PosIdx getPos() const override + { + return pos; + } COMMON_METHODS }; - /* Static environments are used to map variable names onto (level, displacement) pairs used to obtain the value of the variable at runtime. */ @@ -447,14 +572,18 @@ struct StaticEnv typedef std::vector> Vars; Vars vars; - StaticEnv(bool isWith, const StaticEnv * up, size_t expectedSize = 0) : isWith(isWith), up(up) { + StaticEnv(bool isWith, const StaticEnv * up, size_t expectedSize = 0) + : isWith(isWith) + , up(up) + { vars.reserve(expectedSize); }; void sort() { - std::stable_sort(vars.begin(), vars.end(), - [](const Vars::value_type & a, const Vars::value_type & b) { return a.first < b.first; }); + std::stable_sort(vars.begin(), vars.end(), [](const Vars::value_type & a, const Vars::value_type & b) { + return a.first < b.first; + }); } void deduplicate() @@ -462,7 +591,8 @@ struct StaticEnv auto it = vars.begin(), jt = it, end = vars.end(); while (jt != end) { *it = *jt++; - while (jt != end && it->first == jt->first) *it = *jt++; + while (jt != end && it->first == jt->first) + *it = *jt++; it++; } vars.erase(it, end); @@ -472,10 +602,10 @@ struct StaticEnv { Vars::value_type key(name, 0); auto i = std::lower_bound(vars.begin(), vars.end(), key); - if (i != vars.end() && i->first == name) return i; + if (i != vars.end() && i->first == name) + return i; return vars.end(); } }; - } diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index eea2743010eb..16bd3909a284 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -25,17 +25,16 @@ #include - namespace nix { - /************************************************************* * Miscellaneous *************************************************************/ - -InvalidPathError::InvalidPathError(const Path & path) : - EvalError("path '%s' is not valid", path), path(path) {} +InvalidPathError::InvalidPathError(const Path & path) + : EvalError("path '%s' is not valid", path) + , path(path) +{} StringMap EvalState::realiseContext(const PathSet & context) { @@ -54,7 +53,8 @@ StringMap EvalState::realiseContext(const PathSet & context) } } - if (drvs.empty()) return {}; + if (drvs.empty()) + return {}; if (!evalSettings.enableImportFromDerivation) debugThrowLastTrace(Error( @@ -63,7 +63,8 @@ StringMap EvalState::realiseContext(const PathSet & context) /* Build/substitute the context. */ std::vector buildReqs; - for (auto & d : drvs) buildReqs.emplace_back(DerivedPath { d }); + for (auto & d : drvs) + buildReqs.emplace_back(DerivedPath{d}); store->buildPaths(buildReqs); /* Get all the output paths corresponding to the placeholders we had */ @@ -72,12 +73,10 @@ StringMap EvalState::realiseContext(const PathSet & context) for (auto & outputName : outputs) { auto outputPath = get(outputPaths, outputName); if (!outputPath) - debugThrowLastTrace(Error("derivation '%s' does not have an output named '%s'", - store->printStorePath(drvPath), outputName)); + debugThrowLastTrace(Error( + "derivation '%s' does not have an output named '%s'", store->printStorePath(drvPath), outputName)); res.insert_or_assign( - downstreamPlaceholder(*store, drvPath, outputName), - store->printStorePath(*outputPath) - ); + downstreamPlaceholder(*store, drvPath, outputName), store->printStorePath(*outputPath)); } } @@ -92,7 +91,8 @@ StringMap EvalState::realiseContext(const PathSet & context) return res; } -struct RealisePathFlags { +struct RealisePathFlags +{ // Whether to check that the path is allowed in pure eval mode bool checkForPureEval = true; }; @@ -101,8 +101,7 @@ static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const Re { PathSet context; - auto path = [&]() - { + auto path = [&]() { try { return state.coerceToPath(pos, v, context); } catch (Error & e) { @@ -116,9 +115,7 @@ static Path realisePath(EvalState & state, const PosIdx pos, Value & v, const Re auto realPath = state.toRealPath(rewriteStrings(path, rewrites), context); - return flags.checkForPureEval - ? state.checkSourcePath(realPath) - : realPath; + return flags.checkForPureEval ? state.checkSourcePath(realPath) : realPath; } catch (Error & e) { e.addTrace(state.positions[pos], "while realising the context of path '%s'", path); throw; @@ -146,13 +143,12 @@ static void mkOutputString( { auto optOutputPath = o.second.path(*state.store, drv.name, o.first); attrs.alloc(o.first).mkString( - optOutputPath - ? state.store->printStorePath(*optOutputPath) - /* Downstream we would substitute this for an actual path once - we build the floating CA derivation */ - /* FIXME: we need to depend on the basic derivation, not - derivation */ - : downstreamPlaceholder(*state.store, drvPath, o.first), + optOutputPath ? state.store->printStorePath(*optOutputPath) + /* Downstream we would substitute this for an actual path once + we build the floating CA derivation */ + /* FIXME: we need to depend on the basic derivation, not + derivation */ + : downstreamPlaceholder(*state.store, drvPath, o.first), {"!" + o.first + "!" + state.store->printStorePath(drvPath)}); } @@ -191,9 +187,11 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v if (!state.vImportedDrvToDerivation) { state.vImportedDrvToDerivation = allocRootValue(state.allocValue()); - state.eval(state.parseExprFromString( - #include "imported-drv-to-derivation.nix.gen.hh" - , "/"), **state.vImportedDrvToDerivation); + state.eval( + state.parseExprFromString( +#include "imported-drv-to-derivation.nix.gen.hh" + , "/"), + **state.vImportedDrvToDerivation); } state.forceFunction(**state.vImportedDrvToDerivation, pos); @@ -202,9 +200,11 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v } else if (path == corepkgsPrefix + "fetchurl.nix") { - state.eval(state.parseExprFromString( - #include "fetchurl.nix.gen.hh" - , "/"), v); + state.eval( + state.parseExprFromString( +#include "fetchurl.nix.gen.hh" + , "/"), + v); } else { @@ -235,19 +235,15 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v } } -static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info { - .name = "scopedImport", - .arity = 2, - .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) - { +static RegisterPrimOp primop_scopedImport(RegisterPrimOp::Info{ + .name = "scopedImport", .arity = 2, .fun = [](EvalState & state, const PosIdx pos, Value ** args, Value & v) { import(state, pos, *args[1], args[0], v); - } -}); + }}); -static RegisterPrimOp primop_import({ - .name = "import", - .args = {"path"}, - .doc = R"( +static RegisterPrimOp primop_import( + {.name = "import", + .args = {"path"}, + .doc = R"( Load, parse and return the Nix expression in the file *path*. If *path* is a directory, the file ` default.nix ` in that directory is loaded. Evaluation aborts if the file doesn’t exist or contains @@ -300,35 +296,34 @@ static RegisterPrimOp primop_import({ (The function argument doesn’t have to be called `x` in `foo.nix`; any name would work.) )", - .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) - { - import(state, pos, *args[0], nullptr, v); - } -}); + .fun = [](EvalState & state, const PosIdx pos, Value ** args, Value & v) { + import(state, pos, *args[0], nullptr, v); + }}); /* Want reasonable symbol names, so extern C */ /* !!! Should we pass the Pos or the file name too? */ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v); /* Load a ValueInitializer from a DSO and return whatever it initializes */ -void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_importNative(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto path = realisePath(state, pos, *args[0]); std::string sym(state.forceStringNoCtx(*args[1], pos)); - void *handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); + void * handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_LOCAL); if (!handle) state.debugThrowLastTrace(EvalError("could not open '%1%': %2%", path, dlerror())); dlerror(); ValueInitializer func = (ValueInitializer) dlsym(handle, sym.c_str()); - if(!func) { - char *message = dlerror(); + if (!func) { + char * message = dlerror(); if (message) state.debugThrowLastTrace(EvalError("could not load symbol '%1%' from '%2%': %3%", sym, path, message)); else - state.debugThrowLastTrace(EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path)); + state.debugThrowLastTrace( + EvalError("symbol '%1%' from '%2%' resolved to NULL when a function pointer was expected", sym, path)); } (func)(state, v); @@ -336,18 +331,15 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu /* We don't dlclose because v may be a primop referencing a function in the shared object file */ } - /* Execute a program and parse its output */ -void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_exec(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); auto elems = args[0]->listElems(); auto count = args[0]->listSize(); if (count == 0) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("at least one argument to 'exec' required"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("at least one argument to 'exec' required"), .errPos = state.positions[pos]})); PathSet context; auto program = state.coerceToString(pos, *elems[0], context, false, false).toOwned(); Strings commandArgs; @@ -357,11 +349,9 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) try { auto _ = state.realiseContext(context); // FIXME: Handle CA derivations } catch (InvalidPathError & e) { - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid", - program, e.path), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("cannot execute '%1%', since path '%2%' is not valid", program, e.path), + .errPos = state.positions[pos]})); } auto output = runProgram(program, true, commandArgs); @@ -381,26 +371,44 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v) } } - /* Return a string representing the type of the expression. */ -static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_typeOf(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); std::string t; switch (args[0]->type()) { - case nInt: t = "int"; break; - case nBool: t = "bool"; break; - case nString: t = "string"; break; - case nPath: t = "path"; break; - case nNull: t = "null"; break; - case nAttrs: t = "set"; break; - case nList: t = "list"; break; - case nFunction: t = "lambda"; break; - case nExternal: - t = args[0]->external->typeOf(); - break; - case nFloat: t = "float"; break; - case nThunk: abort(); + case nInt: + t = "int"; + break; + case nBool: + t = "bool"; + break; + case nString: + t = "string"; + break; + case nPath: + t = "path"; + break; + case nNull: + t = "null"; + break; + case nAttrs: + t = "set"; + break; + case nList: + t = "list"; + break; + case nFunction: + t = "lambda"; + break; + case nExternal: + t = args[0]->external->typeOf(); + break; + case nFloat: + t = "float"; + break; + case nThunk: + abort(); } v.mkString(t); } @@ -417,7 +425,7 @@ static RegisterPrimOp primop_typeOf({ }); /* Determine whether the argument is the null value. */ -static void prim_isNull(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isNull(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nNull); @@ -437,7 +445,7 @@ static RegisterPrimOp primop_isNull({ }); /* Determine whether the argument is a function. */ -static void prim_isFunction(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isFunction(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nFunction); @@ -453,7 +461,7 @@ static RegisterPrimOp primop_isFunction({ }); /* Determine whether the argument is an integer. */ -static void prim_isInt(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isInt(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nInt); @@ -469,7 +477,7 @@ static RegisterPrimOp primop_isInt({ }); /* Determine whether the argument is a float. */ -static void prim_isFloat(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isFloat(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nFloat); @@ -485,7 +493,7 @@ static RegisterPrimOp primop_isFloat({ }); /* Determine whether the argument is a string. */ -static void prim_isString(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isString(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nString); @@ -501,7 +509,7 @@ static RegisterPrimOp primop_isString({ }); /* Determine whether the argument is a Boolean. */ -static void prim_isBool(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isBool(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nBool); @@ -517,7 +525,7 @@ static RegisterPrimOp primop_isBool({ }); /* Determine whether the argument is a path. */ -static void prim_isPath(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isPath(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nPath); @@ -536,9 +544,10 @@ struct CompareValues { EvalState & state; - CompareValues(EvalState & state) : state(state) { }; + CompareValues(EvalState & state) + : state(state){}; - bool operator () (Value * v1, Value * v2) const + bool operator()(Value * v1, Value * v2) const { if (v1->type() == nFloat && v2->type() == nInt) return v1->fpoint < v2->integer; @@ -547,53 +556,43 @@ struct CompareValues if (v1->type() != v2->type()) state.debugThrowLastTrace(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); switch (v1->type()) { - case nInt: - return v1->integer < v2->integer; - case nFloat: - return v1->fpoint < v2->fpoint; - case nString: - return strcmp(v1->string.s, v2->string.s) < 0; - case nPath: - return strcmp(v1->path, v2->path) < 0; - case nList: - // Lexicographic comparison - for (size_t i = 0;; i++) { - if (i == v2->listSize()) { - return false; - } else if (i == v1->listSize()) { - return true; - } else if (!state.eqValues(*v1->listElems()[i], *v2->listElems()[i])) { - return (*this)(v1->listElems()[i], v2->listElems()[i]); - } + case nInt: + return v1->integer < v2->integer; + case nFloat: + return v1->fpoint < v2->fpoint; + case nString: + return strcmp(v1->string.s, v2->string.s) < 0; + case nPath: + return strcmp(v1->path, v2->path) < 0; + case nList: + // Lexicographic comparison + for (size_t i = 0;; i++) { + if (i == v2->listSize()) { + return false; + } else if (i == v1->listSize()) { + return true; + } else if (!state.eqValues(*v1->listElems()[i], *v2->listElems()[i])) { + return (*this)(v1->listElems()[i], v2->listElems()[i]); } - default: - state.debugThrowLastTrace(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); + } + default: + state.debugThrowLastTrace(EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2))); } } }; - #if HAVE_BOEHMGC typedef std::list> ValueList; #else typedef std::list ValueList; #endif - -static Bindings::iterator getAttr( - EvalState & state, - std::string_view funcName, - Symbol attrSym, - Bindings * attrSet, - const PosIdx pos) +static Bindings::iterator +getAttr(EvalState & state, std::string_view funcName, Symbol attrSym, Bindings * attrSet, const PosIdx pos) { Bindings::iterator value = attrSet->find(attrSym); if (value == attrSet->end()) { - hintformat errorMsg = hintfmt( - "attribute '%s' missing for call to '%s'", - state.symbols[attrSym], - funcName - ); + hintformat errorMsg = hintfmt("attribute '%s' missing for call to '%s'", state.symbols[attrSym], funcName); auto aPos = attrSet->pos; if (!aPos) { @@ -617,18 +616,12 @@ static Bindings::iterator getAttr( return value; } -static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_genericClosure(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); /* Get the start set. */ - Bindings::iterator startSet = getAttr( - state, - "genericClosure", - state.sStartSet, - args[0]->attrs, - pos - ); + Bindings::iterator startSet = getAttr(state, "genericClosure", state.sStartSet, args[0]->attrs, pos); state.forceList(*startSet->value, pos); @@ -637,13 +630,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a workSet.push_back(elem); /* Get the operator. */ - Bindings::iterator op = getAttr( - state, - "genericClosure", - state.sOperator, - args[0]->attrs, - pos - ); + Bindings::iterator op = getAttr(state, "genericClosure", state.sOperator, args[0]->attrs, pos); state.forceValue(*op->value, pos); @@ -661,16 +648,14 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a state.forceAttrs(*e, pos); - Bindings::iterator key = - e->attrs->find(state.sKey); + Bindings::iterator key = e->attrs->find(state.sKey); if (key == e->attrs->end()) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("attribute 'key' required"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("attribute 'key' required"), .errPos = state.positions[pos]})); state.forceValue(*key->value, pos); - if (!doneKeys.insert(key->value).second) continue; + if (!doneKeys.insert(key->value).second) + continue; res.push_back(e); /* Call the `operator' function with `e' as argument. */ @@ -692,7 +677,7 @@ static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * a v.listElems()[n++] = i; } -static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info { +static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info{ .name = "__genericClosure", .args = {"attrset"}, .arity = 1, @@ -723,74 +708,67 @@ static RegisterPrimOp primop_genericClosure(RegisterPrimOp::Info { .fun = prim_genericClosure, }); - -static RegisterPrimOp primop_break({ - .name = "break", - .args = {"v"}, - .doc = R"( +static RegisterPrimOp primop_break( + {.name = "break", + .args = {"v"}, + .doc = R"( In debug mode (enabled using `--debugger`), pause Nix expression evaluation and enter the REPL. Otherwise, return the argument `v`. )", - .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) - { - if (state.debugRepl && !state.debugTraces.empty()) { - auto error = Error(ErrorInfo { - .level = lvlInfo, - .msg = hintfmt("breakpoint reached"), - .errPos = state.positions[pos], - }); - - auto & dt = state.debugTraces.front(); - state.runDebugRepl(&error, dt.env, dt.expr); - - if (state.debugQuit) { - // If the user elects to quit the repl, throw an exception. - throw Error(ErrorInfo{ - .level = lvlInfo, - .msg = hintfmt("quit the debugger"), - .errPos = state.positions[noPos], - }); - } - } - - // Return the value we were passed. - v = *args[0]; - } -}); - -static RegisterPrimOp primop_abort({ - .name = "abort", - .args = {"s"}, - .doc = R"( + .fun = [](EvalState & state, const PosIdx pos, Value ** args, Value & v) { + if (state.debugRepl && !state.debugTraces.empty()) { + auto error = Error(ErrorInfo{ + .level = lvlInfo, + .msg = hintfmt("breakpoint reached"), + .errPos = state.positions[pos], + }); + + auto & dt = state.debugTraces.front(); + state.runDebugRepl(&error, dt.env, dt.expr); + + if (state.debugQuit) { + // If the user elects to quit the repl, throw an exception. + throw Error(ErrorInfo{ + .level = lvlInfo, + .msg = hintfmt("quit the debugger"), + .errPos = state.positions[noPos], + }); + } + } + + // Return the value we were passed. + v = *args[0]; + }}); + +static RegisterPrimOp primop_abort( + {.name = "abort", + .args = {"s"}, + .doc = R"( Abort Nix expression evaluation and print the error message *s*. )", - .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) - { - PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); - state.debugThrowLastTrace(Abort("evaluation aborted with the following error message: '%1%'", s)); - } -}); + .fun = [](EvalState & state, const PosIdx pos, Value ** args, Value & v) { + PathSet context; + auto s = state.coerceToString(pos, *args[0], context).toOwned(); + state.debugThrowLastTrace(Abort("evaluation aborted with the following error message: '%1%'", s)); + }}); -static RegisterPrimOp primop_throw({ - .name = "throw", - .args = {"s"}, - .doc = R"( +static RegisterPrimOp primop_throw( + {.name = "throw", + .args = {"s"}, + .doc = R"( Throw an error message *s*. This usually aborts Nix expression evaluation, but in `nix-env -qa` and other commands that try to evaluate a set of derivations to get information about those derivations, a derivation that throws an error is silently skipped (which is not the case for `abort`). )", - .fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v) - { - PathSet context; - auto s = state.coerceToString(pos, *args[0], context).toOwned(); - state.debugThrowLastTrace(ThrownError(s)); - } -}); + .fun = [](EvalState & state, const PosIdx pos, Value ** args, Value & v) { + PathSet context; + auto s = state.coerceToString(pos, *args[0], context).toOwned(); + state.debugThrowLastTrace(ThrownError(s)); + }}); -static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value ** args, Value & v) { try { state.forceValue(*args[1], pos); @@ -802,13 +780,13 @@ static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * } } -static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info { +static RegisterPrimOp primop_addErrorContext(RegisterPrimOp::Info{ .name = "__addErrorContext", .arity = 2, .fun = prim_addErrorContext, }); -static void prim_ceil(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_ceil(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto value = state.forceFloat(*args[0], args[0]->determinePos(pos)); v.mkInt(ceil(value)); @@ -827,7 +805,7 @@ static RegisterPrimOp primop_ceil({ .fun = prim_ceil, }); -static void prim_floor(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_floor(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto value = state.forceFloat(*args[0], args[0]->determinePos(pos)); v.mkInt(floor(value)); @@ -848,7 +826,7 @@ static RegisterPrimOp primop_floor({ /* Try evaluating the argument. Success => {success=true; value=something;}, * else => {success=false; value=false;} */ -static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_tryEval(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto attrs = state.buildBindings(2); try { @@ -884,7 +862,7 @@ static RegisterPrimOp primop_tryEval({ }); /* Return an environment variable. Use with care. */ -static void prim_getEnv(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_getEnv(EvalState & state, const PosIdx pos, Value ** args, Value & v) { std::string name(state.forceStringNoCtx(*args[0], pos)); v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or("")); @@ -908,7 +886,7 @@ static RegisterPrimOp primop_getEnv({ }); /* Evaluate the first argument, then return the second argument. */ -static void prim_seq(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_seq(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); @@ -927,7 +905,7 @@ static RegisterPrimOp primop_seq({ /* Evaluate the first argument deeply (i.e. recursing into lists and attrsets), then return the second argument. */ -static void prim_deepSeq(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_deepSeq(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValueDeep(*args[0]); state.forceValue(*args[1], pos); @@ -947,7 +925,7 @@ static RegisterPrimOp primop_deepSeq({ /* Evaluate the first expression and print it on standard error. Then return the second expression. Useful for debugging. */ -static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_trace(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); if (args[0]->type() == nString) @@ -969,12 +947,10 @@ static RegisterPrimOp primop_trace({ .fun = prim_trace, }); - /************************************************************* * Derivations *************************************************************/ - /* Construct (as a unobservable side effect) a Nix derivation expression that performs the derivation described by the argument set. Returns the original set extended with the following @@ -982,18 +958,12 @@ static RegisterPrimOp primop_trace({ derivation; `drvPath' containing the path of the Nix expression; and `type' set to `derivation' to indicate that this is a derivation. */ -static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); /* Figure out the name first (for stack backtraces). */ - Bindings::iterator attr = getAttr( - state, - "derivationStrict", - state.sName, - args[0]->attrs, - pos - ); + Bindings::iterator attr = getAttr(state, "derivationStrict", state.sName, args[0]->attrs, pos); std::string drvName; const auto posDrvName = attr->pos; @@ -1033,52 +1003,52 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * outputs.insert("out"); for (auto & i : args[0]->attrs->lexicographicOrder(state.symbols)) { - if (i->name == state.sIgnoreNulls) continue; + if (i->name == state.sIgnoreNulls) + continue; const std::string & key = state.symbols[i->name]; vomit("processing attribute '%1%'", key); auto handleHashMode = [&](const std::string_view s) { - if (s == "recursive") ingestionMethod = FileIngestionMethod::Recursive; - else if (s == "flat") ingestionMethod = FileIngestionMethod::Flat; + if (s == "recursive") + ingestionMethod = FileIngestionMethod::Recursive; + else if (s == "flat") + ingestionMethod = FileIngestionMethod::Flat; else - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("invalid value '%s' for 'outputHashMode' attribute", s), + .errPos = state.positions[posDrvName]})); }; auto handleOutputs = [&](const Strings & ss) { outputs.clear(); for (auto & j : ss) { if (outputs.find(j) != outputs.end()) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("duplicate derivation output '%1%'", j), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("duplicate derivation output '%1%'", j), + .errPos = state.positions[posDrvName]})); /* !!! Check whether j is a valid attribute name. */ /* Derivations cannot be named ‘drv’, because then we'd have an attribute ‘drvPath’ in the resulting set. */ if (j == "drv") - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("invalid derivation output name 'drv'" ), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("invalid derivation output name 'drv'"), + .errPos = state.positions[posDrvName]})); outputs.insert(j); } if (outputs.empty()) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("derivation cannot have an empty set of outputs"), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("derivation cannot have an empty set of outputs"), + .errPos = state.positions[posDrvName]})); }; try { if (ignoreNulls) { state.forceValue(*i->value, pos); - if (i->value->type() == nNull) continue; + if (i->value->type() == nNull) + continue; } if (i->name == state.sContentAddressed) { @@ -1109,7 +1079,8 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * if (jsonObject) { - if (i->name == state.sStructuredAttrs) continue; + if (i->name == state.sStructuredAttrs) + continue; auto placeholder(jsonObject->placeholder(key)); printValueAsJSON(state, true, *i->value, pos, placeholder, context); @@ -1136,21 +1107,25 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * } else { auto s = state.coerceToString(i->pos, *i->value, context, true).toOwned(); drv.env.emplace(key, s); - if (i->name == state.sBuilder) drv.builder = std::move(s); - else if (i->name == state.sSystem) drv.platform = std::move(s); - else if (i->name == state.sOutputHash) outputHash = std::move(s); - else if (i->name == state.sOutputHashAlgo) outputHashAlgo = std::move(s); - else if (i->name == state.sOutputHashMode) handleHashMode(s); + if (i->name == state.sBuilder) + drv.builder = std::move(s); + else if (i->name == state.sSystem) + drv.platform = std::move(s); + else if (i->name == state.sOutputHash) + outputHash = std::move(s); + else if (i->name == state.sOutputHashAlgo) + outputHashAlgo = std::move(s); + else if (i->name == state.sOutputHashMode) + handleHashMode(s); else if (i->name == state.sOutputs) handleOutputs(tokenizeString(s)); } - } } catch (Error & e) { - e.addTrace(state.positions[posDrvName], - "while evaluating the attribute '%1%' of the derivation '%2%'", - key, drvName); + e.addTrace( + state.positions[posDrvName], "while evaluating the attribute '%1%' of the derivation '%2%'", key, + drvName); throw; } } @@ -1196,23 +1171,18 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * /* Do we have all required attributes? */ if (drv.builder == "") - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("required attribute 'builder' missing"), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("required attribute 'builder' missing"), .errPos = state.positions[posDrvName]})); if (drv.platform == "") - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("required attribute 'system' missing"), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("required attribute 'system' missing"), .errPos = state.positions[posDrvName]})); /* Check whether the derivation name is valid. */ if (isDerivation(drvName)) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("derivation names are not allowed to end in '%s'", drvExtension), + .errPos = state.positions[posDrvName]})); if (outputHash) { /* Handle fixed-output derivations. @@ -1220,31 +1190,30 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * Ignore `__contentAddressed` because fixed output derivations are already content addressed. */ if (outputs.size() != 1 || *(outputs.begin()) != "out") - state.debugThrowLastTrace(Error({ - .msg = hintfmt("multiple outputs are not supported in fixed-output derivations"), - .errPos = state.positions[posDrvName] - })); + state.debugThrowLastTrace(Error( + {.msg = hintfmt("multiple outputs are not supported in fixed-output derivations"), + .errPos = state.positions[posDrvName]})); auto h = newHashAllowEmpty(*outputHash, parseHashTypeOpt(outputHashAlgo)); auto method = ingestionMethod.value_or(FileIngestionMethod::Flat); auto outPath = state.store->makeFixedOutputPath(method, h, drvName); drv.env["out"] = state.store->printStorePath(outPath); - drv.outputs.insert_or_assign("out", - DerivationOutput::CAFixed { - .hash = FixedOutputHash { - .method = method, - .hash = std::move(h), - }, - }); + drv.outputs.insert_or_assign( + "out", DerivationOutput::CAFixed{ + .hash = + FixedOutputHash{ + .method = method, + .hash = std::move(h), + }, + }); } else if (contentAddressed || isImpure) { if (contentAddressed && isImpure) - throw EvalError({ - .msg = hintfmt("derivation cannot be both content-addressed and impure"), - .errPos = state.positions[posDrvName] - }); + throw EvalError( + {.msg = hintfmt("derivation cannot be both content-addressed and impure"), + .errPos = state.positions[posDrvName]}); auto ht = parseHashTypeOpt(outputHashAlgo).value_or(htSHA256); auto method = ingestionMethod.value_or(FileIngestionMethod::Recursive); @@ -1252,17 +1221,17 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * for (auto & i : outputs) { drv.env[i] = hashPlaceholder(i); if (isImpure) - drv.outputs.insert_or_assign(i, - DerivationOutput::Impure { - .method = method, - .hashType = ht, - }); + drv.outputs.insert_or_assign( + i, DerivationOutput::Impure{ + .method = method, + .hashType = ht, + }); else - drv.outputs.insert_or_assign(i, - DerivationOutput::CAFloating { - .method = method, - .hashType = ht, - }); + drv.outputs.insert_or_assign( + i, DerivationOutput::CAFloating{ + .method = method, + .hashType = ht, + }); } } @@ -1275,8 +1244,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * the hash. */ for (auto & i : outputs) { drv.env[i] = ""; - drv.outputs.insert_or_assign(i, - DerivationOutput::Deferred { }); + drv.outputs.insert_or_assign(i, DerivationOutput::Deferred{}); } auto hashModulo = hashDerivationModulo(*state.store, Derivation(drv), true); @@ -1292,16 +1260,15 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * auto outPath = state.store->makeOutputPath(i, *h, drvName); drv.env[i] = state.store->printStorePath(outPath); drv.outputs.insert_or_assign( - i, - DerivationOutputInputAddressed { - .path = std::move(outPath), - }); + i, DerivationOutputInputAddressed{ + .path = std::move(outPath), + }); } break; ; case DrvHash::Kind::Deferred: for (auto & i : outputs) { - drv.outputs.insert_or_assign(i, DerivationOutputDeferred {}); + drv.outputs.insert_or_assign(i, DerivationOutputDeferred{}); } } } @@ -1327,7 +1294,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * v.mkAttrs(attrs); } -static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info { +static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info{ .name = "derivationStrict", .arity = 1, .fun = prim_derivationStrict, @@ -1340,7 +1307,7 @@ static RegisterPrimOp primop_derivationStrict(RegisterPrimOp::Info { time, any occurrence of this string in an derivation attribute will be replaced with the concrete path in the Nix store of the output ‘out’. */ -static void prim_placeholder(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_placeholder(EvalState & state, const PosIdx pos, Value ** args, Value & v) { v.mkString(hashPlaceholder(state.forceStringNoCtx(*args[0], pos))); } @@ -1356,14 +1323,12 @@ static RegisterPrimOp primop_placeholder({ .fun = prim_placeholder, }); - /************************************************************* * Paths *************************************************************/ - /* Convert the argument to a path. !!! obsolete? */ -static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_toPath(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; Path path = state.coerceToPath(pos, *args[0], context); @@ -1388,25 +1353,23 @@ static RegisterPrimOp primop_toPath({ /nix/store/newhash-oldhash-oldname. In the past, `toPath' had special case behaviour for store paths, but that created weird corner cases. */ -static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_storePath(EvalState & state, const PosIdx pos, Value ** args, Value & v) { if (evalSettings.pureEval) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"), + .errPos = state.positions[pos]})); PathSet context; Path path = state.checkSourcePath(state.coerceToPath(pos, *args[0], context)); /* Resolve symlinks in ‘path’, unless ‘path’ itself is a symlink directly in the store. The latter condition is necessary so e.g. nix-push does the right thing. */ - if (!state.store->isStorePath(path)) path = canonPath(path, true); + if (!state.store->isStorePath(path)) + path = canonPath(path, true); if (!state.store->isInStore(path)) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("path '%1%' is not in the Nix store", path), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("path '%1%' is not in the Nix store", path), .errPos = state.positions[pos]})); auto path2 = state.store->toStorePath(path).first; if (!settings.readOnlyMode) state.store->ensurePath(path2); @@ -1432,14 +1395,14 @@ static RegisterPrimOp primop_storePath({ .fun = prim_storePath, }); -static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_pathExists(EvalState & state, const PosIdx pos, Value ** args, Value & v) { /* We don’t check the path right now, because we don’t want to throw if the path isn’t allowed, but just return false (and we can’t just catch the exception here because we still want to throw if something in the evaluation of `*args[0]` tries to access an unauthorized path). */ - auto path = realisePath(state, pos, *args[0], { .checkForPureEval = false }); + auto path = realisePath(state, pos, *args[0], {.checkForPureEval = false}); try { v.mkBool(pathExists(state.checkSourcePath(path))); @@ -1464,7 +1427,7 @@ static RegisterPrimOp primop_pathExists({ /* Return the base name of the given string, i.e., everything following the last slash. */ -static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context, false, false)), context); @@ -1484,12 +1447,15 @@ static RegisterPrimOp primop_baseNameOf({ /* Return the directory of the given path, i.e., everything before the last slash. Return either a path or a string depending on the type of the argument. */ -static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_dirOf(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; auto path = state.coerceToString(pos, *args[0], context, false, false); auto dir = dirOf(*path); - if (args[0]->type() == nPath) v.mkPath(dir); else v.mkString(dir, context); + if (args[0]->type() == nPath) + v.mkPath(dir); + else + v.mkString(dir, context); } static RegisterPrimOp primop_dirOf({ @@ -1504,7 +1470,7 @@ static RegisterPrimOp primop_dirOf({ }); /* Return the contents of a file as a string. */ -static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_readFile(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto path = realisePath(state, pos, *args[0]); auto s = readFile(path); @@ -1532,7 +1498,7 @@ static RegisterPrimOp primop_readFile({ /* Find a file in the Nix search path. Used to implement paths, which are desugared to 'findFile __nixPath "x"'. */ -static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_findFile(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); @@ -1546,13 +1512,7 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V if (i != v2->attrs->end()) prefix = state.forceStringNoCtx(*i->value, pos); - i = getAttr( - state, - "findFile", - state.sPath, - v2->attrs, - pos - ); + i = getAttr(state, "findFile", state.sPath, v2->attrs, pos); PathSet context; auto path = state.coerceToString(pos, *i->value, context, false, false).toOwned(); @@ -1561,10 +1521,9 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V auto rewrites = state.realiseContext(context); path = rewriteStrings(path, rewrites); } catch (InvalidPathError & e) { - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("cannot find '%1%', since path '%2%' is not valid", path, e.path), + .errPos = state.positions[pos]})); } searchPath.emplace_back(prefix, path); @@ -1575,22 +1534,20 @@ static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, V v.mkPath(state.checkSourcePath(state.findFile(searchPath, path, pos))); } -static RegisterPrimOp primop_findFile(RegisterPrimOp::Info { +static RegisterPrimOp primop_findFile(RegisterPrimOp::Info{ .name = "__findFile", .arity = 2, .fun = prim_findFile, }); /* Return the cryptographic hash of a file in base-16. */ -static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_hashFile(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - state.debugThrowLastTrace(Error({ - .msg = hintfmt("unknown hash type '%1%'", type), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + Error({.msg = hintfmt("unknown hash type '%1%'", type), .errPos = state.positions[pos]})); auto path = realisePath(state, pos, *args[1]); @@ -1609,7 +1566,7 @@ static RegisterPrimOp primop_hashFile({ }); /* Read a directory (without . or ..) */ -static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_readDir(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto path = realisePath(state, pos, *args[0]); @@ -1621,10 +1578,10 @@ static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Va if (ent.type == DT_UNKNOWN) ent.type = getFileType(path + "/" + ent.name); attrs.alloc(ent.name).mkString( - ent.type == DT_REG ? "regular" : - ent.type == DT_DIR ? "directory" : - ent.type == DT_LNK ? "symlink" : - "unknown"); + ent.type == DT_REG ? "regular" + : ent.type == DT_DIR ? "directory" + : ent.type == DT_LNK ? "symlink" + : "unknown"); } v.mkAttrs(attrs); @@ -1649,16 +1606,14 @@ static RegisterPrimOp primop_readDir({ .fun = prim_readDir, }); - /************************************************************* * Creating files *************************************************************/ - /* Convert the argument (which can be any Nix expression) to an XML representation returned in a string. Not all Nix expressions can be sensibly or completely represented (e.g., functions). */ -static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_toXML(EvalState & state, const PosIdx pos, Value ** args, Value & v) { std::ostringstream out; PathSet context; @@ -1766,7 +1721,7 @@ static RegisterPrimOp primop_toXML({ /* Convert the argument (which can be any Nix expression) to a JSON string. Not all Nix expressions can be sensibly or completely represented (e.g., functions). */ -static void prim_toJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_toJSON(EvalState & state, const PosIdx pos, Value ** args, Value & v) { std::ostringstream out; PathSet context; @@ -1789,12 +1744,12 @@ static RegisterPrimOp primop_toJSON({ }); /* Parse a JSON string to a value. */ -static void prim_fromJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fromJSON(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto s = state.forceStringNoCtx(*args[0], pos); try { parseJSON(state, s, v); - } catch (JSONParseError &e) { + } catch (JSONParseError & e) { e.addTrace(state.positions[pos], "while decoding a JSON string"); throw; } @@ -1817,7 +1772,7 @@ static RegisterPrimOp primop_fromJSON({ /* Store a string in the Nix store as a source file that can be used as an input by derivations. */ -static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_toFile(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; std::string name(state.forceStringNoCtx(*args[0], pos)); @@ -1827,19 +1782,17 @@ static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Val for (auto path : context) { if (path.at(0) != '/') - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt( - "in 'toFile': the file named '%1%' must not contain a reference " - "to a derivation but contains (%2%)", - name, path), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt( + "in 'toFile': the file named '%1%' must not contain a reference " + "to a derivation but contains (%2%)", + name, path), + .errPos = state.positions[pos]})); refs.insert(state.store->parseStorePath(path)); } - auto storePath = settings.readOnlyMode - ? state.store->computeStorePathForText(name, contents, refs) - : state.store->addTextToStore(name, contents, refs, state.repair); + auto storePath = settings.readOnlyMode ? state.store->computeStorePathForText(name, contents, refs) + : state.store->addTextToStore(name, contents, refs, state.repair); /* Note: we don't need to add `context' to the context of the result, since `storePath' itself has references to the paths @@ -1956,9 +1909,7 @@ static void addPath( } } - path = evalSettings.pureEval && expectedHash - ? path - : state.checkSourcePath(path); + path = evalSettings.pureEval && expectedHash ? path : state.checkSourcePath(path); PathFilter filter = filterFun ? ([&](const Path & path) { auto st = lstat(path); @@ -1970,17 +1921,18 @@ static void addPath( Value arg2; arg2.mkString( - S_ISREG(st.st_mode) ? "regular" : - S_ISDIR(st.st_mode) ? "directory" : - S_ISLNK(st.st_mode) ? "symlink" : - "unknown" /* not supported, will fail! */); + S_ISREG(st.st_mode) ? "regular" + : S_ISDIR(st.st_mode) ? "directory" + : S_ISLNK(st.st_mode) ? "symlink" + : "unknown" /* not supported, will fail! */); - Value * args []{&arg1, &arg2}; + Value * args[]{&arg1, &arg2}; Value res; state.callFunction(*filterFun, 2, args, res, pos); return state.forceBool(res, pos); - }) : defaultPathFilter; + }) + : defaultPathFilter; std::optional expectedStorePath; if (expectedHash) @@ -1988,10 +1940,11 @@ static void addPath( if (!expectedHash || !state.store->isValidPath(*expectedStorePath)) { StorePath dstPath = settings.readOnlyMode - ? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first - : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs); + ? state.store->computeStorePathForPath(name, path, method, htSHA256, filter).first + : state.store->addToStore(name, path, method, htSHA256, filter, state.repair, refs); if (expectedHash && expectedStorePath != dstPath) - state.debugThrowLastTrace(Error("store path mismatch in (possibly filtered) path added from '%s'", path)); + state.debugThrowLastTrace( + Error("store path mismatch in (possibly filtered) path added from '%s'", path)); state.allowAndSetStorePathString(dstPath, v); } else state.allowAndSetStorePathString(*expectedStorePath, v); @@ -2001,22 +1954,20 @@ static void addPath( } } - -static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_filterSource(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; Path path = state.coerceToPath(pos, *args[1], context); state.forceValue(*args[0], pos); if (args[0]->type() != nFunction) - state.debugThrowLastTrace(TypeError({ - .msg = hintfmt( - "first argument in call to 'filterSource' is not a function but %1%", - showType(*args[0])), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(TypeError( + {.msg = hintfmt("first argument in call to 'filterSource' is not a function but %1%", showType(*args[0])), + .errPos = state.positions[pos]})); - addPath(state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, context); + addPath( + state, pos, std::string(baseNameOf(path)), path, args[0], FileIngestionMethod::Recursive, std::nullopt, v, + context); } static RegisterPrimOp primop_filterSource({ @@ -2074,7 +2025,7 @@ static RegisterPrimOp primop_filterSource({ .fun = prim_filterSource, }); -static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_path(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); Path path; @@ -2094,20 +2045,16 @@ static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value state.forceValue(*attr.value, pos); filterFun = attr.value; } else if (n == "recursive") - method = FileIngestionMethod { state.forceBool(*attr.value, attr.pos) }; + method = FileIngestionMethod{state.forceBool(*attr.value, attr.pos)}; else if (n == "sha256") expectedHash = newHashAllowEmpty(state.forceStringNoCtx(*attr.value, attr.pos), htSHA256); else - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("unsupported argument '%1%' to 'addPath'", state.symbols[attr.name]), - .errPos = state.positions[attr.pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("unsupported argument '%1%' to 'addPath'", state.symbols[attr.name]), + .errPos = state.positions[attr.pos]})); } if (path.empty()) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("'path' required"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError({.msg = hintfmt("'path' required"), .errPos = state.positions[pos]})); if (name.empty()) name = baseNameOf(path); @@ -2149,15 +2096,13 @@ static RegisterPrimOp primop_path({ .fun = prim_path, }); - /************************************************************* * Sets *************************************************************/ - /* Return the names of the attributes in a set as a sorted list of strings. */ -static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_attrNames(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); @@ -2167,8 +2112,9 @@ static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args, for (auto & i : *args[0]->attrs) (v.listElems()[n++] = state.allocValue())->mkString(state.symbols[i.name]); - std::sort(v.listElems(), v.listElems() + n, - [](Value * v1, Value * v2) { return strcmp(v1->string.s, v2->string.s) < 0; }); + std::sort(v.listElems(), v.listElems() + n, [](Value * v1, Value * v2) { + return strcmp(v1->string.s, v2->string.s) < 0; + }); } static RegisterPrimOp primop_attrNames({ @@ -2184,7 +2130,7 @@ static RegisterPrimOp primop_attrNames({ /* Return the values of the attributes in a set as a list, in the same order as attrNames. */ -static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_attrValues(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); @@ -2194,12 +2140,10 @@ static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args, for (auto & i : *args[0]->attrs) v.listElems()[n++] = (Value *) &i; - std::sort(v.listElems(), v.listElems() + n, - [&](Value * v1, Value * v2) { - std::string_view s1 = state.symbols[((Attr *) v1)->name], - s2 = state.symbols[((Attr *) v2)->name]; - return s1 < s2; - }); + std::sort(v.listElems(), v.listElems() + n, [&](Value * v1, Value * v2) { + std::string_view s1 = state.symbols[((Attr *) v1)->name], s2 = state.symbols[((Attr *) v2)->name]; + return s1 < s2; + }); for (unsigned int i = 0; i < n; ++i) v.listElems()[i] = ((Attr *) v.listElems()[i])->value; @@ -2216,19 +2160,14 @@ static RegisterPrimOp primop_attrValues({ }); /* Dynamic version of the `.' operator. */ -void prim_getAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_getAttr(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); - Bindings::iterator i = getAttr( - state, - "getAttr", - state.symbols.create(attr), - args[1]->attrs, - pos - ); + Bindings::iterator i = getAttr(state, "getAttr", state.symbols.create(attr), args[1]->attrs, pos); // !!! add to stack trace? - if (state.countCalls && i->pos) state.attrSelects[i->pos]++; + if (state.countCalls && i->pos) + state.attrSelects[i->pos]++; state.forceValue(*i->value, pos); v = *i->value; } @@ -2246,7 +2185,7 @@ static RegisterPrimOp primop_getAttr({ }); /* Return position information of the specified attribute. */ -static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); @@ -2257,14 +2196,14 @@ static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * * state.mkPos(v, i->pos); } -static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info { +static RegisterPrimOp primop_unsafeGetAttrPos(RegisterPrimOp::Info{ .name = "__unsafeGetAttrPos", .arity = 2, .fun = prim_unsafeGetAttrPos, }); /* Dynamic version of the `?' operator. */ -static void prim_hasAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_hasAttr(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto attr = state.forceStringNoCtx(*args[0], pos); state.forceAttrs(*args[1], pos); @@ -2283,7 +2222,7 @@ static RegisterPrimOp primop_hasAttr({ }); /* Determine whether the argument is a set. */ -static void prim_isAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nAttrs); @@ -2298,7 +2237,7 @@ static RegisterPrimOp primop_isAttrs({ .fun = prim_isAttrs, }); -static void prim_removeAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_removeAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); state.forceList(*args[1], pos); @@ -2319,9 +2258,7 @@ static void prim_removeAttrs(EvalState & state, const PosIdx pos, Value * * args vector. */ auto attrs = state.buildBindings(args[0]->attrs->size()); std::set_difference( - args[0]->attrs->begin(), args[0]->attrs->end(), - names.begin(), names.end(), - std::back_inserter(attrs)); + args[0]->attrs->begin(), args[0]->attrs->end(), names.begin(), names.end(), std::back_inserter(attrs)); v.mkAttrs(attrs.alreadySorted()); } @@ -2346,7 +2283,7 @@ static RegisterPrimOp primop_removeAttrs({ "nameN"; value = valueN;}] is transformed to {name1 = value1; ... nameN = valueN;}. In case of duplicate occurrences of the same name, the first takes precedence. */ -static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); @@ -2357,25 +2294,13 @@ static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args for (auto v2 : args[0]->listItems()) { state.forceAttrs(*v2, pos); - Bindings::iterator j = getAttr( - state, - "listToAttrs", - state.sName, - v2->attrs, - pos - ); + Bindings::iterator j = getAttr(state, "listToAttrs", state.sName, v2->attrs, pos); auto name = state.forceStringNoCtx(*j->value, j->pos); auto sym = state.symbols.create(name); if (seen.insert(sym).second) { - Bindings::iterator j2 = getAttr( - state, - "listToAttrs", - state.sValue, - v2->attrs, - pos - ); + Bindings::iterator j2 = getAttr(state, "listToAttrs", state.sValue, v2->attrs, pos); attrs.insert(sym, j2->value, j2->pos); } } @@ -2408,7 +2333,7 @@ static RegisterPrimOp primop_listToAttrs({ .fun = prim_listToAttrs, }); -static void prim_intersectAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_intersectAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); state.forceAttrs(*args[1], pos); @@ -2434,7 +2359,7 @@ static RegisterPrimOp primop_intersectAttrs({ .fun = prim_intersectAttrs, }); -static void prim_catAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_catAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos)); state.forceList(*args[1], pos); @@ -2471,7 +2396,7 @@ static RegisterPrimOp primop_catAttrs({ .fun = prim_catAttrs, }); -static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_functionArgs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); if (args[0]->isPrimOpApp() || args[0]->isPrimOp()) { @@ -2479,10 +2404,8 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg return; } if (!args[0]->isLambda()) - state.debugThrowLastTrace(TypeError({ - .msg = hintfmt("'functionArgs' requires a function"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + TypeError({.msg = hintfmt("'functionArgs' requires a function"), .errPos = state.positions[pos]})); if (!args[0]->lambda.fun->hasFormals()) { v.mkAttrs(&state.emptyBindings); @@ -2514,7 +2437,7 @@ static RegisterPrimOp primop_functionArgs({ }); /* */ -static void prim_mapAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_mapAttrs(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[1], pos); @@ -2546,7 +2469,7 @@ static RegisterPrimOp primop_mapAttrs({ .fun = prim_mapAttrs, }); -static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value ** args, Value & v) { // we will first count how many values are present for each given key. // we then allocate a single attrset and pre-populate it with lists of @@ -2555,7 +2478,7 @@ static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * arg // attribute with the merge function application. this way we need not // use (slightly slower) temporary storage the GC does not know about. - std::map> attrsSeen; + std::map> attrsSeen; state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -2631,14 +2554,12 @@ static RegisterPrimOp primop_zipAttrsWith({ .fun = prim_zipAttrsWith, }); - /************************************************************* * Lists *************************************************************/ - /* Determine whether the argument is a list. */ -static void prim_isList(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_isList(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); v.mkBool(args[0]->type() == nList); @@ -2657,16 +2578,14 @@ static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Val { state.forceList(list, pos); if (n < 0 || (unsigned int) n >= list.listSize()) - state.debugThrowLastTrace(Error({ - .msg = hintfmt("list index %1% is out of bounds", n), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + Error({.msg = hintfmt("list index %1% is out of bounds", n), .errPos = state.positions[pos]})); state.forceValue(*list.listElems()[n], pos); v = *list.listElems()[n]; } /* Return the n-1'th element of a list. */ -static void prim_elemAt(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_elemAt(EvalState & state, const PosIdx pos, Value ** args, Value & v) { elemAt(state, pos, *args[0], state.forceInt(*args[1], pos), v); } @@ -2682,7 +2601,7 @@ static RegisterPrimOp primop_elemAt({ }); /* Return the first element of a list. */ -static void prim_head(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_head(EvalState & state, const PosIdx pos, Value ** args, Value & v) { elemAt(state, pos, *args[0], 0, v); } @@ -2701,14 +2620,12 @@ static RegisterPrimOp primop_head({ /* Return a list consisting of everything but the first element of a list. Warning: this function takes O(n) time, so you probably don't want to use it! */ -static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_tail(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); if (args[0]->listSize() == 0) - state.debugThrowLastTrace(Error({ - .msg = hintfmt("'tail' called on an empty list"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + Error({.msg = hintfmt("'tail' called on an empty list"), .errPos = state.positions[pos]})); state.mkList(v, args[0]->listSize() - 1); for (unsigned int n = 0; n < v.listSize(); ++n) @@ -2732,15 +2649,14 @@ static RegisterPrimOp primop_tail({ }); /* Apply a function to every element of a list. */ -static void prim_map(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_map(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[1], pos); state.mkList(v, args[1]->listSize()); for (unsigned int n = 0; n < v.listSize(); ++n) - (v.listElems()[n] = state.allocValue())->mkApp( - args[0], args[1]->listElems()[n]); + (v.listElems()[n] = state.allocValue())->mkApp(args[0], args[1]->listElems()[n]); } static RegisterPrimOp primop_map({ @@ -2762,7 +2678,7 @@ static RegisterPrimOp primop_map({ /* Filter a list using a predicate; that is, return a list containing every element from the list for which the predicate function returns true. */ -static void prim_filter(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_filter(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -2785,7 +2701,8 @@ static void prim_filter(EvalState & state, const PosIdx pos, Value * * args, Val v = *args[1]; else { state.mkList(v, k); - for (unsigned int n = 0; n < k; ++n) v.listElems()[n] = vs[n]; + for (unsigned int n = 0; n < k; ++n) + v.listElems()[n] = vs[n]; } } @@ -2800,7 +2717,7 @@ static RegisterPrimOp primop_filter({ }); /* Return true if a list contains a given element. */ -static void prim_elem(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_elem(EvalState & state, const PosIdx pos, Value ** args, Value & v) { bool res = false; state.forceList(*args[1], pos); @@ -2823,7 +2740,7 @@ static RegisterPrimOp primop_elem({ }); /* Concatenate a list of lists. */ -static void prim_concatLists(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_concatLists(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos); @@ -2839,7 +2756,7 @@ static RegisterPrimOp primop_concatLists({ }); /* Return the length of a list. This is an O(1) time operation. */ -static void prim_length(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_length(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); v.mkInt(args[0]->listSize()); @@ -2856,7 +2773,7 @@ static RegisterPrimOp primop_length({ /* Reduce a list by applying a binary operator, from left to right. The operator is applied strictly. */ -static void prim_foldlStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_foldlStrict(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[2], pos); @@ -2865,7 +2782,7 @@ static void prim_foldlStrict(EvalState & state, const PosIdx pos, Value * * args Value * vCur = args[1]; for (auto [n, elem] : enumerate(args[2]->listItems())) { - Value * vs []{vCur, elem}; + Value * vs[]{vCur, elem}; vCur = n == args[2]->listSize() - 1 ? &v : state.allocValue(); state.callFunction(*args[0], 2, vs, *vCur, pos); } @@ -2889,7 +2806,7 @@ static RegisterPrimOp primop_foldlStrict({ .fun = prim_foldlStrict, }); -static void anyOrAll(bool any, EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void anyOrAll(bool any, EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -2907,8 +2824,7 @@ static void anyOrAll(bool any, EvalState & state, const PosIdx pos, Value * * ar v.mkBool(!any); } - -static void prim_any(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_any(EvalState & state, const PosIdx pos, Value ** args, Value & v) { anyOrAll(true, state, pos, args, v); } @@ -2923,7 +2839,7 @@ static RegisterPrimOp primop_any({ .fun = prim_any, }); -static void prim_all(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_all(EvalState & state, const PosIdx pos, Value ** args, Value & v) { anyOrAll(false, state, pos, args, v); } @@ -2938,15 +2854,13 @@ static RegisterPrimOp primop_all({ .fun = prim_all, }); -static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_genList(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto len = state.forceInt(*args[1], pos); if (len < 0) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("cannot create list of size %1%", len), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("cannot create list of size %1%", len), .errPos = state.positions[pos]})); state.mkList(v, len); @@ -2973,10 +2887,9 @@ static RegisterPrimOp primop_genList({ .fun = prim_genList, }); -static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v); - +static void prim_lessThan(EvalState & state, const PosIdx pos, Value ** args, Value & v); -static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_sort(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -3027,7 +2940,7 @@ static RegisterPrimOp primop_sort({ .fun = prim_sort, }); -static void prim_partition(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_partition(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -3087,7 +3000,7 @@ static RegisterPrimOp primop_partition({ .fun = prim_partition, }); -static void prim_groupBy(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_groupBy(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -3139,7 +3052,7 @@ static RegisterPrimOp primop_groupBy({ .fun = prim_groupBy, }); -static void prim_concatMap(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_concatMap(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceFunction(*args[0], pos); state.forceList(*args[1], pos); @@ -3153,7 +3066,7 @@ static void prim_concatMap(EvalState & state, const PosIdx pos, Value * * args, state.callFunction(*args[0], *vElem, lists[n], pos); try { state.forceList(lists[n], lists[n].determinePos(args[0]->determinePos(pos))); - } catch (TypeError &e) { + } catch (TypeError & e) { e.addTrace(state.positions[pos], hintfmt("while invoking '%s'", "concatMap")); state.debugThrowLastTrace(e); } @@ -3180,13 +3093,11 @@ static RegisterPrimOp primop_concatMap({ .fun = prim_concatMap, }); - /************************************************************* * Integer arithmetic *************************************************************/ - -static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_add(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); @@ -3205,7 +3116,7 @@ static RegisterPrimOp primop_add({ .fun = prim_add, }); -static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_sub(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); @@ -3224,7 +3135,7 @@ static RegisterPrimOp primop_sub({ .fun = prim_sub, }); -static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_mul(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); @@ -3243,17 +3154,14 @@ static RegisterPrimOp primop_mul({ .fun = prim_mul, }); -static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_div(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); NixFloat f2 = state.forceFloat(*args[1], pos); if (f2 == 0) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("division by zero"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError({.msg = hintfmt("division by zero"), .errPos = state.positions[pos]})); if (args[0]->type() == nFloat || args[1]->type() == nFloat) { v.mkFloat(state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); @@ -3262,10 +3170,8 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value NixInt i2 = state.forceInt(*args[1], pos); /* Avoid division overflow as it might raise SIGFPE. */ if (i1 == std::numeric_limits::min() && i2 == -1) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("overflow in integer division"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("overflow in integer division"), .errPos = state.positions[pos]})); v.mkInt(i1 / i2); } @@ -3280,7 +3186,7 @@ static RegisterPrimOp primop_div({ .fun = prim_div, }); -static void prim_bitAnd(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_bitAnd(EvalState & state, const PosIdx pos, Value ** args, Value & v) { v.mkInt(state.forceInt(*args[0], pos) & state.forceInt(*args[1], pos)); } @@ -3294,7 +3200,7 @@ static RegisterPrimOp primop_bitAnd({ .fun = prim_bitAnd, }); -static void prim_bitOr(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_bitOr(EvalState & state, const PosIdx pos, Value ** args, Value & v) { v.mkInt(state.forceInt(*args[0], pos) | state.forceInt(*args[1], pos)); } @@ -3308,7 +3214,7 @@ static RegisterPrimOp primop_bitOr({ .fun = prim_bitOr, }); -static void prim_bitXor(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_bitXor(EvalState & state, const PosIdx pos, Value ** args, Value & v) { v.mkInt(state.forceInt(*args[0], pos) ^ state.forceInt(*args[1], pos)); } @@ -3322,7 +3228,7 @@ static RegisterPrimOp primop_bitXor({ .fun = prim_bitXor, }); -static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_lessThan(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); @@ -3341,16 +3247,14 @@ static RegisterPrimOp primop_lessThan({ .fun = prim_lessThan, }); - /************************************************************* * String manipulation *************************************************************/ - /* Convert the argument to a string. Paths are *not* copied to the store, so `toString /foo/bar' yields `"/foo/bar"', not `"/nix/store/whatever..."'. */ -static void prim_toString(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_toString(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; auto s = state.coerceToString(pos, *args[0], context, true, false); @@ -3385,7 +3289,7 @@ static RegisterPrimOp primop_toString({ at character position `min(start, stringLength str)' inclusive and ending at `min(start + len, stringLength str)'. `start' must be non-negative. */ -static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_substring(EvalState & state, const PosIdx pos, Value ** args, Value & v) { int start = state.forceInt(*args[0], pos); int len = state.forceInt(*args[1], pos); @@ -3393,10 +3297,8 @@ static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, auto s = state.coerceToString(pos, *args[2], context); if (start < 0) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("negative start position in 'substring'"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("negative start position in 'substring'"), .errPos = state.positions[pos]})); v.mkString((unsigned int) start >= s->size() ? "" : s->substr(start, len), context); } @@ -3421,7 +3323,7 @@ static RegisterPrimOp primop_substring({ .fun = prim_substring, }); -static void prim_stringLength(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_stringLength(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; auto s = state.coerceToString(pos, *args[0], context); @@ -3439,15 +3341,13 @@ static RegisterPrimOp primop_stringLength({ }); /* Return the cryptographic hash of a string in base-16. */ -static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_hashString(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto type = state.forceStringNoCtx(*args[0], pos); std::optional ht = parseHashType(type); if (!ht) - state.debugThrowLastTrace(Error({ - .msg = hintfmt("unknown hash type '%1%'", type), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + Error({.msg = hintfmt("unknown hash type '%1%'", type), .errPos = state.positions[pos]})); PathSet context; // discarded auto s = state.forceString(*args[1], context, pos); @@ -3487,7 +3387,7 @@ std::shared_ptr makeRegexCache() return std::make_shared(); } -void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_match(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto re = state.forceStringNoCtx(*args[0], pos); @@ -3508,7 +3408,7 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) const size_t len = match.size() - 1; state.mkList(v, len); for (size_t i = 0; i < len; ++i) { - if (!match[i+1].matched) + if (!match[i + 1].matched) (v.listElems()[i] = state.allocValue())->mkNull(); else (v.listElems()[i] = state.allocValue())->mkString(match[i + 1].str()); @@ -3517,15 +3417,12 @@ void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v) } catch (std::regex_error & e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("memory limit exceeded by regular expression '%s'", re), + .errPos = state.positions[pos]})); } else - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("invalid regular expression '%s'", re), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("invalid regular expression '%s'", re), .errPos = state.positions[pos]})); } } @@ -3567,7 +3464,7 @@ static RegisterPrimOp primop_match({ /* Split a string with a regular expression, and return a list of the non-matching parts interleaved by the lists of the matching groups. */ -void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) +void prim_split(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto re = state.forceStringNoCtx(*args[0], pos); @@ -3621,15 +3518,12 @@ void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v) } catch (std::regex_error & e) { if (e.code() == std::regex_constants::error_space) { // limit is _GLIBCXX_REGEX_STATE_LIMIT for libstdc++ - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("memory limit exceeded by regular expression '%s'", re), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("memory limit exceeded by regular expression '%s'", re), + .errPos = state.positions[pos]})); } else - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("invalid regular expression '%s'", re), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("invalid regular expression '%s'", re), .errPos = state.positions[pos]})); } } @@ -3670,7 +3564,7 @@ static RegisterPrimOp primop_split({ .fun = prim_split, }); -static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; @@ -3682,7 +3576,10 @@ static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value * * bool first = true; for (auto elem : args[1]->listItems()) { - if (first) first = false; else res += sep; + if (first) + first = false; + else + res += sep; res += *state.coerceToString(pos, *elem, context); } @@ -3700,15 +3597,14 @@ static RegisterPrimOp primop_concatStringsSep({ .fun = prim_concatStringsSep, }); -static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceList(*args[0], pos); state.forceList(*args[1], pos); if (args[0]->listSize() != args[1]->listSize()) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("'from' and 'to' arguments to 'replaceStrings' have different lengths"), + .errPos = state.positions[pos]})); std::vector from; from.reserve(args[0]->listSize()); @@ -3728,7 +3624,7 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a std::string res; // Loops one past last character to handle the case where 'from' contains an empty string. - for (size_t p = 0; p <= s.size(); ) { + for (size_t p = 0; p <= s.size();) { bool found = false; auto i = from.begin(); auto j = to.begin(); @@ -3743,7 +3639,7 @@ static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * a } else { p += i->size(); } - for (auto& path : j->second) + for (auto & path : j->second) context.insert(path); j->second.clear(); break; @@ -3774,13 +3670,11 @@ static RegisterPrimOp primop_replaceStrings({ .fun = prim_replaceStrings, }); - /************************************************************* * Versions *************************************************************/ - -static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto name = state.forceStringNoCtx(*args[0], pos); DrvName parsed(name); @@ -3804,7 +3698,7 @@ static RegisterPrimOp primop_parseDrvName({ .fun = prim_parseDrvName, }); -static void prim_compareVersions(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_compareVersions(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto version1 = state.forceStringNoCtx(*args[0], pos); auto version2 = state.forceStringNoCtx(*args[1], pos); @@ -3824,7 +3718,7 @@ static RegisterPrimOp primop_compareVersions({ .fun = prim_compareVersions, }); -static void prim_splitVersion(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_splitVersion(EvalState & state, const PosIdx pos, Value ** args, Value & v) { auto version = state.forceStringNoCtx(*args[0], pos); auto iter = version.cbegin(); @@ -3851,18 +3745,16 @@ static RegisterPrimOp primop_splitVersion({ .fun = prim_splitVersion, }); - /************************************************************* * Primop registration *************************************************************/ - RegisterPrimOp::PrimOps * RegisterPrimOp::primOps; - RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun) { - if (!primOps) primOps = new PrimOps; + if (!primOps) + primOps = new PrimOps; primOps->push_back({ .name = name, .args = {}, @@ -3871,14 +3763,13 @@ RegisterPrimOp::RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun) }); } - RegisterPrimOp::RegisterPrimOp(Info && info) { - if (!primOps) primOps = new PrimOps; + if (!primOps) + primOps = new PrimOps; primOps->push_back(std::move(info)); } - void EvalState::createBaseEnv() { baseEnv.up = 0; @@ -3939,9 +3830,7 @@ void EvalState::createBaseEnv() if (RegisterPrimOp::primOps) for (auto & primOp : *RegisterPrimOp::primOps) - if (!primOp.experimentalFeature - || settings.isExperimentalFeatureEnabled(*primOp.experimentalFeature)) - { + if (!primOp.experimentalFeature || settings.isExperimentalFeatureEnabled(*primOp.experimentalFeature)) { addPrimOp({ .fun = primOp.fun, .arity = std::max(primOp.args.size(), primOp.arity), @@ -3966,12 +3855,11 @@ void EvalState::createBaseEnv() /* Note: we have to initialize the 'derivation' constant *after* building baseEnv/staticBaseEnv because it uses 'builtins'. */ char code[] = - #include "primops/derivation.nix.gen.hh" +#include "primops/derivation.nix.gen.hh" // the parser needs two NUL bytes as terminators; one of them // is implied by being a C string. "\0"; eval(parse(code, sizeof(code), foFile, derivationNixPath, "/", staticBaseEnv), *vDerivation); } - } diff --git a/src/libexpr/primops.hh b/src/libexpr/primops.hh index 1cfb4356b27f..1ef447092756 100644 --- a/src/libexpr/primops.hh +++ b/src/libexpr/primops.hh @@ -25,10 +25,7 @@ struct RegisterPrimOp /* You can register a constant by passing an arity of 0. fun will get called during EvalState initialization, so there may be primops not yet added and builtins is not yet sorted. */ - RegisterPrimOp( - std::string name, - size_t arity, - PrimOpFun fun); + RegisterPrimOp(std::string name, size_t arity, PrimOpFun fun); RegisterPrimOp(Info && info); }; @@ -38,9 +35,9 @@ struct RegisterPrimOp them. */ /* Load a ValueInitializer from a DSO and return whatever it initializes */ -void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Value & v); +void prim_importNative(EvalState & state, const PosIdx pos, Value ** args, Value & v); /* Execute a program and parse its output */ -void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v); +void prim_exec(EvalState & state, const PosIdx pos, Value ** args, Value & v); } diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc index 97913698429f..6b419dbce90f 100644 --- a/src/libexpr/primops/context.cc +++ b/src/libexpr/primops/context.cc @@ -5,17 +5,17 @@ namespace nix { -static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_unsafeDiscardStringContext(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; auto s = state.coerceToString(pos, *args[0], context); v.mkString(*s); } -static RegisterPrimOp primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); +static RegisterPrimOp + primop_unsafeDiscardStringContext("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext); - -static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_hasContext(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; state.forceString(*args[0], context, pos); @@ -24,14 +24,13 @@ static void prim_hasContext(EvalState & state, const PosIdx pos, Value * * args, static RegisterPrimOp primop_hasContext("__hasContext", 1, prim_hasContext); - /* Sometimes we want to pass a derivation path (i.e. pkg.drvPath) to a builder without causing the derivation to be built (for instance, in the derivation that builds NARs in nix-push, when doing source-only deployment). This primop marks the string context so that builtins.derivation adds the path to drv.inputSrcs rather than drv.inputDrvs. */ -static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; auto s = state.coerceToString(pos, *args[0], context); @@ -43,8 +42,8 @@ static void prim_unsafeDiscardOutputDependency(EvalState & state, const PosIdx p v.mkString(*s, context2); } -static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); - +static RegisterPrimOp + primop_unsafeDiscardOutputDependency("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency); /* Extract the context of a string as a structured Nix value. @@ -65,9 +64,10 @@ static RegisterPrimOp primop_unsafeDiscardOutputDependency("__unsafeDiscardOutpu Note that for a given path any combination of the above attributes may be present. */ -static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_getContext(EvalState & state, const PosIdx pos, Value ** args, Value & v) { - struct ContextInfo { + struct ContextInfo + { bool path = false; bool allOutputs = false; Strings outputs; @@ -93,7 +93,8 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args, auto iter = contextInfos.find(*path); if (iter == contextInfos.end()) { - contextInfos.emplace(*path, ContextInfo{isPath, isAllOutputs, output.empty() ? Strings{} : Strings{std::move(output)}}); + contextInfos.emplace( + *path, ContextInfo{isPath, isAllOutputs, output.empty() ? Strings{} : Strings{std::move(output)}}); } else { if (isPath) iter->second.path = true; @@ -128,13 +129,12 @@ static void prim_getContext(EvalState & state, const PosIdx pos, Value * * args, static RegisterPrimOp primop_getContext("__getContext", 1, prim_getContext); - /* Append the given context to a given string. See the commentary above unsafeGetContext for details of the context representation. */ -static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_appendContext(EvalState & state, const PosIdx pos, Value ** args, Value & v) { PathSet context; auto orig = state.forceString(*args[0], context, pos); @@ -146,10 +146,8 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar for (auto & i : *args[1]->attrs) { const auto & name = state.symbols[i.name]; if (!state.store->isStorePath(name)) - throw EvalError({ - .msg = hintfmt("Context key '%s' is not a store path", name), - .errPos = state.positions[i.pos] - }); + throw EvalError( + {.msg = hintfmt("Context key '%s' is not a store path", name), .errPos = state.positions[i.pos]}); if (!settings.readOnlyMode) state.store->ensurePath(state.store->parseStorePath(name)); state.forceAttrs(*i.value, i.pos); @@ -163,10 +161,10 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar if (iter != i.value->attrs->end()) { if (state.forceBool(*iter->value, iter->pos)) { if (!isDerivation(name)) { - throw EvalError({ - .msg = hintfmt("Tried to add all-outputs context of %s, which is not a derivation, to a string", name), - .errPos = state.positions[i.pos] - }); + throw EvalError( + {.msg = hintfmt( + "Tried to add all-outputs context of %s, which is not a derivation, to a string", name), + .errPos = state.positions[i.pos]}); } context.insert(concatStrings("=", name)); } @@ -176,10 +174,10 @@ static void prim_appendContext(EvalState & state, const PosIdx pos, Value * * ar if (iter != i.value->attrs->end()) { state.forceList(*iter->value, iter->pos); if (iter->value->listSize() && !isDerivation(name)) { - throw EvalError({ - .msg = hintfmt("Tried to add derivation output context of %s, which is not a derivation, to a string", name), - .errPos = state.positions[i.pos] - }); + throw EvalError( + {.msg = hintfmt( + "Tried to add derivation output context of %s, which is not a derivation, to a string", name), + .errPos = state.positions[i.pos]}); } for (auto elem : iter->value->listItems()) { auto outputName = state.forceStringNoCtx(*elem, iter->pos); diff --git a/src/libexpr/primops/fetchClosure.cc b/src/libexpr/primops/fetchClosure.cc index 662c9652eaa4..e0f5a6ae6232 100644 --- a/src/libexpr/primops/fetchClosure.cc +++ b/src/libexpr/primops/fetchClosure.cc @@ -5,7 +5,7 @@ namespace nix { -static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value ** args, Value & v) { state.forceAttrs(*args[0], pos); @@ -35,68 +35,59 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg fromStoreUrl = state.forceStringNoCtx(*attr.value, attr.pos); else - throw Error({ - .msg = hintfmt("attribute '%s' isn't supported in call to 'fetchClosure'", attrName), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt("attribute '%s' isn't supported in call to 'fetchClosure'", attrName), + .errPos = state.positions[pos]}); } if (!fromPath) - throw Error({ - .msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromPath"), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromPath"), + .errPos = state.positions[pos]}); if (!fromStoreUrl) - throw Error({ - .msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt("attribute '%s' is missing in call to 'fetchClosure'", "fromStore"), + .errPos = state.positions[pos]}); auto parsedURL = parseURL(*fromStoreUrl); - if (parsedURL.scheme != "http" && - parsedURL.scheme != "https" && - !(getEnv("_NIX_IN_TEST").has_value() && parsedURL.scheme == "file")) - throw Error({ - .msg = hintfmt("'fetchClosure' only supports http:// and https:// stores"), - .errPos = state.positions[pos] - }); + if (parsedURL.scheme != "http" && parsedURL.scheme != "https" + && !(getEnv("_NIX_IN_TEST").has_value() && parsedURL.scheme == "file")) + throw Error( + {.msg = hintfmt("'fetchClosure' only supports http:// and https:// stores"), + .errPos = state.positions[pos]}); if (!parsedURL.query.empty()) - throw Error({ - .msg = hintfmt("'fetchClosure' does not support URL query parameters (in '%s')", *fromStoreUrl), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt("'fetchClosure' does not support URL query parameters (in '%s')", *fromStoreUrl), + .errPos = state.positions[pos]}); auto fromStore = openStore(parsedURL.to_string()); if (toCA) { if (!toPath || !state.store->isValidPath(*toPath)) { - auto remappings = makeContentAddressed(*fromStore, *state.store, { *fromPath }); + auto remappings = makeContentAddressed(*fromStore, *state.store, {*fromPath}); auto i = remappings.find(*fromPath); assert(i != remappings.end()); if (toPath && *toPath != i->second) - throw Error({ - .msg = hintfmt("rewriting '%s' to content-addressed form yielded '%s', while '%s' was expected", - state.store->printStorePath(*fromPath), - state.store->printStorePath(i->second), - state.store->printStorePath(*toPath)), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt( + "rewriting '%s' to content-addressed form yielded '%s', while '%s' was expected", + state.store->printStorePath(*fromPath), state.store->printStorePath(i->second), + state.store->printStorePath(*toPath)), + .errPos = state.positions[pos]}); if (!toPath) - throw Error({ - .msg = hintfmt( - "rewriting '%s' to content-addressed form yielded '%s'; " - "please set this in the 'toPath' attribute passed to 'fetchClosure'", - state.store->printStorePath(*fromPath), - state.store->printStorePath(i->second)), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt( + "rewriting '%s' to content-addressed form yielded '%s'; " + "please set this in the 'toPath' attribute passed to 'fetchClosure'", + state.store->printStorePath(*fromPath), state.store->printStorePath(i->second)), + .errPos = state.positions[pos]}); } } else { if (!state.store->isValidPath(*fromPath)) - copyClosure(*fromStore, *state.store, RealisedPath::Set { *fromPath }); + copyClosure(*fromStore, *state.store, RealisedPath::Set{*fromPath}); toPath = fromPath; } @@ -104,11 +95,11 @@ static void prim_fetchClosure(EvalState & state, const PosIdx pos, Value * * arg if (evalSettings.pureEval) { auto info = state.store->queryPathInfo(*toPath); if (!info->isContentAddressed(*state.store)) - throw Error({ - .msg = hintfmt("in pure mode, 'fetchClosure' requires a content-addressed path, which '%s' isn't", - state.store->printStorePath(*toPath)), - .errPos = state.positions[pos] - }); + throw Error( + {.msg = hintfmt( + "in pure mode, 'fetchClosure' requires a content-addressed path, which '%s' isn't", + state.store->printStorePath(*toPath)), + .errPos = state.positions[pos]}); } auto toPathS = state.store->printStorePath(*toPath); diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index 249c0934e246..6603a8b818f4 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -7,7 +7,7 @@ namespace nix { -static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value ** args, Value & v) { std::string url; std::optional rev; @@ -33,21 +33,16 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a rev = Hash::parseAny(value, htSHA1); else ref = value; - } - else if (n == "name") + } else if (n == "name") name = state.forceStringNoCtx(*attr.value, attr.pos); else - throw EvalError({ - .msg = hintfmt("unsupported argument '%s' to 'fetchMercurial'", state.symbols[attr.name]), - .errPos = state.positions[attr.pos] - }); + throw EvalError( + {.msg = hintfmt("unsupported argument '%s' to 'fetchMercurial'", state.symbols[attr.name]), + .errPos = state.positions[attr.pos]}); } if (url.empty()) - throw EvalError({ - .msg = hintfmt("'url' argument required"), - .errPos = state.positions[pos] - }); + throw EvalError({.msg = hintfmt("'url' argument required"), .errPos = state.positions[pos]}); } else url = state.coerceToString(pos, *args[0], context, false, false).toOwned(); @@ -63,8 +58,10 @@ static void prim_fetchMercurial(EvalState & state, const PosIdx pos, Value * * a attrs.insert_or_assign("type", "hg"); attrs.insert_or_assign("url", url.find("://") != std::string::npos ? url : "file://" + url); attrs.insert_or_assign("name", std::string(name)); - if (ref) attrs.insert_or_assign("ref", *ref); - if (rev) attrs.insert_or_assign("rev", rev->gitRev()); + if (ref) + attrs.insert_or_assign("ref", *ref); + if (rev) + attrs.insert_or_assign("rev", rev->gitRev()); auto input = fetchers::Input::fromAttrs(std::move(attrs)); // FIXME: use name diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 84e7f5c02ee5..aaa1dc513be0 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -34,8 +34,7 @@ void emitTreeAttrs( attrs.alloc("narHash").mkString(narHash->to_string(SRI, true)); if (input.getType() == "git") - attrs.alloc("submodules").mkBool( - fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false)); + attrs.alloc("submodules").mkBool(fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false)); if (!forceDirty) { @@ -53,13 +52,11 @@ void emitTreeAttrs( attrs.alloc("revCount").mkInt(*revCount); else if (emptyRevFallback) attrs.alloc("revCount").mkInt(0); - } if (auto lastModified = input.getLastModified()) { attrs.alloc("lastModified").mkInt(*lastModified); - attrs.alloc("lastModifiedDate").mkString( - fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S"))); + attrs.alloc("lastModifiedDate").mkString(fmt("%s", std::put_time(std::gmtime(&*lastModified), "%Y%m%d%H%M%S"))); } v.mkAttrs(attrs); @@ -83,7 +80,8 @@ std::string fixURIForGit(std::string uri, EvalState & state) return fixURI(uri, state); } -struct FetchTreeParams { +struct FetchTreeParams +{ bool emptyRevFallback = false; bool allowNameArgument = false; }; @@ -91,11 +89,11 @@ struct FetchTreeParams { static void fetchTree( EvalState & state, const PosIdx pos, - Value * * args, + Value ** args, Value & v, std::optional type, - const FetchTreeParams & params = FetchTreeParams{} -) { + const FetchTreeParams & params = FetchTreeParams{}) +{ fetchers::Input input; PathSet context; @@ -108,46 +106,40 @@ static void fetchTree( if (auto aType = args[0]->attrs->get(state.sType)) { if (type) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("unexpected attribute 'type'"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("unexpected attribute 'type'"), .errPos = state.positions[pos]})); type = state.forceStringNoCtx(*aType->value, aType->pos); } else if (!type) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("attribute 'type' is missing in call to 'fetchTree'"), + .errPos = state.positions[pos]})); attrs.emplace("type", type.value()); for (auto & attr : *args[0]->attrs) { - if (attr.name == state.sType) continue; + if (attr.name == state.sType) + continue; state.forceValue(*attr.value, attr.pos); if (attr.value->type() == nPath || attr.value->type() == nString) { auto s = state.coerceToString(attr.pos, *attr.value, context, false, false).toOwned(); - attrs.emplace(state.symbols[attr.name], - state.symbols[attr.name] == "url" - ? type == "git" - ? fixURIForGit(s, state) - : fixURI(s, state) - : s); - } - else if (attr.value->type() == nBool) + attrs.emplace( + state.symbols[attr.name], + state.symbols[attr.name] == "url" ? type == "git" ? fixURIForGit(s, state) : fixURI(s, state) : s); + } else if (attr.value->type() == nBool) attrs.emplace(state.symbols[attr.name], Explicit{attr.value->boolean}); else if (attr.value->type() == nInt) attrs.emplace(state.symbols[attr.name], uint64_t(attr.value->integer)); else - state.debugThrowLastTrace(TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", + state.debugThrowLastTrace(TypeError( + "fetchTree argument '%s' is %s while a string, Boolean or integer is expected", state.symbols[attr.name], showType(*attr.value))); } if (!params.allowNameArgument) if (auto nameIter = attrs.find("name"); nameIter != attrs.end()) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("attribute 'name' isn’t supported in call to 'fetchTree'"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("attribute 'name' isn’t supported in call to 'fetchTree'"), + .errPos = state.positions[pos]})); input = fetchers::Input::fromAttrs(std::move(attrs)); } else { @@ -167,7 +159,8 @@ static void fetchTree( input = lookupInRegistries(state.store, input).first; if (evalSettings.pureEval && !input.isLocked()) - state.debugThrowLastTrace(EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", state.positions[pos])); + state.debugThrowLastTrace( + EvalError("in pure evaluation mode, 'fetchTree' requires a locked input, at %s", state.positions[pos])); auto [tree, input2] = input.fetch(state.store); @@ -176,17 +169,23 @@ static void fetchTree( emitTreeAttrs(state, tree, input2, v, params.emptyRevFallback, false); } -static void prim_fetchTree(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fetchTree(EvalState & state, const PosIdx pos, Value ** args, Value & v) { settings.requireExperimentalFeature(Xp::Flakes); - fetchTree(state, pos, args, v, std::nullopt, FetchTreeParams { .allowNameArgument = false }); + fetchTree(state, pos, args, v, std::nullopt, FetchTreeParams{.allowNameArgument = false}); } // FIXME: document static RegisterPrimOp primop_fetchTree("fetchTree", 1, prim_fetchTree); -static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v, - const std::string & who, bool unpack, std::string name) +static void fetch( + EvalState & state, + const PosIdx pos, + Value ** args, + Value & v, + const std::string & who, + bool unpack, + std::string name) { std::optional url; std::optional expectedHash; @@ -206,17 +205,14 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v else if (n == "name") name = state.forceStringNoCtx(*attr.value, attr.pos); else - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("unsupported argument '%s' to '%s'", n, who), - .errPos = state.positions[attr.pos] - })); + state.debugThrowLastTrace(EvalError( + {.msg = hintfmt("unsupported argument '%s' to '%s'", n, who), + .errPos = state.positions[attr.pos]})); } if (!url) - state.debugThrowLastTrace(EvalError({ - .msg = hintfmt("'url' argument required"), - .errPos = state.positions[pos] - })); + state.debugThrowLastTrace( + EvalError({.msg = hintfmt("'url' argument required"), .errPos = state.positions[pos]})); } else url = state.forceStringNoCtx(*args[0], pos); @@ -233,9 +229,8 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v // early exit if pinned and already in the store if (expectedHash && expectedHash->type == htSHA256) { auto expectedPath = - unpack - ? state.store->makeFixedOutputPath(FileIngestionMethod::Recursive, *expectedHash, name, {}) - : state.store->makeFixedOutputPath(FileIngestionMethod::Flat, *expectedHash, name, {}); + unpack ? state.store->makeFixedOutputPath(FileIngestionMethod::Recursive, *expectedHash, name, {}) + : state.store->makeFixedOutputPath(FileIngestionMethod::Flat, *expectedHash, name, {}); if (state.store->isValidPath(expectedPath)) { state.allowAndSetStorePathString(expectedPath, v); @@ -245,24 +240,22 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v // TODO: fetching may fail, yet the path may be substitutable. // https://github.com/NixOS/nix/issues/4313 - auto storePath = - unpack - ? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath - : fetchers::downloadFile(state.store, *url, name, (bool) expectedHash).storePath; + auto storePath = unpack ? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).first.storePath + : fetchers::downloadFile(state.store, *url, name, (bool) expectedHash).storePath; if (expectedHash) { - auto hash = unpack - ? state.store->queryPathInfo(storePath)->narHash - : hashFile(htSHA256, state.store->toRealPath(storePath)); + auto hash = unpack ? state.store->queryPathInfo(storePath)->narHash + : hashFile(htSHA256, state.store->toRealPath(storePath)); if (hash != *expectedHash) - state.debugThrowLastTrace(EvalError((unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", + state.debugThrowLastTrace(EvalError( + (unsigned int) 102, "hash mismatch in file downloaded from '%s':\n specified: %s\n got: %s", *url, expectedHash->to_string(Base32, true), hash.to_string(Base32, true))); } state.allowAndSetStorePathString(storePath, v); } -static void prim_fetchurl(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fetchurl(EvalState & state, const PosIdx pos, Value ** args, Value & v) { fetch(state, pos, args, v, "fetchurl", false, ""); } @@ -278,7 +271,7 @@ static RegisterPrimOp primop_fetchurl({ .fun = prim_fetchurl, }); -static void prim_fetchTarball(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fetchTarball(EvalState & state, const PosIdx pos, Value ** args, Value & v) { fetch(state, pos, args, v, "fetchTarball", true, "source"); } @@ -329,9 +322,9 @@ static RegisterPrimOp primop_fetchTarball({ .fun = prim_fetchTarball, }); -static void prim_fetchGit(EvalState & state, const PosIdx pos, Value * * args, Value & v) +static void prim_fetchGit(EvalState & state, const PosIdx pos, Value ** args, Value & v) { - fetchTree(state, pos, args, v, "git", FetchTreeParams { .emptyRevFallback = true, .allowNameArgument = true }); + fetchTree(state, pos, args, v, "git", FetchTreeParams{.emptyRevFallback = true, .allowNameArgument = true}); } static RegisterPrimOp primop_fetchGit({ diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc index 9753e2ac9087..46eac08a8177 100644 --- a/src/libexpr/primops/fromTOML.cc +++ b/src/libexpr/primops/fromTOML.cc @@ -5,7 +5,7 @@ namespace nix { -static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, Value & val) +static void prim_fromTOML(EvalState & state, const PosIdx pos, Value ** args, Value & val) { auto toml = state.forceStringNoCtx(*args[0], pos); @@ -14,67 +14,68 @@ static void prim_fromTOML(EvalState & state, const PosIdx pos, Value * * args, V std::function visit; visit = [&](Value & v, toml::value t) { - - switch(t.type()) - { - case toml::value_t::table: - { - auto table = toml::get(t); - - size_t size = 0; - for (auto & i : table) { (void) i; size++; } - - auto attrs = state.buildBindings(size); - - for(auto & elem : table) - visit(attrs.alloc(elem.first), elem.second); - - v.mkAttrs(attrs); - } - break;; - case toml::value_t::array: - { - auto array = toml::get>(t); - - size_t size = array.size(); - state.mkList(v, size); - for (size_t i = 0; i < size; ++i) - visit(*(v.listElems()[i] = state.allocValue()), array[i]); - } - break;; - case toml::value_t::boolean: - v.mkBool(toml::get(t)); - break;; - case toml::value_t::integer: - v.mkInt(toml::get(t)); - break;; - case toml::value_t::floating: - v.mkFloat(toml::get(t)); - break;; - case toml::value_t::string: - v.mkString(toml::get(t)); - break;; - case toml::value_t::local_datetime: - case toml::value_t::offset_datetime: - case toml::value_t::local_date: - case toml::value_t::local_time: - // We fail since Nix doesn't have date and time types - throw std::runtime_error("Dates and times are not supported"); - break;; - case toml::value_t::empty: - v.mkNull(); - break;; - + switch (t.type()) { + case toml::value_t::table: { + auto table = toml::get(t); + + size_t size = 0; + for (auto & i : table) { + (void) i; + size++; + } + + auto attrs = state.buildBindings(size); + + for (auto & elem : table) + visit(attrs.alloc(elem.first), elem.second); + + v.mkAttrs(attrs); + } break; + ; + case toml::value_t::array: { + auto array = toml::get>(t); + + size_t size = array.size(); + state.mkList(v, size); + for (size_t i = 0; i < size; ++i) + visit(*(v.listElems()[i] = state.allocValue()), array[i]); + } break; + ; + case toml::value_t::boolean: + v.mkBool(toml::get(t)); + break; + ; + case toml::value_t::integer: + v.mkInt(toml::get(t)); + break; + ; + case toml::value_t::floating: + v.mkFloat(toml::get(t)); + break; + ; + case toml::value_t::string: + v.mkString(toml::get(t)); + break; + ; + case toml::value_t::local_datetime: + case toml::value_t::offset_datetime: + case toml::value_t::local_date: + case toml::value_t::local_time: + // We fail since Nix doesn't have date and time types + throw std::runtime_error("Dates and times are not supported"); + break; + ; + case toml::value_t::empty: + v.mkNull(); + break; + ; } }; try { visit(val, toml::parse(tomlStream, "fromTOML" /* the "filename" */)); } catch (std::exception & e) { // TODO: toml::syntax_error - throw EvalError({ - .msg = hintfmt("while parsing a TOML string: %s", e.what()), - .errPos = state.positions[pos] - }); + throw EvalError({.msg = hintfmt("while parsing a TOML string: %s", e.what()), .errPos = state.positions[pos]}); } } diff --git a/src/libexpr/symbol-table.hh b/src/libexpr/symbol-table.hh index 288c15602fe0..5f694cf011dc 100644 --- a/src/libexpr/symbol-table.hh +++ b/src/libexpr/symbol-table.hh @@ -25,25 +25,27 @@ class SymbolStr private: const std::string * s; - explicit SymbolStr(const std::string & symbol): s(&symbol) {} + explicit SymbolStr(const std::string & symbol) + : s(&symbol) + {} public: - bool operator == (std::string_view s2) const + bool operator==(std::string_view s2) const { return *s == s2; } - operator const std::string & () const + operator const std::string &() const { return *s; } - operator const std::string_view () const + operator const std::string_view() const { return *s; } - friend std::ostream & operator <<(std::ostream & os, const SymbolStr & symbol); + friend std::ostream & operator<<(std::ostream & os, const SymbolStr & symbol); }; class Symbol @@ -53,16 +55,32 @@ class Symbol private: uint32_t id; - explicit Symbol(uint32_t id): id(id) {} + explicit Symbol(uint32_t id) + : id(id) + {} public: - Symbol() : id(0) {} + Symbol() + : id(0) + {} - explicit operator bool() const { return id > 0; } + explicit operator bool() const + { + return id > 0; + } - bool operator<(const Symbol other) const { return id < other.id; } - bool operator==(const Symbol other) const { return id == other.id; } - bool operator!=(const Symbol other) const { return id != other.id; } + bool operator<(const Symbol other) const + { + return id < other.id; + } + bool operator==(const Symbol other) const + { + return id == other.id; + } + bool operator!=(const Symbol other) const + { + return id != other.id; + } }; class SymbolTable @@ -81,7 +99,8 @@ public: // on the original implementation using unordered_set // FIXME: make this thread-safe. auto it = symbols.find(s); - if (it != symbols.end()) return Symbol(it->second.second + 1); + if (it != symbols.end()) + return Symbol(it->second.second + 1); const auto & [rawSym, idx] = store.add(std::string(s)); symbols.emplace(rawSym, std::make_pair(&rawSym, idx)); diff --git a/src/libexpr/tests/json.cc b/src/libexpr/tests/json.cc index f1ea1b19785f..e8d68ae6f504 100644 --- a/src/libexpr/tests/json.cc +++ b/src/libexpr/tests/json.cc @@ -4,65 +4,75 @@ namespace nix { // Testing the conversion to JSON - class JSONValueTest : public LibExprTest { - protected: - std::string getJSONValue(Value& value) { - std::stringstream ss; - PathSet ps; - printValueAsJSON(state, true, value, noPos, ss, ps); - return ss.str(); - } - }; - - TEST_F(JSONValueTest, null) { - Value v; - v.mkNull(); - ASSERT_EQ(getJSONValue(v), "null"); +class JSONValueTest : public LibExprTest +{ +protected: + std::string getJSONValue(Value & value) + { + std::stringstream ss; + PathSet ps; + printValueAsJSON(state, true, value, noPos, ss, ps); + return ss.str(); } +}; - TEST_F(JSONValueTest, BoolFalse) { - Value v; - v.mkBool(false); - ASSERT_EQ(getJSONValue(v),"false"); - } +TEST_F(JSONValueTest, null) +{ + Value v; + v.mkNull(); + ASSERT_EQ(getJSONValue(v), "null"); +} - TEST_F(JSONValueTest, BoolTrue) { - Value v; - v.mkBool(true); - ASSERT_EQ(getJSONValue(v), "true"); - } +TEST_F(JSONValueTest, BoolFalse) +{ + Value v; + v.mkBool(false); + ASSERT_EQ(getJSONValue(v), "false"); +} - TEST_F(JSONValueTest, IntPositive) { - Value v; - v.mkInt(100); - ASSERT_EQ(getJSONValue(v), "100"); - } +TEST_F(JSONValueTest, BoolTrue) +{ + Value v; + v.mkBool(true); + ASSERT_EQ(getJSONValue(v), "true"); +} - TEST_F(JSONValueTest, IntNegative) { - Value v; - v.mkInt(-100); - ASSERT_EQ(getJSONValue(v), "-100"); - } +TEST_F(JSONValueTest, IntPositive) +{ + Value v; + v.mkInt(100); + ASSERT_EQ(getJSONValue(v), "100"); +} - TEST_F(JSONValueTest, String) { - Value v; - v.mkString("test"); - ASSERT_EQ(getJSONValue(v), "\"test\""); - } +TEST_F(JSONValueTest, IntNegative) +{ + Value v; + v.mkInt(-100); + ASSERT_EQ(getJSONValue(v), "-100"); +} - TEST_F(JSONValueTest, StringQuotes) { - Value v; +TEST_F(JSONValueTest, String) +{ + Value v; + v.mkString("test"); + ASSERT_EQ(getJSONValue(v), "\"test\""); +} - v.mkString("test\""); - ASSERT_EQ(getJSONValue(v), "\"test\\\"\""); - } +TEST_F(JSONValueTest, StringQuotes) +{ + Value v; - // The dummy store doesn't support writing files. Fails with this exception message: - // C++ exception with description "error: operation 'addToStoreFromDump' is - // not supported by store 'dummy'" thrown in the test body. - TEST_F(JSONValueTest, DISABLED_Path) { - Value v; - v.mkPath("test"); - ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\""); - } + v.mkString("test\""); + ASSERT_EQ(getJSONValue(v), "\"test\\\"\""); +} + +// The dummy store doesn't support writing files. Fails with this exception message: +// C++ exception with description "error: operation 'addToStoreFromDump' is +// not supported by store 'dummy'" thrown in the test body. +TEST_F(JSONValueTest, DISABLED_Path) +{ + Value v; + v.mkPath("test"); + ASSERT_EQ(getJSONValue(v), "\"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-x\""); +} } /* namespace nix */ diff --git a/src/libexpr/tests/libexprtests.hh b/src/libexpr/tests/libexprtests.hh index 4f6915882b93..a3a92cd86e25 100644 --- a/src/libexpr/tests/libexprtests.hh +++ b/src/libexpr/tests/libexprtests.hh @@ -7,130 +7,144 @@ #include "eval-inline.hh" #include "store-api.hh" - namespace nix { - class LibExprTest : public ::testing::Test { - public: - static void SetUpTestSuite() { - initGC(); - } - - protected: - LibExprTest() - : store(openStore("dummy://")) - , state({}, store) - { - } - Value eval(std::string input, bool forceValue = true) { - Value v; - Expr * e = state.parseExprFromString(input, ""); - assert(e); - state.eval(e, v); - if (forceValue) - state.forceValue(v, noPos); - return v; - } - - Symbol createSymbol(const char * value) { - return state.symbols.create(value); - } - - ref store; - EvalState state; - }; - - MATCHER(IsListType, "") { - return arg != nList; - } - - MATCHER(IsList, "") { - return arg.type() == nList; - } - - MATCHER(IsString, "") { - return arg.type() == nString; - } - - MATCHER(IsNull, "") { - return arg.type() == nNull; +class LibExprTest : public ::testing::Test +{ +public: + static void SetUpTestSuite() + { + initGC(); } - MATCHER(IsThunk, "") { - return arg.type() == nThunk; +protected: + LibExprTest() + : store(openStore("dummy://")) + , state({}, store) + {} + Value eval(std::string input, bool forceValue = true) + { + Value v; + Expr * e = state.parseExprFromString(input, ""); + assert(e); + state.eval(e, v); + if (forceValue) + state.forceValue(v, noPos); + return v; } - MATCHER(IsAttrs, "") { - return arg.type() == nAttrs; + Symbol createSymbol(const char * value) + { + return state.symbols.create(value); } - MATCHER_P(IsStringEq, s, fmt("The string is equal to \"%1%\"", s)) { - if (arg.type() != nString) { - return false; - } - return std::string_view(arg.string.s) == s; + ref store; + EvalState state; +}; + +MATCHER(IsListType, "") +{ + return arg != nList; +} + +MATCHER(IsList, "") +{ + return arg.type() == nList; +} + +MATCHER(IsString, "") +{ + return arg.type() == nString; +} + +MATCHER(IsNull, "") +{ + return arg.type() == nNull; +} + +MATCHER(IsThunk, "") +{ + return arg.type() == nThunk; +} + +MATCHER(IsAttrs, "") +{ + return arg.type() == nAttrs; +} + +MATCHER_P(IsStringEq, s, fmt("The string is equal to \"%1%\"", s)) +{ + if (arg.type() != nString) { + return false; } + return std::string_view(arg.string.s) == s; +} - MATCHER_P(IsIntEq, v, fmt("The string is equal to \"%1%\"", v)) { - if (arg.type() != nInt) { - return false; - } - return arg.integer == v; +MATCHER_P(IsIntEq, v, fmt("The string is equal to \"%1%\"", v)) +{ + if (arg.type() != nInt) { + return false; } + return arg.integer == v; +} - MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v)) { - if (arg.type() != nFloat) { - return false; - } - return arg.fpoint == v; +MATCHER_P(IsFloatEq, v, fmt("The float is equal to \"%1%\"", v)) +{ + if (arg.type() != nFloat) { + return false; } + return arg.fpoint == v; +} - MATCHER(IsTrue, "") { - if (arg.type() != nBool) { - return false; - } - return arg.boolean == true; +MATCHER(IsTrue, "") +{ + if (arg.type() != nBool) { + return false; } + return arg.boolean == true; +} - MATCHER(IsFalse, "") { - if (arg.type() != nBool) { - return false; - } - return arg.boolean == false; +MATCHER(IsFalse, "") +{ + if (arg.type() != nBool) { + return false; } - - MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) { - if (arg.type() != nPath) { - *result_listener << "Expected a path got " << arg.type(); - return false; - } else if (std::string_view(arg.string.s) != p) { - *result_listener << "Expected a path that equals \"" << p << "\" but got: " << arg.string.s; - return false; - } - return true; + return arg.boolean == false; +} + +MATCHER_P(IsPathEq, p, fmt("Is a path equal to \"%1%\"", p)) +{ + if (arg.type() != nPath) { + *result_listener << "Expected a path got " << arg.type(); + return false; + } else if (std::string_view(arg.string.s) != p) { + *result_listener << "Expected a path that equals \"" << p << "\" but got: " << arg.string.s; + return false; } - - - MATCHER_P(IsListOfSize, n, fmt("Is a list of size [%1%]", n)) { - if (arg.type() != nList) { - *result_listener << "Expected list got " << arg.type(); - return false; - } else if (arg.listSize() != (size_t)n) { - *result_listener << "Expected as list of size " << n << " got " << arg.listSize(); - return false; - } - return true; + return true; +} + +MATCHER_P(IsListOfSize, n, fmt("Is a list of size [%1%]", n)) +{ + if (arg.type() != nList) { + *result_listener << "Expected list got " << arg.type(); + return false; + } else if (arg.listSize() != (size_t) n) { + *result_listener << "Expected as list of size " << n << " got " << arg.listSize(); + return false; } - - MATCHER_P(IsAttrsOfSize, n, fmt("Is a set of size [%1%]", n)) { - if (arg.type() != nAttrs) { - *result_listener << "Expexted set got " << arg.type(); - return false; - } else if (arg.attrs->size() != (size_t)n) { - *result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs->size(); - return false; - } - return true; + return true; +} + +MATCHER_P(IsAttrsOfSize, n, fmt("Is a set of size [%1%]", n)) +{ + if (arg.type() != nAttrs) { + *result_listener << "Expexted set got " << arg.type(); + return false; + } else if (arg.attrs->size() != (size_t) n) { + *result_listener << "Expected a set with " << n << " attributes but got " << arg.attrs->size(); + return false; } - + return true; +} } /* namespace nix */ diff --git a/src/libexpr/tests/primops.cc b/src/libexpr/tests/primops.cc index f65b6593d07b..618c660798f6 100644 --- a/src/libexpr/tests/primops.cc +++ b/src/libexpr/tests/primops.cc @@ -4,836 +4,953 @@ #include "libexprtests.hh" namespace nix { - class CaptureLogger : public Logger - { - std::ostringstream oss; - - public: - CaptureLogger() {} - - std::string get() const { - return oss.str(); - } - - void log(Verbosity lvl, const FormatOrString & fs) override { - oss << fs.s << std::endl; - } - - void logEI(const ErrorInfo & ei) override { - showErrorInfo(oss, ei, loggerSettings.showTrace.get()); - } - }; - - class CaptureLogging { - Logger * oldLogger; - std::unique_ptr tempLogger; - public: - CaptureLogging() : tempLogger(std::make_unique()) { - oldLogger = logger; - logger = tempLogger.get(); - } - - ~CaptureLogging() { - logger = oldLogger; - } - - std::string get() const { - return tempLogger->get(); - } - }; - - - // Testing eval of PrimOp's - class PrimOpTest : public LibExprTest {}; - - - TEST_F(PrimOpTest, throw) { - ASSERT_THROW(eval("throw \"foo\""), ThrownError); - } - - TEST_F(PrimOpTest, abort) { - ASSERT_THROW(eval("abort \"abort\""), Abort); - } - - TEST_F(PrimOpTest, ceil) { - auto v = eval("builtins.ceil 1.9"); - ASSERT_THAT(v, IsIntEq(2)); - } - - TEST_F(PrimOpTest, floor) { - auto v = eval("builtins.floor 1.9"); - ASSERT_THAT(v, IsIntEq(1)); - } - - TEST_F(PrimOpTest, tryEvalFailure) { - auto v = eval("builtins.tryEval (throw \"\")"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - auto s = createSymbol("success"); - auto p = v.attrs->get(s); - ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsFalse()); - } - - TEST_F(PrimOpTest, tryEvalSuccess) { - auto v = eval("builtins.tryEval 123"); - ASSERT_THAT(v, IsAttrs()); - auto s = createSymbol("success"); - auto p = v.attrs->get(s); - ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsTrue()); - s = createSymbol("value"); - p = v.attrs->get(s); - ASSERT_NE(p, nullptr); - ASSERT_THAT(*p->value, IsIntEq(123)); - } - - TEST_F(PrimOpTest, getEnv) { - setenv("_NIX_UNIT_TEST_ENV_VALUE", "test value", 1); - auto v = eval("builtins.getEnv \"_NIX_UNIT_TEST_ENV_VALUE\""); - ASSERT_THAT(v, IsStringEq("test value")); - } - - TEST_F(PrimOpTest, seq) { - ASSERT_THROW(eval("let x = throw \"test\"; in builtins.seq x { }"), ThrownError); - } - - TEST_F(PrimOpTest, seqNotDeep) { - auto v = eval("let x = { z = throw \"test\"; }; in builtins.seq x { }"); - ASSERT_THAT(v, IsAttrs()); - } - - TEST_F(PrimOpTest, deepSeq) { - ASSERT_THROW(eval("let x = { z = throw \"test\"; }; in builtins.deepSeq x { }"), ThrownError); - } - - TEST_F(PrimOpTest, trace) { - CaptureLogging l; - auto v = eval("builtins.trace \"test string 123\" 123"); - ASSERT_THAT(v, IsIntEq(123)); - auto text = l.get(); - ASSERT_NE(text.find("test string 123"), std::string::npos); - } - - TEST_F(PrimOpTest, placeholder) { - auto v = eval("builtins.placeholder \"out\""); - ASSERT_THAT(v, IsStringEq("/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")); - } - - TEST_F(PrimOpTest, baseNameOf) { - auto v = eval("builtins.baseNameOf /some/path"); - ASSERT_THAT(v, IsStringEq("path")); - } - - TEST_F(PrimOpTest, dirOf) { - auto v = eval("builtins.dirOf /some/path"); - ASSERT_THAT(v, IsPathEq("/some")); - } - - TEST_F(PrimOpTest, attrValues) { - auto v = eval("builtins.attrValues { x = \"foo\"; a = 1; }"); - ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); - ASSERT_THAT(*v.listElems()[1], IsStringEq("foo")); - } - - TEST_F(PrimOpTest, getAttr) { - auto v = eval("builtins.getAttr \"x\" { x = \"foo\"; }"); - ASSERT_THAT(v, IsStringEq("foo")); - } - - TEST_F(PrimOpTest, getAttrNotFound) { - // FIXME: TypeError is really bad here, also the error wording is worse - // than on Nix <=2.3 - ASSERT_THROW(eval("builtins.getAttr \"y\" { }"), TypeError); - } - - TEST_F(PrimOpTest, unsafeGetAttrPos) { - // The `y` attribute is at position - const char* expr = "builtins.unsafeGetAttrPos \"y\" { y = \"x\"; }"; - auto v = eval(expr); - ASSERT_THAT(v, IsAttrsOfSize(3)); - - auto file = v.attrs->find(createSymbol("file")); - ASSERT_NE(file, nullptr); - // FIXME: The file when running these tests is the input string?!? - ASSERT_THAT(*file->value, IsStringEq(expr)); - - auto line = v.attrs->find(createSymbol("line")); - ASSERT_NE(line, nullptr); - ASSERT_THAT(*line->value, IsIntEq(1)); - - auto column = v.attrs->find(createSymbol("column")); - ASSERT_NE(column, nullptr); - ASSERT_THAT(*column->value, IsIntEq(33)); - } - - TEST_F(PrimOpTest, hasAttr) { - auto v = eval("builtins.hasAttr \"x\" { x = 1; }"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, hasAttrNotFound) { - auto v = eval("builtins.hasAttr \"x\" { }"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, isAttrs) { - auto v = eval("builtins.isAttrs {}"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, isAttrsFalse) { - auto v = eval("builtins.isAttrs null"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, removeAttrs) { - auto v = eval("builtins.removeAttrs { x = 1; } [\"x\"]"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(PrimOpTest, removeAttrsRetains) { - auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - ASSERT_NE(v.attrs->find(createSymbol("y")), nullptr); - } - - TEST_F(PrimOpTest, listToAttrsEmptyList) { - auto v = eval("builtins.listToAttrs []"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - ASSERT_EQ(v.type(), nAttrs); - ASSERT_EQ(v.attrs->size(), 0); - } - - TEST_F(PrimOpTest, listToAttrsNotFieldName) { - ASSERT_THROW(eval("builtins.listToAttrs [{}]"), Error); - } - - TEST_F(PrimOpTest, listToAttrs) { - auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - auto key = v.attrs->find(createSymbol("key")); - ASSERT_NE(key, nullptr); - ASSERT_THAT(*key->value, IsIntEq(123)); - } - - TEST_F(PrimOpTest, intersectAttrs) { - auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - auto b = v.attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(3)); - } - - TEST_F(PrimOpTest, catAttrs) { - auto v = eval("builtins.catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]"); - ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); - ASSERT_THAT(*v.listElems()[1], IsIntEq(2)); - } - - TEST_F(PrimOpTest, functionArgs) { - auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto x = v.attrs->find(createSymbol("x")); - ASSERT_NE(x, nullptr); - ASSERT_THAT(*x->value, IsFalse()); - - auto y = v.attrs->find(createSymbol("y")); - ASSERT_NE(y, nullptr); - ASSERT_THAT(*y->value, IsTrue()); - } - - TEST_F(PrimOpTest, mapAttrs) { - auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto a = v.attrs->find(createSymbol("a")); - ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsThunk()); - state.forceValue(*a->value, noPos); - ASSERT_THAT(*a->value, IsIntEq(10)); - - auto b = v.attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsThunk()); - state.forceValue(*b->value, noPos); - ASSERT_THAT(*b->value, IsIntEq(20)); - } - - TEST_F(PrimOpTest, isList) { - auto v = eval("builtins.isList []"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, isListFalse) { - auto v = eval("builtins.isList null"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, elemtAt) { - auto v = eval("builtins.elemAt [0 1 2 3] 3"); - ASSERT_THAT(v, IsIntEq(3)); - } +class CaptureLogger : public Logger +{ + std::ostringstream oss; - TEST_F(PrimOpTest, elemtAtOutOfBounds) { - ASSERT_THROW(eval("builtins.elemAt [0 1 2 3] 5"), Error); - } +public: + CaptureLogger() {} - TEST_F(PrimOpTest, head) { - auto v = eval("builtins.head [ 3 2 1 0 ]"); - ASSERT_THAT(v, IsIntEq(3)); + std::string get() const + { + return oss.str(); } - TEST_F(PrimOpTest, headEmpty) { - ASSERT_THROW(eval("builtins.head [ ]"), Error); + void log(Verbosity lvl, const FormatOrString & fs) override + { + oss << fs.s << std::endl; } - TEST_F(PrimOpTest, headWrongType) { - ASSERT_THROW(eval("builtins.head { }"), Error); + void logEI(const ErrorInfo & ei) override + { + showErrorInfo(oss, ei, loggerSettings.showTrace.get()); } +}; - TEST_F(PrimOpTest, tail) { - auto v = eval("builtins.tail [ 3 2 1 0 ]"); - ASSERT_THAT(v, IsListOfSize(3)); - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(2 - static_cast(n))); +class CaptureLogging +{ + Logger * oldLogger; + std::unique_ptr tempLogger; +public: + CaptureLogging() + : tempLogger(std::make_unique()) + { + oldLogger = logger; + logger = tempLogger.get(); } - TEST_F(PrimOpTest, tailEmpty) { - ASSERT_THROW(eval("builtins.tail []"), Error); + ~CaptureLogging() + { + logger = oldLogger; } - TEST_F(PrimOpTest, map) { - auto v = eval("map (x: \"foo\" + x) [ \"bar\" \"bla\" \"abc\" ]"); - ASSERT_THAT(v, IsListOfSize(3)); - auto elem = v.listElems()[0]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("foobar")); - - elem = v.listElems()[1]; - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("foobla")); - - elem = v.listElems()[2]; + std::string get() const + { + return tempLogger->get(); + } +}; + +// Testing eval of PrimOp's +class PrimOpTest : public LibExprTest +{}; + +TEST_F(PrimOpTest, throw) +{ + ASSERT_THROW(eval("throw \"foo\""), ThrownError); +} + +TEST_F(PrimOpTest, abort) +{ + ASSERT_THROW(eval("abort \"abort\""), Abort); +} + +TEST_F(PrimOpTest, ceil) +{ + auto v = eval("builtins.ceil 1.9"); + ASSERT_THAT(v, IsIntEq(2)); +} + +TEST_F(PrimOpTest, floor) +{ + auto v = eval("builtins.floor 1.9"); + ASSERT_THAT(v, IsIntEq(1)); +} + +TEST_F(PrimOpTest, tryEvalFailure) +{ + auto v = eval("builtins.tryEval (throw \"\")"); + ASSERT_THAT(v, IsAttrsOfSize(2)); + auto s = createSymbol("success"); + auto p = v.attrs->get(s); + ASSERT_NE(p, nullptr); + ASSERT_THAT(*p->value, IsFalse()); +} + +TEST_F(PrimOpTest, tryEvalSuccess) +{ + auto v = eval("builtins.tryEval 123"); + ASSERT_THAT(v, IsAttrs()); + auto s = createSymbol("success"); + auto p = v.attrs->get(s); + ASSERT_NE(p, nullptr); + ASSERT_THAT(*p->value, IsTrue()); + s = createSymbol("value"); + p = v.attrs->get(s); + ASSERT_NE(p, nullptr); + ASSERT_THAT(*p->value, IsIntEq(123)); +} + +TEST_F(PrimOpTest, getEnv) +{ + setenv("_NIX_UNIT_TEST_ENV_VALUE", "test value", 1); + auto v = eval("builtins.getEnv \"_NIX_UNIT_TEST_ENV_VALUE\""); + ASSERT_THAT(v, IsStringEq("test value")); +} + +TEST_F(PrimOpTest, seq) +{ + ASSERT_THROW(eval("let x = throw \"test\"; in builtins.seq x { }"), ThrownError); +} + +TEST_F(PrimOpTest, seqNotDeep) +{ + auto v = eval("let x = { z = throw \"test\"; }; in builtins.seq x { }"); + ASSERT_THAT(v, IsAttrs()); +} + +TEST_F(PrimOpTest, deepSeq) +{ + ASSERT_THROW(eval("let x = { z = throw \"test\"; }; in builtins.deepSeq x { }"), ThrownError); +} + +TEST_F(PrimOpTest, trace) +{ + CaptureLogging l; + auto v = eval("builtins.trace \"test string 123\" 123"); + ASSERT_THAT(v, IsIntEq(123)); + auto text = l.get(); + ASSERT_NE(text.find("test string 123"), std::string::npos); +} + +TEST_F(PrimOpTest, placeholder) +{ + auto v = eval("builtins.placeholder \"out\""); + ASSERT_THAT(v, IsStringEq("/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9")); +} + +TEST_F(PrimOpTest, baseNameOf) +{ + auto v = eval("builtins.baseNameOf /some/path"); + ASSERT_THAT(v, IsStringEq("path")); +} + +TEST_F(PrimOpTest, dirOf) +{ + auto v = eval("builtins.dirOf /some/path"); + ASSERT_THAT(v, IsPathEq("/some")); +} + +TEST_F(PrimOpTest, attrValues) +{ + auto v = eval("builtins.attrValues { x = \"foo\"; a = 1; }"); + ASSERT_THAT(v, IsListOfSize(2)); + ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); + ASSERT_THAT(*v.listElems()[1], IsStringEq("foo")); +} + +TEST_F(PrimOpTest, getAttr) +{ + auto v = eval("builtins.getAttr \"x\" { x = \"foo\"; }"); + ASSERT_THAT(v, IsStringEq("foo")); +} + +TEST_F(PrimOpTest, getAttrNotFound) +{ + // FIXME: TypeError is really bad here, also the error wording is worse + // than on Nix <=2.3 + ASSERT_THROW(eval("builtins.getAttr \"y\" { }"), TypeError); +} + +TEST_F(PrimOpTest, unsafeGetAttrPos) +{ + // The `y` attribute is at position + const char * expr = "builtins.unsafeGetAttrPos \"y\" { y = \"x\"; }"; + auto v = eval(expr); + ASSERT_THAT(v, IsAttrsOfSize(3)); + + auto file = v.attrs->find(createSymbol("file")); + ASSERT_NE(file, nullptr); + // FIXME: The file when running these tests is the input string?!? + ASSERT_THAT(*file->value, IsStringEq(expr)); + + auto line = v.attrs->find(createSymbol("line")); + ASSERT_NE(line, nullptr); + ASSERT_THAT(*line->value, IsIntEq(1)); + + auto column = v.attrs->find(createSymbol("column")); + ASSERT_NE(column, nullptr); + ASSERT_THAT(*column->value, IsIntEq(33)); +} + +TEST_F(PrimOpTest, hasAttr) +{ + auto v = eval("builtins.hasAttr \"x\" { x = 1; }"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, hasAttrNotFound) +{ + auto v = eval("builtins.hasAttr \"x\" { }"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, isAttrs) +{ + auto v = eval("builtins.isAttrs {}"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, isAttrsFalse) +{ + auto v = eval("builtins.isAttrs null"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, removeAttrs) +{ + auto v = eval("builtins.removeAttrs { x = 1; } [\"x\"]"); + ASSERT_THAT(v, IsAttrsOfSize(0)); +} + +TEST_F(PrimOpTest, removeAttrsRetains) +{ + auto v = eval("builtins.removeAttrs { x = 1; y = 2; } [\"x\"]"); + ASSERT_THAT(v, IsAttrsOfSize(1)); + ASSERT_NE(v.attrs->find(createSymbol("y")), nullptr); +} + +TEST_F(PrimOpTest, listToAttrsEmptyList) +{ + auto v = eval("builtins.listToAttrs []"); + ASSERT_THAT(v, IsAttrsOfSize(0)); + ASSERT_EQ(v.type(), nAttrs); + ASSERT_EQ(v.attrs->size(), 0); +} + +TEST_F(PrimOpTest, listToAttrsNotFieldName) +{ + ASSERT_THROW(eval("builtins.listToAttrs [{}]"), Error); +} + +TEST_F(PrimOpTest, listToAttrs) +{ + auto v = eval("builtins.listToAttrs [ { name = \"key\"; value = 123; } ]"); + ASSERT_THAT(v, IsAttrsOfSize(1)); + auto key = v.attrs->find(createSymbol("key")); + ASSERT_NE(key, nullptr); + ASSERT_THAT(*key->value, IsIntEq(123)); +} + +TEST_F(PrimOpTest, intersectAttrs) +{ + auto v = eval("builtins.intersectAttrs { a = 1; b = 2; } { b = 3; c = 4; }"); + ASSERT_THAT(v, IsAttrsOfSize(1)); + auto b = v.attrs->find(createSymbol("b")); + ASSERT_NE(b, nullptr); + ASSERT_THAT(*b->value, IsIntEq(3)); +} + +TEST_F(PrimOpTest, catAttrs) +{ + auto v = eval("builtins.catAttrs \"a\" [{a = 1;} {b = 0;} {a = 2;}]"); + ASSERT_THAT(v, IsListOfSize(2)); + ASSERT_THAT(*v.listElems()[0], IsIntEq(1)); + ASSERT_THAT(*v.listElems()[1], IsIntEq(2)); +} + +TEST_F(PrimOpTest, functionArgs) +{ + auto v = eval("builtins.functionArgs ({ x, y ? 123}: 1)"); + ASSERT_THAT(v, IsAttrsOfSize(2)); + + auto x = v.attrs->find(createSymbol("x")); + ASSERT_NE(x, nullptr); + ASSERT_THAT(*x->value, IsFalse()); + + auto y = v.attrs->find(createSymbol("y")); + ASSERT_NE(y, nullptr); + ASSERT_THAT(*y->value, IsTrue()); +} + +TEST_F(PrimOpTest, mapAttrs) +{ + auto v = eval("builtins.mapAttrs (name: value: value * 10) { a = 1; b = 2; }"); + ASSERT_THAT(v, IsAttrsOfSize(2)); + + auto a = v.attrs->find(createSymbol("a")); + ASSERT_NE(a, nullptr); + ASSERT_THAT(*a->value, IsThunk()); + state.forceValue(*a->value, noPos); + ASSERT_THAT(*a->value, IsIntEq(10)); + + auto b = v.attrs->find(createSymbol("b")); + ASSERT_NE(b, nullptr); + ASSERT_THAT(*b->value, IsThunk()); + state.forceValue(*b->value, noPos); + ASSERT_THAT(*b->value, IsIntEq(20)); +} + +TEST_F(PrimOpTest, isList) +{ + auto v = eval("builtins.isList []"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, isListFalse) +{ + auto v = eval("builtins.isList null"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, elemtAt) +{ + auto v = eval("builtins.elemAt [0 1 2 3] 3"); + ASSERT_THAT(v, IsIntEq(3)); +} + +TEST_F(PrimOpTest, elemtAtOutOfBounds) +{ + ASSERT_THROW(eval("builtins.elemAt [0 1 2 3] 5"), Error); +} + +TEST_F(PrimOpTest, head) +{ + auto v = eval("builtins.head [ 3 2 1 0 ]"); + ASSERT_THAT(v, IsIntEq(3)); +} + +TEST_F(PrimOpTest, headEmpty) +{ + ASSERT_THROW(eval("builtins.head [ ]"), Error); +} + +TEST_F(PrimOpTest, headWrongType) +{ + ASSERT_THROW(eval("builtins.head { }"), Error); +} + +TEST_F(PrimOpTest, tail) +{ + auto v = eval("builtins.tail [ 3 2 1 0 ]"); + ASSERT_THAT(v, IsListOfSize(3)); + for (const auto [n, elem] : enumerate(v.listItems())) + ASSERT_THAT(*elem, IsIntEq(2 - static_cast(n))); +} + +TEST_F(PrimOpTest, tailEmpty) +{ + ASSERT_THROW(eval("builtins.tail []"), Error); +} + +TEST_F(PrimOpTest, map) +{ + auto v = eval("map (x: \"foo\" + x) [ \"bar\" \"bla\" \"abc\" ]"); + ASSERT_THAT(v, IsListOfSize(3)); + auto elem = v.listElems()[0]; + ASSERT_THAT(*elem, IsThunk()); + state.forceValue(*elem, noPos); + ASSERT_THAT(*elem, IsStringEq("foobar")); + + elem = v.listElems()[1]; + ASSERT_THAT(*elem, IsThunk()); + state.forceValue(*elem, noPos); + ASSERT_THAT(*elem, IsStringEq("foobla")); + + elem = v.listElems()[2]; + ASSERT_THAT(*elem, IsThunk()); + state.forceValue(*elem, noPos); + ASSERT_THAT(*elem, IsStringEq("fooabc")); +} + +TEST_F(PrimOpTest, filter) +{ + auto v = eval("builtins.filter (x: x == 2) [ 3 2 3 2 3 2 ]"); + ASSERT_THAT(v, IsListOfSize(3)); + for (const auto elem : v.listItems()) + ASSERT_THAT(*elem, IsIntEq(2)); +} + +TEST_F(PrimOpTest, elemTrue) +{ + auto v = eval("builtins.elem 3 [ 1 2 3 4 5 ]"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, elemFalse) +{ + auto v = eval("builtins.elem 6 [ 1 2 3 4 5 ]"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, concatLists) +{ + auto v = eval("builtins.concatLists [[1 2] [3 4]]"); + ASSERT_THAT(v, IsListOfSize(4)); + for (const auto [i, elem] : enumerate(v.listItems())) + ASSERT_THAT(*elem, IsIntEq(static_cast(i) + 1)); +} + +TEST_F(PrimOpTest, length) +{ + auto v = eval("builtins.length [ 1 2 3 ]"); + ASSERT_THAT(v, IsIntEq(3)); +} + +TEST_F(PrimOpTest, foldStrict) +{ + auto v = eval("builtins.foldl' (a: b: a + b) 0 [1 2 3]"); + ASSERT_THAT(v, IsIntEq(6)); +} + +TEST_F(PrimOpTest, anyTrue) +{ + auto v = eval("builtins.any (x: x == 2) [ 1 2 3 ]"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, anyFalse) +{ + auto v = eval("builtins.any (x: x == 5) [ 1 2 3 ]"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, allTrue) +{ + auto v = eval("builtins.all (x: x > 0) [ 1 2 3 ]"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, allFalse) +{ + auto v = eval("builtins.all (x: x <= 0) [ 1 2 3 ]"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, genList) +{ + auto v = eval("builtins.genList (x: x + 1) 3"); + ASSERT_EQ(v.type(), nList); + ASSERT_EQ(v.listSize(), 3); + for (const auto [i, elem] : enumerate(v.listItems())) { ASSERT_THAT(*elem, IsThunk()); state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsStringEq("fooabc")); - } - - TEST_F(PrimOpTest, filter) { - auto v = eval("builtins.filter (x: x == 2) [ 3 2 3 2 3 2 ]"); - ASSERT_THAT(v, IsListOfSize(3)); - for (const auto elem : v.listItems()) - ASSERT_THAT(*elem, IsIntEq(2)); - } - - TEST_F(PrimOpTest, elemTrue) { - auto v = eval("builtins.elem 3 [ 1 2 3 4 5 ]"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, elemFalse) { - auto v = eval("builtins.elem 6 [ 1 2 3 4 5 ]"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, concatLists) { - auto v = eval("builtins.concatLists [[1 2] [3 4]]"); - ASSERT_THAT(v, IsListOfSize(4)); - for (const auto [i, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(static_cast(i)+1)); - } - - TEST_F(PrimOpTest, length) { - auto v = eval("builtins.length [ 1 2 3 ]"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, foldStrict) { - auto v = eval("builtins.foldl' (a: b: a + b) 0 [1 2 3]"); - ASSERT_THAT(v, IsIntEq(6)); - } - - TEST_F(PrimOpTest, anyTrue) { - auto v = eval("builtins.any (x: x == 2) [ 1 2 3 ]"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, anyFalse) { - auto v = eval("builtins.any (x: x == 5) [ 1 2 3 ]"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, allTrue) { - auto v = eval("builtins.all (x: x > 0) [ 1 2 3 ]"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, allFalse) { - auto v = eval("builtins.all (x: x <= 0) [ 1 2 3 ]"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, genList) { - auto v = eval("builtins.genList (x: x + 1) 3"); - ASSERT_EQ(v.type(), nList); - ASSERT_EQ(v.listSize(), 3); - for (const auto [i, elem] : enumerate(v.listItems())) { - ASSERT_THAT(*elem, IsThunk()); - state.forceValue(*elem, noPos); - ASSERT_THAT(*elem, IsIntEq(static_cast(i)+1)); - } - } - - TEST_F(PrimOpTest, sortLessThan) { - auto v = eval("builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]"); - ASSERT_EQ(v.type(), nList); - ASSERT_EQ(v.listSize(), 6); - - const std::vector numbers = { 42, 77, 147, 249, 483, 526 }; - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(numbers[n])); - } - - TEST_F(PrimOpTest, partition) { - auto v = eval("builtins.partition (x: x > 10) [1 23 9 3 42]"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto right = v.attrs->get(createSymbol("right")); - ASSERT_NE(right, nullptr); - ASSERT_THAT(*right->value, IsListOfSize(2)); - ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23)); - ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42)); - - auto wrong = v.attrs->get(createSymbol("wrong")); - ASSERT_NE(wrong, nullptr); - ASSERT_EQ(wrong->value->type(), nList); - ASSERT_EQ(wrong->value->listSize(), 3); - ASSERT_THAT(*wrong->value, IsListOfSize(3)); - ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1)); - ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9)); - ASSERT_THAT(*wrong->value->listElems()[2], IsIntEq(3)); - } - - TEST_F(PrimOpTest, concatMap) { - auto v = eval("builtins.concatMap (x: x ++ [0]) [ [1 2] [3 4] ]"); - ASSERT_EQ(v.type(), nList); - ASSERT_EQ(v.listSize(), 6); - - const std::vector numbers = { 1, 2, 0, 3, 4, 0 }; - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsIntEq(numbers[n])); - } - - TEST_F(PrimOpTest, addInt) { - auto v = eval("builtins.add 3 5"); - ASSERT_THAT(v, IsIntEq(8)); - } - - TEST_F(PrimOpTest, addFloat) { - auto v = eval("builtins.add 3.0 5.0"); - ASSERT_THAT(v, IsFloatEq(8.0)); - } - - TEST_F(PrimOpTest, addFloatToInt) { - auto v = eval("builtins.add 3.0 5"); - ASSERT_THAT(v, IsFloatEq(8.0)); - - v = eval("builtins.add 3 5.0"); - ASSERT_THAT(v, IsFloatEq(8.0)); - } - - TEST_F(PrimOpTest, subInt) { - auto v = eval("builtins.sub 5 2"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, subFloat) { - auto v = eval("builtins.sub 5.0 2.0"); - ASSERT_THAT(v, IsFloatEq(3.0)); - } - - TEST_F(PrimOpTest, subFloatFromInt) { - auto v = eval("builtins.sub 5.0 2"); - ASSERT_THAT(v, IsFloatEq(3.0)); - - v = eval("builtins.sub 4 2.0"); - ASSERT_THAT(v, IsFloatEq(2.0)); - } - - TEST_F(PrimOpTest, mulInt) { - auto v = eval("builtins.mul 3 5"); - ASSERT_THAT(v, IsIntEq(15)); - } - - TEST_F(PrimOpTest, mulFloat) { - auto v = eval("builtins.mul 3.0 5.0"); - ASSERT_THAT(v, IsFloatEq(15.0)); - } - - TEST_F(PrimOpTest, mulFloatMixed) { - auto v = eval("builtins.mul 3 5.0"); - ASSERT_THAT(v, IsFloatEq(15.0)); - - v = eval("builtins.mul 2.0 5"); - ASSERT_THAT(v, IsFloatEq(10.0)); - } - - TEST_F(PrimOpTest, divInt) { - auto v = eval("builtins.div 5 (-1)"); - ASSERT_THAT(v, IsIntEq(-5)); - } - - TEST_F(PrimOpTest, divIntZero) { - ASSERT_THROW(eval("builtins.div 5 0"), EvalError); - } - - TEST_F(PrimOpTest, divFloat) { - auto v = eval("builtins.div 5.0 (-1)"); - ASSERT_THAT(v, IsFloatEq(-5.0)); - } - - TEST_F(PrimOpTest, divFloatZero) { - ASSERT_THROW(eval("builtins.div 5.0 0.0"), EvalError); - } - - TEST_F(PrimOpTest, bitOr) { - auto v = eval("builtins.bitOr 1 2"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(PrimOpTest, bitXor) { - auto v = eval("builtins.bitXor 3 2"); - ASSERT_THAT(v, IsIntEq(1)); - } - - TEST_F(PrimOpTest, lessThanFalse) { - auto v = eval("builtins.lessThan 3 1"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(PrimOpTest, lessThanTrue) { - auto v = eval("builtins.lessThan 1 3"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(PrimOpTest, toStringAttrsThrows) { - ASSERT_THROW(eval("builtins.toString {}"), EvalError); - } - - TEST_F(PrimOpTest, toStringLambdaThrows) { - ASSERT_THROW(eval("builtins.toString (x: x)"), EvalError); - } - - class ToStringPrimOpTest : - public PrimOpTest, - public testing::WithParamInterface> - {}; - - TEST_P(ToStringPrimOpTest, toString) { - const auto [input, output] = GetParam(); - auto v = eval(input); - ASSERT_THAT(v, IsStringEq(output)); - } + ASSERT_THAT(*elem, IsIntEq(static_cast(i) + 1)); + } +} + +TEST_F(PrimOpTest, sortLessThan) +{ + auto v = eval("builtins.sort builtins.lessThan [ 483 249 526 147 42 77 ]"); + ASSERT_EQ(v.type(), nList); + ASSERT_EQ(v.listSize(), 6); + + const std::vector numbers = {42, 77, 147, 249, 483, 526}; + for (const auto [n, elem] : enumerate(v.listItems())) + ASSERT_THAT(*elem, IsIntEq(numbers[n])); +} + +TEST_F(PrimOpTest, partition) +{ + auto v = eval("builtins.partition (x: x > 10) [1 23 9 3 42]"); + ASSERT_THAT(v, IsAttrsOfSize(2)); + + auto right = v.attrs->get(createSymbol("right")); + ASSERT_NE(right, nullptr); + ASSERT_THAT(*right->value, IsListOfSize(2)); + ASSERT_THAT(*right->value->listElems()[0], IsIntEq(23)); + ASSERT_THAT(*right->value->listElems()[1], IsIntEq(42)); + + auto wrong = v.attrs->get(createSymbol("wrong")); + ASSERT_NE(wrong, nullptr); + ASSERT_EQ(wrong->value->type(), nList); + ASSERT_EQ(wrong->value->listSize(), 3); + ASSERT_THAT(*wrong->value, IsListOfSize(3)); + ASSERT_THAT(*wrong->value->listElems()[0], IsIntEq(1)); + ASSERT_THAT(*wrong->value->listElems()[1], IsIntEq(9)); + ASSERT_THAT(*wrong->value->listElems()[2], IsIntEq(3)); +} + +TEST_F(PrimOpTest, concatMap) +{ + auto v = eval("builtins.concatMap (x: x ++ [0]) [ [1 2] [3 4] ]"); + ASSERT_EQ(v.type(), nList); + ASSERT_EQ(v.listSize(), 6); + + const std::vector numbers = {1, 2, 0, 3, 4, 0}; + for (const auto [n, elem] : enumerate(v.listItems())) + ASSERT_THAT(*elem, IsIntEq(numbers[n])); +} + +TEST_F(PrimOpTest, addInt) +{ + auto v = eval("builtins.add 3 5"); + ASSERT_THAT(v, IsIntEq(8)); +} + +TEST_F(PrimOpTest, addFloat) +{ + auto v = eval("builtins.add 3.0 5.0"); + ASSERT_THAT(v, IsFloatEq(8.0)); +} + +TEST_F(PrimOpTest, addFloatToInt) +{ + auto v = eval("builtins.add 3.0 5"); + ASSERT_THAT(v, IsFloatEq(8.0)); + + v = eval("builtins.add 3 5.0"); + ASSERT_THAT(v, IsFloatEq(8.0)); +} + +TEST_F(PrimOpTest, subInt) +{ + auto v = eval("builtins.sub 5 2"); + ASSERT_THAT(v, IsIntEq(3)); +} + +TEST_F(PrimOpTest, subFloat) +{ + auto v = eval("builtins.sub 5.0 2.0"); + ASSERT_THAT(v, IsFloatEq(3.0)); +} + +TEST_F(PrimOpTest, subFloatFromInt) +{ + auto v = eval("builtins.sub 5.0 2"); + ASSERT_THAT(v, IsFloatEq(3.0)); + + v = eval("builtins.sub 4 2.0"); + ASSERT_THAT(v, IsFloatEq(2.0)); +} + +TEST_F(PrimOpTest, mulInt) +{ + auto v = eval("builtins.mul 3 5"); + ASSERT_THAT(v, IsIntEq(15)); +} + +TEST_F(PrimOpTest, mulFloat) +{ + auto v = eval("builtins.mul 3.0 5.0"); + ASSERT_THAT(v, IsFloatEq(15.0)); +} + +TEST_F(PrimOpTest, mulFloatMixed) +{ + auto v = eval("builtins.mul 3 5.0"); + ASSERT_THAT(v, IsFloatEq(15.0)); + + v = eval("builtins.mul 2.0 5"); + ASSERT_THAT(v, IsFloatEq(10.0)); +} + +TEST_F(PrimOpTest, divInt) +{ + auto v = eval("builtins.div 5 (-1)"); + ASSERT_THAT(v, IsIntEq(-5)); +} + +TEST_F(PrimOpTest, divIntZero) +{ + ASSERT_THROW(eval("builtins.div 5 0"), EvalError); +} + +TEST_F(PrimOpTest, divFloat) +{ + auto v = eval("builtins.div 5.0 (-1)"); + ASSERT_THAT(v, IsFloatEq(-5.0)); +} + +TEST_F(PrimOpTest, divFloatZero) +{ + ASSERT_THROW(eval("builtins.div 5.0 0.0"), EvalError); +} + +TEST_F(PrimOpTest, bitOr) +{ + auto v = eval("builtins.bitOr 1 2"); + ASSERT_THAT(v, IsIntEq(3)); +} + +TEST_F(PrimOpTest, bitXor) +{ + auto v = eval("builtins.bitXor 3 2"); + ASSERT_THAT(v, IsIntEq(1)); +} + +TEST_F(PrimOpTest, lessThanFalse) +{ + auto v = eval("builtins.lessThan 3 1"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(PrimOpTest, lessThanTrue) +{ + auto v = eval("builtins.lessThan 1 3"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(PrimOpTest, toStringAttrsThrows) +{ + ASSERT_THROW(eval("builtins.toString {}"), EvalError); +} + +TEST_F(PrimOpTest, toStringLambdaThrows) +{ + ASSERT_THROW(eval("builtins.toString (x: x)"), EvalError); +} + +class ToStringPrimOpTest : public PrimOpTest, + public testing::WithParamInterface> +{}; + +TEST_P(ToStringPrimOpTest, toString) +{ + const auto [input, output] = GetParam(); + auto v = eval(input); + ASSERT_THAT(v, IsStringEq(output)); +} #define CASE(input, output) (std::make_tuple(std::string_view("builtins.toString " #input), std::string_view(output))) - INSTANTIATE_TEST_SUITE_P( - toString, - ToStringPrimOpTest, - testing::Values( - CASE("foo", "foo"), - CASE(1, "1"), - CASE([1 2 3], "1 2 3"), - CASE(.123, "0.123000"), - CASE(true, "1"), - CASE(false, ""), - CASE(null, ""), - CASE({ v = "bar"; __toString = self: self.v; }, "bar"), - CASE({ v = "bar"; __toString = self: self.v; outPath = "foo"; }, "bar"), - CASE({ outPath = "foo"; }, "foo"), - CASE(./test, "/test") - ) - ); +INSTANTIATE_TEST_SUITE_P( + toString, + ToStringPrimOpTest, + testing::Values( + CASE("foo", "foo"), + CASE(1, "1"), + CASE([1 2 3], "1 2 3"), + CASE(.123, "0.123000"), + CASE(true, "1"), + CASE(false, ""), + CASE(null, ""), + CASE( + { + v = "bar"; + __toString = self : self.v; + }, + "bar"), + CASE( + { + v = "bar"; + __toString = self : self.v; + outPath = "foo"; + }, + "bar"), + CASE({ outPath = "foo"; }, "foo"), + CASE(./ test, "/test"))); #undef CASE - TEST_F(PrimOpTest, substring){ - auto v = eval("builtins.substring 0 3 \"nixos\""); - ASSERT_THAT(v, IsStringEq("nix")); - } - - TEST_F(PrimOpTest, substringSmallerString){ - auto v = eval("builtins.substring 0 3 \"n\""); - ASSERT_THAT(v, IsStringEq("n")); - } - - TEST_F(PrimOpTest, substringEmptyString){ - auto v = eval("builtins.substring 1 3 \"\""); - ASSERT_THAT(v, IsStringEq("")); - } - - TEST_F(PrimOpTest, stringLength) { - auto v = eval("builtins.stringLength \"123\""); - ASSERT_THAT(v, IsIntEq(3)); - } - TEST_F(PrimOpTest, hashStringMd5) { - auto v = eval("builtins.hashString \"md5\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("912ec803b2ce49e4a541068d495ab570")); - } - - TEST_F(PrimOpTest, hashStringSha1) { - auto v = eval("builtins.hashString \"sha1\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("3da541559918a808c2402bba5012f6c60b27661c")); - } - - TEST_F(PrimOpTest, hashStringSha256) { - auto v = eval("builtins.hashString \"sha256\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b")); - } - - TEST_F(PrimOpTest, hashStringSha512) { - auto v = eval("builtins.hashString \"sha512\" \"asdf\""); - ASSERT_THAT(v, IsStringEq("401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1")); - } - - TEST_F(PrimOpTest, hashStringInvalidHashType) { - ASSERT_THROW(eval("builtins.hashString \"foobar\" \"asdf\""), Error); - } - - TEST_F(PrimOpTest, nixPath) { - auto v = eval("builtins.nixPath"); - ASSERT_EQ(v.type(), nList); - // We can't test much more as currently the EvalSettings are a global - // that we can't easily swap / replace - } - - TEST_F(PrimOpTest, langVersion) { - auto v = eval("builtins.langVersion"); - ASSERT_EQ(v.type(), nInt); - } - - TEST_F(PrimOpTest, storeDir) { - auto v = eval("builtins.storeDir"); - ASSERT_THAT(v, IsStringEq("/nix/store")); - } - - TEST_F(PrimOpTest, nixVersion) { - auto v = eval("builtins.nixVersion"); - ASSERT_THAT(v, IsStringEq(nixVersion)); - } - - TEST_F(PrimOpTest, currentSystem) { - auto v = eval("builtins.currentSystem"); - ASSERT_THAT(v, IsStringEq(settings.thisSystem.get())); - } - - TEST_F(PrimOpTest, derivation) { - auto v = eval("derivation"); - ASSERT_EQ(v.type(), nFunction); - ASSERT_TRUE(v.isLambda()); - ASSERT_NE(v.lambda.fun, nullptr); - ASSERT_TRUE(v.lambda.fun->hasFormals()); - } - - TEST_F(PrimOpTest, currentTime) { - auto v = eval("builtins.currentTime"); - ASSERT_EQ(v.type(), nInt); - ASSERT_TRUE(v.integer > 0); - } - - TEST_F(PrimOpTest, splitVersion) { - auto v = eval("builtins.splitVersion \"1.2.3git\""); - ASSERT_THAT(v, IsListOfSize(4)); - - const std::vector strings = { "1", "2", "3", "git" }; - for (const auto [n, p] : enumerate(v.listItems())) - ASSERT_THAT(*p, IsStringEq(strings[n])); - } - - class CompareVersionsPrimOpTest : - public PrimOpTest, - public testing::WithParamInterface> - {}; - - TEST_P(CompareVersionsPrimOpTest, compareVersions) { - auto [expression, expectation] = GetParam(); - auto v = eval(expression); - ASSERT_THAT(v, IsIntEq(expectation)); - } +TEST_F(PrimOpTest, substring) +{ + auto v = eval("builtins.substring 0 3 \"nixos\""); + ASSERT_THAT(v, IsStringEq("nix")); +} + +TEST_F(PrimOpTest, substringSmallerString) +{ + auto v = eval("builtins.substring 0 3 \"n\""); + ASSERT_THAT(v, IsStringEq("n")); +} + +TEST_F(PrimOpTest, substringEmptyString) +{ + auto v = eval("builtins.substring 1 3 \"\""); + ASSERT_THAT(v, IsStringEq("")); +} + +TEST_F(PrimOpTest, stringLength) +{ + auto v = eval("builtins.stringLength \"123\""); + ASSERT_THAT(v, IsIntEq(3)); +} +TEST_F(PrimOpTest, hashStringMd5) +{ + auto v = eval("builtins.hashString \"md5\" \"asdf\""); + ASSERT_THAT(v, IsStringEq("912ec803b2ce49e4a541068d495ab570")); +} + +TEST_F(PrimOpTest, hashStringSha1) +{ + auto v = eval("builtins.hashString \"sha1\" \"asdf\""); + ASSERT_THAT(v, IsStringEq("3da541559918a808c2402bba5012f6c60b27661c")); +} + +TEST_F(PrimOpTest, hashStringSha256) +{ + auto v = eval("builtins.hashString \"sha256\" \"asdf\""); + ASSERT_THAT(v, IsStringEq("f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b")); +} + +TEST_F(PrimOpTest, hashStringSha512) +{ + auto v = eval("builtins.hashString \"sha512\" \"asdf\""); + ASSERT_THAT( + v, + IsStringEq( + "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1")); +} + +TEST_F(PrimOpTest, hashStringInvalidHashType) +{ + ASSERT_THROW(eval("builtins.hashString \"foobar\" \"asdf\""), Error); +} + +TEST_F(PrimOpTest, nixPath) +{ + auto v = eval("builtins.nixPath"); + ASSERT_EQ(v.type(), nList); + // We can't test much more as currently the EvalSettings are a global + // that we can't easily swap / replace +} + +TEST_F(PrimOpTest, langVersion) +{ + auto v = eval("builtins.langVersion"); + ASSERT_EQ(v.type(), nInt); +} + +TEST_F(PrimOpTest, storeDir) +{ + auto v = eval("builtins.storeDir"); + ASSERT_THAT(v, IsStringEq("/nix/store")); +} + +TEST_F(PrimOpTest, nixVersion) +{ + auto v = eval("builtins.nixVersion"); + ASSERT_THAT(v, IsStringEq(nixVersion)); +} + +TEST_F(PrimOpTest, currentSystem) +{ + auto v = eval("builtins.currentSystem"); + ASSERT_THAT(v, IsStringEq(settings.thisSystem.get())); +} + +TEST_F(PrimOpTest, derivation) +{ + auto v = eval("derivation"); + ASSERT_EQ(v.type(), nFunction); + ASSERT_TRUE(v.isLambda()); + ASSERT_NE(v.lambda.fun, nullptr); + ASSERT_TRUE(v.lambda.fun->hasFormals()); +} + +TEST_F(PrimOpTest, currentTime) +{ + auto v = eval("builtins.currentTime"); + ASSERT_EQ(v.type(), nInt); + ASSERT_TRUE(v.integer > 0); +} + +TEST_F(PrimOpTest, splitVersion) +{ + auto v = eval("builtins.splitVersion \"1.2.3git\""); + ASSERT_THAT(v, IsListOfSize(4)); + + const std::vector strings = {"1", "2", "3", "git"}; + for (const auto [n, p] : enumerate(v.listItems())) + ASSERT_THAT(*p, IsStringEq(strings[n])); +} + +class CompareVersionsPrimOpTest : public PrimOpTest, + public testing::WithParamInterface> +{}; + +TEST_P(CompareVersionsPrimOpTest, compareVersions) +{ + auto [expression, expectation] = GetParam(); + auto v = eval(expression); + ASSERT_THAT(v, IsIntEq(expectation)); +} #define CASE(a, b, expected) (std::make_tuple("builtins.compareVersions \"" #a "\" \"" #b "\"", expected)) - INSTANTIATE_TEST_SUITE_P( - compareVersions, - CompareVersionsPrimOpTest, - testing::Values( - // The first two are weird cases. Intuition tells they should - // be the same but they aren't. - CASE(1.0, 1.0.0, -1), - CASE(1.0.0, 1.0, 1), - // the following are from the nix-env manual: - CASE(1.0, 2.3, -1), - CASE(2.1, 2.3, -1), - CASE(2.3, 2.3, 0), - CASE(2.5, 2.3, 1), - CASE(3.1, 2.3, 1), - CASE(2.3.1, 2.3, 1), - CASE(2.3.1, 2.3a, 1), - CASE(2.3pre1, 2.3, -1), - CASE(2.3pre3, 2.3pre12, -1), - CASE(2.3a, 2.3c, -1), - CASE(2.3pre1, 2.3c, -1), - CASE(2.3pre1, 2.3q, -1) - ) - ); +INSTANTIATE_TEST_SUITE_P( + compareVersions, + CompareVersionsPrimOpTest, + testing::Values( + // The first two are weird cases. Intuition tells they should + // be the same but they aren't. + CASE(1.0, 1.0.0, -1), + CASE(1.0.0, 1.0, 1), + // the following are from the nix-env manual: + CASE(1.0, 2.3, -1), + CASE(2.1, 2.3, -1), + CASE(2.3, 2.3, 0), + CASE(2.5, 2.3, 1), + CASE(3.1, 2.3, 1), + CASE(2.3.1, 2.3, 1), + CASE(2.3.1, 2.3a, 1), + CASE(2.3pre1, 2.3, -1), + CASE(2.3pre3, 2.3pre12, -1), + CASE(2.3a, 2.3c, -1), + CASE(2.3pre1, 2.3c, -1), + CASE(2.3pre1, 2.3q, -1))); #undef CASE - - class ParseDrvNamePrimOpTest : - public PrimOpTest, +class ParseDrvNamePrimOpTest + : public PrimOpTest, public testing::WithParamInterface> - {}; - - TEST_P(ParseDrvNamePrimOpTest, parseDrvName) { - auto [input, expectedName, expectedVersion] = GetParam(); - const auto expr = fmt("builtins.parseDrvName \"%1%\"", input); - auto v = eval(expr); - ASSERT_THAT(v, IsAttrsOfSize(2)); - - auto name = v.attrs->find(createSymbol("name")); - ASSERT_TRUE(name); - ASSERT_THAT(*name->value, IsStringEq(expectedName)); - - auto version = v.attrs->find(createSymbol("version")); - ASSERT_TRUE(version); - ASSERT_THAT(*version->value, IsStringEq(expectedVersion)); - } - - INSTANTIATE_TEST_SUITE_P( - parseDrvName, - ParseDrvNamePrimOpTest, - testing::Values( - std::make_tuple("nix-0.12pre12876", "nix", "0.12pre12876"), - std::make_tuple("a-b-c-1234pre5+git", "a-b-c", "1234pre5+git") - ) - ); - - TEST_F(PrimOpTest, replaceStrings) { - // FIXME: add a test that verifies the string context is as expected - auto v = eval("builtins.replaceStrings [\"oo\" \"a\"] [\"a\" \"i\"] \"foobar\""); - ASSERT_EQ(v.type(), nString); - ASSERT_EQ(v.string.s, std::string_view("fabir")); - } - - TEST_F(PrimOpTest, concatStringsSep) { - // FIXME: add a test that verifies the string context is as expected - auto v = eval("builtins.concatStringsSep \"%\" [\"foo\" \"bar\" \"baz\"]"); - ASSERT_EQ(v.type(), nString); - ASSERT_EQ(std::string_view(v.string.s), "foo%bar%baz"); - } - - TEST_F(PrimOpTest, split1) { - // v = [ "" [ "a" ] "c" ] - auto v = eval("builtins.split \"(a)b\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(3)); - - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); - - ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - - ASSERT_THAT(*v.listElems()[2], IsStringEq("c")); - } - - TEST_F(PrimOpTest, split2) { - // v is expected to be a list [ "" [ "a" ] "b" [ "c"] "" ] - auto v = eval("builtins.split \"([ac])\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(5)); - - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); - - ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - - ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); - - ASSERT_THAT(*v.listElems()[3], IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsStringEq("c")); - - ASSERT_THAT(*v.listElems()[4], IsStringEq("")); - } - - TEST_F(PrimOpTest, split3) { - auto v = eval("builtins.split \"(a)|(c)\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(5)); - - // First list element - ASSERT_THAT(*v.listElems()[0], IsStringEq("")); - - // 2nd list element is a list [ "" null ] - ASSERT_THAT(*v.listElems()[1], IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); - ASSERT_THAT(*v.listElems()[1]->listElems()[1], IsNull()); - - // 3rd element - ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); - - // 4th element is a list: [ null "c" ] - ASSERT_THAT(*v.listElems()[3], IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsNull()); - ASSERT_THAT(*v.listElems()[3]->listElems()[1], IsStringEq("c")); - - // 5th element is the empty string - ASSERT_THAT(*v.listElems()[4], IsStringEq("")); - } - - TEST_F(PrimOpTest, split4) { - auto v = eval("builtins.split \"([[:upper:]]+)\" \" FOO \""); - ASSERT_THAT(v, IsListOfSize(3)); - auto first = v.listElems()[0]; - auto second = v.listElems()[1]; - auto third = v.listElems()[2]; - - ASSERT_THAT(*first, IsStringEq(" ")); - - ASSERT_THAT(*second, IsListOfSize(1)); - ASSERT_THAT(*second->listElems()[0], IsStringEq("FOO")); - - ASSERT_THAT(*third, IsStringEq(" ")); - } - - TEST_F(PrimOpTest, match1) { - auto v = eval("builtins.match \"ab\" \"abc\""); - ASSERT_THAT(v, IsNull()); - } - - TEST_F(PrimOpTest, match2) { - auto v = eval("builtins.match \"abc\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(0)); - } - - TEST_F(PrimOpTest, match3) { - auto v = eval("builtins.match \"a(b)(c)\" \"abc\""); - ASSERT_THAT(v, IsListOfSize(2)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("b")); - ASSERT_THAT(*v.listElems()[1], IsStringEq("c")); - } - - TEST_F(PrimOpTest, match4) { - auto v = eval("builtins.match \"[[:space:]]+([[:upper:]]+)[[:space:]]+\" \" FOO \""); - ASSERT_THAT(v, IsListOfSize(1)); - ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO")); - } - - TEST_F(PrimOpTest, attrNames) { - auto v = eval("builtins.attrNames { x = 1; y = 2; z = 3; a = 2; }"); - ASSERT_THAT(v, IsListOfSize(4)); - - // ensure that the list is sorted - const std::vector expected { "a", "x", "y", "z" }; - for (const auto [n, elem] : enumerate(v.listItems())) - ASSERT_THAT(*elem, IsStringEq(expected[n])); - } +{}; + +TEST_P(ParseDrvNamePrimOpTest, parseDrvName) +{ + auto [input, expectedName, expectedVersion] = GetParam(); + const auto expr = fmt("builtins.parseDrvName \"%1%\"", input); + auto v = eval(expr); + ASSERT_THAT(v, IsAttrsOfSize(2)); + + auto name = v.attrs->find(createSymbol("name")); + ASSERT_TRUE(name); + ASSERT_THAT(*name->value, IsStringEq(expectedName)); + + auto version = v.attrs->find(createSymbol("version")); + ASSERT_TRUE(version); + ASSERT_THAT(*version->value, IsStringEq(expectedVersion)); +} + +INSTANTIATE_TEST_SUITE_P( + parseDrvName, + ParseDrvNamePrimOpTest, + testing::Values( + std::make_tuple("nix-0.12pre12876", "nix", "0.12pre12876"), + std::make_tuple("a-b-c-1234pre5+git", "a-b-c", "1234pre5+git"))); + +TEST_F(PrimOpTest, replaceStrings) +{ + // FIXME: add a test that verifies the string context is as expected + auto v = eval("builtins.replaceStrings [\"oo\" \"a\"] [\"a\" \"i\"] \"foobar\""); + ASSERT_EQ(v.type(), nString); + ASSERT_EQ(v.string.s, std::string_view("fabir")); +} + +TEST_F(PrimOpTest, concatStringsSep) +{ + // FIXME: add a test that verifies the string context is as expected + auto v = eval("builtins.concatStringsSep \"%\" [\"foo\" \"bar\" \"baz\"]"); + ASSERT_EQ(v.type(), nString); + ASSERT_EQ(std::string_view(v.string.s), "foo%bar%baz"); +} + +TEST_F(PrimOpTest, split1) +{ + // v = [ "" [ "a" ] "c" ] + auto v = eval("builtins.split \"(a)b\" \"abc\""); + ASSERT_THAT(v, IsListOfSize(3)); + + ASSERT_THAT(*v.listElems()[0], IsStringEq("")); + + ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); + ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); + + ASSERT_THAT(*v.listElems()[2], IsStringEq("c")); +} + +TEST_F(PrimOpTest, split2) +{ + // v is expected to be a list [ "" [ "a" ] "b" [ "c"] "" ] + auto v = eval("builtins.split \"([ac])\" \"abc\""); + ASSERT_THAT(v, IsListOfSize(5)); + + ASSERT_THAT(*v.listElems()[0], IsStringEq("")); + + ASSERT_THAT(*v.listElems()[1], IsListOfSize(1)); + ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); + + ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); + + ASSERT_THAT(*v.listElems()[3], IsListOfSize(1)); + ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsStringEq("c")); + + ASSERT_THAT(*v.listElems()[4], IsStringEq("")); +} + +TEST_F(PrimOpTest, split3) +{ + auto v = eval("builtins.split \"(a)|(c)\" \"abc\""); + ASSERT_THAT(v, IsListOfSize(5)); + + // First list element + ASSERT_THAT(*v.listElems()[0], IsStringEq("")); + + // 2nd list element is a list [ "" null ] + ASSERT_THAT(*v.listElems()[1], IsListOfSize(2)); + ASSERT_THAT(*v.listElems()[1]->listElems()[0], IsStringEq("a")); + ASSERT_THAT(*v.listElems()[1]->listElems()[1], IsNull()); + + // 3rd element + ASSERT_THAT(*v.listElems()[2], IsStringEq("b")); + + // 4th element is a list: [ null "c" ] + ASSERT_THAT(*v.listElems()[3], IsListOfSize(2)); + ASSERT_THAT(*v.listElems()[3]->listElems()[0], IsNull()); + ASSERT_THAT(*v.listElems()[3]->listElems()[1], IsStringEq("c")); + + // 5th element is the empty string + ASSERT_THAT(*v.listElems()[4], IsStringEq("")); +} + +TEST_F(PrimOpTest, split4) +{ + auto v = eval("builtins.split \"([[:upper:]]+)\" \" FOO \""); + ASSERT_THAT(v, IsListOfSize(3)); + auto first = v.listElems()[0]; + auto second = v.listElems()[1]; + auto third = v.listElems()[2]; + + ASSERT_THAT(*first, IsStringEq(" ")); + + ASSERT_THAT(*second, IsListOfSize(1)); + ASSERT_THAT(*second->listElems()[0], IsStringEq("FOO")); + + ASSERT_THAT(*third, IsStringEq(" ")); +} + +TEST_F(PrimOpTest, match1) +{ + auto v = eval("builtins.match \"ab\" \"abc\""); + ASSERT_THAT(v, IsNull()); +} + +TEST_F(PrimOpTest, match2) +{ + auto v = eval("builtins.match \"abc\" \"abc\""); + ASSERT_THAT(v, IsListOfSize(0)); +} + +TEST_F(PrimOpTest, match3) +{ + auto v = eval("builtins.match \"a(b)(c)\" \"abc\""); + ASSERT_THAT(v, IsListOfSize(2)); + ASSERT_THAT(*v.listElems()[0], IsStringEq("b")); + ASSERT_THAT(*v.listElems()[1], IsStringEq("c")); +} + +TEST_F(PrimOpTest, match4) +{ + auto v = eval("builtins.match \"[[:space:]]+([[:upper:]]+)[[:space:]]+\" \" FOO \""); + ASSERT_THAT(v, IsListOfSize(1)); + ASSERT_THAT(*v.listElems()[0], IsStringEq("FOO")); +} + +TEST_F(PrimOpTest, attrNames) +{ + auto v = eval("builtins.attrNames { x = 1; y = 2; z = 3; a = 2; }"); + ASSERT_THAT(v, IsListOfSize(4)); + + // ensure that the list is sorted + const std::vector expected{"a", "x", "y", "z"}; + for (const auto [n, elem] : enumerate(v.listItems())) + ASSERT_THAT(*elem, IsStringEq(expected[n])); +} } /* namespace nix */ diff --git a/src/libexpr/tests/trivial.cc b/src/libexpr/tests/trivial.cc index 8ce276e52665..5a2edde77822 100644 --- a/src/libexpr/tests/trivial.cc +++ b/src/libexpr/tests/trivial.cc @@ -1,196 +1,220 @@ #include "libexprtests.hh" namespace nix { - // Testing of trivial expressions - class TrivialExpressionTest : public LibExprTest {}; - - TEST_F(TrivialExpressionTest, true) { - auto v = eval("true"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(TrivialExpressionTest, false) { - auto v = eval("false"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(TrivialExpressionTest, null) { - auto v = eval("null"); - ASSERT_THAT(v, IsNull()); - } - - TEST_F(TrivialExpressionTest, 1) { - auto v = eval("1"); - ASSERT_THAT(v, IsIntEq(1)); - } - - TEST_F(TrivialExpressionTest, 1plus1) { - auto v = eval("1+1"); - ASSERT_THAT(v, IsIntEq(2)); - } - - TEST_F(TrivialExpressionTest, minus1) { - auto v = eval("-1"); - ASSERT_THAT(v, IsIntEq(-1)); - } - - TEST_F(TrivialExpressionTest, 1minus1) { - auto v = eval("1-1"); - ASSERT_THAT(v, IsIntEq(0)); - } - - TEST_F(TrivialExpressionTest, lambdaAdd) { - auto v = eval("let add = a: b: a + b; in add 1 2"); - ASSERT_THAT(v, IsIntEq(3)); - } - - TEST_F(TrivialExpressionTest, list) { - auto v = eval("[]"); - ASSERT_THAT(v, IsListOfSize(0)); - } - - TEST_F(TrivialExpressionTest, attrs) { - auto v = eval("{}"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(TrivialExpressionTest, float) { - auto v = eval("1.234"); - ASSERT_THAT(v, IsFloatEq(1.234)); - } - - TEST_F(TrivialExpressionTest, updateAttrs) { - auto v = eval("{ a = 1; } // { b = 2; a = 3; }"); - ASSERT_THAT(v, IsAttrsOfSize(2)); - auto a = v.attrs->find(createSymbol("a")); - ASSERT_NE(a, nullptr); - ASSERT_THAT(*a->value, IsIntEq(3)); - - auto b = v.attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(2)); - } - - TEST_F(TrivialExpressionTest, hasAttrOpFalse) { - auto v = eval("{} ? a"); - ASSERT_THAT(v, IsFalse()); - } - - TEST_F(TrivialExpressionTest, hasAttrOpTrue) { - auto v = eval("{ a = 123; } ? a"); - ASSERT_THAT(v, IsTrue()); - } - - TEST_F(TrivialExpressionTest, withFound) { - auto v = eval("with { a = 23; }; a"); - ASSERT_THAT(v, IsIntEq(23)); - } - - TEST_F(TrivialExpressionTest, withNotFound) { - ASSERT_THROW(eval("with {}; a"), Error); - } - - TEST_F(TrivialExpressionTest, withOverride) { - auto v = eval("with { a = 23; }; with { a = 42; }; a"); - ASSERT_THAT(v, IsIntEq(42)); - } - - TEST_F(TrivialExpressionTest, letOverWith) { - auto v = eval("let a = 23; in with { a = 1; }; a"); - ASSERT_THAT(v, IsIntEq(23)); - } - - TEST_F(TrivialExpressionTest, multipleLet) { - auto v = eval("let a = 23; in let a = 42; in a"); - ASSERT_THAT(v, IsIntEq(42)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgs) { - auto v = eval("({ a ? 123 }: a) {}"); - ASSERT_THAT(v, IsIntEq(123)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgsOverride) { - auto v = eval("({ a ? 123 }: a) { a = 5; }"); - ASSERT_THAT(v, IsIntEq(5)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureBack) { - auto v = eval("({ a ? 123 }@args: args) {}"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureFront) { - auto v = eval("(args@{ a ? 123 }: args) {}"); - ASSERT_THAT(v, IsAttrsOfSize(0)); - } - - TEST_F(TrivialExpressionTest, assertThrows) { - ASSERT_THROW(eval("let x = arg: assert arg == 1; 123; in x 2"), Error); - } - - TEST_F(TrivialExpressionTest, assertPassed) { - auto v = eval("let x = arg: assert arg == 1; 123; in x 1"); - ASSERT_THAT(v, IsIntEq(123)); - } - - class AttrSetMergeTrvialExpressionTest : - public TrivialExpressionTest, - public testing::WithParamInterface - {}; - - TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy) { - // Usually Nix rejects duplicate keys in an attrset but it does allow - // so if it is an attribute set that contains disjoint sets of keys. - // The below is equivalent to `{a.b = 1; a.c = 2; }`. - // The attribute set `a` will be a Thunk at first as the attribuets - // have to be merged (or otherwise computed) and that is done in a lazy - // manner. - - auto expr = GetParam(); - auto v = eval(expr); - ASSERT_THAT(v, IsAttrsOfSize(1)); - - auto a = v.attrs->find(createSymbol("a")); - ASSERT_NE(a, nullptr); - - ASSERT_THAT(*a->value, IsThunk()); - state.forceValue(*a->value, noPos); - - ASSERT_THAT(*a->value, IsAttrsOfSize(2)); - - auto b = a->value->attrs->find(createSymbol("b")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(1)); - - auto c = a->value->attrs->find(createSymbol("c")); - ASSERT_NE(c, nullptr); - ASSERT_THAT(*c->value, IsIntEq(2)); - } - - INSTANTIATE_TEST_SUITE_P( - attrsetMergeLazy, - AttrSetMergeTrvialExpressionTest, - testing::Values( - "{ a.b = 1; a.c = 2; }", - "{ a = { b = 1; }; a = { c = 2; }; }" - ) - ); - - TEST_F(TrivialExpressionTest, functor) { - auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5"); - ASSERT_THAT(v, IsIntEq(15)); - } - - TEST_F(TrivialExpressionTest, bindOr) { - auto v = eval("{ or = 1; }"); - ASSERT_THAT(v, IsAttrsOfSize(1)); - auto b = v.attrs->find(createSymbol("or")); - ASSERT_NE(b, nullptr); - ASSERT_THAT(*b->value, IsIntEq(1)); - } - - TEST_F(TrivialExpressionTest, orCantBeUsed) { - ASSERT_THROW(eval("let or = 1; in or"), Error); - } +// Testing of trivial expressions +class TrivialExpressionTest : public LibExprTest +{}; + +TEST_F(TrivialExpressionTest, true) +{ + auto v = eval("true"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(TrivialExpressionTest, false) +{ + auto v = eval("false"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(TrivialExpressionTest, null) +{ + auto v = eval("null"); + ASSERT_THAT(v, IsNull()); +} + +TEST_F(TrivialExpressionTest, 1) +{ + auto v = eval("1"); + ASSERT_THAT(v, IsIntEq(1)); +} + +TEST_F(TrivialExpressionTest, 1plus1) +{ + auto v = eval("1+1"); + ASSERT_THAT(v, IsIntEq(2)); +} + +TEST_F(TrivialExpressionTest, minus1) +{ + auto v = eval("-1"); + ASSERT_THAT(v, IsIntEq(-1)); +} + +TEST_F(TrivialExpressionTest, 1minus1) +{ + auto v = eval("1-1"); + ASSERT_THAT(v, IsIntEq(0)); +} + +TEST_F(TrivialExpressionTest, lambdaAdd) +{ + auto v = eval("let add = a: b: a + b; in add 1 2"); + ASSERT_THAT(v, IsIntEq(3)); +} + +TEST_F(TrivialExpressionTest, list) +{ + auto v = eval("[]"); + ASSERT_THAT(v, IsListOfSize(0)); +} + +TEST_F(TrivialExpressionTest, attrs) +{ + auto v = eval("{}"); + ASSERT_THAT(v, IsAttrsOfSize(0)); +} + +TEST_F(TrivialExpressionTest, float) +{ + auto v = eval("1.234"); + ASSERT_THAT(v, IsFloatEq(1.234)); +} + +TEST_F(TrivialExpressionTest, updateAttrs) +{ + auto v = eval("{ a = 1; } // { b = 2; a = 3; }"); + ASSERT_THAT(v, IsAttrsOfSize(2)); + auto a = v.attrs->find(createSymbol("a")); + ASSERT_NE(a, nullptr); + ASSERT_THAT(*a->value, IsIntEq(3)); + + auto b = v.attrs->find(createSymbol("b")); + ASSERT_NE(b, nullptr); + ASSERT_THAT(*b->value, IsIntEq(2)); +} + +TEST_F(TrivialExpressionTest, hasAttrOpFalse) +{ + auto v = eval("{} ? a"); + ASSERT_THAT(v, IsFalse()); +} + +TEST_F(TrivialExpressionTest, hasAttrOpTrue) +{ + auto v = eval("{ a = 123; } ? a"); + ASSERT_THAT(v, IsTrue()); +} + +TEST_F(TrivialExpressionTest, withFound) +{ + auto v = eval("with { a = 23; }; a"); + ASSERT_THAT(v, IsIntEq(23)); +} + +TEST_F(TrivialExpressionTest, withNotFound) +{ + ASSERT_THROW(eval("with {}; a"), Error); +} + +TEST_F(TrivialExpressionTest, withOverride) +{ + auto v = eval("with { a = 23; }; with { a = 42; }; a"); + ASSERT_THAT(v, IsIntEq(42)); +} + +TEST_F(TrivialExpressionTest, letOverWith) +{ + auto v = eval("let a = 23; in with { a = 1; }; a"); + ASSERT_THAT(v, IsIntEq(23)); +} + +TEST_F(TrivialExpressionTest, multipleLet) +{ + auto v = eval("let a = 23; in let a = 42; in a"); + ASSERT_THAT(v, IsIntEq(42)); +} + +TEST_F(TrivialExpressionTest, defaultFunctionArgs) +{ + auto v = eval("({ a ? 123 }: a) {}"); + ASSERT_THAT(v, IsIntEq(123)); +} + +TEST_F(TrivialExpressionTest, defaultFunctionArgsOverride) +{ + auto v = eval("({ a ? 123 }: a) { a = 5; }"); + ASSERT_THAT(v, IsIntEq(5)); +} + +TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureBack) +{ + auto v = eval("({ a ? 123 }@args: args) {}"); + ASSERT_THAT(v, IsAttrsOfSize(0)); +} + +TEST_F(TrivialExpressionTest, defaultFunctionArgsCaptureFront) +{ + auto v = eval("(args@{ a ? 123 }: args) {}"); + ASSERT_THAT(v, IsAttrsOfSize(0)); +} + +TEST_F(TrivialExpressionTest, assertThrows) +{ + ASSERT_THROW(eval("let x = arg: assert arg == 1; 123; in x 2"), Error); +} + +TEST_F(TrivialExpressionTest, assertPassed) +{ + auto v = eval("let x = arg: assert arg == 1; 123; in x 1"); + ASSERT_THAT(v, IsIntEq(123)); +} + +class AttrSetMergeTrvialExpressionTest : public TrivialExpressionTest, public testing::WithParamInterface +{}; + +TEST_P(AttrSetMergeTrvialExpressionTest, attrsetMergeLazy) +{ + // Usually Nix rejects duplicate keys in an attrset but it does allow + // so if it is an attribute set that contains disjoint sets of keys. + // The below is equivalent to `{a.b = 1; a.c = 2; }`. + // The attribute set `a` will be a Thunk at first as the attribuets + // have to be merged (or otherwise computed) and that is done in a lazy + // manner. + + auto expr = GetParam(); + auto v = eval(expr); + ASSERT_THAT(v, IsAttrsOfSize(1)); + + auto a = v.attrs->find(createSymbol("a")); + ASSERT_NE(a, nullptr); + + ASSERT_THAT(*a->value, IsThunk()); + state.forceValue(*a->value, noPos); + + ASSERT_THAT(*a->value, IsAttrsOfSize(2)); + + auto b = a->value->attrs->find(createSymbol("b")); + ASSERT_NE(b, nullptr); + ASSERT_THAT(*b->value, IsIntEq(1)); + + auto c = a->value->attrs->find(createSymbol("c")); + ASSERT_NE(c, nullptr); + ASSERT_THAT(*c->value, IsIntEq(2)); +} + +INSTANTIATE_TEST_SUITE_P( + attrsetMergeLazy, + AttrSetMergeTrvialExpressionTest, + testing::Values("{ a.b = 1; a.c = 2; }", "{ a = { b = 1; }; a = { c = 2; }; }")); + +TEST_F(TrivialExpressionTest, functor) +{ + auto v = eval("{ __functor = self: arg: self.v + arg; v = 10; } 5"); + ASSERT_THAT(v, IsIntEq(15)); +} + +TEST_F(TrivialExpressionTest, bindOr) +{ + auto v = eval("{ or = 1; }"); + ASSERT_THAT(v, IsAttrsOfSize(1)); + auto b = v.attrs->find(createSymbol("or")); + ASSERT_NE(b, nullptr); + ASSERT_THAT(*b->value, IsIntEq(1)); +} + +TEST_F(TrivialExpressionTest, orCantBeUsed) +{ + ASSERT_THROW(eval("let or = 1; in or"), Error); +} } /* namespace nix */ diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 03504db6192b..74a940f74239 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -6,102 +6,99 @@ #include #include - namespace nix { -void printValueAsJSON(EvalState & state, bool strict, - Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context) +void printValueAsJSON( + EvalState & state, bool strict, Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context) { checkInterrupt(); - if (strict) state.forceValue(v, pos); + if (strict) + state.forceValue(v, pos); switch (v.type()) { - case nInt: - out.write(v.integer); - break; + case nInt: + out.write(v.integer); + break; - case nBool: - out.write(v.boolean); - break; + case nBool: + out.write(v.boolean); + break; - case nString: - copyContext(v, context); - out.write(v.string.s); - break; + case nString: + copyContext(v, context); + out.write(v.string.s); + break; - case nPath: - out.write(state.copyPathToStore(context, v.path)); - break; + case nPath: + out.write(state.copyPathToStore(context, v.path)); + break; - case nNull: - out.write(nullptr); - break; + case nNull: + out.write(nullptr); + break; - case nAttrs: { - auto maybeString = state.tryAttrsToString(pos, v, context, false, false); - if (maybeString) { - out.write(*maybeString); - break; - } - auto i = v.attrs->find(state.sOutPath); - if (i == v.attrs->end()) { - auto obj(out.object()); - StringSet names; - for (auto & j : *v.attrs) - names.emplace(state.symbols[j.name]); - for (auto & j : names) { - Attr & a(*v.attrs->find(state.symbols.create(j))); - auto placeholder(obj.placeholder(j)); - printValueAsJSON(state, strict, *a.value, a.pos, placeholder, context); - } - } else - printValueAsJSON(state, strict, *i->value, i->pos, out, context); + case nAttrs: { + auto maybeString = state.tryAttrsToString(pos, v, context, false, false); + if (maybeString) { + out.write(*maybeString); break; } - - case nList: { - auto list(out.list()); - for (auto elem : v.listItems()) { - auto placeholder(list.placeholder()); - printValueAsJSON(state, strict, *elem, pos, placeholder, context); + auto i = v.attrs->find(state.sOutPath); + if (i == v.attrs->end()) { + auto obj(out.object()); + StringSet names; + for (auto & j : *v.attrs) + names.emplace(state.symbols[j.name]); + for (auto & j : names) { + Attr & a(*v.attrs->find(state.symbols.create(j))); + auto placeholder(obj.placeholder(j)); + printValueAsJSON(state, strict, *a.value, a.pos, placeholder, context); } - break; - } - - case nExternal: - v.external->printValueAsJSON(state, strict, out, context); - break; + } else + printValueAsJSON(state, strict, *i->value, i->pos, out, context); + break; + } - case nFloat: - out.write(v.fpoint); - break; + case nList: { + auto list(out.list()); + for (auto elem : v.listItems()) { + auto placeholder(list.placeholder()); + printValueAsJSON(state, strict, *elem, pos, placeholder, context); + } + break; + } - case nThunk: - case nFunction: - auto e = TypeError({ - .msg = hintfmt("cannot convert %1% to JSON", showType(v)), - .errPos = state.positions[v.determinePos(pos)] - }); - e.addTrace(state.positions[pos], hintfmt("message for the trace")); - state.debugThrowLastTrace(e); - throw e; + case nExternal: + v.external->printValueAsJSON(state, strict, out, context); + break; + + case nFloat: + out.write(v.fpoint); + break; + + case nThunk: + case nFunction: + auto e = TypeError( + {.msg = hintfmt("cannot convert %1% to JSON", showType(v)), + .errPos = state.positions[v.determinePos(pos)]}); + e.addTrace(state.positions[pos], hintfmt("message for the trace")); + state.debugThrowLastTrace(e); + throw e; } } -void printValueAsJSON(EvalState & state, bool strict, - Value & v, const PosIdx pos, std::ostream & str, PathSet & context) +void printValueAsJSON( + EvalState & state, bool strict, Value & v, const PosIdx pos, std::ostream & str, PathSet & context) { JSONPlaceholder out(str); printValueAsJSON(state, strict, v, pos, out, context); } -void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, - JSONPlaceholder & out, PathSet & context) const +void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, JSONPlaceholder & out, PathSet & context) const { state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType())); } - } diff --git a/src/libexpr/value-to-json.hh b/src/libexpr/value-to-json.hh index c020a817ab7c..b71919bff033 100644 --- a/src/libexpr/value-to-json.hh +++ b/src/libexpr/value-to-json.hh @@ -10,10 +10,10 @@ namespace nix { class JSONPlaceholder; -void printValueAsJSON(EvalState & state, bool strict, - Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context); +void printValueAsJSON( + EvalState & state, bool strict, Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context); -void printValueAsJSON(EvalState & state, bool strict, - Value & v, const PosIdx pos, std::ostream & str, PathSet & context); +void printValueAsJSON( + EvalState & state, bool strict, Value & v, const PosIdx pos, std::ostream & str, PathSet & context); } diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index 7c3bf9492622..f5a13c0bed90 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -5,10 +5,8 @@ #include - namespace nix { - static XMLAttrs singletonAttrs(const std::string & name, const std::string & value) { XMLAttrs attrs; @@ -16,12 +14,16 @@ static XMLAttrs singletonAttrs(const std::string & name, const std::string & val return attrs; } - -static void printValueAsXML(EvalState & state, bool strict, bool location, - Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen, +static void printValueAsXML( + EvalState & state, + bool strict, + bool location, + Value & v, + XMLWriter & doc, + PathSet & context, + PathSet & drvsSeen, const PosIdx pos); - static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos) { xmlAttrs["path"] = pos.file; @@ -29,9 +31,14 @@ static void posToXML(EvalState & state, XMLAttrs & xmlAttrs, const Pos & pos) xmlAttrs["column"] = (format("%1%") % pos.column).str(); } - -static void showAttrs(EvalState & state, bool strict, bool location, - Bindings & attrs, XMLWriter & doc, PathSet & context, PathSet & drvsSeen) +static void showAttrs( + EvalState & state, + bool strict, + bool location, + Bindings & attrs, + XMLWriter & doc, + PathSet & context, + PathSet & drvsSeen) { StringSet names; @@ -43,137 +50,151 @@ static void showAttrs(EvalState & state, bool strict, bool location, XMLAttrs xmlAttrs; xmlAttrs["name"] = i; - if (location && a.pos) posToXML(state, xmlAttrs, state.positions[a.pos]); + if (location && a.pos) + posToXML(state, xmlAttrs, state.positions[a.pos]); XMLOpenElement _(doc, "attr", xmlAttrs); - printValueAsXML(state, strict, location, - *a.value, doc, context, drvsSeen, a.pos); + printValueAsXML(state, strict, location, *a.value, doc, context, drvsSeen, a.pos); } } - -static void printValueAsXML(EvalState & state, bool strict, bool location, - Value & v, XMLWriter & doc, PathSet & context, PathSet & drvsSeen, +static void printValueAsXML( + EvalState & state, + bool strict, + bool location, + Value & v, + XMLWriter & doc, + PathSet & context, + PathSet & drvsSeen, const PosIdx pos) { checkInterrupt(); - if (strict) state.forceValue(v, pos); + if (strict) + state.forceValue(v, pos); switch (v.type()) { - case nInt: - doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % v.integer).str())); - break; + case nInt: + doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % v.integer).str())); + break; - case nBool: - doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false")); - break; + case nBool: + doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false")); + break; - case nString: - /* !!! show the context? */ - copyContext(v, context); - doc.writeEmptyElement("string", singletonAttrs("value", v.string.s)); - break; + case nString: + /* !!! show the context? */ + copyContext(v, context); + doc.writeEmptyElement("string", singletonAttrs("value", v.string.s)); + break; - case nPath: - doc.writeEmptyElement("path", singletonAttrs("value", v.path)); - break; + case nPath: + doc.writeEmptyElement("path", singletonAttrs("value", v.path)); + break; - case nNull: - doc.writeEmptyElement("null"); - break; + case nNull: + doc.writeEmptyElement("null"); + break; + + case nAttrs: + if (state.isDerivation(v)) { + XMLAttrs xmlAttrs; - case nAttrs: - if (state.isDerivation(v)) { - XMLAttrs xmlAttrs; - - Bindings::iterator a = v.attrs->find(state.symbols.create("derivation")); - - Path drvPath; - a = v.attrs->find(state.sDrvPath); - if (a != v.attrs->end()) { - if (strict) state.forceValue(*a->value, a->pos); - if (a->value->type() == nString) - xmlAttrs["drvPath"] = drvPath = a->value->string.s; - } - - a = v.attrs->find(state.sOutPath); - if (a != v.attrs->end()) { - if (strict) state.forceValue(*a->value, a->pos); - if (a->value->type() == nString) - xmlAttrs["outPath"] = a->value->string.s; - } - - XMLOpenElement _(doc, "derivation", xmlAttrs); - - if (drvPath != "" && drvsSeen.insert(drvPath).second) - showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen); - else - doc.writeEmptyElement("repeated"); + Bindings::iterator a = v.attrs->find(state.symbols.create("derivation")); + + Path drvPath; + a = v.attrs->find(state.sDrvPath); + if (a != v.attrs->end()) { + if (strict) + state.forceValue(*a->value, a->pos); + if (a->value->type() == nString) + xmlAttrs["drvPath"] = drvPath = a->value->string.s; } - else { - XMLOpenElement _(doc, "attrs"); - showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen); + a = v.attrs->find(state.sOutPath); + if (a != v.attrs->end()) { + if (strict) + state.forceValue(*a->value, a->pos); + if (a->value->type() == nString) + xmlAttrs["outPath"] = a->value->string.s; } - break; + XMLOpenElement _(doc, "derivation", xmlAttrs); - case nList: { - XMLOpenElement _(doc, "list"); - for (auto v2 : v.listItems()) - printValueAsXML(state, strict, location, *v2, doc, context, drvsSeen, pos); - break; + if (drvPath != "" && drvsSeen.insert(drvPath).second) + showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen); + else + doc.writeEmptyElement("repeated"); } - case nFunction: { - if (!v.isLambda()) { - // FIXME: Serialize primops and primopapps - doc.writeEmptyElement("unevaluated"); - break; - } - XMLAttrs xmlAttrs; - if (location) posToXML(state, xmlAttrs, state.positions[v.lambda.fun->pos]); - XMLOpenElement _(doc, "function", xmlAttrs); - - if (v.lambda.fun->hasFormals()) { - XMLAttrs attrs; - if (v.lambda.fun->arg) attrs["name"] = state.symbols[v.lambda.fun->arg]; - if (v.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1"; - XMLOpenElement _(doc, "attrspat", attrs); - for (auto & i : v.lambda.fun->formals->lexicographicOrder(state.symbols)) - doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name])); - } else - doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.lambda.fun->arg])); + else { + XMLOpenElement _(doc, "attrs"); + showAttrs(state, strict, location, *v.attrs, doc, context, drvsSeen); + } + break; + + case nList: { + XMLOpenElement _(doc, "list"); + for (auto v2 : v.listItems()) + printValueAsXML(state, strict, location, *v2, doc, context, drvsSeen, pos); + break; + } + + case nFunction: { + if (!v.isLambda()) { + // FIXME: Serialize primops and primopapps + doc.writeEmptyElement("unevaluated"); break; } + XMLAttrs xmlAttrs; + if (location) + posToXML(state, xmlAttrs, state.positions[v.lambda.fun->pos]); + XMLOpenElement _(doc, "function", xmlAttrs); + + if (v.lambda.fun->hasFormals()) { + XMLAttrs attrs; + if (v.lambda.fun->arg) + attrs["name"] = state.symbols[v.lambda.fun->arg]; + if (v.lambda.fun->formals->ellipsis) + attrs["ellipsis"] = "1"; + XMLOpenElement _(doc, "attrspat", attrs); + for (auto & i : v.lambda.fun->formals->lexicographicOrder(state.symbols)) + doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name])); + } else + doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.lambda.fun->arg])); + + break; + } - case nExternal: - v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen, pos); - break; + case nExternal: + v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen, pos); + break; - case nFloat: - doc.writeEmptyElement("float", singletonAttrs("value", (format("%1%") % v.fpoint).str())); - break; + case nFloat: + doc.writeEmptyElement("float", singletonAttrs("value", (format("%1%") % v.fpoint).str())); + break; - case nThunk: - doc.writeEmptyElement("unevaluated"); + case nThunk: + doc.writeEmptyElement("unevaluated"); } } - -void ExternalValueBase::printValueAsXML(EvalState & state, bool strict, - bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen, +void ExternalValueBase::printValueAsXML( + EvalState & state, + bool strict, + bool location, + XMLWriter & doc, + PathSet & context, + PathSet & drvsSeen, const PosIdx pos) const { doc.writeEmptyElement("unevaluated"); } - -void printValueAsXML(EvalState & state, bool strict, bool location, - Value & v, std::ostream & out, PathSet & context, const PosIdx pos) +void printValueAsXML( + EvalState & state, bool strict, bool location, Value & v, std::ostream & out, PathSet & context, const PosIdx pos) { XMLWriter doc(true, out); XMLOpenElement root(doc, "expr"); @@ -181,5 +202,4 @@ void printValueAsXML(EvalState & state, bool strict, bool location, printValueAsXML(state, strict, location, v, doc, context, drvsSeen, pos); } - } diff --git a/src/libexpr/value-to-xml.hh b/src/libexpr/value-to-xml.hh index 506f32b6b702..cca94d74b519 100644 --- a/src/libexpr/value-to-xml.hh +++ b/src/libexpr/value-to-xml.hh @@ -8,7 +8,7 @@ namespace nix { -void printValueAsXML(EvalState & state, bool strict, bool location, - Value & v, std::ostream & out, PathSet & context, const PosIdx pos); +void printValueAsXML( + EvalState & state, bool strict, bool location, Value & v, std::ostream & out, PathSet & context, const PosIdx pos); } diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 2008df74d609..04972bef5357 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -12,7 +12,6 @@ namespace nix { class BindingsBuilder; - typedef enum { tInt = 1, tBool, @@ -36,19 +35,7 @@ typedef enum { // This type abstracts over all actual value types in the language, // grouping together implementation details like tList*, different function // types, and types in non-normal form (so thunks and co.) -typedef enum { - nThunk, - nInt, - nFloat, - nBool, - nString, - nPath, - nNull, - nAttrs, - nList, - nFunction, - nExternal -} ValueType; +typedef enum { nThunk, nInt, nFloat, nBool, nString, nPath, nNull, nAttrs, nList, nFunction, nExternal } ValueType; class Bindings; struct Env; @@ -64,7 +51,6 @@ class EvalState; class XMLWriter; class JSONPlaceholder; - typedef int64_t NixInt; typedef double NixFloat; typedef std::pair NixStringContextElem; @@ -75,12 +61,12 @@ typedef std::vector NixStringContext; */ class ExternalValueBase { - friend std::ostream & operator << (std::ostream & str, const ExternalValueBase & v); - protected: + friend std::ostream & operator<<(std::ostream & str, const ExternalValueBase & v); +protected: /* Print out the value */ virtual std::ostream & print(std::ostream & str) const = 0; - public: +public: /* Return a simple string describing the type */ virtual std::string showType() const = 0; @@ -95,24 +81,25 @@ class ExternalValueBase /* Compare to another value of the same type. Defaults to uncomparable, * i.e. always false. */ - virtual bool operator ==(const ExternalValueBase & b) const; + virtual bool operator==(const ExternalValueBase & b) const; /* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */ - virtual void printValueAsJSON(EvalState & state, bool strict, - JSONPlaceholder & out, PathSet & context) const; + virtual void printValueAsJSON(EvalState & state, bool strict, JSONPlaceholder & out, PathSet & context) const; /* Print the value as XML. Defaults to unevaluated */ - virtual void printValueAsXML(EvalState & state, bool strict, bool location, - XMLWriter & doc, PathSet & context, PathSet & drvsSeen, + virtual void printValueAsXML( + EvalState & state, + bool strict, + bool location, + XMLWriter & doc, + PathSet & context, + PathSet & drvsSeen, const PosIdx pos) const; - virtual ~ExternalValueBase() - { - }; + virtual ~ExternalValueBase(){}; }; -std::ostream & operator << (std::ostream & str, const ExternalValueBase & v); - +std::ostream & operator<<(std::ostream & str, const ExternalValueBase & v); struct Value { @@ -132,14 +119,32 @@ public: // needed by callers into methods of this type // type() == nThunk - inline bool isThunk() const { return internalType == tThunk; }; - inline bool isApp() const { return internalType == tApp; }; - inline bool isBlackhole() const { return internalType == tBlackhole; }; + inline bool isThunk() const + { + return internalType == tThunk; + }; + inline bool isApp() const + { + return internalType == tApp; + }; + inline bool isBlackhole() const + { + return internalType == tBlackhole; + }; // type() == nFunction - inline bool isLambda() const { return internalType == tLambda; }; - inline bool isPrimOp() const { return internalType == tPrimOp; }; - inline bool isPrimOpApp() const { return internalType == tPrimOpApp; }; + inline bool isLambda() const + { + return internalType == tLambda; + }; + inline bool isPrimOp() const + { + return internalType == tPrimOp; + }; + inline bool isPrimOpApp() const + { + return internalType == tPrimOpApp; + }; union { @@ -166,32 +171,38 @@ public: the inputSrcs of the derivations. For canonicity, the store paths should be in sorted order. */ - struct { + struct + { const char * s; - const char * * context; // must be in sorted order + const char ** context; // must be in sorted order } string; const char * path; Bindings * attrs; - struct { + struct + { size_t size; - Value * * elems; + Value ** elems; } bigList; Value * smallList[2]; - struct { + struct + { Env * env; Expr * expr; } thunk; - struct { - Value * left, * right; + struct + { + Value *left, *right; } app; - struct { + struct + { Env * env; ExprLambda * fun; } lambda; PrimOp * primOp; - struct { - Value * left, * right; + struct + { + Value *left, *right; } primOpApp; ExternalValueBase * external; NixFloat fpoint; @@ -202,17 +213,34 @@ public: inline ValueType type() const { switch (internalType) { - case tInt: return nInt; - case tBool: return nBool; - case tString: return nString; - case tPath: return nPath; - case tNull: return nNull; - case tAttrs: return nAttrs; - case tList1: case tList2: case tListN: return nList; - case tLambda: case tPrimOp: case tPrimOpApp: return nFunction; - case tExternal: return nExternal; - case tFloat: return nFloat; - case tThunk: case tApp: case tBlackhole: return nThunk; + case tInt: + return nInt; + case tBool: + return nBool; + case tString: + return nString; + case tPath: + return nPath; + case tNull: + return nNull; + case tAttrs: + return nAttrs; + case tList1: + case tList2: + case tListN: + return nList; + case tLambda: + case tPrimOp: + case tPrimOpApp: + return nFunction; + case tExternal: + return nExternal; + case tFloat: + return nFloat; + case tThunk: + case tApp: + case tBlackhole: + return nThunk; } abort(); } @@ -238,7 +266,7 @@ public: boolean = b; } - inline void mkString(const char * s, const char * * context = 0) + inline void mkString(const char * s, const char ** context = 0) { internalType = tString; string.s = s; @@ -322,7 +350,6 @@ public: primOp = p; } - inline void mkPrimOpApp(Value * l, Value * r) { internalType = tPrimOpApp; @@ -349,7 +376,7 @@ public: return internalType == tList1 || internalType == tList2 || internalType == tListN; } - Value * * listElems() + Value ** listElems() { return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems; } @@ -379,12 +406,18 @@ public: { typedef Value * const * iterator; iterator _begin, _end; - iterator begin() const { return _begin; } - iterator end() const { return _end; } + iterator begin() const + { + return _begin; + } + iterator end() const + { + return _end; + } }; assert(isList()); auto begin = listElems(); - return ListIterable { begin, begin + listSize() }; + return ListIterable{begin, begin + listSize()}; } auto listItems() const @@ -393,27 +426,32 @@ public: { typedef const Value * const * iterator; iterator _begin, _end; - iterator begin() const { return _begin; } - iterator end() const { return _end; } + iterator begin() const + { + return _begin; + } + iterator end() const + { + return _end; + } }; assert(isList()); auto begin = listElems(); - return ConstListIterable { begin, begin + listSize() }; + return ConstListIterable{begin, begin + listSize()}; } }; - #if HAVE_BOEHMGC typedef std::vector> ValueVector; typedef std::map, traceable_allocator>> ValueMap; -typedef std::map, traceable_allocator>> ValueVectorMap; +typedef std::map, traceable_allocator>> + ValueVectorMap; #else typedef std::vector ValueVector; typedef std::map ValueMap; typedef std::map ValueVectorMap; #endif - /* A value allocated in traceable memory. */ typedef std::shared_ptr RootValue; diff --git a/src/libfetchers/attrs.cc b/src/libfetchers/attrs.cc index a565d19d4e72..cd124bad42af 100644 --- a/src/libfetchers/attrs.cc +++ b/src/libfetchers/attrs.cc @@ -15,7 +15,7 @@ Attrs jsonToAttrs(const nlohmann::json & json) else if (i.value().is_string()) attrs.emplace(i.key(), i.value().get()); else if (i.value().is_boolean()) - attrs.emplace(i.key(), Explicit { i.value().get() }); + attrs.emplace(i.key(), Explicit{i.value().get()}); else throw Error("unsupported input attribute type in lock file"); } @@ -33,7 +33,8 @@ nlohmann::json attrsToJSON(const Attrs & attrs) json[attr.first] = *v; } else if (auto v = std::get_if>(&attr.second)) { json[attr.first] = v->t; - } else abort(); + } else + abort(); } return json; } @@ -41,7 +42,8 @@ nlohmann::json attrsToJSON(const Attrs & attrs) std::optional maybeGetStrAttr(const Attrs & attrs, const std::string & name) { auto i = attrs.find(name); - if (i == attrs.end()) return {}; + if (i == attrs.end()) + return {}; if (auto v = std::get_if(&i->second)) return *v; throw Error("input attribute '%s' is not a string %s", name, attrsToJSON(attrs).dump()); @@ -58,7 +60,8 @@ std::string getStrAttr(const Attrs & attrs, const std::string & name) std::optional maybeGetIntAttr(const Attrs & attrs, const std::string & name) { auto i = attrs.find(name); - if (i == attrs.end()) return {}; + if (i == attrs.end()) + return {}; if (auto v = std::get_if(&i->second)) return *v; throw Error("input attribute '%s' is not an integer", name); @@ -75,7 +78,8 @@ uint64_t getIntAttr(const Attrs & attrs, const std::string & name) std::optional maybeGetBoolAttr(const Attrs & attrs, const std::string & name) { auto i = attrs.find(name); - if (i == attrs.end()) return {}; + if (i == attrs.end()) + return {}; if (auto v = std::get_if>(&i->second)) return v->t; throw Error("input attribute '%s' is not a Boolean", name); @@ -99,7 +103,8 @@ std::map attrsToQuery(const Attrs & attrs) query.insert_or_assign(attr.first, *v); } else if (auto v = std::get_if>(&attr.second)) { query.insert_or_assign(attr.first, v->t ? "1" : "0"); - } else abort(); + } else + abort(); } return query; } diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc index 0c8ecac9d48a..17759a7652bc 100644 --- a/src/libfetchers/cache.cc +++ b/src/libfetchers/cache.cc @@ -40,44 +40,33 @@ struct CacheImpl : Cache state->db.isCache(); state->db.exec(schema); - state->add.create(state->db, - "insert or replace into Cache(input, info, path, immutable, timestamp) values (?, ?, ?, ?, ?)"); + state->add.create( + state->db, "insert or replace into Cache(input, info, path, immutable, timestamp) values (?, ?, ?, ?, ?)"); - state->lookup.create(state->db, - "select info, path, immutable, timestamp from Cache where input = ?"); + state->lookup.create(state->db, "select info, path, immutable, timestamp from Cache where input = ?"); } - void add( - ref store, - const Attrs & inAttrs, - const Attrs & infoAttrs, - const StorePath & storePath, - bool locked) override + void add(ref store, const Attrs & inAttrs, const Attrs & infoAttrs, const StorePath & storePath, bool locked) + override { - _state.lock()->add.use() - (attrsToJSON(inAttrs).dump()) - (attrsToJSON(infoAttrs).dump()) - (store->printStorePath(storePath)) - (locked) - (time(0)).exec(); + _state.lock() + ->add + .use()(attrsToJSON(inAttrs).dump())(attrsToJSON(infoAttrs).dump())(store->printStorePath(storePath))( + locked) (time(0)) + .exec(); } - std::optional> lookup( - ref store, - const Attrs & inAttrs) override + std::optional> lookup(ref store, const Attrs & inAttrs) override { if (auto res = lookupExpired(store, inAttrs)) { if (!res->expired) return std::make_pair(std::move(res->infoAttrs), std::move(res->storePath)); - debug("ignoring expired cache entry '%s'", - attrsToJSON(inAttrs).dump()); + debug("ignoring expired cache entry '%s'", attrsToJSON(inAttrs).dump()); } return {}; } - std::optional lookupExpired( - ref store, - const Attrs & inAttrs) override + std::optional lookupExpired(ref store, const Attrs & inAttrs) override { auto state(_state.lock()); @@ -101,14 +90,12 @@ struct CacheImpl : Cache return {}; } - debug("using cache entry '%s' -> '%s', '%s'", - inAttrsJSON, infoJSON, store->printStorePath(storePath)); + debug("using cache entry '%s' -> '%s', '%s'", inAttrsJSON, infoJSON, store->printStorePath(storePath)); - return Result { + return Result{ .expired = !locked && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)), .infoAttrs = jsonToAttrs(nlohmann::json::parse(infoJSON)), - .storePath = std::move(storePath) - }; + .storePath = std::move(storePath)}; } }; diff --git a/src/libfetchers/cache.hh b/src/libfetchers/cache.hh index 3763ee2a6309..d9d98e6dbb7e 100644 --- a/src/libfetchers/cache.hh +++ b/src/libfetchers/cache.hh @@ -6,18 +6,12 @@ namespace nix::fetchers { struct Cache { - virtual ~Cache() { } + virtual ~Cache() {} - virtual void add( - ref store, - const Attrs & inAttrs, - const Attrs & infoAttrs, - const StorePath & storePath, - bool locked) = 0; + virtual void + add(ref store, const Attrs & inAttrs, const Attrs & infoAttrs, const StorePath & storePath, bool locked) = 0; - virtual std::optional> lookup( - ref store, - const Attrs & inAttrs) = 0; + virtual std::optional> lookup(ref store, const Attrs & inAttrs) = 0; struct Result { @@ -26,9 +20,7 @@ struct Cache StorePath storePath; }; - virtual std::optional lookupExpired( - ref store, - const Attrs & inAttrs) = 0; + virtual std::optional lookupExpired(ref store, const Attrs & inAttrs) = 0; }; ref getCache(); diff --git a/src/libfetchers/fetch-settings.cc b/src/libfetchers/fetch-settings.cc index e7d5244dc2cd..68082a8d5784 100644 --- a/src/libfetchers/fetch-settings.cc +++ b/src/libfetchers/fetch-settings.cc @@ -2,9 +2,7 @@ namespace nix { -FetchSettings::FetchSettings() -{ -} +FetchSettings::FetchSettings() {} FetchSettings fetchSettings; diff --git a/src/libfetchers/fetch-settings.hh b/src/libfetchers/fetch-settings.hh index 6452143a11b4..523b9da70e6c 100644 --- a/src/libfetchers/fetch-settings.hh +++ b/src/libfetchers/fetch-settings.hh @@ -15,7 +15,10 @@ struct FetchSettings : public Config { FetchSettings(); - Setting accessTokens{this, {}, "access-tokens", + Setting accessTokens{ + this, + {}, + "access-tokens", R"( Access tokens used to access protected GitHub, GitLab, or other locations requiring token-based authentication. @@ -64,20 +67,19 @@ struct FetchSettings : public Config value. )"}; - Setting allowDirty{this, true, "allow-dirty", - "Whether to allow dirty Git/Mercurial trees."}; + Setting allowDirty{this, true, "allow-dirty", "Whether to allow dirty Git/Mercurial trees."}; - Setting warnDirty{this, true, "warn-dirty", - "Whether to warn about dirty Git/Mercurial trees."}; + Setting warnDirty{this, true, "warn-dirty", "Whether to warn about dirty Git/Mercurial trees."}; - Setting flakeRegistry{this, "https://channels.nixos.org/flake-registry.json", "flake-registry", + Setting flakeRegistry{ + this, "https://channels.nixos.org/flake-registry.json", "flake-registry", "Path or URI of the global flake registry."}; - Setting useRegistries{this, true, "use-registries", - "Whether to use flake registries to resolve flake references."}; + Setting useRegistries{ + this, true, "use-registries", "Whether to use flake registries to resolve flake references."}; - Setting acceptFlakeConfig{this, false, "accept-flake-config", - "Whether to accept nix configuration from a flake without prompting."}; + Setting acceptFlakeConfig{ + this, false, "accept-flake-config", "Whether to accept nix configuration from a flake without prompting."}; Setting commitLockFileSummary{ this, "", "commit-lockfile-summary", diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 6957d2da408c..50bbdf783279 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -9,7 +9,8 @@ std::unique_ptr>> inputSchemes = nullpt void registerInputScheme(std::shared_ptr && inputScheme) { - if (!inputSchemes) inputSchemes = std::make_unique>>(); + if (!inputSchemes) + inputSchemes = std::make_unique>>(); inputSchemes->push_back(std::move(inputScheme)); } @@ -92,18 +93,20 @@ bool Input::hasAllInfo() const return getNarHash() && scheme && scheme->hasAllInfo(*this); } -bool Input::operator ==(const Input & other) const +bool Input::operator==(const Input & other) const { return attrs == other.attrs; } bool Input::contains(const Input & other) const { - if (*this == other) return true; + if (*this == other) + return true; auto other2(other); other2.attrs.erase("ref"); other2.attrs.erase("rev"); - if (*this == other2) return true; + if (*this == other2) + return true; return false; } @@ -121,10 +124,9 @@ std::pair Input::fetch(ref store) const store->ensurePath(storePath); - debug("using substituted/cached input '%s' in '%s'", - to_string(), store->printStorePath(storePath)); + debug("using substituted/cached input '%s' in '%s'", to_string(), store->printStorePath(storePath)); - return {Tree { .actualPath = store->toRealPath(storePath), .storePath = std::move(storePath) }, *this}; + return {Tree{.actualPath = store->toRealPath(storePath), .storePath = std::move(storePath)}, *this}; } catch (Error & e) { debug("substitution of input '%s' failed: %s", to_string(), e.what()); } @@ -139,7 +141,7 @@ std::pair Input::fetch(ref store) const } }(); - Tree tree { + Tree tree{ .actualPath = store->toRealPath(storePath), .storePath = storePath, }; @@ -149,20 +151,20 @@ std::pair Input::fetch(ref store) const if (auto prevNarHash = getNarHash()) { if (narHash != *prevNarHash) - throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'", - to_string(), tree.actualPath, prevNarHash->to_string(SRI, true), narHash.to_string(SRI, true)); + throw Error( + (unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'", to_string(), + tree.actualPath, prevNarHash->to_string(SRI, true), narHash.to_string(SRI, true)); } if (auto prevLastModified = getLastModified()) { if (input.getLastModified() != prevLastModified) - throw Error("'lastModified' attribute mismatch in input '%s', expected %d", - input.to_string(), *prevLastModified); + throw Error( + "'lastModified' attribute mismatch in input '%s', expected %d", input.to_string(), *prevLastModified); } if (auto prevRevCount = getRevCount()) { if (input.getRevCount() != prevRevCount) - throw Error("'revCount' attribute mismatch in input '%s', expected %d", - input.to_string(), *prevRevCount); + throw Error("'revCount' attribute mismatch in input '%s', expected %d", input.to_string(), *prevRevCount); } input.locked = true; @@ -172,11 +174,10 @@ std::pair Input::fetch(ref store) const return {std::move(tree), input}; } -Input Input::applyOverrides( - std::optional ref, - std::optional rev) const +Input Input::applyOverrides(std::optional ref, std::optional rev) const { - if (!scheme) return *this; + if (!scheme) + return *this; return scheme->applyOverrides(*this, ref, rev); } @@ -192,9 +193,7 @@ std::optional Input::getSourcePath() const return scheme->getSourcePath(*this); } -void Input::markChangedFile( - std::string_view file, - std::optional commitMsg) const +void Input::markChangedFile(std::string_view file, std::optional commitMsg) const { assert(scheme); return scheme->markChangedFile(*this, file, commitMsg); @@ -243,7 +242,7 @@ std::optional Input::getRev() const if (auto s = maybeGetStrAttr(attrs, "rev")) { try { hash = Hash::parseAnyPrefixed(*s); - } catch (BadHash &e) { + } catch (BadHash & e) { // Default to sha1 for backwards compatibility with existing flakes hash = Hash::parseAny(*s, htSHA1); } @@ -271,10 +270,7 @@ ParsedURL InputScheme::toURL(const Input & input) throw Error("don't know how to convert input '%s' to a URL", attrsToJSON(input.attrs)); } -Input InputScheme::applyOverrides( - const Input & input, - std::optional ref, - std::optional rev) +Input InputScheme::applyOverrides(const Input & input, std::optional ref, std::optional rev) { if (ref) throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref); diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index bc9a76b0bb4f..0161d69a1550 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -8,7 +8,9 @@ #include -namespace nix { class Store; } +namespace nix { +class Store; +} namespace nix::fetchers { @@ -57,15 +59,21 @@ public: /* Check whether this is a "direct" input, that is, not one that goes through a registry. */ - bool isDirect() const { return direct; } + bool isDirect() const + { + return direct; + } /* Check whether this is a "locked" input, that is, one that contains a commit hash or content hash. */ - bool isLocked() const { return locked; } + bool isLocked() const + { + return locked; + } bool hasAllInfo() const; - bool operator ==(const Input & other) const; + bool operator==(const Input & other) const; bool contains(const Input & other) const; @@ -73,17 +81,13 @@ public: the Nix store and the locked input. */ std::pair fetch(ref store) const; - Input applyOverrides( - std::optional ref, - std::optional rev) const; + Input applyOverrides(std::optional ref, std::optional rev) const; void clone(const Path & destDir) const; std::optional getSourcePath() const; - void markChangedFile( - std::string_view file, - std::optional commitMsg) const; + void markChangedFile(std::string_view file, std::optional commitMsg) const; std::string getName() const; @@ -98,7 +102,6 @@ public: std::optional getLastModified() const; }; - /* The InputScheme represents a type of fetcher. Each fetcher * registers with nix at startup time. When processing an input for a * flake, each scheme is given an opportunity to "recognize" that @@ -110,8 +113,7 @@ public: struct InputScheme { - virtual ~InputScheme() - { } + virtual ~InputScheme() {} virtual std::optional inputFromURL(const ParsedURL & url) = 0; @@ -121,10 +123,7 @@ struct InputScheme virtual bool hasAllInfo(const Input & input) = 0; - virtual Input applyOverrides( - const Input & input, - std::optional ref, - std::optional rev); + virtual Input applyOverrides(const Input & input, std::optional ref, std::optional rev); virtual void clone(const Input & input, const Path & destDir); @@ -145,17 +144,9 @@ struct DownloadFileResult }; DownloadFileResult downloadFile( - ref store, - const std::string & url, - const std::string & name, - bool locked, - const Headers & headers = {}); + ref store, const std::string & url, const std::string & name, bool locked, const Headers & headers = {}); std::pair downloadTarball( - ref store, - const std::string & url, - const std::string & name, - bool locked, - const Headers & headers = {}); + ref store, const std::string & url, const std::string & name, bool locked, const Headers & headers = {}); } diff --git a/src/libfetchers/git.cc b/src/libfetchers/git.cc index 7d01aaa7a011..7426712357a3 100644 --- a/src/libfetchers/git.cc +++ b/src/libfetchers/git.cc @@ -31,21 +31,20 @@ bool isCacheFileWithinTtl(const time_t now, const struct stat & st) return st.st_mtime + settings.tarballTtl > now; } -bool touchCacheFile(const Path& path, const time_t& touch_time) +bool touchCacheFile(const Path & path, const time_t & touch_time) { - struct timeval times[2]; - times[0].tv_sec = touch_time; - times[0].tv_usec = 0; - times[1].tv_sec = touch_time; - times[1].tv_usec = 0; + struct timeval times[2]; + times[0].tv_sec = touch_time; + times[0].tv_usec = 0; + times[1].tv_sec = touch_time; + times[1].tv_usec = 0; - return lutimes(path.c_str(), times) == 0; + return lutimes(path.c_str(), times) == 0; } Path getCachePath(std::string key) { - return getCacheDir() + "/nix/gitv3/" + - hashString(htSHA256, key).to_string(Base32, false); + return getCacheDir() + "/nix/gitv3/" + hashString(htSHA256, key).to_string(Base32, false); } // Returns the name of the HEAD branch. @@ -57,7 +56,7 @@ Path getCachePath(std::string key) // ... std::optional readHead(const Path & path) { - auto [exit_code, output] = runProgram(RunOptions { + auto [exit_code, output] = runProgram(RunOptions{ .program = "git", .args = {"ls-remote", "--symref", path}, }); @@ -69,12 +68,12 @@ std::optional readHead(const Path & path) line = line.substr(0, line.find("\n")); if (const auto parseResult = git::parseLsRemoteLine(line)) { switch (parseResult->kind) { - case git::LsRemoteRefLine::Kind::Symbolic: - debug("resolved HEAD ref '%s' for repo '%s'", parseResult->target, path); - break; - case git::LsRemoteRefLine::Kind::Object: - debug("resolved HEAD rev '%s' for repo '%s'", parseResult->target, path); - break; + case git::LsRemoteRefLine::Kind::Symbolic: + debug("resolved HEAD ref '%s' for repo '%s'", parseResult->target, path); + break; + case git::LsRemoteRefLine::Kind::Object: + debug("resolved HEAD rev '%s' for repo '%s'", parseResult->target, path); + break; } return parseResult->target; } @@ -82,21 +81,22 @@ std::optional readHead(const Path & path) } // Persist the HEAD ref from the remote repo in the local cached repo. -bool storeCachedHead(const std::string& actualUrl, const std::string& headRef) +bool storeCachedHead(const std::string & actualUrl, const std::string & headRef) { Path cacheDir = getCachePath(actualUrl); auto gitDir = "."; try { - runProgram("git", true, { "-C", cacheDir, "--git-dir", gitDir, "symbolic-ref", "--", "HEAD", headRef }); - } catch (ExecError &e) { - if (!WIFEXITED(e.status)) throw; + runProgram("git", true, {"-C", cacheDir, "--git-dir", gitDir, "symbolic-ref", "--", "HEAD", headRef}); + } catch (ExecError & e) { + if (!WIFEXITED(e.status)) + throw; return false; } /* No need to touch refs/HEAD, because `git symbolic-ref` updates the mtime. */ return true; } -std::optional readHeadCached(const std::string& actualUrl) +std::optional readHeadCached(const std::string & actualUrl) { // Create a cache path to store the branch of the HEAD ref. Append something // in front of the URL to prevent collision with the repository itself. @@ -108,9 +108,7 @@ std::optional readHeadCached(const std::string& actualUrl) std::optional cachedRef; if (stat(headRefFile.c_str(), &st) == 0) { cachedRef = readHead(cacheDir); - if (cachedRef != std::nullopt && - *cachedRef != gitInitialBranch && - isCacheFileWithinTtl(now, st)) { + if (cachedRef != std::nullopt && *cachedRef != gitInitialBranch && isCacheFileWithinTtl(now, st)) { debug("using cached HEAD ref '%s' for repo '%s'", *cachedRef, actualUrl); return cachedRef; } @@ -157,12 +155,11 @@ WorkdirInfo getWorkdirInfo(const Input & input, const Path & workdir) /* Check whether HEAD points to something that looks like a commit, since that is the refrence we want to use later on. */ - auto result = runProgram(RunOptions { + auto result = runProgram(RunOptions{ .program = "git", - .args = { "-C", workdir, "--git-dir", gitDir, "rev-parse", "--verify", "--no-revs", "HEAD^{commit}" }, + .args = {"-C", workdir, "--git-dir", gitDir, "rev-parse", "--verify", "--no-revs", "HEAD^{commit}"}, .environment = env, - .mergeStderrToStdout = true - }); + .mergeStderrToStdout = true}); auto exitCode = WEXITSTATUS(result.first); auto errorMessage = result.second; @@ -173,7 +170,8 @@ WorkdirInfo getWorkdirInfo(const Input & input, const Path & workdir) // we want to proceed and will consider it dirty later } else if (exitCode != 0) { // any other errors should lead to a failure - throw Error("getting the HEAD of the Git tree '%s' failed with exit code %d:\n%s", workdir, exitCode, errorMessage); + throw Error( + "getting the HEAD of the Git tree '%s' failed with exit code %d:\n%s", workdir, exitCode, errorMessage); } bool clean = false; @@ -183,7 +181,7 @@ WorkdirInfo getWorkdirInfo(const Input & input, const Path & workdir) if (hasHead) { // Using git diff is preferrable over lower-level operations here, // because its conceptually simpler and we only need the exit code anyways. - auto gitDiffOpts = Strings({ "-C", workdir, "--git-dir", gitDir, "diff", "HEAD", "--quiet"}); + auto gitDiffOpts = Strings({"-C", workdir, "--git-dir", gitDir, "diff", "HEAD", "--quiet"}); if (!submodules) { // Changes in submodules should only make the tree dirty // when those submodules will be copied as well. @@ -195,13 +193,15 @@ WorkdirInfo getWorkdirInfo(const Input & input, const Path & workdir) clean = true; } } catch (ExecError & e) { - if (!WIFEXITED(e.status) || WEXITSTATUS(e.status) != 1) throw; + if (!WIFEXITED(e.status) || WEXITSTATUS(e.status) != 1) + throw; } - return WorkdirInfo { .clean = clean, .hasHead = hasHead }; + return WorkdirInfo{.clean = clean, .hasHead = hasHead}; } -std::pair fetchFromWorkdir(ref store, Input & input, const Path & workdir, const WorkdirInfo & workdirInfo) +std::pair +fetchFromWorkdir(ref store, Input & input, const Path & workdir, const WorkdirInfo & workdirInfo) { const bool submodules = maybeGetBoolAttr(input.attrs, "submodules").value_or(false); auto gitDir = ".git"; @@ -212,12 +212,11 @@ std::pair fetchFromWorkdir(ref store, Input & input, co if (fetchSettings.warnDirty) warn("Git tree '%s' is dirty", workdir); - auto gitOpts = Strings({ "-C", workdir, "--git-dir", gitDir, "ls-files", "-z" }); + auto gitOpts = Strings({"-C", workdir, "--git-dir", gitDir, "ls-files", "-z"}); if (submodules) gitOpts.emplace_back("--recurse-submodules"); - auto files = tokenizeString>( - runProgram("git", true, gitOpts), "\0"s); + auto files = tokenizeString>(runProgram("git", true, gitOpts), "\0"s); Path actualPath(absPath(workdir)); @@ -242,34 +241,36 @@ std::pair fetchFromWorkdir(ref store, Input & input, co // modified dirty file? input.attrs.insert_or_assign( "lastModified", - workdirInfo.hasHead ? std::stoull(runProgram("git", true, { "-C", actualPath, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD" })) : 0); + workdirInfo.hasHead ? std::stoull(runProgram( + "git", true, + {"-C", actualPath, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", "HEAD"})) + : 0); return {std::move(storePath), input}; } -} // end namespace +} // end namespace struct GitInputScheme : InputScheme { std::optional inputFromURL(const ParsedURL & url) override { - if (url.scheme != "git" && - url.scheme != "git+http" && - url.scheme != "git+https" && - url.scheme != "git+ssh" && - url.scheme != "git+file") return {}; + if (url.scheme != "git" && url.scheme != "git+http" && url.scheme != "git+https" && url.scheme != "git+ssh" + && url.scheme != "git+file") + return {}; auto url2(url); - if (hasPrefix(url2.scheme, "git+")) url2.scheme = std::string(url2.scheme, 4); + if (hasPrefix(url2.scheme, "git+")) + url2.scheme = std::string(url2.scheme, 4); url2.query.clear(); Attrs attrs; attrs.emplace("type", "git"); - for (auto &[name, value] : url.query) { + for (auto & [name, value] : url.query) { if (name == "rev" || name == "ref") attrs.emplace(name, value); else if (name == "shallow" || name == "submodules") - attrs.emplace(name, Explicit { value == "1" }); + attrs.emplace(name, Explicit{value == "1"}); else url2.query.emplace(name, value); } @@ -281,10 +282,13 @@ struct GitInputScheme : InputScheme std::optional inputFromAttrs(const Attrs & attrs) override { - if (maybeGetStrAttr(attrs, "type") != "git") return {}; + if (maybeGetStrAttr(attrs, "type") != "git") + return {}; for (auto & [name, value] : attrs) - if (name != "type" && name != "url" && name != "ref" && name != "rev" && name != "shallow" && name != "submodules" && name != "lastModified" && name != "revCount" && name != "narHash" && name != "allRefs" && name != "name") + if (name != "type" && name != "url" && name != "ref" && name != "rev" && name != "shallow" + && name != "submodules" && name != "lastModified" && name != "revCount" && name != "narHash" + && name != "allRefs" && name != "name") throw Error("unsupported Git input attribute '%s'", name); parseURL(getStrAttr(attrs, "url")); @@ -305,9 +309,12 @@ struct GitInputScheme : InputScheme ParsedURL toURL(const Input & input) override { auto url = parseURL(getStrAttr(input.attrs, "url")); - if (url.scheme != "git") url.scheme = "git+" + url.scheme; - if (auto rev = input.getRev()) url.query.insert_or_assign("rev", rev->gitRev()); - if (auto ref = input.getRef()) url.query.insert_or_assign("ref", *ref); + if (url.scheme != "git") + url.scheme = "git+" + url.scheme; + if (auto rev = input.getRev()) + url.query.insert_or_assign("rev", rev->gitRev()); + if (auto ref = input.getRef()) + url.query.insert_or_assign("ref", *ref); if (maybeGetBoolAttr(input.attrs, "shallow").value_or(false)) url.query.insert_or_assign("shallow", "1"); return url; @@ -317,19 +324,17 @@ struct GitInputScheme : InputScheme { bool maybeDirty = !input.getRef(); bool shallow = maybeGetBoolAttr(input.attrs, "shallow").value_or(false); - return - maybeGetIntAttr(input.attrs, "lastModified") - && (shallow || maybeDirty || maybeGetIntAttr(input.attrs, "revCount")); + return maybeGetIntAttr(input.attrs, "lastModified") + && (shallow || maybeDirty || maybeGetIntAttr(input.attrs, "revCount")); } - Input applyOverrides( - const Input & input, - std::optional ref, - std::optional rev) override + Input applyOverrides(const Input & input, std::optional ref, std::optional rev) override { auto res(input); - if (rev) res.attrs.insert_or_assign("rev", rev->gitRev()); - if (ref) res.attrs.insert_or_assign("ref", *ref); + if (rev) + res.attrs.insert_or_assign("rev", rev->gitRev()); + if (ref) + res.attrs.insert_or_assign("ref", *ref); if (!res.getRef() && res.getRev()) throw Error("Git input '%s' has a commit hash but no branch/tag name", res.to_string()); return res; @@ -348,7 +353,8 @@ struct GitInputScheme : InputScheme args.push_back(*ref); } - if (input.getRev()) throw UnimplementedError("cloning a specific revision is not implemented"); + if (input.getRev()) + throw UnimplementedError("cloning a specific revision is not implemented"); args.push_back(destDir); @@ -369,12 +375,13 @@ struct GitInputScheme : InputScheme assert(sourcePath); auto gitDir = ".git"; - runProgram("git", true, - { "-C", *sourcePath, "--git-dir", gitDir, "add", "--force", "--intent-to-add", "--", std::string(file) }); + runProgram( + "git", true, + {"-C", *sourcePath, "--git-dir", gitDir, "add", "--force", "--intent-to-add", "--", std::string(file)}); if (commitMsg) - runProgram("git", true, - { "-C", *sourcePath, "--git-dir", gitDir, "commit", std::string(file), "-m", *commitMsg }); + runProgram( + "git", true, {"-C", *sourcePath, "--git-dir", gitDir, "commit", std::string(file), "-m", *commitMsg}); } std::pair getActualUrl(const Input & input) const @@ -402,18 +409,21 @@ struct GitInputScheme : InputScheme bool allRefs = maybeGetBoolAttr(input.attrs, "allRefs").value_or(false); std::string cacheType = "git"; - if (shallow) cacheType += "-shallow"; - if (submodules) cacheType += "-submodules"; - if (allRefs) cacheType += "-all-refs"; - - auto checkHashType = [&](const std::optional & hash) - { + if (shallow) + cacheType += "-shallow"; + if (submodules) + cacheType += "-submodules"; + if (allRefs) + cacheType += "-all-refs"; + + auto checkHashType = [&](const std::optional & hash) { if (hash.has_value() && !(hash->type == htSHA1 || hash->type == htSHA256)) - throw Error("Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", hash->to_string(Base16, true)); + throw Error( + "Hash '%s' is not supported by Git. Supported types are sha1 and sha256.", + hash->to_string(Base16, true)); }; - auto getLockedAttrs = [&]() - { + auto getLockedAttrs = [&]() { checkHashType(input.getRev()); return Attrs({ @@ -423,9 +433,7 @@ struct GitInputScheme : InputScheme }); }; - auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath) - -> std::pair - { + auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath) -> std::pair { assert(input.getRev()); assert(!_input.getRev() || _input.getRev() == input.getRev()); if (!shallow) @@ -471,8 +479,12 @@ struct GitInputScheme : InputScheme } if (!input.getRev()) - input.attrs.insert_or_assign("rev", - Hash::parseAny(chomp(runProgram("git", true, { "-C", actualUrl, "--git-dir", gitDir, "rev-parse", *input.getRef() })), htSHA1).gitRev()); + input.attrs.insert_or_assign( + "rev", Hash::parseAny( + chomp(runProgram( + "git", true, {"-C", actualUrl, "--git-dir", gitDir, "rev-parse", *input.getRef()})), + htSHA1) + .gitRev()); repoDir = actualUrl; } else { @@ -503,13 +515,12 @@ struct GitInputScheme : InputScheme PathLocks cacheDirLock({cacheDir + ".lock"}); if (!pathExists(cacheDir)) { - runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir }); + runProgram("git", true, {"-c", "init.defaultBranch=" + gitInitialBranch, "init", "--bare", repoDir}); } - Path localRefFile = - input.getRef()->compare(0, 5, "refs/") == 0 - ? cacheDir + "/" + *input.getRef() - : cacheDir + "/refs/heads/" + *input.getRef(); + Path localRefFile = input.getRef()->compare(0, 5, "refs/") == 0 + ? cacheDir + "/" + *input.getRef() + : cacheDir + "/refs/heads/" + *input.getRef(); bool doFetch; time_t now = time(0); @@ -518,7 +529,8 @@ struct GitInputScheme : InputScheme repo. */ if (input.getRev()) { try { - runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "cat-file", "-e", input.getRev()->gitRev() }); + runProgram( + "git", true, {"-C", repoDir, "--git-dir", gitDir, "cat-file", "-e", input.getRev()->gitRev()}); doFetch = false; } catch (ExecError & e) { if (WIFEXITED(e.status)) { @@ -534,8 +546,7 @@ struct GitInputScheme : InputScheme /* If the local ref is older than ‘tarball-ttl’ seconds, do a git fetch to update the local ref to the remote ref. */ struct stat st; - doFetch = stat(localRefFile.c_str(), &st) != 0 || - !isCacheFileWithinTtl(now, st); + doFetch = stat(localRefFile.c_str(), &st) != 0 || !isCacheFileWithinTtl(now, st); } } @@ -546,17 +557,20 @@ struct GitInputScheme : InputScheme // we're using --quiet for now. Should process its stderr. try { auto ref = input.getRef(); - auto fetchRef = allRefs - ? "refs/*" - : ref->compare(0, 5, "refs/") == 0 - ? *ref - : ref == "HEAD" - ? *ref - : "refs/heads/" + *ref; - runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "fetch", "--quiet", "--force", "--", actualUrl, fmt("%s:%s", fetchRef, fetchRef) }); + auto fetchRef = allRefs ? "refs/*" + : ref->compare(0, 5, "refs/") == 0 ? *ref + : ref == "HEAD" ? *ref + : "refs/heads/" + *ref; + runProgram( + "git", true, + {"-C", repoDir, "--git-dir", gitDir, "fetch", "--quiet", "--force", "--", actualUrl, + fmt("%s:%s", fetchRef, fetchRef)}); } catch (Error & e) { - if (!pathExists(localRefFile)) throw; - warn("could not update local clone of Git repository '%s'; continuing with the most recent version", actualUrl); + if (!pathExists(localRefFile)) + throw; + warn( + "could not update local clone of Git repository '%s'; continuing with the most recent version", + actualUrl); } if (!touchCacheFile(localRefFile, now)) @@ -568,13 +582,18 @@ struct GitInputScheme : InputScheme if (!input.getRev()) input.attrs.insert_or_assign("rev", Hash::parseAny(chomp(readFile(localRefFile)), htSHA1).gitRev()); - // cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in the remainder + // cache dir lock is removed at scope end; we will only use read-only operations on specific revisions in + // the remainder } - bool isShallow = chomp(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-parse", "--is-shallow-repository" })) == "true"; + bool isShallow = + chomp(runProgram("git", true, {"-C", repoDir, "--git-dir", gitDir, "rev-parse", "--is-shallow-repository"})) + == "true"; if (isShallow && !shallow) - throw Error("'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified.", actualUrl); + throw Error( + "'%s' is a shallow Git repository, but shallow repositories are only allowed when `shallow = true;` is specified.", + actualUrl); // FIXME: check whether rev is an ancestor of ref. @@ -589,50 +608,46 @@ struct GitInputScheme : InputScheme AutoDelete delTmpDir(tmpDir, true); PathFilter filter = defaultPathFilter; - auto result = runProgram(RunOptions { + auto result = runProgram(RunOptions{ .program = "git", - .args = { "-C", repoDir, "--git-dir", gitDir, "cat-file", "commit", input.getRev()->gitRev() }, - .mergeStderrToStdout = true - }); - if (WEXITSTATUS(result.first) == 128 - && result.second.find("bad file") != std::string::npos) - { + .args = {"-C", repoDir, "--git-dir", gitDir, "cat-file", "commit", input.getRev()->gitRev()}, + .mergeStderrToStdout = true}); + if (WEXITSTATUS(result.first) == 128 && result.second.find("bad file") != std::string::npos) { throw Error( "Cannot find Git revision '%s' in ref '%s' of repository '%s'! " - "Please make sure that the " ANSI_BOLD "rev" ANSI_NORMAL " exists on the " - ANSI_BOLD "ref" ANSI_NORMAL " you've specified or add " ANSI_BOLD - "allRefs = true;" ANSI_NORMAL " to " ANSI_BOLD "fetchGit" ANSI_NORMAL ".", - input.getRev()->gitRev(), - *input.getRef(), - actualUrl - ); + "Please make sure that the " ANSI_BOLD "rev" ANSI_NORMAL " exists on the " ANSI_BOLD "ref" ANSI_NORMAL + " you've specified or add " ANSI_BOLD "allRefs = true;" ANSI_NORMAL " to " ANSI_BOLD + "fetchGit" ANSI_NORMAL ".", + input.getRev()->gitRev(), *input.getRef(), actualUrl); } if (submodules) { Path tmpGitDir = createTempDir(); AutoDelete delTmpGitDir(tmpGitDir, true); - runProgram("git", true, { "-c", "init.defaultBranch=" + gitInitialBranch, "init", tmpDir, "--separate-git-dir", tmpGitDir }); + runProgram( + "git", true, + {"-c", "init.defaultBranch=" + gitInitialBranch, "init", tmpDir, "--separate-git-dir", tmpGitDir}); // TODO: repoDir might lack the ref (it only checks if rev // exists, see FIXME above) so use a big hammer and fetch // everything to ensure we get the rev. - runProgram("git", true, { "-C", tmpDir, "fetch", "--quiet", "--force", - "--update-head-ok", "--", repoDir, "refs/*:refs/*" }); + runProgram( + "git", true, + {"-C", tmpDir, "fetch", "--quiet", "--force", "--update-head-ok", "--", repoDir, "refs/*:refs/*"}); - runProgram("git", true, { "-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev() }); - runProgram("git", true, { "-C", tmpDir, "remote", "add", "origin", actualUrl }); - runProgram("git", true, { "-C", tmpDir, "submodule", "--quiet", "update", "--init", "--recursive" }); + runProgram("git", true, {"-C", tmpDir, "checkout", "--quiet", input.getRev()->gitRev()}); + runProgram("git", true, {"-C", tmpDir, "remote", "add", "origin", actualUrl}); + runProgram("git", true, {"-C", tmpDir, "submodule", "--quiet", "update", "--init", "--recursive"}); filter = isNotDotGitDirectory; } else { // FIXME: should pipe this, or find some better way to extract a // revision. auto source = sinkToSource([&](Sink & sink) { - runProgram2({ - .program = "git", - .args = { "-C", repoDir, "--git-dir", gitDir, "archive", input.getRev()->gitRev() }, - .standardOut = &sink - }); + runProgram2( + {.program = "git", + .args = {"-C", repoDir, "--git-dir", gitDir, "archive", input.getRev()->gitRev()}, + .standardOut = &sink}); }); unpackTarfile(*source, tmpDir); @@ -640,7 +655,10 @@ struct GitInputScheme : InputScheme auto storePath = store->addToStore(name, tmpDir, FileIngestionMethod::Recursive, htSHA256, filter); - auto lastModified = std::stoull(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", input.getRev()->gitRev() })); + auto lastModified = std::stoull(runProgram( + "git", true, + {"-C", repoDir, "--git-dir", gitDir, "log", "-1", "--format=%ct", "--no-show-signature", + input.getRev()->gitRev()})); Attrs infoAttrs({ {"rev", input.getRev()->gitRev()}, @@ -648,23 +666,16 @@ struct GitInputScheme : InputScheme }); if (!shallow) - infoAttrs.insert_or_assign("revCount", - std::stoull(runProgram("git", true, { "-C", repoDir, "--git-dir", gitDir, "rev-list", "--count", input.getRev()->gitRev() }))); + infoAttrs.insert_or_assign( + "revCount", + std::stoull(runProgram( + "git", true, + {"-C", repoDir, "--git-dir", gitDir, "rev-list", "--count", input.getRev()->gitRev()}))); if (!_input.getRev()) - getCache()->add( - store, - unlockedAttrs, - infoAttrs, - storePath, - false); - - getCache()->add( - store, - getLockedAttrs(), - infoAttrs, - storePath, - true); + getCache()->add(store, unlockedAttrs, infoAttrs, storePath, false); + + getCache()->add(store, getLockedAttrs(), infoAttrs, storePath, true); return makeResult(infoAttrs, std::move(storePath)); } diff --git a/src/libfetchers/github.cc b/src/libfetchers/github.cc index a491d82a67a7..ea747fae10d9 100644 --- a/src/libfetchers/github.cc +++ b/src/libfetchers/github.cc @@ -28,11 +28,13 @@ struct GitArchiveInputScheme : InputScheme { virtual std::string type() = 0; - virtual std::optional> accessHeaderFromToken(const std::string & token) const = 0; + virtual std::optional> + accessHeaderFromToken(const std::string & token) const = 0; std::optional inputFromURL(const ParsedURL & url) override { - if (url.scheme != type()) return {}; + if (url.scheme != type()) + return {}; auto path = tokenizeString>(url.path, "/"); @@ -65,20 +67,18 @@ struct GitArchiveInputScheme : InputScheme } else if (size < 2) throw BadURL("URL '%s' is invalid", url.url); - for (auto &[name, value] : url.query) { + for (auto & [name, value] : url.query) { if (name == "rev") { if (rev) throw BadURL("URL '%s' contains multiple commit hashes", url.url); rev = Hash::parseAny(value, htSHA1); - } - else if (name == "ref") { + } else if (name == "ref") { if (!std::regex_match(value, refRegex)) throw BadURL("URL '%s' contains an invalid branch/tag name", url.url); if (ref) throw BadURL("URL '%s' contains multiple branch/tag names", url.url); ref = value; - } - else if (name == "host") { + } else if (name == "host") { if (!std::regex_match(value, hostRegex)) throw BadURL("URL '%s' contains an invalid instance host", url.url); host_url = value; @@ -87,25 +87,31 @@ struct GitArchiveInputScheme : InputScheme } if (ref && rev) - throw BadURL("URL '%s' contains both a commit hash and a branch/tag name %s %s", url.url, *ref, rev->gitRev()); + throw BadURL( + "URL '%s' contains both a commit hash and a branch/tag name %s %s", url.url, *ref, rev->gitRev()); Input input; input.attrs.insert_or_assign("type", type()); input.attrs.insert_or_assign("owner", path[0]); input.attrs.insert_or_assign("repo", path[1]); - if (rev) input.attrs.insert_or_assign("rev", rev->gitRev()); - if (ref) input.attrs.insert_or_assign("ref", *ref); - if (host_url) input.attrs.insert_or_assign("host", *host_url); + if (rev) + input.attrs.insert_or_assign("rev", rev->gitRev()); + if (ref) + input.attrs.insert_or_assign("ref", *ref); + if (host_url) + input.attrs.insert_or_assign("host", *host_url); return input; } std::optional inputFromAttrs(const Attrs & attrs) override { - if (maybeGetStrAttr(attrs, "type") != type()) return {}; + if (maybeGetStrAttr(attrs, "type") != type()) + return {}; for (auto & [name, value] : attrs) - if (name != "type" && name != "owner" && name != "repo" && name != "ref" && name != "rev" && name != "narHash" && name != "lastModified" && name != "host") + if (name != "type" && name != "owner" && name != "repo" && name != "ref" && name != "rev" + && name != "narHash" && name != "lastModified" && name != "host") throw Error("unsupported input attribute '%s'", name); getStrAttr(attrs, "owner"); @@ -124,9 +130,11 @@ struct GitArchiveInputScheme : InputScheme auto rev = input.getRev(); auto path = owner + "/" + repo; assert(!(ref && rev)); - if (ref) path += "/" + *ref; - if (rev) path += "/" + rev->to_string(Base16, false); - return ParsedURL { + if (ref) + path += "/" + *ref; + if (rev) + path += "/" + rev->to_string(Base16, false); + return ParsedURL{ .scheme = type(), .path = path, }; @@ -137,15 +145,13 @@ struct GitArchiveInputScheme : InputScheme return input.getRev() && maybeGetIntAttr(input.attrs, "lastModified"); } - Input applyOverrides( - const Input & _input, - std::optional ref, - std::optional rev) override + Input applyOverrides(const Input & _input, std::optional ref, std::optional rev) override { auto input(_input); if (rev && ref) - throw BadURL("cannot apply both a commit hash (%s) and a branch/tag name ('%s') to input '%s'", - rev->gitRev(), *ref, input.to_string()); + throw BadURL( + "cannot apply both a commit hash (%s) and a branch/tag name ('%s') to input '%s'", rev->gitRev(), *ref, + input.to_string()); if (rev) { input.attrs.insert_or_assign("rev", rev->gitRev()); input.attrs.erase("ref"); @@ -187,10 +193,12 @@ struct GitArchiveInputScheme : InputScheme { Input input(_input); - if (!maybeGetStrAttr(input.attrs, "ref")) input.attrs.insert_or_assign("ref", "HEAD"); + if (!maybeGetStrAttr(input.attrs, "ref")) + input.attrs.insert_or_assign("ref", "HEAD"); auto rev = input.getRev(); - if (!rev) rev = getRevFromRef(store, input); + if (!rev) + rev = getRevFromRef(store, input); input.attrs.erase("ref"); input.attrs.insert_or_assign("rev", rev->gitRev()); @@ -212,13 +220,7 @@ struct GitArchiveInputScheme : InputScheme input.attrs.insert_or_assign("lastModified", uint64_t(lastModified)); getCache()->add( - store, - lockedAttrs, - { - {"rev", rev->gitRev()}, - {"lastModified", uint64_t(lastModified)} - }, - tree.storePath, + store, lockedAttrs, {{"rev", rev->gitRev()}, {"lastModified", uint64_t(lastModified)}}, tree.storePath, true); return {std::move(tree.storePath), input}; @@ -227,7 +229,10 @@ struct GitArchiveInputScheme : InputScheme struct GitHubInputScheme : GitArchiveInputScheme { - std::string type() override { return "github"; } + std::string type() override + { + return "github"; + } std::optional> accessHeaderFromToken(const std::string & token) const override { @@ -244,18 +249,14 @@ struct GitHubInputScheme : GitArchiveInputScheme { auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com"); auto url = fmt( - host == "github.com" - ? "https://api.%s/repos/%s/%s/commits/%s" - : "https://%s/api/v3/repos/%s/%s/commits/%s", + host == "github.com" ? "https://api.%s/repos/%s/%s/commits/%s" : "https://%s/api/v3/repos/%s/%s/commits/%s", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), *input.getRef()); Headers headers = makeHeadersWithAuthTokens(host); auto json = nlohmann::json::parse( - readFile( - store->toRealPath( - downloadFile(store, url, "source", false, headers).storePath))); - auto rev = Hash::parseAny(std::string { json["sha"] }, htSHA1); + readFile(store->toRealPath(downloadFile(store, url, "source", false, headers).storePath))); + auto rev = Hash::parseAny(std::string{json["sha"]}, htSHA1); debug("HEAD revision for '%s' is %s", url, rev.gitRev()); return rev; } @@ -266,21 +267,19 @@ struct GitHubInputScheme : GitArchiveInputScheme // 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 == "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"), input.getRev()->to_string(Base16, false)); Headers headers = makeHeadersWithAuthTokens(host); - return DownloadUrl { url, headers }; + return DownloadUrl{url, headers}; } void clone(const Input & input, const Path & destDir) override { auto host = maybeGetStrAttr(input.attrs, "host").value_or("github.com"); - Input::fromURL(fmt("git+https://%s/%s/%s.git", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) + Input::fromURL( + fmt("git+https://%s/%s/%s.git", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) .applyOverrides(input.getRef(), input.getRev()) .clone(destDir); } @@ -288,7 +287,10 @@ struct GitHubInputScheme : GitArchiveInputScheme struct GitLabInputScheme : GitArchiveInputScheme { - std::string type() override { return "gitlab"; } + std::string type() override + { + return "gitlab"; + } std::optional> accessHeaderFromToken(const std::string & token) const override { @@ -302,26 +304,25 @@ struct GitLabInputScheme : GitArchiveInputScheme auto fldsplit = token.find_first_of(':'); // n.b. C++20 would allow: if (token.starts_with("OAuth2:")) ... if ("OAuth2" == token.substr(0, fldsplit)) - return std::make_pair("Authorization", fmt("Bearer %s", token.substr(fldsplit+1))); + return std::make_pair("Authorization", fmt("Bearer %s", token.substr(fldsplit + 1))); if ("PAT" == token.substr(0, fldsplit)) - return std::make_pair("Private-token", token.substr(fldsplit+1)); - warn("Unrecognized GitLab token type %s", token.substr(0, fldsplit)); - return std::make_pair(token.substr(0,fldsplit), token.substr(fldsplit+1)); + return std::make_pair("Private-token", token.substr(fldsplit + 1)); + warn("Unrecognized GitLab token type %s", token.substr(0, fldsplit)); + return std::make_pair(token.substr(0, fldsplit), token.substr(fldsplit + 1)); } Hash getRevFromRef(nix::ref store, const Input & input) const override { auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com"); // See rate limiting note below - auto url = fmt("https://%s/api/v4/projects/%s%%2F%s/repository/commits?ref_name=%s", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), *input.getRef()); + auto url = + fmt("https://%s/api/v4/projects/%s%%2F%s/repository/commits?ref_name=%s", host, + getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), *input.getRef()); Headers headers = makeHeadersWithAuthTokens(host); auto json = nlohmann::json::parse( - readFile( - store->toRealPath( - downloadFile(store, url, "source", false, headers).storePath))); + readFile(store->toRealPath(downloadFile(store, url, "source", false, headers).storePath))); auto rev = Hash::parseAny(std::string(json[0]["id"]), htSHA1); debug("HEAD revision for '%s' is %s", url, rev.gitRev()); return rev; @@ -335,20 +336,21 @@ struct GitLabInputScheme : GitArchiveInputScheme // is 10 reqs/sec/ip-addr. See // https://docs.gitlab.com/ee/user/gitlab_com/index.html#gitlabcom-specific-rate-limits auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com"); - auto url = fmt("https://%s/api/v4/projects/%s%%2F%s/repository/archive.tar.gz?sha=%s", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), - input.getRev()->to_string(Base16, false)); + auto url = + fmt("https://%s/api/v4/projects/%s%%2F%s/repository/archive.tar.gz?sha=%s", host, + getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), + input.getRev()->to_string(Base16, false)); Headers headers = makeHeadersWithAuthTokens(host); - return DownloadUrl { url, headers }; + return DownloadUrl{url, headers}; } void clone(const Input & input, const Path & destDir) override { auto host = maybeGetStrAttr(input.attrs, "host").value_or("gitlab.com"); // FIXME: get username somewhere - Input::fromURL(fmt("git+https://%s/%s/%s.git", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) + Input::fromURL( + fmt("git+https://%s/%s/%s.git", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) .applyOverrides(input.getRef(), input.getRev()) .clone(destDir); } @@ -356,7 +358,10 @@ struct GitLabInputScheme : GitArchiveInputScheme struct SourceHutInputScheme : GitArchiveInputScheme { - std::string type() override { return "sourcehut"; } + std::string type() override + { + return "sourcehut"; + } std::optional> accessHeaderFromToken(const std::string & token) const override { @@ -376,15 +381,15 @@ struct SourceHutInputScheme : GitArchiveInputScheme auto ref = *input.getRef(); auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht"); - auto base_url = fmt("https://%s/%s/%s", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")); + auto base_url = + fmt("https://%s/%s/%s", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo")); Headers headers = makeHeadersWithAuthTokens(host); std::string refUri; if (ref == "HEAD") { - auto file = store->toRealPath( - downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath); + auto file = + store->toRealPath(downloadFile(store, fmt("%s/HEAD", base_url), "source", false, headers).storePath); std::ifstream is(file); std::string line; getline(is, line); @@ -399,19 +404,19 @@ struct SourceHutInputScheme : GitArchiveInputScheme } std::regex refRegex(refUri); - auto file = store->toRealPath( - downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath); + auto file = + store->toRealPath(downloadFile(store, fmt("%s/info/refs", base_url), "source", false, headers).storePath); std::ifstream is(file); std::string line; std::optional id; - while(!id && getline(is, line)) { + while (!id && getline(is, line)) { auto parsedLine = git::parseLsRemoteLine(line); if (parsedLine && parsedLine->reference && std::regex_match(*parsedLine->reference, refRegex)) id = parsedLine->target; } - if(!id) + if (!id) throw BadURL("in '%d', couldn't find ref '%d'", input.to_string(), ref); auto rev = Hash::parseAny(*id, htSHA1); @@ -422,19 +427,19 @@ struct SourceHutInputScheme : GitArchiveInputScheme DownloadUrl getDownloadUrl(const Input & input) const override { auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht"); - auto url = fmt("https://%s/%s/%s/archive/%s.tar.gz", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"), - input.getRev()->to_string(Base16, false)); + auto url = + fmt("https://%s/%s/%s/archive/%s.tar.gz", host, getStrAttr(input.attrs, "owner"), + getStrAttr(input.attrs, "repo"), input.getRev()->to_string(Base16, false)); Headers headers = makeHeadersWithAuthTokens(host); - return DownloadUrl { url, headers }; + return DownloadUrl{url, headers}; } void clone(const Input & input, const Path & destDir) override { auto host = maybeGetStrAttr(input.attrs, "host").value_or("git.sr.ht"); - Input::fromURL(fmt("git+https://%s/%s/%s", - host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) + Input::fromURL( + fmt("git+https://%s/%s/%s", host, getStrAttr(input.attrs, "owner"), getStrAttr(input.attrs, "repo"))) .applyOverrides(input.getRef(), input.getRev()) .clone(destDir); } diff --git a/src/libfetchers/indirect.cc b/src/libfetchers/indirect.cc index 9288fc6cfcf5..b4f2edc2f535 100644 --- a/src/libfetchers/indirect.cc +++ b/src/libfetchers/indirect.cc @@ -9,7 +9,8 @@ struct IndirectInputScheme : InputScheme { std::optional inputFromURL(const ParsedURL & url) override { - if (url.scheme != "flake") return {}; + if (url.scheme != "flake") + return {}; auto path = tokenizeString>(url.path, "/"); @@ -44,15 +45,18 @@ struct IndirectInputScheme : InputScheme input.direct = false; input.attrs.insert_or_assign("type", "indirect"); input.attrs.insert_or_assign("id", id); - if (rev) input.attrs.insert_or_assign("rev", rev->gitRev()); - if (ref) input.attrs.insert_or_assign("ref", *ref); + if (rev) + input.attrs.insert_or_assign("rev", rev->gitRev()); + if (ref) + input.attrs.insert_or_assign("ref", *ref); return input; } std::optional inputFromAttrs(const Attrs & attrs) override { - if (maybeGetStrAttr(attrs, "type") != "indirect") return {}; + if (maybeGetStrAttr(attrs, "type") != "indirect") + return {}; for (auto & [name, value] : attrs) if (name != "type" && name != "id" && name != "ref" && name != "rev" && name != "narHash") @@ -73,8 +77,14 @@ struct IndirectInputScheme : InputScheme ParsedURL url; url.scheme = "flake"; url.path = getStrAttr(input.attrs, "id"); - if (auto ref = input.getRef()) { url.path += '/'; url.path += *ref; }; - if (auto rev = input.getRev()) { url.path += '/'; url.path += rev->gitRev(); }; + if (auto ref = input.getRef()) { + url.path += '/'; + url.path += *ref; + }; + if (auto rev = input.getRev()) { + url.path += '/'; + url.path += rev->gitRev(); + }; return url; } @@ -83,14 +93,13 @@ struct IndirectInputScheme : InputScheme return false; } - Input applyOverrides( - const Input & _input, - std::optional ref, - std::optional rev) override + Input applyOverrides(const Input & _input, std::optional ref, std::optional rev) override { auto input(_input); - if (rev) input.attrs.insert_or_assign("rev", rev->gitRev()); - if (ref) input.attrs.insert_or_assign("ref", *ref); + if (rev) + input.attrs.insert_or_assign("rev", rev->gitRev()); + if (ref) + input.attrs.insert_or_assign("ref", *ref); return input; } diff --git a/src/libfetchers/mercurial.cc b/src/libfetchers/mercurial.cc index 5c56716816f2..c222f31daab7 100644 --- a/src/libfetchers/mercurial.cc +++ b/src/libfetchers/mercurial.cc @@ -19,12 +19,7 @@ static RunOptions hgOptions(const Strings & args) // Set HGPLAIN: this means we get consistent output from hg and avoids leakage from a user or system .hgrc. env["HGPLAIN"] = ""; - return { - .program = "hg", - .searchPath = true, - .args = args, - .environment = env - }; + return {.program = "hg", .searchPath = true, .args = args, .environment = env}; } // runProgram wrapper that uses hgOptions instead of stock RunOptions. @@ -45,10 +40,8 @@ struct MercurialInputScheme : InputScheme { std::optional inputFromURL(const ParsedURL & url) override { - if (url.scheme != "hg+http" && - url.scheme != "hg+https" && - url.scheme != "hg+ssh" && - url.scheme != "hg+file") return {}; + if (url.scheme != "hg+http" && url.scheme != "hg+https" && url.scheme != "hg+ssh" && url.scheme != "hg+file") + return {}; auto url2(url); url2.scheme = std::string(url2.scheme, 3); @@ -57,7 +50,7 @@ struct MercurialInputScheme : InputScheme Attrs attrs; attrs.emplace("type", "hg"); - for (auto &[name, value] : url.query) { + for (auto & [name, value] : url.query) { if (name == "rev" || name == "ref") attrs.emplace(name, value); else @@ -71,10 +64,12 @@ struct MercurialInputScheme : InputScheme std::optional inputFromAttrs(const Attrs & attrs) override { - if (maybeGetStrAttr(attrs, "type") != "hg") return {}; + if (maybeGetStrAttr(attrs, "type") != "hg") + return {}; for (auto & [name, value] : attrs) - if (name != "type" && name != "url" && name != "ref" && name != "rev" && name != "revCount" && name != "narHash" && name != "name") + if (name != "type" && name != "url" && name != "ref" && name != "rev" && name != "revCount" + && name != "narHash" && name != "name") throw Error("unsupported Mercurial input attribute '%s'", name); parseURL(getStrAttr(attrs, "url")); @@ -93,8 +88,10 @@ struct MercurialInputScheme : InputScheme { auto url = parseURL(getStrAttr(input.attrs, "url")); url.scheme = "hg+" + url.scheme; - if (auto rev = input.getRev()) url.query.insert_or_assign("rev", rev->gitRev()); - if (auto ref = input.getRef()) url.query.insert_or_assign("ref", *ref); + if (auto rev = input.getRev()) + url.query.insert_or_assign("rev", rev->gitRev()); + if (auto ref = input.getRef()) + url.query.insert_or_assign("ref", *ref); return url; } @@ -105,14 +102,13 @@ struct MercurialInputScheme : InputScheme return input.getRef() == "default" || maybeGetIntAttr(input.attrs, "revCount"); } - Input applyOverrides( - const Input & input, - std::optional ref, - std::optional rev) override + Input applyOverrides(const Input & input, std::optional ref, std::optional rev) override { auto res(input); - if (rev) res.attrs.insert_or_assign("rev", rev->gitRev()); - if (ref) res.attrs.insert_or_assign("ref", *ref); + if (rev) + res.attrs.insert_or_assign("rev", rev->gitRev()); + if (ref) + res.attrs.insert_or_assign("ref", *ref); return res; } @@ -130,12 +126,10 @@ struct MercurialInputScheme : InputScheme assert(sourcePath); // FIXME: shut up if file is already tracked. - runHg( - { "add", *sourcePath + "/" + std::string(file) }); + runHg({"add", *sourcePath + "/" + std::string(file)}); if (commitMsg) - runHg( - { "commit", *sourcePath + "/" + std::string(file), "-m", *commitMsg }); + runHg({"commit", *sourcePath + "/" + std::string(file), "-m", *commitMsg}); } std::pair getActualUrl(const Input & input) const @@ -160,7 +154,7 @@ struct MercurialInputScheme : InputScheme if (!input.getRef() && !input.getRev() && isLocal && pathExists(actualUrl + "/.hg")) { - bool clean = runHg({ "status", "-R", actualUrl, "--modified", "--added", "--removed" }) == ""; + bool clean = runHg({"status", "-R", actualUrl, "--modified", "--added", "--removed"}) == ""; if (!clean) { @@ -173,10 +167,11 @@ struct MercurialInputScheme : InputScheme if (fetchSettings.warnDirty) warn("Mercurial tree '%s' is unclean", actualUrl); - input.attrs.insert_or_assign("ref", chomp(runHg({ "branch", "-R", actualUrl }))); + input.attrs.insert_or_assign("ref", chomp(runHg({"branch", "-R", actualUrl}))); auto files = tokenizeString>( - runHg({ "status", "-R", actualUrl, "--clean", "--modified", "--added", "--no-status", "--print0" }), "\0"s); + runHg({"status", "-R", actualUrl, "--clean", "--modified", "--added", "--no-status", "--print0"}), + "\0"s); Path actualPath(absPath(actualUrl)); @@ -195,23 +190,23 @@ struct MercurialInputScheme : InputScheme return files.count(file); }; - auto storePath = store->addToStore(input.getName(), actualPath, FileIngestionMethod::Recursive, htSHA256, filter); + auto storePath = + store->addToStore(input.getName(), actualPath, FileIngestionMethod::Recursive, htSHA256, filter); return {std::move(storePath), input}; } } - if (!input.getRef()) input.attrs.insert_or_assign("ref", "default"); + if (!input.getRef()) + input.attrs.insert_or_assign("ref", "default"); - auto checkHashType = [&](const std::optional & hash) - { + auto checkHashType = [&](const std::optional & hash) { if (hash.has_value() && hash->type != htSHA1) - throw Error("Hash '%s' is not supported by Mercurial. Only sha1 is supported.", hash->to_string(Base16, true)); + throw Error( + "Hash '%s' is not supported by Mercurial. Only sha1 is supported.", hash->to_string(Base16, true)); }; - - auto getLockedAttrs = [&]() - { + auto getLockedAttrs = [&]() { checkHashType(input.getRev()); return Attrs({ @@ -221,9 +216,7 @@ struct MercurialInputScheme : InputScheme }); }; - auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath) - -> std::pair - { + auto makeResult = [&](const Attrs & infoAttrs, StorePath && storePath) -> std::pair { assert(input.getRev()); assert(!_input.getRev() || _input.getRev() == input.getRev()); input.attrs.insert_or_assign("revCount", getIntAttr(infoAttrs, "revCount")); @@ -256,34 +249,33 @@ struct MercurialInputScheme : InputScheme /* If this is a commit hash that we already have, we don't have to pull again. */ - if (!(input.getRev() - && pathExists(cacheDir) - && runProgram(hgOptions({ "log", "-R", cacheDir, "-r", input.getRev()->gitRev(), "--template", "1" })).second == "1")) - { + if (!(input.getRev() && pathExists(cacheDir) + && runProgram(hgOptions({"log", "-R", cacheDir, "-r", input.getRev()->gitRev(), "--template", "1"})) + .second + == "1")) { Activity act(*logger, lvlTalkative, actUnknown, fmt("fetching Mercurial repository '%s'", actualUrl)); if (pathExists(cacheDir)) { try { - runHg({ "pull", "-R", cacheDir, "--", actualUrl }); - } - catch (ExecError & e) { + runHg({"pull", "-R", cacheDir, "--", actualUrl}); + } catch (ExecError & e) { auto transJournal = cacheDir + "/.hg/store/journal"; /* hg throws "abandoned transaction" error only if this file exists */ if (pathExists(transJournal)) { - runHg({ "recover", "-R", cacheDir }); - runHg({ "pull", "-R", cacheDir, "--", actualUrl }); + runHg({"recover", "-R", cacheDir}); + runHg({"pull", "-R", cacheDir, "--", actualUrl}); } else { throw ExecError(e.status, "'hg pull' %s", statusToString(e.status)); } } } else { createDirs(dirOf(cacheDir)); - runHg({ "clone", "--noupdate", "--", actualUrl, cacheDir }); + runHg({"clone", "--noupdate", "--", actualUrl, cacheDir}); } } auto tokens = tokenizeString>( - runHg({ "log", "-R", cacheDir, "-r", revOrRef, "--template", "{node} {rev} {branch}" })); + runHg({"log", "-R", cacheDir, "-r", revOrRef, "--template", "{node} {rev} {branch}"})); assert(tokens.size() == 3); input.attrs.insert_or_assign("rev", Hash::parseAny(tokens[0], htSHA1).gitRev()); @@ -296,7 +288,7 @@ struct MercurialInputScheme : InputScheme Path tmpDir = createTempDir(); AutoDelete delTmpDir(tmpDir, true); - runHg({ "archive", "-R", cacheDir, "-r", input.getRev()->gitRev(), tmpDir }); + runHg({"archive", "-R", cacheDir, "-r", input.getRev()->gitRev(), tmpDir}); deletePath(tmpDir + "/.hg_archival.txt"); @@ -308,19 +300,9 @@ struct MercurialInputScheme : InputScheme }); if (!_input.getRev()) - getCache()->add( - store, - unlockedAttrs, - infoAttrs, - storePath, - false); - - getCache()->add( - store, - getLockedAttrs(), - infoAttrs, - storePath, - true); + getCache()->add(store, unlockedAttrs, infoAttrs, storePath, false); + + getCache()->add(store, getLockedAttrs(), infoAttrs, storePath, true); return makeResult(infoAttrs, std::move(storePath)); } diff --git a/src/libfetchers/path.cc b/src/libfetchers/path.cc index f0ef97da5af0..35873148582a 100644 --- a/src/libfetchers/path.cc +++ b/src/libfetchers/path.cc @@ -8,7 +8,8 @@ struct PathInputScheme : InputScheme { std::optional inputFromURL(const ParsedURL & url) override { - if (url.scheme != "path") return {}; + if (url.scheme != "path") + return {}; if (url.authority && *url.authority != "") throw Error("path URL '%s' should not have an authority ('%s')", url.url, *url.authority); @@ -25,8 +26,7 @@ struct PathInputScheme : InputScheme input.attrs.insert_or_assign(name, *n); else throw Error("path URL '%s' has invalid parameter '%s'", url.to_string(), name); - } - else + } else throw Error("path URL '%s' has unsupported parameter '%s'", url.to_string(), name); return input; @@ -34,7 +34,8 @@ struct PathInputScheme : InputScheme std::optional inputFromAttrs(const Attrs & attrs) override { - if (maybeGetStrAttr(attrs, "type") != "path") return {}; + if (maybeGetStrAttr(attrs, "type") != "path") + return {}; getStrAttr(attrs, "path"); @@ -43,7 +44,8 @@ struct PathInputScheme : InputScheme attributes. This is useful for making a pinned tree work the same as the repository from which is exported (e.g. path:/nix/store/...-source?lastModified=1585388205&rev=b0c285...). */ - if (name == "type" || name == "rev" || name == "revCount" || name == "lastModified" || name == "narHash" || name == "path") + if (name == "type" || name == "rev" || name == "revCount" || name == "lastModified" || name == "narHash" + || name == "path") // checked in Input::fromAttrs ; else @@ -59,7 +61,7 @@ struct PathInputScheme : InputScheme auto query = attrsToQuery(input.attrs); query.erase("path"); query.erase("type"); - return ParsedURL { + return ParsedURL{ .scheme = "path", .path = getStrAttr(input.attrs, "path"), .query = query, @@ -100,7 +102,8 @@ struct PathInputScheme : InputScheme if (store->isInStore(parent)) { auto storePath = store->printStorePath(store->toStorePath(parent).first); if (!isDirOrInDir(absPath, storePath)) - throw BadStorePath("relative path '%s' points outside of its parent's store path '%s'", path, storePath); + throw BadStorePath( + "relative path '%s' points outside of its parent's store path '%s'", path, storePath); } } else absPath = path; @@ -116,9 +119,8 @@ struct PathInputScheme : InputScheme time_t mtime = 0; if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath)) { // FIXME: try to substitute storePath. - auto src = sinkToSource([&](Sink & sink) { - mtime = dumpPathAndGetMtime(absPath, sink, defaultPathFilter); - }); + auto src = + sinkToSource([&](Sink & sink) { mtime = dumpPathAndGetMtime(absPath, sink, defaultPathFilter); }); storePath = store->addToStoreFromDump(*src, "source"); } input.attrs.insert_or_assign("lastModified", uint64_t(mtime)); diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc index acd1ff8667d6..ccde58146a87 100644 --- a/src/libfetchers/registry.cc +++ b/src/libfetchers/registry.cc @@ -11,8 +11,7 @@ namespace nix::fetchers { -std::shared_ptr Registry::read( - const Path & path, RegistryType type) +std::shared_ptr Registry::read(const Path & path, RegistryType type) { auto registry = std::make_shared(type); @@ -35,13 +34,11 @@ std::shared_ptr Registry::read( toAttrs.erase(j); } auto exact = i.find("exact"); - registry->entries.push_back( - Entry { - .from = Input::fromAttrs(jsonToAttrs(i["from"])), - .to = Input::fromAttrs(std::move(toAttrs)), - .extraAttrs = extraAttrs, - .exact = exact != i.end() && exact.value() - }); + registry->entries.push_back(Entry{ + .from = Input::fromAttrs(jsonToAttrs(i["from"])), + .to = Input::fromAttrs(std::move(toAttrs)), + .extraAttrs = extraAttrs, + .exact = exact != i.end() && exact.value()}); } } @@ -79,23 +76,15 @@ void Registry::write(const Path & path) writeFile(path, json.dump(2)); } -void Registry::add( - const Input & from, - const Input & to, - const Attrs & extraAttrs) +void Registry::add(const Input & from, const Input & to, const Attrs & extraAttrs) { - entries.emplace_back( - Entry { - .from = from, - .to = to, - .extraAttrs = extraAttrs - }); + entries.emplace_back(Entry{.from = from, .to = to, .extraAttrs = extraAttrs}); } void Registry::remove(const Input & input) { // FIXME: use C++20 std::erase. - for (auto i = entries.begin(); i != entries.end(); ) + for (auto i = entries.begin(); i != entries.end();) if (i->from == input) i = entries.erase(i); else @@ -109,8 +98,7 @@ static Path getSystemRegistryPath() static std::shared_ptr getSystemRegistry() { - static auto systemRegistry = - Registry::read(getSystemRegistryPath(), Registry::System); + static auto systemRegistry = Registry::read(getSystemRegistryPath(), Registry::System); return systemRegistry; } @@ -121,30 +109,24 @@ Path getUserRegistryPath() std::shared_ptr getUserRegistry() { - static auto userRegistry = - Registry::read(getUserRegistryPath(), Registry::User); + static auto userRegistry = Registry::read(getUserRegistryPath(), Registry::User); return userRegistry; } std::shared_ptr getCustomRegistry(const Path & p) { - static auto customRegistry = - Registry::read(p, Registry::Custom); + static auto customRegistry = Registry::read(p, Registry::Custom); return customRegistry; } -static std::shared_ptr flagRegistry = - std::make_shared(Registry::Flag); +static std::shared_ptr flagRegistry = std::make_shared(Registry::Flag); std::shared_ptr getFlagRegistry() { return flagRegistry; } -void overrideRegistry( - const Input & from, - const Input & to, - const Attrs & extraAttrs) +void overrideRegistry(const Input & from, const Input & to, const Attrs & extraAttrs) { flagRegistry->add(from, to, extraAttrs); } @@ -177,18 +159,17 @@ Registries getRegistries(ref store) return registries; } -std::pair lookupInRegistries( - ref store, - const Input & _input) +std::pair lookupInRegistries(ref store, const Input & _input) { Attrs extraAttrs; int n = 0; Input input(_input); - restart: +restart: n++; - if (n > 100) throw Error("cycle detected in flake registry for '%s'", input.to_string()); + if (n > 100) + throw Error("cycle detected in flake registry for '%s'", input.to_string()); for (auto & registry : getRegistries(store)) { // FIXME: O(n) diff --git a/src/libfetchers/registry.hh b/src/libfetchers/registry.hh index 260a2c460162..e1d99d29fd74 100644 --- a/src/libfetchers/registry.hh +++ b/src/libfetchers/registry.hh @@ -3,7 +3,9 @@ #include "types.hh" #include "fetchers.hh" -namespace nix { class Store; } +namespace nix { +class Store; +} namespace nix::fetchers { @@ -30,17 +32,13 @@ struct Registry Registry(RegistryType type) : type(type) - { } + {} - static std::shared_ptr read( - const Path & path, RegistryType type); + static std::shared_ptr read(const Path & path, RegistryType type); void write(const Path & path); - void add( - const Input & from, - const Input & to, - const Attrs & extraAttrs); + void add(const Input & from, const Input & to, const Attrs & extraAttrs); void remove(const Input & input); }; @@ -55,13 +53,8 @@ Path getUserRegistryPath(); Registries getRegistries(ref store); -void overrideRegistry( - const Input & from, - const Input & to, - const Attrs & extraAttrs); +void overrideRegistry(const Input & from, const Input & to, const Attrs & extraAttrs); -std::pair lookupInRegistries( - ref store, - const Input & input); +std::pair lookupInRegistries(ref store, const Input & input); } diff --git a/src/libfetchers/tarball.cc b/src/libfetchers/tarball.cc index 6c551bd93f48..2485d801cc4b 100644 --- a/src/libfetchers/tarball.cc +++ b/src/libfetchers/tarball.cc @@ -10,12 +10,8 @@ namespace nix::fetchers { -DownloadFileResult downloadFile( - ref store, - const std::string & url, - const std::string & name, - bool locked, - const Headers & headers) +DownloadFileResult +downloadFile(ref store, const std::string & url, const std::string & name, bool locked, const Headers & headers) { // FIXME: check store @@ -27,13 +23,11 @@ DownloadFileResult downloadFile( auto cached = getCache()->lookupExpired(store, inAttrs); - auto useCached = [&]() -> DownloadFileResult - { + auto useCached = [&]() -> DownloadFileResult { return { .storePath = std::move(cached->storePath), .etag = getStrAttr(cached->infoAttrs, "etag"), - .effectiveUrl = getStrAttr(cached->infoAttrs, "url") - }; + .effectiveUrl = getStrAttr(cached->infoAttrs, "url")}; }; if (cached && !cached->expired) @@ -70,12 +64,12 @@ DownloadFileResult downloadFile( StringSink sink; dumpString(res.data, sink); auto hash = hashString(htSHA256, res.data); - ValidPathInfo info { + ValidPathInfo info{ store->makeFixedOutputPath(FileIngestionMethod::Flat, hash, name), hashString(htSHA256, sink.s), }; info.narSize = sink.s.size(); - info.ca = FixedOutputHash { + info.ca = FixedOutputHash{ .method = FileIngestionMethod::Flat, .hash = hash, }; @@ -84,12 +78,7 @@ DownloadFileResult downloadFile( storePath = std::move(info.path); } - getCache()->add( - store, - inAttrs, - infoAttrs, - *storePath, - locked); + getCache()->add(store, inAttrs, infoAttrs, *storePath, locked); if (url != res.effectiveUri) getCache()->add( @@ -99,9 +88,7 @@ DownloadFileResult downloadFile( {"url", res.effectiveUri}, {"name", name}, }, - infoAttrs, - *storePath, - locked); + infoAttrs, *storePath, locked); return { .storePath = std::move(*storePath), @@ -111,11 +98,7 @@ DownloadFileResult downloadFile( } std::pair downloadTarball( - ref store, - const std::string & url, - const std::string & name, - bool locked, - const Headers & headers) + ref store, const std::string & url, const std::string & name, bool locked, const Headers & headers) { Attrs inAttrs({ {"type", "tarball"}, @@ -127,9 +110,8 @@ std::pair downloadTarball( if (cached && !cached->expired) return { - Tree { .actualPath = store->toRealPath(cached->storePath), .storePath = std::move(cached->storePath) }, - getIntAttr(cached->infoAttrs, "lastModified") - }; + Tree{.actualPath = store->toRealPath(cached->storePath), .storePath = std::move(cached->storePath)}, + getIntAttr(cached->infoAttrs, "lastModified")}; auto res = downloadFile(store, url, name, locked, headers); @@ -148,7 +130,8 @@ std::pair downloadTarball( throw nix::Error("tarball '%s' contains an unexpected number of top-level files", url); auto topDir = tmpDir + "/" + members.begin()->name; lastModified = lstat(topDir).st_mtime; - unpackedStorePath = store->addToStore(name, topDir, FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, NoRepair); + unpackedStorePath = + store->addToStore(name, topDir, FileIngestionMethod::Recursive, htSHA256, defaultPathFilter, NoRepair); } Attrs infoAttrs({ @@ -156,15 +139,10 @@ std::pair downloadTarball( {"etag", res.etag}, }); - getCache()->add( - store, - inAttrs, - infoAttrs, - *unpackedStorePath, - locked); + getCache()->add(store, inAttrs, infoAttrs, *unpackedStorePath, locked); return { - Tree { .actualPath = store->toRealPath(*unpackedStorePath), .storePath = std::move(*unpackedStorePath) }, + Tree{.actualPath = store->toRealPath(*unpackedStorePath), .storePath = std::move(*unpackedStorePath)}, lastModified, }; } @@ -177,10 +155,9 @@ struct CurlInputScheme : InputScheme const bool hasTarballExtension(std::string_view path) const { - return hasSuffix(path, ".zip") || hasSuffix(path, ".tar") - || hasSuffix(path, ".tgz") || hasSuffix(path, ".tar.gz") - || hasSuffix(path, ".tar.xz") || hasSuffix(path, ".tar.bz2") - || hasSuffix(path, ".tar.zst"); + return hasSuffix(path, ".zip") || hasSuffix(path, ".tar") || hasSuffix(path, ".tgz") + || hasSuffix(path, ".tar.gz") || hasSuffix(path, ".tar.xz") || hasSuffix(path, ".tar.bz2") + || hasSuffix(path, ".tar.zst"); } virtual bool isValidURL(const ParsedURL & url) const = 0; @@ -206,7 +183,8 @@ struct CurlInputScheme : InputScheme std::optional inputFromAttrs(const Attrs & attrs) override { auto type = maybeGetStrAttr(attrs, "type"); - if (type != inputType()) return {}; + if (type != inputType()) + return {}; std::set allowedNames = {"type", "url", "narHash", "name", "unpack"}; for (auto & [name, value] : attrs) @@ -216,14 +194,15 @@ struct CurlInputScheme : InputScheme Input input; input.attrs = attrs; - //input.locked = (bool) maybeGetStrAttr(input.attrs, "hash"); + // input.locked = (bool) maybeGetStrAttr(input.attrs, "hash"); return input; } ParsedURL toURL(const Input & input) override { auto url = parseURL(getStrAttr(input.attrs, "url")); - // NAR hashes are preferred over file hashes since tar/zip files // don't have a canonical representation. + // NAR hashes are preferred over file hashes since tar/zip files // don't have a canonical + // representation. if (auto narHash = input.getNarHash()) url.query.insert_or_assign("narHash", narHash->to_string(SRI, true)); return url; @@ -233,20 +212,21 @@ struct CurlInputScheme : InputScheme { return true; } - }; struct FileInputScheme : CurlInputScheme { - const std::string inputType() const override { return "file"; } + const std::string inputType() const override + { + return "file"; + } bool isValidURL(const ParsedURL & url) const override { auto parsedUrlScheme = parseUrlScheme(url.scheme); return transportUrlSchemes.count(std::string(parsedUrlScheme.transport)) - && (parsedUrlScheme.application - ? parsedUrlScheme.application.value() == inputType() - : !hasTarballExtension(url.path)); + && (parsedUrlScheme.application ? parsedUrlScheme.application.value() == inputType() + : !hasTarballExtension(url.path)); } std::pair fetch(ref store, const Input & input) override @@ -258,16 +238,18 @@ struct FileInputScheme : CurlInputScheme struct TarballInputScheme : CurlInputScheme { - const std::string inputType() const override { return "tarball"; } + const std::string inputType() const override + { + return "tarball"; + } bool isValidURL(const ParsedURL & url) const override { auto parsedUrlScheme = parseUrlScheme(url.scheme); return transportUrlSchemes.count(std::string(parsedUrlScheme.transport)) - && (parsedUrlScheme.application - ? parsedUrlScheme.application.value() == inputType() - : hasTarballExtension(url.path)); + && (parsedUrlScheme.application ? parsedUrlScheme.application.value() == inputType() + : hasTarballExtension(url.path)); } std::pair fetch(ref store, const Input & input) override diff --git a/src/libmain/common-args.cc b/src/libmain/common-args.cc index 12f5403ea610..31eb0a6dc2e4 100644 --- a/src/libmain/common-args.cc +++ b/src/libmain/common-args.cc @@ -29,28 +29,27 @@ MixCommonArgs::MixCommonArgs(const std::string & programName) .handler = {[]() { verbosity = lvlDebug; }}, }); - addFlag({ - .longName = "option", - .description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).", - .labels = {"name", "value"}, - .handler = {[](std::string name, std::string value) { - try { - globalConfig.set(name, value); - } catch (UsageError & e) { - if (!completions) - warn(e.what()); - } - }}, - .completer = [](size_t index, std::string_view prefix) { - if (index == 0) { - std::map settings; - globalConfig.getSettings(settings); - for (auto & s : settings) - if (hasPrefix(s.first, prefix)) - completions->add(s.first, fmt("Set the `%s` setting.", s.first)); - } - } - }); + addFlag( + {.longName = "option", + .description = "Set the Nix configuration setting *name* to *value* (overriding `nix.conf`).", + .labels = {"name", "value"}, + .handler = {[](std::string name, std::string value) { + try { + globalConfig.set(name, value); + } catch (UsageError & e) { + if (!completions) + warn(e.what()); + } + }}, + .completer = [](size_t index, std::string_view prefix) { + if (index == 0) { + std::map settings; + globalConfig.getSettings(settings); + for (auto & s : settings) + if (hasPrefix(s.first, prefix)) + completions->add(s.first, fmt("Set the `%s` setting.", s.first)); + } + }}); addFlag({ .longName = "log-format", @@ -60,21 +59,19 @@ MixCommonArgs::MixCommonArgs(const std::string & programName) .handler = {[](std::string format) { setLogFormat(format); }}, }); - addFlag({ - .longName = "max-jobs", - .shortName = 'j', - .description = "The maximum number of parallel builds.", - .labels = Strings{"jobs"}, - .handler = {[=](std::string s) { - settings.set("max-jobs", s); - }} - }); + addFlag( + {.longName = "max-jobs", + .shortName = 'j', + .description = "The maximum number of parallel builds.", + .labels = Strings{"jobs"}, + .handler = {[=](std::string s) { settings.set("max-jobs", s); }}}); std::string cat = "Options to override configuration settings"; globalConfig.convertToArgs(*this, cat); // Backward compatibility hack: nix-env already had a --system flag. - if (programName == "nix-env") longFlags.erase("system"); + if (programName == "nix-env") + longFlags.erase("system"); hiddenCategories.insert(cat); } @@ -85,5 +82,4 @@ void MixCommonArgs::initialFlagsProcessed() pluginsInited(); } - } diff --git a/src/libmain/common-args.hh b/src/libmain/common-args.hh index 25453b8c63eb..b06370e9a2af 100644 --- a/src/libmain/common-args.hh +++ b/src/libmain/common-args.hh @@ -4,7 +4,7 @@ namespace nix { -//static constexpr auto commonArgsCategory = "Miscellaneous common options"; +// static constexpr auto commonArgsCategory = "Miscellaneous common options"; static constexpr auto loggingCategory = "Logging-related options"; class MixCommonArgs : public virtual Args diff --git a/src/libmain/loggers.cc b/src/libmain/loggers.cc index cdf23859baac..ffbfef90481b 100644 --- a/src/libmain/loggers.cc +++ b/src/libmain/loggers.cc @@ -6,7 +6,8 @@ namespace nix { LogFormat defaultLogFormat = LogFormat::raw; -LogFormat parseLogFormat(const std::string & logFormatStr) { +LogFormat parseLogFormat(const std::string & logFormatStr) +{ if (logFormatStr == "raw" || getEnv("NIX_GET_COMPLETIONS")) return LogFormat::raw; else if (logFormatStr == "raw-with-logs") @@ -20,7 +21,8 @@ LogFormat parseLogFormat(const std::string & logFormatStr) { throw Error("option 'log-format' has an invalid value '%s'", logFormatStr); } -Logger * makeDefaultLogger() { +Logger * makeDefaultLogger() +{ switch (defaultLogFormat) { case LogFormat::raw: return makeSimpleLogger(false); @@ -37,16 +39,19 @@ Logger * makeDefaultLogger() { } } -void setLogFormat(const std::string & logFormatStr) { +void setLogFormat(const std::string & logFormatStr) +{ setLogFormat(parseLogFormat(logFormatStr)); } -void setLogFormat(const LogFormat & logFormat) { +void setLogFormat(const LogFormat & logFormat) +{ defaultLogFormat = logFormat; createDefaultLogger(); } -void createDefaultLogger() { +void createDefaultLogger() +{ logger = makeDefaultLogger(); } diff --git a/src/libmain/loggers.hh b/src/libmain/loggers.hh index f3c759193f5e..d8e99a44f6b4 100644 --- a/src/libmain/loggers.hh +++ b/src/libmain/loggers.hh @@ -5,11 +5,11 @@ namespace nix { enum class LogFormat { - raw, - rawWithLogs, - internalJSON, - bar, - barWithLogs, + raw, + rawWithLogs, + internalJSON, + bar, + barWithLogs, }; void setLogFormat(const std::string & logFormatStr); diff --git a/src/libmain/progress-bar.cc b/src/libmain/progress-bar.cc index f4306ab91165..083ca61dcf45 100644 --- a/src/libmain/progress-bar.cc +++ b/src/libmain/progress-bar.cc @@ -109,7 +109,8 @@ class ProgressBar : public Logger { { auto state(state_.lock()); - if (!state->active) return; + if (!state->active) + return; state->active = false; writeToStderr("\r\e[K"); updateCV.notify_one(); @@ -118,18 +119,20 @@ class ProgressBar : public Logger updateThread.join(); } - bool isVerbose() override { + bool isVerbose() override + { return printBuildLogs; } void log(Verbosity lvl, const FormatOrString & fs) override { - if (lvl > verbosity) return; + if (lvl > verbosity) + return; auto state(state_.lock()); log(*state, lvl, fs.s); } - void logEI(const ErrorInfo &ei) override + void logEI(const ErrorInfo & ei) override { auto state(state_.lock()); @@ -146,13 +149,19 @@ class ProgressBar : public Logger draw(state); } else { auto s2 = s + ANSI_NORMAL "\n"; - if (!isTTY) s2 = filterANSIEscapes(s2, true); + if (!isTTY) + s2 = filterANSIEscapes(s2, true); writeToStderr(s2); } } - void startActivity(ActivityId act, Verbosity lvl, ActivityType type, - const std::string & s, const Fields & fields, ActivityId parent) override + void startActivity( + ActivityId act, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Fields & fields, + ActivityId parent) override { auto state(state_.lock()); @@ -185,11 +194,10 @@ class ProgressBar : public Logger if (type == actSubstitute) { auto name = storePathToName(getS(fields, 0)); auto sub = getS(fields, 1); - i->s = fmt( - hasPrefix(sub, "local") - ? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s" - : "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s", - name, sub); + i->s = + fmt(hasPrefix(sub, "local") ? "copying " ANSI_BOLD "%s" ANSI_NORMAL " from %s" + : "fetching " ANSI_BOLD "%s" ANSI_NORMAL " from %s", + name, sub); } if (type == actPostBuildHook) { @@ -219,8 +227,10 @@ class ProgressBar : public Logger { while (act != 0) { auto i = state.its.find(act); - if (i == state.its.end()) break; - if (i->second->type == type) return true; + if (i == state.its.end()) + break; + if (i->second->type == type) + return true; act = i->second->parent; } return false; @@ -330,7 +340,8 @@ class ProgressBar : public Logger void draw(State & state) { state.haveUpdate = false; - if (!state.active) return; + if (!state.active) + return; std::string line; @@ -342,7 +353,8 @@ class ProgressBar : public Logger } if (!state.activities.empty()) { - if (!status.empty()) line += " "; + if (!status.empty()) + line += " "; auto i = state.activities.rbegin(); while (i != state.activities.rend() && (!i->visible || (i->s.empty() && i->lastLine.empty()))) @@ -356,14 +368,16 @@ class ProgressBar : public Logger line += ")"; } if (!i->lastLine.empty()) { - if (!i->s.empty()) line += ": "; + if (!i->s.empty()) + line += ": "; line += i->lastLine; } } } auto width = getWindowSize().second; - if (width <= 0) width = std::numeric_limits::max(); + if (width <= 0) + width = std::numeric_limits::max(); writeToStderr("\r" + filterANSIEscapes(line, false, width) + ANSI_NORMAL + "\e[K"); } @@ -374,7 +388,8 @@ class ProgressBar : public Logger std::string res; - auto renderActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) { + auto renderActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", + double unit = 1) { auto & act = state.activitiesByType[type]; uint64_t done = act.done, expected = act.done, running = 0, failed = act.failed; for (auto & j : act.its) { @@ -391,15 +406,17 @@ class ProgressBar : public Logger if (running || done || expected || failed) { if (running) if (expected != 0) - s = fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt, - running / unit, done / unit, expected / unit); + s = + fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + + numberFmt, + running / unit, done / unit, expected / unit); else - s = fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL, - running / unit, done / unit); + s = + fmt(ANSI_BLUE + numberFmt + ANSI_NORMAL "/" ANSI_GREEN + numberFmt + ANSI_NORMAL, + running / unit, done / unit); else if (expected != done) if (expected != 0) - s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt, - done / unit, expected / unit); + s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL "/" + numberFmt, done / unit, expected / unit); else s = fmt(ANSI_GREEN + numberFmt + ANSI_NORMAL, done / unit); else @@ -413,10 +430,13 @@ class ProgressBar : public Logger return s; }; - auto showActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", double unit = 1) { + auto showActivity = [&](ActivityType type, const std::string & itemFmt, const std::string & numberFmt = "%d", + double unit = 1) { auto s = renderActivity(type, itemFmt, numberFmt, unit); - if (s.empty()) return; - if (!res.empty()) res += ", "; + if (s.empty()) + return; + if (!res.empty()) + res += ", "; res += s; }; @@ -426,9 +446,17 @@ class ProgressBar : public Logger auto s2 = renderActivity(actCopyPath, "%s MiB", "%.1f", MiB); if (!s1.empty() || !s2.empty()) { - if (!res.empty()) res += ", "; - if (s1.empty()) res += "0 copied"; else res += s1; - if (!s2.empty()) { res += " ("; res += s2; res += ')'; } + if (!res.empty()) + res += ", "; + if (s1.empty()) + res += "0 copied"; + else + res += s1; + if (!s2.empty()) { + res += " ("; + res += s2; + res += ')'; + } } showActivity(actFileTransfer, "%s MiB DL", "%.1f", MiB); @@ -437,7 +465,8 @@ class ProgressBar : public Logger auto s = renderActivity(actOptimiseStore, "%s paths optimised"); if (s != "") { s += fmt(", %.1f MiB / %d inodes freed", state.bytesLinked / MiB, state.filesLinked); - if (!res.empty()) res += ", "; + if (!res.empty()) + res += ", "; res += s; } } @@ -446,12 +475,14 @@ class ProgressBar : public Logger showActivity(actVerifyPaths, "%s paths verified"); if (state.corruptedPaths) { - if (!res.empty()) res += ", "; + if (!res.empty()) + res += ", "; res += fmt(ANSI_RED "%d corrupted" ANSI_NORMAL, state.corruptedPaths); } if (state.untrustedPaths) { - if (!res.empty()) res += ", "; + if (!res.empty()) + res += ", "; res += fmt(ANSI_RED "%d untrusted" ANSI_NORMAL, state.untrustedPaths); } @@ -473,10 +504,12 @@ class ProgressBar : public Logger std::optional ask(std::string_view msg) override { auto state(state_.lock()); - if (!state->active || !isatty(STDIN_FILENO)) return {}; + if (!state->active || !isatty(STDIN_FILENO)) + return {}; std::cerr << fmt("\r\e[K%s ", msg); auto s = trim(readLine(STDIN_FILENO)); - if (s.size() != 1) return {}; + if (s.size() != 1) + return {}; draw(*state); return s[0]; } @@ -484,10 +517,7 @@ class ProgressBar : public Logger Logger * makeProgressBar(bool printBuildLogs) { - return new ProgressBar( - printBuildLogs, - shouldANSI() - ); + return new ProgressBar(printBuildLogs, shouldANSI()); } void startProgressBar(bool printBuildLogs) @@ -498,8 +528,8 @@ void startProgressBar(bool printBuildLogs) void stopProgressBar() { auto progressBar = dynamic_cast(logger); - if (progressBar) progressBar->stop(); - + if (progressBar) + progressBar->stop(); } } diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 31454e49d170..c3166a9b9f99 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -29,22 +29,21 @@ #include - namespace nix { - static bool gcWarning = true; void printGCWarning() { - if (!gcWarning) return; + if (!gcWarning) + return; static bool haveWarned = false; - warnOnce(haveWarned, + warnOnce( + haveWarned, "you did not specify '--add-root'; " "the result might be removed by the garbage collector"); } - void printMissing(ref store, const std::vector & paths, Verbosity lvl) { uint64_t downloadSize, narSize; @@ -53,10 +52,14 @@ void printMissing(ref store, const std::vector & paths, Verb printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl); } - -void printMissing(ref store, const StorePathSet & willBuild, - const StorePathSet & willSubstitute, const StorePathSet & unknown, - uint64_t downloadSize, uint64_t narSize, Verbosity lvl) +void printMissing( + ref store, + const StorePathSet & willBuild, + const StorePathSet & willSubstitute, + const StorePathSet & unknown, + uint64_t downloadSize, + uint64_t narSize, + Verbosity lvl) { if (!willBuild.empty()) { if (willBuild.size() == 1) @@ -73,37 +76,34 @@ void printMissing(ref store, const StorePathSet & willBuild, const float downloadSizeMiB = downloadSize / (1024.f * 1024.f); const float narSizeMiB = narSize / (1024.f * 1024.f); if (willSubstitute.size() == 1) { - printMsg(lvl, "this path will be fetched (%.2f MiB download, %.2f MiB unpacked):", - downloadSizeMiB, - narSizeMiB); + printMsg( + lvl, "this path will be fetched (%.2f MiB download, %.2f MiB unpacked):", downloadSizeMiB, narSizeMiB); } else { - printMsg(lvl, "these %d paths will be fetched (%.2f MiB download, %.2f MiB unpacked):", - willSubstitute.size(), - downloadSizeMiB, - narSizeMiB); + printMsg( + lvl, "these %d paths will be fetched (%.2f MiB download, %.2f MiB unpacked):", willSubstitute.size(), + downloadSizeMiB, narSizeMiB); } for (auto & i : willSubstitute) printMsg(lvl, " %s", store->printStorePath(i)); } if (!unknown.empty()) { - printMsg(lvl, "don't know how to build these paths%s:", - (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")); + printMsg( + lvl, "don't know how to build these paths%s:", + (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")); for (auto & i : unknown) printMsg(lvl, " %s", store->printStorePath(i)); } } - -std::string getArg(const std::string & opt, - Strings::iterator & i, const Strings::iterator & end) +std::string getArg(const std::string & opt, Strings::iterator & i, const Strings::iterator & end) { ++i; - if (i == end) throw UsageError("'%1%' requires an argument", opt); + if (i == end) + throw UsageError("'%1%' requires an argument", opt); return *i; } - #if OPENSSL_VERSION_NUMBER < 0x10101000L /* OpenSSL is not thread-safe by default - it will randomly crash unless the user supplies a mutex locking function. So let's do @@ -121,7 +121,8 @@ static void opensslLockCallback(int mode, int type, const char * file, int line) static std::once_flag dns_resolve_flag; -static void preloadNSS() { +static void preloadNSS() +{ /* builtin:fetchurl can trigger a DNS lookup, which with glibc can trigger a dynamic library load of one of the glibc NSS libraries in a sandboxed child, which will fail unless the library's already been loaded in the parent. So we force a lookup of an invalid domain to force the NSS machinery to @@ -154,8 +155,7 @@ static void preloadNSS() { }); } -static void sigHandler(int signo) { } - +static void sigHandler(int signo) {} void initNix() { @@ -188,7 +188,8 @@ void initNix() /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */ act.sa_handler = sigHandler; - if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1"); + if (sigaction(SIGUSR1, &act, 0)) + throw SysError("handling SIGUSR1"); #if __APPLE__ /* HACK: on darwin, we need can’t use sigprocmask with SIGWINCH. @@ -196,7 +197,8 @@ void initNix() * can handle the rest. */ struct sigaction sa; sa.sa_handler = sigHandler; - if (sigaction(SIGWINCH, &sa, 0)) throw SysError("handling SIGWINCH"); + if (sigaction(SIGWINCH, &sa, 0)) + throw SysError("handling SIGWINCH"); #endif /* Register a SIGSEGV handler to detect stack overflows. */ @@ -223,51 +225,50 @@ void initNix() preloadNSS(); } - -LegacyArgs::LegacyArgs(const std::string & programName, +LegacyArgs::LegacyArgs( + const std::string & programName, std::function parseArg) - : MixCommonArgs(programName), parseArg(parseArg) + : MixCommonArgs(programName) + , parseArg(parseArg) { addFlag({ .longName = "no-build-output", .shortName = 'Q', .description = "Do not show build output.", - .handler = {[&]() {setLogFormat(LogFormat::raw); }}, + .handler = {[&]() { setLogFormat(LogFormat::raw); }}, }); addFlag({ .longName = "keep-failed", - .shortName ='K', + .shortName = 'K', .description = "Keep temporary directories of failed builds.", - .handler = {&(bool&) settings.keepFailed, true}, + .handler = {&(bool &) settings.keepFailed, true}, }); addFlag({ .longName = "keep-going", - .shortName ='k', + .shortName = 'k', .description = "Keep going after a build fails.", - .handler = {&(bool&) settings.keepGoing, true}, + .handler = {&(bool &) settings.keepGoing, true}, }); addFlag({ .longName = "fallback", .description = "Build from source if substitution fails.", - .handler = {&(bool&) settings.tryFallback, true}, + .handler = {&(bool &) settings.tryFallback, true}, }); - auto intSettingAlias = [&](char shortName, const std::string & longName, - const std::string & description, const std::string & dest) - { - addFlag({ - .longName = longName, - .shortName = shortName, - .description = description, - .labels = {"n"}, - .handler = {[=](std::string s) { - auto n = string2IntWithUnitPrefix(s); - settings.set(dest, std::to_string(n)); - }} - }); + auto intSettingAlias = [&](char shortName, const std::string & longName, const std::string & description, + const std::string & dest) { + addFlag( + {.longName = longName, + .shortName = shortName, + .description = description, + .labels = {"n"}, + .handler = {[=](std::string s) { + auto n = string2IntWithUnitPrefix(s); + settings.set(dest, std::to_string(n)); + }}}); }; intSettingAlias(0, "cores", "Maximum number of CPU cores to use inside a build.", "cores"); @@ -290,23 +291,24 @@ LegacyArgs::LegacyArgs(const std::string & programName, .longName = "store", .description = "The URL of the Nix store to use.", .labels = {"store-uri"}, - .handler = {&(std::string&) settings.storeUri}, + .handler = {&(std::string &) settings.storeUri}, }); } - bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end) { - if (MixCommonArgs::processFlag(pos, end)) return true; + if (MixCommonArgs::processFlag(pos, end)) + return true; bool res = parseArg(pos, end); - if (res) ++pos; + if (res) + ++pos; return res; } - bool LegacyArgs::processArgs(const Strings & args, bool finish) { - if (args.empty()) return true; + if (args.empty()) + return true; assert(args.size() == 1); Strings ss(args); auto pos = ss.begin(); @@ -315,21 +317,20 @@ bool LegacyArgs::processArgs(const Strings & args, bool finish) return true; } - -void parseCmdLine(int argc, char * * argv, - std::function parseArg) +void parseCmdLine( + int argc, char ** argv, std::function parseArg) { parseCmdLine(std::string(baseNameOf(argv[0])), argvToStrings(argc, argv), parseArg); } - -void parseCmdLine(const std::string & programName, const Strings & args, +void parseCmdLine( + const std::string & programName, + const Strings & args, std::function parseArg) { LegacyArgs(programName, parseArg).parseCmdline(args); } - void printVersion(const std::string & programName) { std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl; @@ -342,17 +343,15 @@ void printVersion(const std::string & programName) std::cout << "System type: " << settings.thisSystem << "\n"; std::cout << "Additional system types: " << concatStringsSep(", ", settings.extraPlatforms.get()) << "\n"; std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n"; - std::cout << "System configuration file: " << settings.nixConfDir + "/nix.conf" << "\n"; - std::cout << "User configuration files: " << - concatStringsSep(":", settings.nixUserConfFiles) - << "\n"; + std::cout << "System configuration file: " << settings.nixConfDir + "/nix.conf" + << "\n"; + std::cout << "User configuration files: " << concatStringsSep(":", settings.nixUserConfFiles) << "\n"; std::cout << "Store directory: " << settings.nixStore << "\n"; std::cout << "State directory: " << settings.nixStateDir << "\n"; } throw Exit(); } - void showManPage(const std::string & name) { restoreProcessContext(); @@ -361,7 +360,6 @@ void showManPage(const std::string & name) throw SysError("command 'man %1%' failed", name.c_str()); } - int handleExceptions(const std::string & programName, std::function fun) { ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this @@ -402,13 +400,15 @@ int handleExceptions(const std::string & programName, std::function fun) return 0; } - RunPager::RunPager() { - if (!isatty(STDOUT_FILENO)) return; + if (!isatty(STDOUT_FILENO)) + return; char * pager = getenv("NIX_PAGER"); - if (!pager) pager = getenv("PAGER"); - if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) return; + if (!pager) + pager = getenv("PAGER"); + if (pager && ((std::string) pager == "" || (std::string) pager == "cat")) + return; Pipe toPager; toPager.create(); @@ -433,7 +433,6 @@ RunPager::RunPager() throw SysError("dupping stdout"); } - RunPager::~RunPager() { try { @@ -447,15 +446,12 @@ RunPager::~RunPager() } } - PrintFreed::~PrintFreed() { if (show) - std::cout << fmt("%d store paths deleted, %s freed\n", - results.paths.size(), - showBytes(results.bytesFreed)); + std::cout << fmt("%d store paths deleted, %s freed\n", results.paths.size(), showBytes(results.bytesFreed)); } -Exit::~Exit() { } +Exit::~Exit() {} } diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 0cc56d47d174..799dd0db2382 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -10,15 +10,18 @@ #include - namespace nix { class Exit : public std::exception { public: int status; - Exit() : status(0) { } - Exit(int status) : status(status) { } + Exit() + : status(0) + {} + Exit(int status) + : status(status) + {} virtual ~Exit(); }; @@ -27,10 +30,12 @@ int handleExceptions(const std::string & programName, std::function fun) /* Don't forget to call initPlugins() after settings are initialized! */ void initNix(); -void parseCmdLine(int argc, char * * argv, - std::function parseArg); +void parseCmdLine( + int argc, char ** argv, std::function parseArg); -void parseCmdLine(const std::string & programName, const Strings & args, +void parseCmdLine( + const std::string & programName, + const Strings & args, std::function parseArg); void printVersion(const std::string & programName); @@ -41,32 +46,34 @@ void printGCWarning(); class Store; struct StorePathWithOutputs; +void printMissing(ref store, const std::vector & paths, Verbosity lvl = lvlInfo); + void printMissing( ref store, - const std::vector & paths, + const StorePathSet & willBuild, + const StorePathSet & willSubstitute, + const StorePathSet & unknown, + uint64_t downloadSize, + uint64_t narSize, Verbosity lvl = lvlInfo); -void printMissing(ref store, const StorePathSet & willBuild, - const StorePathSet & willSubstitute, const StorePathSet & unknown, - uint64_t downloadSize, uint64_t narSize, Verbosity lvl = lvlInfo); +std::string getArg(const std::string & opt, Strings::iterator & i, const Strings::iterator & end); -std::string getArg(const std::string & opt, - Strings::iterator & i, const Strings::iterator & end); - -template N getIntArg(const std::string & opt, - Strings::iterator & i, const Strings::iterator & end, bool allowUnit) +template +N getIntArg(const std::string & opt, Strings::iterator & i, const Strings::iterator & end, bool allowUnit) { ++i; - if (i == end) throw UsageError("'%1%' requires an argument", opt); + if (i == end) + throw UsageError("'%1%' requires an argument", opt); return string2IntWithUnitPrefix(*i); } - struct LegacyArgs : public MixCommonArgs { std::function parseArg; - LegacyArgs(const std::string & programName, + LegacyArgs( + const std::string & programName, std::function parseArg); bool processFlag(Strings::iterator & pos, Strings::iterator end) override; @@ -74,7 +81,6 @@ struct LegacyArgs : public MixCommonArgs bool processArgs(const Strings & args, bool finish) override; }; - /* Show the manual page for the specified program. */ void showManPage(const std::string & name); @@ -93,7 +99,6 @@ private: extern volatile ::sig_atomic_t blockInt; - /* GC helpers. */ std::string showBytes(uint64_t bytes); @@ -105,13 +110,13 @@ struct PrintFreed bool show; const GCResults & results; PrintFreed(bool show, const GCResults & results) - : show(show), results(results) { } + : show(show) + , results(results) + {} ~PrintFreed(); }; - /* Install a SIGSEGV handler to detect stack overflows. */ void detectStackOverflow(); - } diff --git a/src/libmain/stack.cc b/src/libmain/stack.cc index b0a4a4c5dbe4..f4beb39750b5 100644 --- a/src/libmain/stack.cc +++ b/src/libmain/stack.cc @@ -9,7 +9,6 @@ namespace nix { - static void sigsegvHandler(int signo, siginfo_t * info, void * ctx) { /* Detect stack overflows by comparing the faulting address with @@ -27,7 +26,8 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx) if (haveSP) { ptrdiff_t diff = (char *) info->si_addr - sp; - if (diff < 0) diff = -diff; + 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)); @@ -40,13 +40,13 @@ static void sigsegvHandler(int signo, siginfo_t * info, void * ctx) sigfillset(&act.sa_mask); act.sa_handler = SIG_DFL; act.sa_flags = 0; - if (sigaction(SIGSEGV, &act, 0)) abort(); + if (sigaction(SIGSEGV, &act, 0)) + abort(); } - void detectStackOverflow() { -#if defined(SA_SIGINFO) && defined (SA_ONSTACK) +#if defined(SA_SIGINFO) && defined(SA_ONSTACK) /* Install a SIGSEGV handler to detect stack overflows. This requires an alternative stack, otherwise the signal cannot be delivered when we're out of stack space. */ @@ -54,9 +54,11 @@ void detectStackOverflow() stack.ss_size = 4096 * 4 + MINSIGSTKSZ; static auto stackBuf = std::make_unique>(stack.ss_size); stack.ss_sp = stackBuf->data(); - if (!stack.ss_sp) throw Error("cannot allocate alternative stack"); + if (!stack.ss_sp) + throw Error("cannot allocate alternative stack"); stack.ss_flags = 0; - if (sigaltstack(&stack, 0) == -1) throw SysError("cannot set alternative stack"); + if (sigaltstack(&stack, 0) == -1) + throw SysError("cannot set alternative stack"); struct sigaction act; sigfillset(&act.sa_mask); @@ -67,5 +69,4 @@ void detectStackOverflow() #endif } - } diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index 9226c4e193c8..b43c2a13a819 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -43,14 +43,15 @@ void BinaryCacheStore::init() upsertFile(cacheInfoFile, "StoreDir: " + storeDir + "\n", "text/x-nix-cache-info"); } else { for (auto & line : tokenizeString(*cacheInfo, "\n")) { - size_t colon= line.find(':'); - if (colon ==std::string::npos) continue; + size_t colon = line.find(':'); + if (colon == std::string::npos) + continue; auto name = line.substr(0, colon); auto value = trim(line.substr(colon + 1, std::string::npos)); if (name == "StoreDir") { if (value != storeDir) - throw Error("binary cache '%s' is for Nix stores with prefix '%s', not '%s'", - getUri(), value, storeDir); + throw Error( + "binary cache '%s' is for Nix stores with prefix '%s', not '%s'", getUri(), value, storeDir); } else if (name == "WantMassQuery") { wantMassQuery.setDefault(value == "1"); } else if (name == "Priority") { @@ -60,32 +61,30 @@ void BinaryCacheStore::init() } } -void BinaryCacheStore::upsertFile(const std::string & path, - std::string && data, - const std::string & mimeType) +void BinaryCacheStore::upsertFile(const std::string & path, std::string && data, const std::string & mimeType) { upsertFile(path, std::make_shared(std::move(data)), mimeType); } -void BinaryCacheStore::getFile(const std::string & path, - Callback> callback) noexcept +void BinaryCacheStore::getFile(const std::string & path, Callback> callback) noexcept { try { callback(getFile(path)); - } catch (...) { callback.rethrow(); } + } catch (...) { + callback.rethrow(); + } } void BinaryCacheStore::getFile(const std::string & path, Sink & sink) { std::promise> promise; - getFile(path, - {[&](std::future> result) { - try { - promise.set_value(result.get()); - } catch (...) { - promise.set_exception(std::current_exception()); - } - }}); + getFile(path, {[&](std::future> result) { + try { + promise.set_value(result.get()); + } catch (...) { + promise.set_exception(std::current_exception()); + } + }}); sink(*promise.get_future().get()); } @@ -114,8 +113,7 @@ void BinaryCacheStore::writeNarInfo(ref narInfo) { auto state_(state.lock()); state_->pathInfoCache.upsert( - std::string(narInfo->path.to_string()), - PathInfoCacheValue { .value = std::shared_ptr(narInfo) }); + std::string(narInfo->path.to_string()), PathInfoCacheValue{.value = std::shared_ptr(narInfo)}); } if (diskCache) @@ -131,8 +129,7 @@ AutoCloseFD openFile(const Path & path) } ref BinaryCacheStore::addToStoreCommon( - Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs, - std::function mkInfo) + Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs, std::function mkInfo) { auto [fdTemp, fnTemp] = createTempFile(); @@ -143,18 +140,19 @@ ref BinaryCacheStore::addToStoreCommon( /* Read the NAR simultaneously into a CompressionSink+FileSink (to write the compressed NAR to disk), into a HashSink (to get the NAR hash), and into a NarAccessor (to get the NAR listing). */ - HashSink fileHashSink { htSHA256 }; + HashSink fileHashSink{htSHA256}; std::shared_ptr narAccessor; - HashSink narHashSink { htSHA256 }; + HashSink narHashSink{htSHA256}; { - FdSink fileSink(fdTemp.get()); - TeeSink teeSinkCompressed { fileSink, fileHashSink }; - auto compressionSink = makeCompressionSink(compression, teeSinkCompressed, parallelCompression, compressionLevel); - TeeSink teeSinkUncompressed { *compressionSink, narHashSink }; - TeeSource teeSource { narSource, teeSinkUncompressed }; - narAccessor = makeNarAccessor(teeSource); - compressionSink->finish(); - fileSink.flush(); + FdSink fileSink(fdTemp.get()); + TeeSink teeSinkCompressed{fileSink, fileHashSink}; + auto compressionSink = + makeCompressionSink(compression, teeSinkCompressed, parallelCompression, compressionLevel); + TeeSink teeSinkUncompressed{*compressionSink, narHashSink}; + TeeSource teeSource{narSource, teeSinkUncompressed}; + narAccessor = makeNarAccessor(teeSource); + compressionSink->finish(); + fileSink.flush(); } auto now2 = std::chrono::steady_clock::now(); @@ -166,19 +164,18 @@ ref BinaryCacheStore::addToStoreCommon( narInfo->fileHash = fileHash; narInfo->fileSize = fileSize; narInfo->url = "nar/" + narInfo->fileHash->to_string(Base32, false) + ".nar" - + (compression == "xz" ? ".xz" : - compression == "bzip2" ? ".bz2" : - compression == "zstd" ? ".zst" : - compression == "lzip" ? ".lzip" : - compression == "lz4" ? ".lz4" : - compression == "br" ? ".br" : - ""); + + (compression == "xz" ? ".xz" + : compression == "bzip2" ? ".bz2" + : compression == "zstd" ? ".zst" + : compression == "lzip" ? ".lzip" + : compression == "lz4" ? ".lz4" + : compression == "br" ? ".br" + : ""); auto duration = std::chrono::duration_cast(now2 - now1).count(); - printMsg(lvlTalkative, "copying path '%1%' (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache", - printStorePath(narInfo->path), info.narSize, - ((1.0 - (double) fileSize / info.narSize) * 100.0), - duration); + printMsg( + lvlTalkative, "copying path '%1%' (%2% bytes, compressed %3$.1f%% in %4% ms) to binary cache", + printStorePath(narInfo->path), info.narSize, ((1.0 - (double) fileSize / info.narSize) * 100.0), duration); /* Verify that all references are valid. This may do some .narinfo reads, but typically they'll already be cached. */ @@ -187,7 +184,8 @@ ref BinaryCacheStore::addToStoreCommon( if (ref != info.path) queryPathInfo(ref); } catch (InvalidPath &) { - throw Error("cannot add '%s' to the binary cache because the reference '%s' is not valid", + throw Error( + "cannot add '%s' to the binary cache because the reference '%s' is not valid", printStorePath(info.path), printStorePath(ref)); } @@ -229,7 +227,8 @@ ref BinaryCacheStore::addToStoreCommon( // FIXME: or should we overwrite? The previous link may point // to a GC'ed file, so overwriting might be useful... - if (fileExists(key)) return; + if (fileExists(key)) + return; printMsg(lvlTalkative, "creating debuginfo link from '%s' to '%s'", key, target); @@ -242,15 +241,13 @@ ref BinaryCacheStore::addToStoreCommon( for (auto & s1 : narAccessor->readDirectory(buildIdDir)) { auto dir = buildIdDir + "/" + s1; - if (narAccessor->stat(dir).type != FSAccessor::tDirectory - || !std::regex_match(s1, regex1)) + if (narAccessor->stat(dir).type != FSAccessor::tDirectory || !std::regex_match(s1, regex1)) continue; for (auto & s2 : narAccessor->readDirectory(dir)) { auto debugPath = dir + "/" + s2; - if (narAccessor->stat(debugPath).type != FSAccessor::tRegular - || !std::regex_match(s2, regex2)) + if (narAccessor->stat(debugPath).type != FSAccessor::tRegular || !std::regex_match(s2, regex2)) continue; auto buildId = s1 + s2; @@ -269,8 +266,8 @@ ref BinaryCacheStore::addToStoreCommon( /* Atomically write the NAR file. */ if (repair || !fileExists(narInfo->url)) { stats.narWrite++; - upsertFile(narInfo->url, - std::make_shared(fnTemp, std::ios_base::in | std::ios_base::binary), + upsertFile( + narInfo->url, std::make_shared(fnTemp, std::ios_base::in | std::ios_base::binary), "application/x-nix-nar"); } else stats.narWriteAverted++; @@ -280,7 +277,8 @@ ref BinaryCacheStore::addToStoreCommon( stats.narWriteCompressionTimeMs += duration; /* Atomically write the NAR info file.*/ - if (secretKey) narInfo->sign(*this, *secretKey); + if (secretKey) + narInfo->sign(*this, *secretKey); writeNarInfo(narInfo); @@ -289,8 +287,8 @@ ref BinaryCacheStore::addToStoreCommon( return narInfo; } -void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource, - RepairFlag repair, CheckSigsFlag checkSigs) +void BinaryCacheStore::addToStore( + const ValidPathInfo & info, Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs) { if (!repair && isValidPath(info.path)) { // FIXME: copyNAR -> null sink @@ -299,28 +297,36 @@ void BinaryCacheStore::addToStore(const ValidPathInfo & info, Source & narSource } addToStoreCommon(narSource, repair, checkSigs, {[&](HashResult nar) { - /* FIXME reinstate these, once we can correctly do hash modulo sink as - needed. We need to throw here in case we uploaded a corrupted store path. */ - // assert(info.narHash == nar.first); - // assert(info.narSize == nar.second); - return info; - }}); + /* FIXME reinstate these, once we can correctly do hash modulo sink as + needed. We need to throw here in case we uploaded a corrupted store path. */ + // assert(info.narHash == nar.first); + // assert(info.narSize == nar.second); + return info; + }}); } -StorePath BinaryCacheStore::addToStoreFromDump(Source & dump, std::string_view name, - FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) +StorePath BinaryCacheStore::addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method, + HashType hashAlgo, + RepairFlag repair, + const StorePathSet & references) { if (method != FileIngestionMethod::Recursive || hashAlgo != htSHA256) unsupported("addToStoreFromDump"); - return addToStoreCommon(dump, repair, CheckSigs, [&](HashResult nar) { - ValidPathInfo info { - makeFixedOutputPath(method, nar.first, name, references), - nar.first, - }; - info.narSize = nar.second; - info.references = references; - return info; - })->path; + return addToStoreCommon( + dump, repair, CheckSigs, + [&](HashResult nar) { + ValidPathInfo info{ + makeFixedOutputPath(method, nar.first, name, references), + nar.first, + }; + info.narSize = nar.second; + info.references = references; + return info; + }) + ->path; } bool BinaryCacheStore::isValidPathUncached(const StorePath & storePath) @@ -336,7 +342,7 @@ void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink) auto info = queryPathInfo(storePath).cast(); LengthSink narSize; - TeeSink tee { sink, narSize }; + TeeSink tee{sink, narSize}; auto decompressor = makeDecompressionSink(info->compression, tee); @@ -349,40 +355,41 @@ void BinaryCacheStore::narFromPath(const StorePath & storePath, Sink & sink) decompressor->finish(); stats.narRead++; - //stats.narReadCompressedBytes += nar->size(); // FIXME + // stats.narReadCompressedBytes += nar->size(); // FIXME stats.narReadBytes += narSize.length; } -void BinaryCacheStore::queryPathInfoUncached(const StorePath & storePath, - Callback> callback) noexcept +void BinaryCacheStore::queryPathInfoUncached( + const StorePath & storePath, Callback> callback) noexcept { auto uri = getUri(); auto storePathS = printStorePath(storePath); - auto act = std::make_shared(*logger, lvlTalkative, actQueryPathInfo, - fmt("querying info about '%s' on '%s'", storePathS, uri), Logger::Fields{storePathS, uri}); + auto act = std::make_shared( + *logger, lvlTalkative, actQueryPathInfo, fmt("querying info about '%s' on '%s'", storePathS, uri), + Logger::Fields{storePathS, uri}); PushActivity pact(act->id); auto narInfoFile = narInfoFileFor(storePath); auto callbackPtr = std::make_shared(std::move(callback)); - getFile(narInfoFile, - {[=](std::future> fut) { - try { - auto data = fut.get(); + getFile(narInfoFile, {[=](std::future> fut) { + try { + auto data = fut.get(); - if (!data) return (*callbackPtr)({}); + if (!data) + return (*callbackPtr)({}); - stats.narInfoRead++; + stats.narInfoRead++; - (*callbackPtr)((std::shared_ptr) - std::make_shared(*this, *data, narInfoFile)); + (*callbackPtr)( + (std::shared_ptr) std::make_shared(*this, *data, narInfoFile)); - (void) act; // force Activity into this lambda to ensure it stays alive - } catch (...) { - callbackPtr->rethrow(); - } - }}); + (void) act; // force Activity into this lambda to ensure it stays alive + } catch (...) { + callbackPtr->rethrow(); + } + }}); } StorePath BinaryCacheStore::addToStore( @@ -398,7 +405,7 @@ StorePath BinaryCacheStore::addToStore( non-recursive+sha256 so we can just use the default implementation of this method in terms of addToStoreFromDump. */ - HashSink sink { hashAlgo }; + HashSink sink{hashAlgo}; if (method == FileIngestionMethod::Recursive) { dumpPath(srcPath, sink, filter); } else { @@ -406,29 +413,27 @@ StorePath BinaryCacheStore::addToStore( } auto h = sink.finish().first; - auto source = sinkToSource([&](Sink & sink) { - dumpPath(srcPath, sink, filter); - }); - return addToStoreCommon(*source, repair, CheckSigs, [&](HashResult nar) { - ValidPathInfo info { - makeFixedOutputPath(method, h, name, references), - nar.first, - }; - info.narSize = nar.second; - info.references = references; - info.ca = FixedOutputHash { - .method = method, - .hash = h, - }; - return info; - })->path; + auto source = sinkToSource([&](Sink & sink) { dumpPath(srcPath, sink, filter); }); + return addToStoreCommon( + *source, repair, CheckSigs, + [&](HashResult nar) { + ValidPathInfo info{ + makeFixedOutputPath(method, h, name, references), + nar.first, + }; + info.narSize = nar.second; + info.references = references; + info.ca = FixedOutputHash{ + .method = method, + .hash = h, + }; + return info; + }) + ->path; } StorePath BinaryCacheStore::addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) { auto textHash = hashString(htSHA256, s); auto path = makeTextPath(name, textHash, references); @@ -439,41 +444,43 @@ StorePath BinaryCacheStore::addTextToStore( StringSink sink; dumpString(s, sink); StringSource source(sink.s); - return addToStoreCommon(source, repair, CheckSigs, [&](HashResult nar) { - ValidPathInfo info { path, nar.first }; - info.narSize = nar.second; - info.ca = TextHash { textHash }; - info.references = references; - return info; - })->path; + return addToStoreCommon( + source, repair, CheckSigs, + [&](HashResult nar) { + ValidPathInfo info{path, nar.first}; + info.narSize = nar.second; + info.ca = TextHash{textHash}; + info.references = references; + return info; + }) + ->path; } -void BinaryCacheStore::queryRealisationUncached(const DrvOutput & id, - Callback> callback) noexcept +void BinaryCacheStore::queryRealisationUncached( + const DrvOutput & id, Callback> callback) noexcept { auto outputInfoFilePath = realisationsPrefix + "/" + id.to_string() + ".doi"; auto callbackPtr = std::make_shared(std::move(callback)); - Callback> newCallback = { - [=](std::future> fut) { - try { - auto data = fut.get(); - if (!data) return (*callbackPtr)({}); - - auto realisation = Realisation::fromJSON( - nlohmann::json::parse(*data), outputInfoFilePath); - return (*callbackPtr)(std::make_shared(realisation)); - } catch (...) { - callbackPtr->rethrow(); - } + Callback> newCallback = {[=](std::future> fut) { + try { + auto data = fut.get(); + if (!data) + return (*callbackPtr)({}); + + auto realisation = Realisation::fromJSON(nlohmann::json::parse(*data), outputInfoFilePath); + return (*callbackPtr)(std::make_shared(realisation)); + } catch (...) { + callbackPtr->rethrow(); } - }; + }}; getFile(outputInfoFilePath, std::move(newCallback)); } -void BinaryCacheStore::registerDrvOutput(const Realisation& info) { +void BinaryCacheStore::registerDrvOutput(const Realisation & info) +{ if (diskCache) diskCache->upsertRealisation(getUri(), info); auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi"; @@ -507,7 +514,8 @@ std::optional BinaryCacheStore::getBuildLog(const StorePath & path) try { auto info = queryPathInfo(path); // FIXME: add a "Log" field to .narinfo - if (!info->deriver) return std::nullopt; + if (!info->deriver) + return std::nullopt; drvPath = *info->deriver; } catch (InvalidPath &) { return std::nullopt; diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh index ca538b3cbfb7..3414cf1ae28e 100644 --- a/src/libstore/binary-cache-store.hh +++ b/src/libstore/binary-cache-store.hh @@ -16,22 +16,26 @@ struct BinaryCacheStoreConfig : virtual StoreConfig { using StoreConfig::StoreConfig; - const Setting compression{(StoreConfig*) this, "xz", "compression", "NAR compression method ('xz', 'bzip2', 'gzip', 'zstd', or 'none')"}; - const Setting writeNARListing{(StoreConfig*) this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"}; - const Setting writeDebugInfo{(StoreConfig*) this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"}; - const Setting secretKeyFile{(StoreConfig*) this, "", "secret-key", "path to secret key used to sign the binary cache"}; - const Setting localNarCache{(StoreConfig*) this, "", "local-nar-cache", "path to a local cache of NARs"}; - const Setting parallelCompression{(StoreConfig*) this, false, "parallel-compression", + const Setting compression{ + (StoreConfig *) this, "xz", "compression", "NAR compression method ('xz', 'bzip2', 'gzip', 'zstd', or 'none')"}; + const Setting writeNARListing{ + (StoreConfig *) this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"}; + const Setting writeDebugInfo{ + (StoreConfig *) this, false, "index-debug-info", "whether to index DWARF debug info files by build ID"}; + const Setting secretKeyFile{ + (StoreConfig *) this, "", "secret-key", "path to secret key used to sign the binary cache"}; + const Setting localNarCache{(StoreConfig *) this, "", "local-nar-cache", "path to a local cache of NARs"}; + const Setting parallelCompression{ + (StoreConfig *) this, false, "parallel-compression", "enable multi-threading compression for NARs, available for xz and zstd only currently"}; - const Setting compressionLevel{(StoreConfig*) this, -1, "compression-level", + const Setting compressionLevel{ + (StoreConfig *) this, -1, "compression-level", "specify 'preset level' of compression to be used with NARs: " "meaning and accepted range of values depends on compression method selected, " "other than -1 which we reserve to indicate Nix defaults should be used"}; }; -class BinaryCacheStore : public virtual BinaryCacheStoreConfig, - public virtual Store, - public virtual LogStore +class BinaryCacheStore : public virtual BinaryCacheStoreConfig, public virtual Store, public virtual LogStore { private: @@ -49,11 +53,11 @@ public: virtual bool fileExists(const std::string & path) = 0; - virtual void upsertFile(const std::string & path, - std::shared_ptr> istream, - const std::string & mimeType) = 0; + virtual void upsertFile( + const std::string & path, std::shared_ptr> istream, const std::string & mimeType) = 0; - void upsertFile(const std::string & path, + void upsertFile( + const std::string & path, // FIXME: use std::string_view std::string && data, const std::string & mimeType); @@ -66,9 +70,7 @@ public: /* Fetch the specified file and call the specified callback with the result. A subclass may implement this asynchronously. */ - virtual void getFile( - const std::string & path, - Callback> callback) noexcept; + virtual void getFile(const std::string & path, Callback> callback) noexcept; std::optional getFile(const std::string & path); @@ -85,24 +87,33 @@ private: void writeNarInfo(ref narInfo); ref addToStoreCommon( - Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs, + Source & narSource, + RepairFlag repair, + CheckSigsFlag checkSigs, std::function mkInfo); public: bool isValidPathUncached(const StorePath & path) override; - void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept override; + void queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept override; std::optional queryPathFromHashPart(const std::string & hashPart) override - { unsupported("queryPathFromHashPart"); } + { + unsupported("queryPathFromHashPart"); + } - void addToStore(const ValidPathInfo & info, Source & narSource, - RepairFlag repair, CheckSigsFlag checkSigs) override; + void + addToStore(const ValidPathInfo & info, Source & narSource, RepairFlag repair, CheckSigsFlag checkSigs) override; - StorePath addToStoreFromDump(Source & dump, std::string_view name, - FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override; + StorePath addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method, + HashType hashAlgo, + RepairFlag repair, + const StorePathSet & references) override; StorePath addToStore( std::string_view name, @@ -114,15 +125,12 @@ public: const StorePathSet & references) override; StorePath addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) override; + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) override; void registerDrvOutput(const Realisation & info) override; - void queryRealisationUncached(const DrvOutput &, - Callback> callback) noexcept override; + void queryRealisationUncached( + const DrvOutput &, Callback> callback) noexcept override; void narFromPath(const StorePath & path, Sink & sink) override; @@ -133,7 +141,6 @@ public: std::optional getBuildLog(const StorePath & path) override; void addBuildLog(const StorePath & drvPath, std::string_view log) override; - }; MakeError(NoSuchBinaryCacheFile, Error); diff --git a/src/libstore/build-result.hh b/src/libstore/build-result.hh index 24fb1f763d47..c02801ff8a94 100644 --- a/src/libstore/build-result.hh +++ b/src/libstore/build-result.hh @@ -6,7 +6,6 @@ #include #include - namespace nix { struct BuildResult @@ -22,7 +21,7 @@ struct BuildResult InputRejected, OutputRejected, TransientFailure, // possibly transient - CachedFailure, // no longer used + CachedFailure, // no longer used TimedOut, MiscFailure, DependencyFailed, @@ -35,24 +34,40 @@ struct BuildResult // FIXME: include entire ErrorInfo object. std::string errorMsg; - std::string toString() const { + std::string toString() const + { auto strStatus = [&]() { switch (status) { - case Built: return "Built"; - case Substituted: return "Substituted"; - case AlreadyValid: return "AlreadyValid"; - case PermanentFailure: return "PermanentFailure"; - case InputRejected: return "InputRejected"; - case OutputRejected: return "OutputRejected"; - case TransientFailure: return "TransientFailure"; - case CachedFailure: return "CachedFailure"; - case TimedOut: return "TimedOut"; - case MiscFailure: return "MiscFailure"; - case DependencyFailed: return "DependencyFailed"; - case LogLimitExceeded: return "LogLimitExceeded"; - case NotDeterministic: return "NotDeterministic"; - case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid"; - default: return "Unknown"; + case Built: + return "Built"; + case Substituted: + return "Substituted"; + case AlreadyValid: + return "AlreadyValid"; + case PermanentFailure: + return "PermanentFailure"; + case InputRejected: + return "InputRejected"; + case OutputRejected: + return "OutputRejected"; + case TransientFailure: + return "TransientFailure"; + case CachedFailure: + return "CachedFailure"; + case TimedOut: + return "TimedOut"; + case MiscFailure: + return "MiscFailure"; + case DependencyFailed: + return "DependencyFailed"; + case LogLimitExceeded: + return "LogLimitExceeded"; + case NotDeterministic: + return "NotDeterministic"; + case ResolvesToAlreadyValid: + return "ResolvesToAlreadyValid"; + default: + return "Unknown"; }; }(); return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg); diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 3fff2385fdac..daf0671f2e6f 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -64,28 +64,29 @@ namespace nix { -DerivationGoal::DerivationGoal(const StorePath & drvPath, - const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode) - : Goal(worker, DerivedPath::Built { .drvPath = drvPath, .outputs = wantedOutputs }) +DerivationGoal::DerivationGoal( + const StorePath & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode) + : Goal(worker, DerivedPath::Built{.drvPath = drvPath, .outputs = wantedOutputs}) , useDerivation(true) , drvPath(drvPath) , wantedOutputs(wantedOutputs) , buildMode(buildMode) { state = &DerivationGoal::getDerivation; - name = fmt( - "building of '%s' from .drv file", - DerivedPath::Built { drvPath, wantedOutputs }.to_string(worker.store)); + name = fmt("building of '%s' from .drv file", DerivedPath::Built{drvPath, wantedOutputs}.to_string(worker.store)); trace("created"); mcExpectedBuilds = std::make_unique>(worker.expectedBuilds); worker.updateProgress(); } - -DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv, - const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode) - : Goal(worker, DerivedPath::Built { .drvPath = drvPath, .outputs = wantedOutputs }) +DerivationGoal::DerivationGoal( + const StorePath & drvPath, + const BasicDerivation & drv, + const StringSet & wantedOutputs, + Worker & worker, + BuildMode buildMode) + : Goal(worker, DerivedPath::Built{.drvPath = drvPath, .outputs = wantedOutputs}) , useDerivation(false) , drvPath(drvPath) , wantedOutputs(wantedOutputs) @@ -94,9 +95,9 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation this->drv = std::make_unique(drv); state = &DerivationGoal::haveDerivation; - name = fmt( - "building of '%s' from in-memory derivation", - DerivedPath::Built { drvPath, drv.outputNames() }.to_string(worker.store)); + name = + fmt("building of '%s' from in-memory derivation", + DerivedPath::Built{drvPath, drv.outputNames()}.to_string(worker.store)); trace("created"); mcExpectedBuilds = std::make_unique>(worker.expectedBuilds); @@ -107,15 +108,17 @@ DerivationGoal::DerivationGoal(const StorePath & drvPath, const BasicDerivation worker.store.addTempRoot(this->drvPath); } - DerivationGoal::~DerivationGoal() { /* Careful: we should never ever throw an exception from a destructor. */ - try { closeLogFile(); } catch (...) { ignoreException(); } + try { + closeLogFile(); + } catch (...) { + ignoreException(); + } } - std::string DerivationGoal::key() { /* Ensure that derivations get built in order of their name, @@ -125,20 +128,17 @@ std::string DerivationGoal::key() return "b$" + std::string(drvPath.name()) + "$" + worker.store.printStorePath(drvPath); } - void DerivationGoal::killChild() { hook.reset(); } - void DerivationGoal::timedOut(Error && ex) { killChild(); done(BuildResult::TimedOut, {}, ex); } - void DerivationGoal::work() { (this->*state)(); @@ -147,7 +147,8 @@ void DerivationGoal::work() void DerivationGoal::addWantedOutputs(const StringSet & outputs) { /* If we already want all outputs, there is nothing to do. */ - if (wantedOutputs.empty()) return; + if (wantedOutputs.empty()) + return; if (outputs.empty()) { wantedOutputs.clear(); @@ -158,7 +159,6 @@ void DerivationGoal::addWantedOutputs(const StringSet & outputs) needRestart = true; } - void DerivationGoal::getDerivation() { trace("init"); @@ -176,13 +176,14 @@ void DerivationGoal::getDerivation() state = &DerivationGoal::loadDerivation; } - void DerivationGoal::loadDerivation() { trace("loading derivation"); if (nrFailed != 0) { - done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath))); + done( + BuildResult::MiscFailure, {}, + Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath))); return; } @@ -199,7 +200,6 @@ void DerivationGoal::loadDerivation() haveDerivation(); } - void DerivationGoal::haveDerivation() { trace("have derivation"); @@ -215,17 +215,11 @@ void DerivationGoal::haveDerivation() for (auto & [outputName, output] : drv->outputs) { auto randomPath = StorePath::random(outputPathName(drv->name, outputName)); assert(!worker.store.isValidPath(randomPath)); - initialOutputs.insert({ - outputName, - InitialOutput { - .wanted = true, - .outputHash = impureOutputHash, - .known = InitialOutputStatus { - .path = randomPath, - .status = PathStatus::Absent - } - } - }); + initialOutputs.insert( + {outputName, InitialOutput{ + .wanted = true, + .outputHash = impureOutputHash, + .known = InitialOutputStatus{.path = randomPath, .status = PathStatus::Absent}}}); } gaveUpOnSubstitution(); @@ -238,13 +232,11 @@ void DerivationGoal::haveDerivation() auto outputHashes = staticOutputHashes(worker.evalStore, *drv); for (auto & [outputName, outputHash] : outputHashes) - initialOutputs.insert({ - outputName, - InitialOutput { - .wanted = true, // Will be refined later - .outputHash = outputHash - } - }); + initialOutputs.insert( + {outputName, + InitialOutput{ + .wanted = true, // Will be refined later + .outputHash = outputHash}}); /* Check what outputs paths are not already valid. */ auto [allValid, validOutputs] = checkPathValidity(); @@ -260,21 +252,14 @@ void DerivationGoal::haveDerivation() them. */ if (settings.useSubstitutes && parsedDrv->substitutesAllowed()) for (auto & [outputName, status] : initialOutputs) { - if (!status.wanted) continue; + if (!status.wanted) + continue; if (!status.known) - addWaitee( - upcast_goal( - worker.makeDrvOutputSubstitutionGoal( - DrvOutput{status.outputHash, outputName}, - buildMode == bmRepair ? Repair : NoRepair - ) - ) - ); + addWaitee(upcast_goal(worker.makeDrvOutputSubstitutionGoal( + DrvOutput{status.outputHash, outputName}, buildMode == bmRepair ? Repair : NoRepair))); else addWaitee(upcast_goal(worker.makePathSubstitutionGoal( - status.known->path, - buildMode == bmRepair ? Repair : NoRepair, - getDerivationCA(*drv)))); + status.known->path, buildMode == bmRepair ? Repair : NoRepair, getDerivationCA(*drv)))); } if (waitees.empty()) /* to prevent hang (no wake-up event) */ @@ -283,7 +268,6 @@ void DerivationGoal::haveDerivation() state = &DerivationGoal::outputsSubstitutionTried; } - void DerivationGoal::outputsSubstitutionTried() { trace("all outputs substituted (maybe)"); @@ -291,8 +275,10 @@ void DerivationGoal::outputsSubstitutionTried() assert(drv->type().isPure()); if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) { - done(BuildResult::TransientFailure, {}, - Error("some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ", + done( + BuildResult::TransientFailure, {}, + Error( + "some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ", worker.store.printStorePath(drvPath))); return; } @@ -305,7 +291,8 @@ void DerivationGoal::outputsSubstitutionTried() In particular, it may be the case that the hole in the closure is an output of the current derivation, which causes a loop if retried. */ - if (nrIncompleteClosure > 0 && nrIncompleteClosure == nrFailed) retrySubstitution = true; + if (nrIncompleteClosure > 0 && nrIncompleteClosure == nrFailed) + retrySubstitution = true; nrFailed = nrNoSubstituters = nrIncompleteClosure = 0; @@ -326,14 +313,13 @@ void DerivationGoal::outputsSubstitutionTried() return; } if (buildMode == bmCheck && !allValid) - throw Error("some outputs of '%s' are not valid, so checking is not possible", - worker.store.printStorePath(drvPath)); + throw Error( + "some outputs of '%s' are not valid, so checking is not possible", worker.store.printStorePath(drvPath)); /* Nothing to wait for; tail call */ gaveUpOnSubstitution(); } - /* At least one of the output paths could not be produced using a substitute. So we have to build instead. */ void DerivationGoal::gaveUpOnSubstitution() @@ -347,8 +333,8 @@ void DerivationGoal::gaveUpOnSubstitution() if (drv->type().isPure() && !drv->type().isFixed()) { auto inputDrv = worker.evalStore.readDerivation(i.first); if (!inputDrv.type().isPure()) - throw Error("pure derivation '%s' depends on impure derivation '%s'", - worker.store.printStorePath(drvPath), + throw Error( + "pure derivation '%s' depends on impure derivation '%s'", worker.store.printStorePath(drvPath), worker.store.printStorePath(i.first)); } @@ -365,10 +351,12 @@ void DerivationGoal::gaveUpOnSubstitution() } for (auto & i : drv->inputSrcs) { - if (worker.store.isValidPath(i)) continue; + if (worker.store.isValidPath(i)) + continue; if (!settings.useSubstitutes) - throw Error("dependency '%s' of '%s' does not exist, and substitution is disabled", - worker.store.printStorePath(i), worker.store.printStorePath(drvPath)); + throw Error( + "dependency '%s' of '%s' does not exist, and substitution is disabled", worker.store.printStorePath(i), + worker.store.printStorePath(drvPath)); addWaitee(upcast_goal(worker.makePathSubstitutionGoal(i))); } @@ -378,7 +366,6 @@ void DerivationGoal::gaveUpOnSubstitution() state = &DerivationGoal::inputsRealised; } - void DerivationGoal::repairClosure() { assert(drv->type().isPure()); @@ -392,7 +379,8 @@ void DerivationGoal::repairClosure() auto outputs = queryDerivationOutputMap(); StorePathSet outputClosure; for (auto & i : outputs) { - if (!wantOutput(i.first, wantedOutputs)) continue; + if (!wantOutput(i.first, wantedOutputs)) + continue; worker.store.computeFSClosure(i.second, outputClosure); } @@ -404,7 +392,8 @@ void DerivationGoal::repairClosure() derivation is responsible for which path in the output closure. */ StorePathSet inputClosure; - if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure); + if (useDerivation) + worker.store.computeFSClosure(drvPath, inputClosure); std::map outputsToDrv; for (auto & i : inputClosure) if (i.isDerivation()) { @@ -416,10 +405,11 @@ void DerivationGoal::repairClosure() /* Check each path (slow!). */ for (auto & i : outputClosure) { - if (worker.pathContentsGood(i)) continue; + if (worker.pathContentsGood(i)) + continue; printError( - "found corrupted or missing path '%s' in the output closure of '%s'", - worker.store.printStorePath(i), worker.store.printStorePath(drvPath)); + "found corrupted or missing path '%s' in the output closure of '%s'", worker.store.printStorePath(i), + worker.store.printStorePath(drvPath)); auto drvPath2 = outputsToDrv.find(i); if (drvPath2 == outputsToDrv.end()) addWaitee(upcast_goal(worker.makePathSubstitutionGoal(i, Repair))); @@ -435,17 +425,16 @@ void DerivationGoal::repairClosure() state = &DerivationGoal::closureRepaired; } - void DerivationGoal::closureRepaired() { trace("closure repaired"); if (nrFailed > 0) - throw Error("some paths in the output closure of derivation '%s' could not be repaired", + throw Error( + "some paths in the output closure of derivation '%s' could not be repaired", worker.store.printStorePath(drvPath)); done(BuildResult::AlreadyValid, assertPathValidity()); } - void DerivationGoal::inputsRealised() { trace("all inputs realised"); @@ -453,9 +442,10 @@ void DerivationGoal::inputsRealised() if (nrFailed != 0) { if (!useDerivation) throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath)); - done(BuildResult::DependencyFailed, {}, Error( - "%s dependencies of derivation '%s' failed to build", - nrFailed, worker.store.printStorePath(drvPath))); + done( + BuildResult::DependencyFailed, {}, + Error( + "%s dependencies of derivation '%s' failed to build", nrFailed, worker.store.printStorePath(drvPath))); return; } @@ -475,25 +465,24 @@ void DerivationGoal::inputsRealised() auto & fullDrv = *dynamic_cast(drv.get()); auto drvType = fullDrv.type(); - bool resolveDrv = std::visit(overloaded { - [&](const DerivationType::InputAddressed & ia) { - /* must resolve if deferred. */ - return ia.deferred; - }, - [&](const DerivationType::ContentAddressed & ca) { - return !fullDrv.inputDrvs.empty() && ( - ca.fixed - /* Can optionally resolve if fixed, which is good - for avoiding unnecessary rebuilds. */ - ? settings.isExperimentalFeatureEnabled(Xp::CaDerivations) - /* Must resolve if floating and there are any inputs - drvs. */ - : true); - }, - [&](const DerivationType::Impure &) { - return true; - } - }, drvType.raw()); + bool resolveDrv = std::visit( + overloaded{ + [&](const DerivationType::InputAddressed & ia) { + /* must resolve if deferred. */ + return ia.deferred; + }, + [&](const DerivationType::ContentAddressed & ca) { + return !fullDrv.inputDrvs.empty() + && (ca.fixed + /* Can optionally resolve if fixed, which is good + for avoiding unnecessary rebuilds. */ + ? settings.isExperimentalFeatureEnabled(Xp::CaDerivations) + /* Must resolve if floating and there are any inputs + drvs. */ + : true); + }, + [&](const DerivationType::Impure &) { return true; }}, + drvType.raw()); if (resolveDrv && !fullDrv.inputDrvs.empty()) { settings.requireExperimentalFeature(Xp::CaDerivations); @@ -503,21 +492,21 @@ void DerivationGoal::inputsRealised() stub goal aliasing that resolved derivation goal. */ std::optional attempt = fullDrv.tryResolve(worker.store, inputDrvOutputs); assert(attempt); - Derivation drvResolved { *std::move(attempt) }; + Derivation drvResolved{*std::move(attempt)}; auto pathResolved = writeDerivation(worker.store, drvResolved); - auto msg = fmt("resolved derivation: '%s' -> '%s'", - worker.store.printStorePath(drvPath), - worker.store.printStorePath(pathResolved)); - act = std::make_unique(*logger, lvlInfo, actBuildWaiting, msg, - Logger::Fields { - worker.store.printStorePath(drvPath), - worker.store.printStorePath(pathResolved), - }); - - resolvedDrvGoal = worker.makeDerivationGoal( - pathResolved, wantedOutputs, buildMode); + auto msg = + fmt("resolved derivation: '%s' -> '%s'", worker.store.printStorePath(drvPath), + worker.store.printStorePath(pathResolved)); + act = std::make_unique( + *logger, lvlInfo, actBuildWaiting, msg, + Logger::Fields{ + worker.store.printStorePath(drvPath), + worker.store.printStorePath(pathResolved), + }); + + resolvedDrvGoal = worker.makeDerivationGoal(pathResolved, wantedOutputs, buildMode); addWaitee(resolvedDrvGoal); state = &DerivationGoal::resolvedFinished; @@ -529,7 +518,7 @@ void DerivationGoal::inputsRealised() `i' as input paths. Only add the closures of output paths that are specified as inputs. */ for (auto & j : wantedDepOutputs) - if (auto outPath = get(inputDrvOutputs, { depDrvPath, j })) + if (auto outPath = get(inputDrvOutputs, {depDrvPath, j})) worker.store.computeFSClosure(*outPath, inputPaths); else throw Error( @@ -556,19 +545,22 @@ void DerivationGoal::inputsRealised() state = &DerivationGoal::tryToBuild; worker.wakeUp(shared_from_this()); - buildResult = BuildResult { .path = buildResult.path }; + buildResult = BuildResult{.path = buildResult.path}; } void DerivationGoal::started() { - auto msg = fmt( - buildMode == bmRepair ? "repairing outputs of '%s'" : - buildMode == bmCheck ? "checking outputs of '%s'" : - nrRounds > 1 ? "building '%s' (round %d/%d)" : - "building '%s'", worker.store.printStorePath(drvPath), curRound, nrRounds); + auto msg = + fmt(buildMode == bmRepair ? "repairing outputs of '%s'" + : buildMode == bmCheck ? "checking outputs of '%s'" + : nrRounds > 1 ? "building '%s' (round %d/%d)" + : "building '%s'", + worker.store.printStorePath(drvPath), curRound, nrRounds); fmt("building '%s'", worker.store.printStorePath(drvPath)); - if (hook) msg += fmt(" on '%s'", machineName); - act = std::make_unique(*logger, lvlInfo, actBuild, msg, + if (hook) + msg += fmt(" on '%s'", machineName); + act = std::make_unique( + *logger, lvlInfo, actBuild, msg, Logger::Fields{worker.store.printStorePath(drvPath), hook ? machineName : "", curRound, nrRounds}); mcRunningBuilds = std::make_unique>(worker.runningBuilds); worker.updateProgress(); @@ -599,16 +591,14 @@ void DerivationGoal::tryToBuild() if (i.second.second) lockFiles.insert(worker.store.Store::toRealPath(*i.second.second)); else - lockFiles.insert( - worker.store.Store::toRealPath(drvPath) + "." + i.first - ); + lockFiles.insert(worker.store.Store::toRealPath(drvPath) + "." + i.first); } } if (!outputLocks.lockPaths(lockFiles, "", false)) { if (!actLock) - actLock = std::make_unique(*logger, lvlWarn, actBuildWaiting, - fmt("waiting for lock on %s", yellowtxt(showPaths(lockFiles)))); + actLock = std::make_unique( + *logger, lvlWarn, actBuildWaiting, fmt("waiting for lock on %s", yellowtxt(showPaths(lockFiles)))); worker.waitForAWhile(shared_from_this()); return; } @@ -634,7 +624,8 @@ void DerivationGoal::tryToBuild() /* If any of the outputs already exist but are not valid, delete them. */ for (auto & [_, status] : initialOutputs) { - if (!status.known || status.known->isValid()) continue; + if (!status.known || status.known->isValid()) + continue; auto storePath = status.known->path; debug("removing invalid path '%s'", worker.store.printStorePath(status.known->path)); deletePath(worker.store.Store::toRealPath(storePath)); @@ -644,31 +635,31 @@ void DerivationGoal::tryToBuild() `preferLocalBuild' set. Also, check and repair modes are only supported for local builds. */ bool buildLocally = - (buildMode != bmNormal || parsedDrv->willBuildLocally(worker.store)) - && settings.maxBuildJobs.get() != 0; + (buildMode != bmNormal || parsedDrv->willBuildLocally(worker.store)) && settings.maxBuildJobs.get() != 0; if (!buildLocally) { switch (tryBuildHook()) { - case rpAccept: - /* Yes, it has started doing so. Wait until we get - EOF from the hook. */ - actLock.reset(); - buildResult.startTime = time(0); // inexact - state = &DerivationGoal::buildDone; - started(); - return; - case rpPostpone: - /* Not now; wait until at least one child finishes or - the wake-up timeout expires. */ - if (!actLock) - actLock = std::make_unique(*logger, lvlWarn, actBuildWaiting, - fmt("waiting for a machine to build '%s'", yellowtxt(worker.store.printStorePath(drvPath)))); - worker.waitForAWhile(shared_from_this()); - outputLocks.unlock(); - return; - case rpDecline: - /* We should do it ourselves. */ - break; + case rpAccept: + /* Yes, it has started doing so. Wait until we get + EOF from the hook. */ + actLock.reset(); + buildResult.startTime = time(0); // inexact + state = &DerivationGoal::buildDone; + started(); + return; + case rpPostpone: + /* Not now; wait until at least one child finishes or + the wake-up timeout expires. */ + if (!actLock) + actLock = std::make_unique( + *logger, lvlWarn, actBuildWaiting, + fmt("waiting for a machine to build '%s'", yellowtxt(worker.store.printStorePath(drvPath)))); + worker.waitForAWhile(shared_from_this()); + outputLocks.unlock(); + return; + case rpDecline: + /* We should do it ourselves. */ + break; } } @@ -678,21 +669,20 @@ void DerivationGoal::tryToBuild() worker.wakeUp(shared_from_this()); } -void DerivationGoal::tryLocalBuild() { +void DerivationGoal::tryLocalBuild() +{ throw Error( "unable to build with a primary store that isn't a local store; " "either pass a different '--store' or enable remote builds." "\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html"); } - static void chmod_(const Path & path, mode_t mode) { if (chmod(path.c_str(), mode) == -1) throw SysError("setting permissions on '%s'", path); } - /* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if it's a directory and we're not root (to be able to update the directory's parent link ".."). */ @@ -712,7 +702,6 @@ static void movePath(const Path & src, const Path & dst) chmod_(dst, st.st_mode); } - void replaceValidPath(const Path & storePath, const Path & tmpPath) { /* We can't atomically replace storePath (the original) with @@ -738,63 +727,41 @@ void replaceValidPath(const Path & storePath, const Path & tmpPath) deletePath(oldPath); } - int DerivationGoal::getChildStatus() { return hook->pid.kill(); } - void DerivationGoal::closeReadPipes() { hook->builderOut.readSide = -1; hook->fromHook.readSide = -1; } +void DerivationGoal::cleanupHookFinally() {} -void DerivationGoal::cleanupHookFinally() -{ -} - - -void DerivationGoal::cleanupPreChildKill() -{ -} - - -void DerivationGoal::cleanupPostChildKill() -{ -} +void DerivationGoal::cleanupPreChildKill() {} +void DerivationGoal::cleanupPostChildKill() {} bool DerivationGoal::cleanupDecideWhetherDiskFull() { return false; } +void DerivationGoal::cleanupPostOutputsRegisteredModeCheck() {} -void DerivationGoal::cleanupPostOutputsRegisteredModeCheck() -{ -} - - -void DerivationGoal::cleanupPostOutputsRegisteredModeNonCheck() -{ -} +void DerivationGoal::cleanupPostOutputsRegisteredModeNonCheck() {} -void runPostBuildHook( - Store & store, - Logger & logger, - const StorePath & drvPath, - const StorePathSet & outputPaths) +void runPostBuildHook(Store & store, Logger & logger, const StorePath & drvPath, const StorePathSet & outputPaths) { auto hook = settings.postBuildHook; if (hook == "") return; - Activity act(logger, lvlInfo, actPostBuildHook, - fmt("running post-build-hook '%s'", settings.postBuildHook), - Logger::Fields{store.printStorePath(drvPath)}); + Activity act( + logger, lvlInfo, actPostBuildHook, fmt("running post-build-hook '%s'", settings.postBuildHook), + Logger::Fields{store.printStorePath(drvPath)}); PushActivity pact(act.id); std::map hookEnvironment = getEnv(); @@ -802,13 +769,17 @@ void runPostBuildHook( hookEnvironment.emplace("OUT_PATHS", chomp(concatStringsSep(" ", store.printStorePathSet(outputPaths)))); hookEnvironment.emplace("NIX_CONFIG", globalConfig.toKeyValue()); - struct LogSink : Sink { + struct LogSink : Sink + { Activity & act; std::string currentLine; - LogSink(Activity & act) : act(act) { } + LogSink(Activity & act) + : act(act) + {} - void operator() (std::string_view data) override { + void operator()(std::string_view data) override + { for (auto c : data) { if (c == '\n') { flushLine(); @@ -818,12 +789,14 @@ void runPostBuildHook( } } - void flushLine() { + void flushLine() + { act.result(resPostBuildLogLine, currentLine); currentLine.clear(); } - ~LogSink() { + ~LogSink() + { if (currentLine != "") { currentLine += '\n'; flushLine(); @@ -844,7 +817,7 @@ void DerivationGoal::buildDone() { trace("build done"); - Finally releaseBuildUser([&](){ this->cleanupHookFinally(); }); + Finally releaseBuildUser([&]() { this->cleanupHookFinally(); }); cleanupPreChildKill(); @@ -879,9 +852,8 @@ void DerivationGoal::buildDone() diskFull |= cleanupDecideWhetherDiskFull(); - auto msg = fmt("builder for '%s' %s", - yellowtxt(worker.store.printStorePath(drvPath)), - statusToString(status)); + auto msg = + fmt("builder for '%s' %s", yellowtxt(worker.store.printStorePath(drvPath)), statusToString(status)); if (!logger->isVerbose() && !logTail.empty()) { msg += fmt(";\nlast %d log lines:\n", logTail.size()); @@ -890,8 +862,9 @@ void DerivationGoal::buildDone() msg += line; msg += "\n"; } - msg += fmt("For full logs, run '" ANSI_BOLD "nix log %s" ANSI_NORMAL "'.", - worker.store.printStorePath(drvPath)); + msg += + fmt("For full logs, run '" ANSI_BOLD "nix log %s" ANSI_NORMAL "'.", + worker.store.printStorePath(drvPath)); } if (diskFull) @@ -907,12 +880,7 @@ void DerivationGoal::buildDone() StorePathSet outputPaths; for (auto & [_, output] : builtOutputs) outputPaths.insert(output.outPath); - runPostBuildHook( - worker.store, - *logger, - drvPath, - outputPaths - ); + runPostBuildHook(worker.store, *logger, drvPath, outputPaths); if (buildMode == bmCheck) { cleanupPostOutputsRegisteredModeCheck(); @@ -951,11 +919,10 @@ void DerivationGoal::buildDone() } else { - st = - dynamic_cast(&e) ? BuildResult::NotDeterministic : - statusOk(status) ? BuildResult::OutputRejected : - !derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure : - BuildResult::PermanentFailure; + st = dynamic_cast(&e) ? BuildResult::NotDeterministic + : statusOk(status) ? BuildResult::OutputRejected + : !derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure + : BuildResult::PermanentFailure; } done(st, {}, e); @@ -990,17 +957,18 @@ void DerivationGoal::resolvedFinished() throw Error( "derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolvedFinished,resolve)", worker.store.printStorePath(drvPath), wantedOutput); - auto realisation = get(resolvedResult.builtOutputs, DrvOutput { *resolvedHash, wantedOutput }); + auto realisation = get(resolvedResult.builtOutputs, DrvOutput{*resolvedHash, wantedOutput}); if (!realisation) throw Error( "derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolvedFinished,realisation)", worker.store.printStorePath(resolvedDrvGoal->drvPath), wantedOutput); if (drv->type().isPure()) { auto newRealisation = *realisation; - newRealisation.id = DrvOutput { initialOutput->outputHash, wantedOutput }; + newRealisation.id = DrvOutput{initialOutput->outputHash, wantedOutput}; newRealisation.signatures.clear(); if (!drv->type().isFixed()) - newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation->outPath); + newRealisation.dependentRealisations = + drvOutputReferences(worker.store, *drv, realisation->outPath); signRealisation(newRealisation); worker.store.registerDrvOutput(newRealisation); } @@ -1008,12 +976,7 @@ void DerivationGoal::resolvedFinished() builtOutputs.emplace(realisation->id, *realisation); } - runPostBuildHook( - worker.store, - *logger, - drvPath, - outputPaths - ); + runPostBuildHook(worker.store, *logger, drvPath, outputPaths); } auto status = resolvedResult.status; @@ -1025,7 +988,8 @@ void DerivationGoal::resolvedFinished() HookReply DerivationGoal::tryBuildHook() { - if (!worker.tryBuildHook || !useDerivation) return rpDecline; + if (!worker.tryBuildHook || !useDerivation) + return rpDecline; if (!worker.hook) worker.hook = std::make_unique(); @@ -1033,12 +997,8 @@ HookReply DerivationGoal::tryBuildHook() try { /* Send the request to the hook. */ - worker.hook->sink - << "try" - << (worker.getNrLocalBuilds() < settings.maxBuildJobs ? 1 : 0) - << drv->platform - << worker.store.printStorePath(drvPath) - << parsedDrv->getRequiredSystemFeatures(); + worker.hook->sink << "try" << (worker.getNrLocalBuilds() < settings.maxBuildJobs ? 1 : 0) << drv->platform + << worker.store.printStorePath(drvPath) << parsedDrv->getRequiredSystemFeatures(); worker.hook->sink.flush(); /* Read the first line of input, which should be a word indicating @@ -1058,8 +1018,7 @@ HookReply DerivationGoal::tryBuildHook() else if (s.substr(0, 2) == "# ") { reply = s.substr(2); break; - } - else { + } else { s += "\n"; writeToStderr(s); } @@ -1073,17 +1032,14 @@ HookReply DerivationGoal::tryBuildHook() worker.tryBuildHook = false; worker.hook = 0; return rpDecline; - } - else if (reply == "postpone") + } else if (reply == "postpone") return rpPostpone; else if (reply != "accept") throw Error("bad hook reply '%s'", reply); } catch (SysError & e) { if (e.errNo == EPIPE) { - printError( - "build hook died unexpectedly: %s", - chomp(drainFD(worker.hook->fromHook.readSide.get()))); + printError("build hook died unexpectedly: %s", chomp(drainFD(worker.hook->fromHook.readSide.get()))); worker.hook = 0; return rpDecline; } else @@ -1109,7 +1065,8 @@ HookReply DerivationGoal::tryBuildHook() StringSet missingOutputs; for (auto & [outputName, status] : initialOutputs) { // XXX: Does this include known CA outputs? - if (buildMode != bmCheck && status.known && status.known->isValid()) continue; + if (buildMode != bmCheck && status.known && status.known->isValid()) + continue; missingOutputs.insert(outputName); } worker_proto::write(worker.store, hook->sink, missingOutputs); @@ -1129,7 +1086,6 @@ HookReply DerivationGoal::tryBuildHook() return rpAccept; } - DrvOutputs DerivationGoal::registerOutputs() { /* When using a build hook, the build hook can register the output @@ -1146,7 +1102,8 @@ Path DerivationGoal::openLogFile() { logSize = 0; - if (!settings.keepLog) return ""; + if (!settings.keepLog) + return ""; auto baseName = std::string(baseNameOf(worker.store.printStorePath(drvPath))); @@ -1159,11 +1116,11 @@ Path DerivationGoal::openLogFile() Path dir = fmt("%s/%s/%s/", logDir, LocalFSStore::drvsLogDir, baseName.substr(0, 2)); createDirs(dir); - Path logFileName = fmt("%s/%s%s", dir, baseName.substr(2), - settings.compressLog ? ".bz2" : ""); + Path logFileName = fmt("%s/%s%s", dir, baseName.substr(2), settings.compressLog ? ".bz2" : ""); fdLogFile = open(logFileName.c_str(), O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0666); - if (!fdLogFile) throw SysError("creating log file '%1%'", logFileName); + if (!fdLogFile) + throw SysError("creating log file '%1%'", logFileName); logFileSink = std::make_shared(fdLogFile.get()); @@ -1175,17 +1132,17 @@ Path DerivationGoal::openLogFile() return logFileName; } - void DerivationGoal::closeLogFile() { auto logSink2 = std::dynamic_pointer_cast(logSink); - if (logSink2) logSink2->finish(); - if (logFileSink) logFileSink->flush(); + if (logSink2) + logSink2->finish(); + if (logFileSink) + logFileSink->flush(); logSink = logFileSink = 0; fdLogFile = -1; } - bool DerivationGoal::isReadDesc(int fd) { return fd == hook->builderOut.readSide.get(); @@ -1195,15 +1152,13 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data) { // local & `ssh://`-builds are dealt with here. auto isWrittenToLog = isReadDesc(fd); - if (isWrittenToLog) - { + if (isWrittenToLog) { logSize += data.size(); if (settings.maxLogSize && logSize > settings.maxLogSize) { killChild(); done( BuildResult::LogLimitExceeded, {}, - Error("%s killed after writing more than %d bytes of log output", - getName(), settings.maxLogSize)); + Error("%s killed after writing more than %d bytes of log output", getName(), settings.maxLogSize)); return; } @@ -1218,7 +1173,8 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data) currentLogLine[currentLogLinePos++] = c; } - if (logSink) (*logSink)(data); + if (logSink) + (*logSink)(data); } if (hook && fd == hook->fromHook.readSide.get()) { @@ -1240,14 +1196,13 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data) } } - void DerivationGoal::handleEOF(int fd) { - if (!currentLogLine.empty()) flushLine(); + if (!currentLogLine.empty()) + flushLine(); worker.wakeUp(shared_from_this()); } - void DerivationGoal::flushLine() { if (handleJSONLogMessage(currentLogLine, *act, builderActivities, false)) @@ -1255,7 +1210,8 @@ void DerivationGoal::flushLine() else { logTail.push_back(currentLogLine); - if (logTail.size() > settings.logLines) logTail.pop_front(); + if (logTail.size() > settings.logLines) + logTail.pop_front(); act->result(resBuildLogLine, currentLogLine); } @@ -1264,7 +1220,6 @@ void DerivationGoal::flushLine() currentLogLinePos = 0; } - std::map> DerivationGoal::queryPartialDerivationOutputMap() { assert(drv->type().isPure()); @@ -1291,10 +1246,10 @@ OutputPathMap DerivationGoal::queryDerivationOutputMap() } } - std::pair DerivationGoal::checkPathValidity() { - if (!drv->type().isPure()) return { false, {} }; + if (!drv->type().isPure()) + return {false, {}}; bool checkHash = buildMode == bmRepair; auto wantedOutputsLeft = wantedOutputs; @@ -1313,11 +1268,9 @@ std::pair DerivationGoal::checkPathValidity() auto outputPath = *i.second; info.known = { .path = outputPath, - .status = !worker.store.isValidPath(outputPath) - ? PathStatus::Absent - : !checkHash || worker.pathContentsGood(outputPath) - ? PathStatus::Valid - : PathStatus::Corrupt, + .status = !worker.store.isValidPath(outputPath) ? PathStatus::Absent + : !checkHash || worker.pathContentsGood(outputPath) ? PathStatus::Valid + : PathStatus::Corrupt, }; } auto drvOutput = DrvOutput{info.outputHash, i.first}; @@ -1332,39 +1285,37 @@ std::pair DerivationGoal::checkPathValidity() // derivation, and the output path is valid, but we don't have // its realisation stored (probably because it has been built // without the `ca-derivations` experimental flag). - worker.store.registerDrvOutput( - Realisation { - drvOutput, - info.known->path, - } - ); + worker.store.registerDrvOutput(Realisation{ + drvOutput, + info.known->path, + }); } } if (info.wanted && info.known && info.known->isValid()) - validOutputs.emplace(drvOutput, Realisation { drvOutput, info.known->path }); + validOutputs.emplace(drvOutput, Realisation{drvOutput, info.known->path}); } // If we requested all the outputs via the empty set, we are always fine. // If we requested specific elements, the loop above removes all the valid // ones, so any that are left must be invalid. if (!wantedOutputsLeft.empty()) - throw Error("derivation '%s' does not have wanted outputs %s", - worker.store.printStorePath(drvPath), + throw Error( + "derivation '%s' does not have wanted outputs %s", worker.store.printStorePath(drvPath), concatStringsSep(", ", quoteStrings(wantedOutputsLeft))); bool allValid = true; for (auto & [_, status] : initialOutputs) { - if (!status.wanted) continue; + if (!status.wanted) + continue; if (!status.known || !status.known->isValid()) { allValid = false; break; } } - return { allValid, validOutputs }; + return {allValid, validOutputs}; } - DrvOutputs DerivationGoal::assertPathValidity() { auto [allValid, validOutputs] = checkPathValidity(); @@ -1373,11 +1324,7 @@ DrvOutputs DerivationGoal::assertPathValidity() return validOutputs; } - -void DerivationGoal::done( - BuildResult::Status status, - DrvOutputs builtOutputs, - std::optional ex) +void DerivationGoal::done(BuildResult::Status status, DrvOutputs builtOutputs, std::optional ex) { buildResult.status = status; if (ex) @@ -1412,7 +1359,6 @@ void DerivationGoal::done( amDone(buildResult.success() ? ecSuccess : ecFailed, ex); } - void DerivationGoal::waiteeDone(GoalPtr waitee, ExitCode result) { Goal::waiteeDone(waitee, result); @@ -1420,9 +1366,7 @@ void DerivationGoal::waiteeDone(GoalPtr waitee, ExitCode result) if (waitee->buildResult.success()) if (auto bfd = std::get_if(&waitee->buildResult.path)) for (auto & [output, realisation] : waitee->buildResult.builtOutputs) - inputDrvOutputs.insert_or_assign( - { bfd->drvPath, output.outputName }, - realisation.outPath); + inputDrvOutputs.insert_or_assign({bfd->drvPath, output.outputName}, realisation.outPath); } } diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh index 2d8bfd59293f..c1d9abafa7fc 100644 --- a/src/libstore/build/derivation-goal.hh +++ b/src/libstore/build/derivation-goal.hh @@ -12,7 +12,7 @@ using std::map; struct HookInstance; -typedef enum {rpAccept, rpDecline, rpPostpone} HookReply; +typedef enum { rpAccept, rpDecline, rpPostpone } HookReply; /* Unless we are repairing, we don't both to test validity and just assume it, so the choices are `Absent` or `Valid`. */ @@ -22,21 +22,24 @@ enum struct PathStatus { Valid, }; -struct InitialOutputStatus { +struct InitialOutputStatus +{ StorePath path; PathStatus status; /* Valid in the store, and additionally non-corrupt if we are repairing */ - bool isValid() const { + bool isValid() const + { return status == PathStatus::Valid; } /* Merely present, allowed to be corrupt */ - bool isPresent() const { - return status == PathStatus::Corrupt - || status == PathStatus::Valid; + bool isPresent() const + { + return status == PathStatus::Corrupt || status == PathStatus::Valid; } }; -struct InitialOutput { +struct InitialOutput +{ bool wanted; Hash outputHash; std::optional known; @@ -132,11 +135,13 @@ struct DerivationGoal : public Goal /* The remote machine on which we're building. */ std::string machineName; - DerivationGoal(const StorePath & drvPath, - const StringSet & wantedOutputs, Worker & worker, - BuildMode buildMode = bmNormal); - DerivationGoal(const StorePath & drvPath, const BasicDerivation & drv, - const StringSet & wantedOutputs, Worker & worker, + DerivationGoal( + const StorePath & drvPath, const StringSet & wantedOutputs, Worker & worker, BuildMode buildMode = bmNormal); + DerivationGoal( + const StorePath & drvPath, + const BasicDerivation & drv, + const StringSet & wantedOutputs, + Worker & worker, BuildMode buildMode = bmNormal); virtual ~DerivationGoal(); @@ -176,7 +181,7 @@ struct DerivationGoal : public Goal Path openLogFile(); /* Sign the newly built realisation if the store allows it */ - virtual void signRealisation(Realisation&) {} + virtual void signRealisation(Realisation &) {} /* Close the log file. */ void closeLogFile(); @@ -224,10 +229,7 @@ struct DerivationGoal : public Goal void started(); - void done( - BuildResult::Status status, - DrvOutputs builtOutputs = {}, - std::optional ex = {}); + void done(BuildResult::Status status, DrvOutputs builtOutputs = {}, std::optional ex = {}); void waiteeDone(GoalPtr waitee, ExitCode result) override; diff --git a/src/libstore/build/drv-output-substitution-goal.cc b/src/libstore/build/drv-output-substitution-goal.cc index b7f7b5ab129f..a85d625b1eea 100644 --- a/src/libstore/build/drv-output-substitution-goal.cc +++ b/src/libstore/build/drv-output-substitution-goal.cc @@ -7,11 +7,8 @@ namespace nix { DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal( - const DrvOutput & id, - Worker & worker, - RepairFlag repair, - std::optional ca) - : Goal(worker, DerivedPath::Opaque { StorePath::dummy }) + const DrvOutput & id, Worker & worker, RepairFlag repair, std::optional ca) + : Goal(worker, DerivedPath::Opaque{StorePath::dummy}) , id(id) { state = &DrvOutputSubstitutionGoal::init; @@ -19,7 +16,6 @@ DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal( trace("created"); } - void DrvOutputSubstitutionGoal::init() { trace("init"); @@ -64,15 +60,14 @@ void DrvOutputSubstitutionGoal::tryNext() outPipe.create(); promise = decltype(promise)(); - sub->queryRealisation( - id, { [&](std::future> res) { - try { - Finally updateStats([this]() { outPipe.writeSide.close(); }); - promise.set_value(res.get()); - } catch (...) { - promise.set_exception(std::current_exception()); - } - } }); + sub->queryRealisation(id, {[&](std::future> res) { + try { + Finally updateStats([this]() { outPipe.writeSide.close(); }); + promise.set_value(res.get()); + } catch (...) { + promise.set_exception(std::current_exception()); + } + }}); worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false); @@ -102,11 +97,8 @@ void DrvOutputSubstitutionGoal::realisationFetched() "substituter '%s' has an incompatible realisation for '%s', ignoring.\n" "Local: %s\n" "Remote: %s", - sub->getUri(), - depId.to_string(), - worker.store.printStorePath(localOutputInfo->outPath), - worker.store.printStorePath(depPath) - ); + sub->getUri(), depId.to_string(), worker.store.printStorePath(localOutputInfo->outPath), + worker.store.printStorePath(depPath)); tryNext(); return; } @@ -116,8 +108,10 @@ void DrvOutputSubstitutionGoal::realisationFetched() addWaitee(worker.makePathSubstitutionGoal(outputInfo->outPath)); - if (waitees.empty()) outPathValid(); - else state = &DrvOutputSubstitutionGoal::outPathValid; + if (waitees.empty()) + outPathValid(); + else + state = &DrvOutputSubstitutionGoal::outPathValid; } void DrvOutputSubstitutionGoal::outPathValid() @@ -155,8 +149,8 @@ void DrvOutputSubstitutionGoal::work() void DrvOutputSubstitutionGoal::handleEOF(int fd) { - if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this()); + if (fd == 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 948dbda8fc8e..fcfc6dd16c10 100644 --- a/src/libstore/build/drv-output-substitution-goal.hh +++ b/src/libstore/build/drv-output-substitution-goal.hh @@ -15,7 +15,8 @@ class Worker; // 1. Fetch the output info from a substituter // 2. Substitute the corresponding output path // 3. Register the output info -class DrvOutputSubstitutionGoal : public Goal { +class DrvOutputSubstitutionGoal : public Goal +{ private: // The drv output we're trying to substitue DrvOutput id; @@ -38,7 +39,11 @@ private: bool substituterFailed = false; public: - DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair = NoRepair, std::optional ca = std::nullopt); + DrvOutputSubstitutionGoal( + const DrvOutput & id, + Worker & worker, + RepairFlag repair = NoRepair, + std::optional ca = std::nullopt); typedef void (DrvOutputSubstitutionGoal::*GoalState)(); GoalState state; @@ -49,7 +54,10 @@ public: void outPathValid(); void finished(); - void timedOut(Error && ex) override { abort(); }; + void timedOut(Error && ex) override + { + abort(); + }; std::string key() override; diff --git a/src/libstore/build/entry-points.cc b/src/libstore/build/entry-points.cc index bea7363dbfae..695a9b8a7d65 100644 --- a/src/libstore/build/entry-points.cc +++ b/src/libstore/build/entry-points.cc @@ -11,14 +11,16 @@ void Store::buildPaths(const std::vector & reqs, BuildMode buildMod Goals goals; for (const auto & br : reqs) { - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - goals.insert(worker.makeDerivationGoal(bfd.drvPath, bfd.outputs, buildMode)); + std::visit( + overloaded{ + [&](const DerivedPath::Built & bfd) { + goals.insert(worker.makeDerivationGoal(bfd.drvPath, bfd.outputs, buildMode)); + }, + [&](const DerivedPath::Opaque & bo) { + goals.insert(worker.makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair)); + }, }, - [&](const DerivedPath::Opaque & bo) { - goals.insert(worker.makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair)); - }, - }, br.raw()); + br.raw()); } worker.run(goals); @@ -33,8 +35,10 @@ void Store::buildPaths(const std::vector & reqs, BuildMode buildMod ex = i->ex; } if (i->exitCode != Goal::ecSuccess) { - if (auto i2 = dynamic_cast(i.get())) failed.insert(i2->drvPath); - else if (auto i2 = dynamic_cast(i.get())) failed.insert(i2->storePath); + if (auto i2 = dynamic_cast(i.get())) + failed.insert(i2->drvPath); + else if (auto i2 = dynamic_cast(i.get())) + failed.insert(i2->storePath); } } @@ -42,28 +46,29 @@ void Store::buildPaths(const std::vector & reqs, BuildMode buildMod ex->status = worker.exitStatus(); throw *ex; } else if (!failed.empty()) { - if (ex) logError(ex->info()); + if (ex) + logError(ex->info()); throw Error(worker.exitStatus(), "build of %s failed", showPaths(failed)); } } std::vector Store::buildPathsWithResults( - const std::vector & reqs, - BuildMode buildMode, - std::shared_ptr evalStore) + const std::vector & reqs, BuildMode buildMode, std::shared_ptr evalStore) { Worker worker(*this, evalStore ? *evalStore : *this); Goals goals; for (const auto & br : reqs) { - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - goals.insert(worker.makeDerivationGoal(bfd.drvPath, bfd.outputs, buildMode)); - }, - [&](const DerivedPath::Opaque & bo) { - goals.insert(worker.makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair)); + std::visit( + overloaded{ + [&](const DerivedPath::Built & bfd) { + goals.insert(worker.makeDerivationGoal(bfd.drvPath, bfd.outputs, buildMode)); + }, + [&](const DerivedPath::Opaque & bo) { + goals.insert(worker.makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair)); + }, }, - }, br.raw()); + br.raw()); } worker.run(goals); @@ -76,8 +81,7 @@ std::vector Store::buildPathsWithResults( return results; } -BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, - BuildMode buildMode) +BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode) { Worker worker(*this, *this); auto goal = worker.makeBasicDerivationGoal(drvPath, drv, {}, buildMode); @@ -86,19 +90,19 @@ BuildResult Store::buildDerivation(const StorePath & drvPath, const BasicDerivat worker.run(Goals{goal}); return goal->buildResult; } catch (Error & e) { - return BuildResult { + return BuildResult{ .status = BuildResult::MiscFailure, .errorMsg = e.msg(), - .path = DerivedPath::Built { .drvPath = drvPath }, + .path = DerivedPath::Built{.drvPath = drvPath}, }; }; } - void Store::ensurePath(const StorePath & path) { /* If the path is already valid, we're done. */ - if (isValidPath(path)) return; + if (isValidPath(path)) + return; Worker worker(*this, *this); GoalPtr goal = worker.makePathSubstitutionGoal(path); @@ -115,7 +119,6 @@ void Store::ensurePath(const StorePath & path) } } - void LocalStore::repairPath(const StorePath & path) { Worker worker(*this, *this); diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc index 58e805f55075..197445a2791f 100644 --- a/src/libstore/build/goal.cc +++ b/src/libstore/build/goal.cc @@ -3,14 +3,13 @@ namespace nix { - -bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) const { +bool CompareGoalPtrs::operator()(const GoalPtr & a, const GoalPtr & b) const +{ std::string s1 = a->key(); std::string s2 = b->key(); return s1 < s2; } - void addToWeakGoals(WeakGoals & goals, GoalPtr p) { if (goals.find(p) != goals.end()) @@ -18,14 +17,12 @@ void addToWeakGoals(WeakGoals & goals, GoalPtr p) goals.insert(p); } - void Goal::addWaitee(GoalPtr waitee) { waitees.insert(waitee); addToWeakGoals(waitee->waiters, shared_from_this()); } - void Goal::waiteeDone(GoalPtr waitee, ExitCode result) { assert(waitees.count(waitee)); @@ -33,11 +30,14 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result) trace(fmt("waitee '%s' done; %d left", waitee->name, waitees.size())); - if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) ++nrFailed; + if (result == ecFailed || result == ecNoSubstituters || result == ecIncompleteClosure) + ++nrFailed; - if (result == ecNoSubstituters) ++nrNoSubstituters; + if (result == ecNoSubstituters) + ++nrNoSubstituters; - if (result == ecIncompleteClosure) ++nrIncompleteClosure; + if (result == ecIncompleteClosure) + ++nrIncompleteClosure; if (waitees.empty() || (result == ecFailed && !settings.keepGoing)) { @@ -52,7 +52,6 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result) } } - void Goal::amDone(ExitCode result, std::optional ex) { trace("done"); @@ -69,7 +68,8 @@ void Goal::amDone(ExitCode result, std::optional ex) for (auto & i : waiters) { GoalPtr goal = i.lock(); - if (goal) goal->waiteeDone(shared_from_this(), result); + if (goal) + goal->waiteeDone(shared_from_this(), result); } waiters.clear(); worker.removeGoal(shared_from_this()); @@ -77,7 +77,6 @@ void Goal::amDone(ExitCode result, std::optional ex) cleanup(); } - void Goal::trace(const FormatOrString & fs) { debug("%1%: %2%", name, fs.s); diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh index 35121c5d9e7c..4c9082b908d9 100644 --- a/src/libstore/build/goal.hh +++ b/src/libstore/build/goal.hh @@ -14,8 +14,9 @@ class Worker; typedef std::shared_ptr GoalPtr; typedef std::weak_ptr WeakGoalPtr; -struct CompareGoalPtrs { - bool operator() (const GoalPtr & a, const GoalPtr & b) const; +struct CompareGoalPtrs +{ + bool operator()(const GoalPtr & a, const GoalPtr & b) const; }; /* Set of goals. */ @@ -27,7 +28,7 @@ typedef std::map WeakGoalMap; struct Goal : public std::enable_shared_from_this { - typedef enum {ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure} ExitCode; + typedef enum { ecBusy, ecSuccess, ecFailed, ecNoSubstituters, ecIncompleteClosure } ExitCode; /* Backlink to the worker. */ Worker & worker; @@ -64,8 +65,8 @@ struct Goal : public std::enable_shared_from_this Goal(Worker & worker, DerivedPath path) : worker(worker) - , buildResult { .path = std::move(path) } - { } + , buildResult{.path = std::move(path)} + {} virtual ~Goal() { @@ -104,7 +105,7 @@ struct Goal : public std::enable_shared_from_this void amDone(ExitCode result, std::optional ex = {}); - virtual void cleanup() { } + virtual void cleanup() {} }; void addToWeakGoals(WeakGoals & goals, GoalPtr p); diff --git a/src/libstore/build/hook-instance.cc b/src/libstore/build/hook-instance.cc index 1f19ddccc077..f89b12bab65d 100644 --- a/src/libstore/build/hook-instance.cc +++ b/src/libstore/build/hook-instance.cc @@ -34,10 +34,10 @@ HookInstance::HookInstance() /* Fork the hook. */ pid = startProcess([&]() { - commonChildInit(fromHook); - if (chdir("/") == -1) throw SysError("changing into /"); + if (chdir("/") == -1) + throw SysError("changing into /"); /* Dup the communication pipes. */ if (dup2(toHook.readSide.get(), STDIN_FILENO) == -1) @@ -69,12 +69,12 @@ HookInstance::HookInstance() sink << 0; } - HookInstance::~HookInstance() { try { toHook.writeSide = -1; - if (pid != -1) pid.kill(); + if (pid != -1) + pid.kill(); } catch (...) { ignoreException(); } diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index d1ec91ed5b23..01674ff65ce5 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -60,26 +60,20 @@ namespace nix { void handleDiffHook( - uid_t uid, uid_t gid, - const Path & tryA, const Path & tryB, - const Path & drvPath, const Path & tmpDir) + uid_t uid, uid_t gid, const Path & tryA, const Path & tryB, const Path & drvPath, const Path & tmpDir) { auto diffHook = settings.diffHook; if (diffHook != "" && settings.runDiffHook) { try { - auto diffRes = runProgram(RunOptions { + auto diffRes = runProgram(RunOptions{ .program = diffHook, .searchPath = true, .args = {tryA, tryB, drvPath, tmpDir}, .uid = uid, .gid = gid, - .chdir = "/" - }); + .chdir = "/"}); if (!statusOk(diffRes.first)) - throw ExecError(diffRes.first, - "diff-hook program '%1%' %2%", - diffHook, - statusToString(diffRes.first)); + throw ExecError(diffRes.first, "diff-hook program '%1%' %2%", diffHook, statusToString(diffRes.first)); if (diffRes.second != "") printError(chomp(diffRes.second)); @@ -94,17 +88,27 @@ void handleDiffHook( const Path LocalDerivationGoal::homeDir = "/homeless-shelter"; - LocalDerivationGoal::~LocalDerivationGoal() { /* Careful: we should never ever throw an exception from a destructor. */ - try { deleteTmpDir(false); } catch (...) { ignoreException(); } - try { killChild(); } catch (...) { ignoreException(); } - try { stopDaemon(); } catch (...) { ignoreException(); } + try { + deleteTmpDir(false); + } catch (...) { + ignoreException(); + } + try { + killChild(); + } catch (...) { + ignoreException(); + } + try { + stopDaemon(); + } catch (...) { + ignoreException(); + } } - inline bool LocalDerivationGoal::needsHashRewrite() { #if __linux__ @@ -115,7 +119,6 @@ inline bool LocalDerivationGoal::needsHashRewrite() #endif } - LocalStore & LocalDerivationGoal::getLocalStore() { auto p = dynamic_cast(&worker.store); @@ -123,7 +126,6 @@ LocalStore & LocalDerivationGoal::getLocalStore() return *p; } - void LocalDerivationGoal::killChild() { if (pid != -1) { @@ -148,8 +150,8 @@ void LocalDerivationGoal::killChild() DerivationGoal::killChild(); } - -void LocalDerivationGoal::tryLocalBuild() { +void LocalDerivationGoal::tryLocalBuild() +{ unsigned int curBuilds = worker.getNrLocalBuilds(); if (curBuilds >= settings.maxBuildJobs) { state = &DerivationGoal::tryToBuild; @@ -162,7 +164,8 @@ void LocalDerivationGoal::tryLocalBuild() { one of the members of that group. */ if (settings.buildUsersGroup != "" && getuid() == 0) { #if defined(__linux__) || defined(__APPLE__) - if (!buildUser) buildUser = std::make_unique(); + if (!buildUser) + buildUser = std::make_unique(); if (buildUser->findFreeUser()) { /* Make sure that no other processes are executing under this @@ -170,7 +173,8 @@ void LocalDerivationGoal::tryLocalBuild() { buildUser->kill(); } else { if (!actLock) - actLock = std::make_unique(*logger, lvlWarn, actBuildWaiting, + actLock = std::make_unique( + *logger, lvlWarn, actBuildWaiting, fmt("waiting for UID to build '%s'", yellowtxt(worker.store.printStorePath(drvPath)))); worker.waitForAWhile(shared_from_this()); return; @@ -210,7 +214,6 @@ static void chmod_(const Path & path, mode_t mode) throw SysError("setting permissions on '%s'", path); } - /* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if it's a directory and we're not root (to be able to update the directory's parent link ".."). */ @@ -230,10 +233,8 @@ static void movePath(const Path & src, const Path & dst) chmod_(dst, st.st_mode); } - extern void replaceValidPath(const Path & storePath, const Path & tmpPath); - int LocalDerivationGoal::getChildStatus() { return hook ? DerivationGoal::getChildStatus() : pid.kill(); @@ -247,7 +248,6 @@ void LocalDerivationGoal::closeReadPipes() builderOut.readSide = -1; } - void LocalDerivationGoal::cleanupHookFinally() { /* Release the build user at the end of this function. We don't do @@ -256,14 +256,12 @@ void LocalDerivationGoal::cleanupHookFinally() buildUser.reset(); } - void LocalDerivationGoal::cleanupPreChildKill() { sandboxMountNamespace = -1; sandboxUserNamespace = -1; } - void LocalDerivationGoal::cleanupPostChildKill() { /* When running under a build user, make sure that all processes @@ -271,13 +269,13 @@ void LocalDerivationGoal::cleanupPostChildKill() malicious user from leaving behind a process that keeps files open and modifies them after they have been chown'ed to root. */ - if (buildUser) buildUser->kill(); + if (buildUser) + buildUser->kill(); /* Terminate the recursive Nix daemon. */ stopDaemon(); } - bool LocalDerivationGoal::cleanupDecideWhetherDiskFull() { bool diskFull = false; @@ -292,11 +290,9 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull() auto & localStore = getLocalStore(); uint64_t required = 8ULL * 1024 * 1024; // FIXME: make configurable struct statvfs st; - if (statvfs(localStore.realStoreDir.get().c_str(), &st) == 0 && - (uint64_t) st.f_bavail * st.f_bsize < required) + if (statvfs(localStore.realStoreDir.get().c_str(), &st) == 0 && (uint64_t) st.f_bavail * st.f_bsize < required) diskFull = true; - if (statvfs(tmpDir.c_str(), &st) == 0 && - (uint64_t) st.f_bavail * st.f_bsize < required) + if (statvfs(tmpDir.c_str(), &st) == 0 && (uint64_t) st.f_bavail * st.f_bsize < required) diskFull = true; } #endif @@ -307,8 +303,10 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull() build failures. */ if (useChroot && buildMode == bmNormal) for (auto & [_, status] : initialOutputs) { - if (!status.known) continue; - if (buildMode != bmCheck && status.known->isValid()) continue; + if (!status.known) + continue; + if (buildMode != bmCheck && status.known->isValid()) + continue; auto p = worker.store.printStorePath(status.known->path); if (pathExists(chrootRootDir + p)) rename((chrootRootDir + p).c_str(), p.c_str()); @@ -317,13 +315,11 @@ bool LocalDerivationGoal::cleanupDecideWhetherDiskFull() return diskFull; } - void LocalDerivationGoal::cleanupPostOutputsRegisteredModeCheck() { deleteTmpDir(true); } - void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck() { /* Delete unused redirected outputs (when doing hash rewriting). */ @@ -336,7 +332,6 @@ void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck() cleanupPostOutputsRegisteredModeCheck(); } - int childEntry(void * arg) { ((LocalDerivationGoal *) arg)->runChild(); @@ -361,17 +356,14 @@ static void linkOrCopy(const Path & from, const Path & to) } #endif - void LocalDerivationGoal::startBuilder() { /* Right platform? */ if (!parsedDrv->canBuildLocally(worker.store)) - throw Error("a '%s' with features {%s} is required to build '%s', but I am a '%s' with features {%s}", - drv->platform, - concatStringsSep(", ", parsedDrv->getRequiredSystemFeatures()), - worker.store.printStorePath(drvPath), - settings.thisSystem, - concatStringsSep(", ", worker.store.systemFeatures)); + throw Error( + "a '%s' with features {%s} is required to build '%s', but I am a '%s' with features {%s}", drv->platform, + concatStringsSep(", ", parsedDrv->getRequiredSystemFeatures()), worker.store.printStorePath(drvPath), + settings.thisSystem, concatStringsSep(", ", worker.store.systemFeatures)); #if __APPLE__ additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or(""); @@ -382,16 +374,19 @@ void LocalDerivationGoal::startBuilder() auto noChroot = parsedDrv->getBoolAttr("__noChroot"); if (settings.sandboxMode == smEnabled) { if (noChroot) - throw Error("derivation '%s' has '__noChroot' set, " - "but that's not allowed when 'sandbox' is 'true'", worker.store.printStorePath(drvPath)); + throw Error( + "derivation '%s' has '__noChroot' set, " + "but that's not allowed when 'sandbox' is 'true'", + worker.store.printStorePath(drvPath)); #if __APPLE__ if (additionalSandboxProfile != "") - throw Error("derivation '%s' specifies a sandbox profile, " - "but this is only allowed when 'sandbox' is 'relaxed'", worker.store.printStorePath(drvPath)); + throw Error( + "derivation '%s' specifies a sandbox profile, " + "but this is only allowed when 'sandbox' is 'relaxed'", + worker.store.printStorePath(drvPath)); #endif useChroot = true; - } - else if (settings.sandboxMode == smDisabled) + } else if (settings.sandboxMode == smDisabled) useChroot = false; else if (settings.sandboxMode == smRelaxed) useChroot = derivationType.isSandboxed() && !noChroot; @@ -399,11 +394,11 @@ void LocalDerivationGoal::startBuilder() auto & localStore = getLocalStore(); if (localStore.storeDir != localStore.realStoreDir.get()) { - #if __linux__ - useChroot = true; - #else - throw Error("building using a diverted store is not supported on this platform"); - #endif +#if __linux__ + useChroot = true; +#else + throw Error("building using a diverted store is not supported on this platform"); +#endif } /* Create a temporary directory where the build will take @@ -424,22 +419,20 @@ void LocalDerivationGoal::startBuilder() corresponding to the valid outputs, and rewrite the contents of the new outputs to replace the dummy strings with the actual hashes. */ - auto scratchPath = - !status.known - ? makeFallbackPath(outputName) - : !needsHashRewrite() - /* Can always use original path in sandbox */ - ? status.known->path - : !status.known->isPresent() - /* If path doesn't yet exist can just use it */ - ? status.known->path - : buildMode != bmRepair && !status.known->isValid() - /* If we aren't repairing we'll delete a corrupted path, so we - can use original path */ - ? status.known->path - : /* If we are repairing or the path is totally valid, we'll need - to use a temporary path */ - makeFallbackPath(status.known->path); + auto scratchPath = !status.known ? makeFallbackPath(outputName) + : !needsHashRewrite() + /* Can always use original path in sandbox */ + ? status.known->path + : !status.known->isPresent() + /* If path doesn't yet exist can just use it */ + ? status.known->path + : buildMode != bmRepair && !status.known->isValid() + /* If we aren't repairing we'll delete a corrupted path, so we + can use original path */ + ? status.known->path + : /* If we are repairing or the path is totally valid, we'll need + to use a temporary path */ + makeFallbackPath(status.known->path); scratchOutputs.insert_or_assign(outputName, scratchPath); /* Substitute output placeholders with the scratch output paths. @@ -447,20 +440,22 @@ void LocalDerivationGoal::startBuilder() inputRewrites[hashPlaceholder(outputName)] = worker.store.printStorePath(scratchPath); /* Additional tasks if we know the final path a priori. */ - if (!status.known) continue; + if (!status.known) + continue; auto fixedFinalPath = status.known->path; /* Additional tasks if the final and scratch are both known and differ. */ - if (fixedFinalPath == scratchPath) continue; + if (fixedFinalPath == scratchPath) + continue; /* Ensure scratch path is ours to use. */ deletePath(worker.store.printStorePath(scratchPath)); /* Rewrite and unrewrite paths */ { - std::string h1 { fixedFinalPath.hashPart() }; - std::string h2 { scratchPath.hashPart() }; + std::string h1{fixedFinalPath.hashPart()}; + std::string h2{scratchPath.hashPart()}; inputRewrites[h1] = h2; } @@ -485,7 +480,7 @@ void LocalDerivationGoal::startBuilder() Strings ss = tokenizeString(s); if (ss.size() % 2 != 0) throw BuildError("odd number of tokens in 'exportReferencesGraph': '%1%'", s); - for (Strings::iterator i = ss.begin(); i != ss.end(); ) { + for (Strings::iterator i = ss.begin(); i != ss.end();) { auto fileName = *i++; static std::regex regex("[A-Za-z_][A-Za-z0-9_.-]*"); if (!std::regex_match(fileName, regex)) @@ -497,9 +492,9 @@ void LocalDerivationGoal::startBuilder() auto storePath = worker.store.toStorePath(storePathS).first; /* Write closure info to . */ - writeFile(tmpDir + "/" + fileName, - worker.store.makeValidityRegistration( - worker.store.exportReferences({storePath}, inputPaths), false, false)); + writeFile( + tmpDir + "/" + fileName, worker.store.makeValidityRegistration( + worker.store.exportReferences({storePath}, inputPaths), false, false)); } } @@ -510,7 +505,8 @@ void LocalDerivationGoal::startBuilder() dirsInChroot.clear(); for (auto i : settings.sandboxPaths.get()) { - if (i.empty()) continue; + if (i.empty()) + continue; bool optional = false; if (i[i.size() - 1] == '?') { optional = true; @@ -551,7 +547,8 @@ void LocalDerivationGoal::startBuilder() giving a non-root user info about inaccessible files. */ Path canonI = canonPath(i); - /* If only we had a trie to do this more efficiently :) luckily, these are generally going to be pretty small */ + /* If only we had a trie to do this more efficiently :) luckily, these are generally going to be pretty + * small */ for (auto & a : allowedPaths) { Path canonA = canonPath(a); if (canonI == canonA || isInDir(canonI, canonA)) { @@ -560,7 +557,8 @@ void LocalDerivationGoal::startBuilder() } } if (!found) - throw Error("derivation '%s' requested impure path '%s', but it was not in allowed-impure-host-deps", + throw Error( + "derivation '%s' requested impure path '%s', but it was not in allowed-impure-host-deps", worker.store.printStorePath(drvPath), i); /* Allow files in __impureHostDeps to be missing; e.g. @@ -601,10 +599,11 @@ void LocalDerivationGoal::startBuilder() /* Declare the build user's group so that programs get a consistent view of the system (e.g., "id -gn"). */ - writeFile(chrootRootDir + "/etc/group", - fmt("root:x:0:\n" - "nixbld:!:%1%:\n" - "nogroup:x:65534:\n", sandboxGid())); + writeFile( + chrootRootDir + "/etc/group", fmt("root:x:0:\n" + "nixbld:!:%1%:\n" + "nogroup:x:65534:\n", + sandboxGid())); /* Create /etc/hosts with localhost entry. */ if (derivationType.isSandboxed()) @@ -657,23 +656,18 @@ void LocalDerivationGoal::startBuilder() } if (needsHashRewrite() && pathExists(homeDir)) - throw Error("home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir); + throw Error( + "home directory '%1%' exists; please remove it to assure purity of builds without sandboxing", homeDir); if (useChroot && settings.preBuildHook != "" && dynamic_cast(drv.get())) { - printMsg(lvlChatty, format("executing pre-build hook '%1%'") - % settings.preBuildHook); - auto args = useChroot ? Strings({worker.store.printStorePath(drvPath), chrootRootDir}) : - Strings({ worker.store.printStorePath(drvPath) }); - enum BuildHookState { - stBegin, - stExtraChrootDirs - }; + printMsg(lvlChatty, format("executing pre-build hook '%1%'") % settings.preBuildHook); + auto args = useChroot ? Strings({worker.store.printStorePath(drvPath), chrootRootDir}) + : Strings({worker.store.printStorePath(drvPath)}); + enum BuildHookState { stBegin, stExtraChrootDirs }; auto state = stBegin; auto lines = runProgram(settings.preBuildHook, false, args); auto lastPos = std::string::size_type{0}; - for (auto nlPos = lines.find('\n'); nlPos != std::string::npos; - nlPos = lines.find('\n', lastPos)) - { + for (auto nlPos = lines.find('\n'); nlPos != std::string::npos; nlPos = lines.find('\n', lastPos)) { auto line = lines.substr(lastPos, nlPos - lastPos); lastPos = nlPos + 1; if (state == stBegin) { @@ -711,7 +705,7 @@ void LocalDerivationGoal::startBuilder() Path logFile = openLogFile(); /* Create a pipe to get the output of the builder. */ - //builderOut.create(); + // builderOut.create(); builderOut.readSide = posix_openpt(O_RDWR | O_NOCTTY); if (!builderOut.readSide) @@ -734,12 +728,12 @@ void LocalDerivationGoal::startBuilder() } #endif - #if 0 +#if 0 // Mount the pt in the sandbox so that the "tty" command works. // FIXME: this doesn't work with the new devpts in the sandbox. if (useChroot) dirsInChroot[slaveName] = {slaveName, false}; - #endif +#endif if (unlockpt(builderOut.readSide.get())) throw SysError("unlocking pseudoterminal"); @@ -804,14 +798,11 @@ void LocalDerivationGoal::startBuilder() userNamespaceSync.create(); Path maxUserNamespaces = "/proc/sys/user/max_user_namespaces"; - static bool userNamespacesEnabled = - pathExists(maxUserNamespaces) - && trim(readFile(maxUserNamespaces)) != "0"; + static bool userNamespacesEnabled = pathExists(maxUserNamespaces) && trim(readFile(maxUserNamespaces)) != "0"; usingUserNamespace = userNamespacesEnabled; Pid helper = startProcess([&]() { - /* Drop additional groups here because we can't do it after we've created the new user namespace. FIXME: this means that if we're not root in the parent @@ -824,9 +815,10 @@ void LocalDerivationGoal::startBuilder() throw SysError("setgroups failed"); size_t stackSize = 1 * 1024 * 1024; - char * stack = (char *) mmap(0, stackSize, - PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); - if (stack == MAP_FAILED) throw SysError("allocating stack"); + char * stack = + (char *) mmap(0, stackSize, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); + if (stack == MAP_FAILED) + throw SysError("allocating stack"); int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWUTS | CLONE_PARENT | SIGCHLD; if (privateNetwork) @@ -855,10 +847,10 @@ void LocalDerivationGoal::startBuilder() to true (the default). */ if (child == -1 && (errno == EPERM || errno == EINVAL) && settings.sandboxFallback) _exit(1); - if (child == -1) throw SysError("cloning builder process"); + if (child == -1) + throw SysError("cloning builder process"); - writeFull(builderOut.writeSide.get(), - fmt("%d %d\n", usingUserNamespace, child)); + writeFull(builderOut.writeSide.get(), fmt("%d %d\n", usingUserNamespace, child)); _exit(0); }); @@ -874,9 +866,7 @@ void LocalDerivationGoal::startBuilder() /* Close the write side to prevent runChild() from hanging reading from this. */ - Finally cleanup([&]() { - userNamespaceSync.writeSide = -1; - }); + Finally cleanup([&]() { userNamespaceSync.writeSide = -1; }); auto ss = tokenizeString>(readLine(builderOut.readSide.get())); assert(ss.size() == 2); @@ -890,29 +880,28 @@ void LocalDerivationGoal::startBuilder() uid_t hostUid = buildUser ? buildUser->getUID() : getuid(); uid_t hostGid = buildUser ? buildUser->getGID() : getgid(); - writeFile("/proc/" + std::to_string(pid) + "/uid_map", - fmt("%d %d 1", sandboxUid(), hostUid)); + writeFile("/proc/" + std::to_string(pid) + "/uid_map", fmt("%d %d 1", sandboxUid(), hostUid)); writeFile("/proc/" + std::to_string(pid) + "/setgroups", "deny"); - writeFile("/proc/" + std::to_string(pid) + "/gid_map", - fmt("%d %d 1", sandboxGid(), hostGid)); + writeFile("/proc/" + std::to_string(pid) + "/gid_map", fmt("%d %d 1", sandboxGid(), hostGid)); } else { debug("note: not using a user namespace"); if (!buildUser) - throw Error("cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces"); + throw Error( + "cannot perform a sandboxed build because user namespaces are not enabled; check /proc/sys/user/max_user_namespaces"); } /* Now that we now the sandbox uid, we can write /etc/passwd. */ - writeFile(chrootRootDir + "/etc/passwd", fmt( - "root:x:0:0:Nix build user:%3%:/noshell\n" - "nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n" - "nobody:x:65534:65534:Nobody:/:/noshell\n", - sandboxUid(), sandboxGid(), settings.sandboxBuildDir)); + writeFile( + chrootRootDir + "/etc/passwd", fmt("root:x:0:0:Nix build user:%3%:/noshell\n" + "nixbld:x:%1%:%2%:Nix build user:%3%:/noshell\n" + "nobody:x:65534:65534:Nobody:/:/noshell\n", + sandboxUid(), sandboxGid(), settings.sandboxBuildDir)); /* Save the mount- and user namespace of the child. We have to do this - *before* the child does a chroot. */ + *before* the child does a chroot. */ sandboxMountNamespace = open(fmt("/proc/%d/ns/mnt", (pid_t) pid).c_str(), O_RDONLY); if (sandboxMountNamespace.get() == -1) throw SysError("getting sandbox mount namespace"); @@ -932,9 +921,7 @@ void LocalDerivationGoal::startBuilder() #if __linux__ fallback: #endif - pid = startProcess([&]() { - runChild(); - }); + pid = startProcess([&]() { runChild(); }); } /* parent */ @@ -950,14 +937,14 @@ void LocalDerivationGoal::startBuilder() return readLine(builderOut.readSide.get()); } catch (Error & e) { auto status = pid.wait(); - e.addTrace({}, "while waiting for the build environment for '%s' to initialize (%s, previous messages: %s)", - worker.store.printStorePath(drvPath), - statusToString(status), - concatStringsSep("|", msgs)); + e.addTrace( + {}, "while waiting for the build environment for '%s' to initialize (%s, previous messages: %s)", + worker.store.printStorePath(drvPath), statusToString(status), concatStringsSep("|", msgs)); throw; } }(); - if (msg.substr(0, 1) == "\2") break; + if (msg.substr(0, 1) == "\2") + break; if (msg.substr(0, 1) == "\1") { FdSource source(builderOut.readSide.get()); auto ex = readError(source); @@ -969,8 +956,8 @@ void LocalDerivationGoal::startBuilder() } } - -void LocalDerivationGoal::initTmpDir() { +void LocalDerivationGoal::initTmpDir() +{ /* In a sandbox, for determinism, always use the same temporary directory. */ #if __linux__ @@ -1001,7 +988,6 @@ void LocalDerivationGoal::initTmpDir() { env[i.first + "Path"] = tmpDirInSandbox + "/" + fn; } } - } /* For convenience, set an environment pointing to the top build @@ -1018,7 +1004,6 @@ void LocalDerivationGoal::initTmpDir() { env["PWD"] = tmpDirInSandbox; } - void LocalDerivationGoal::initEnv() { env.clear(); @@ -1051,7 +1036,8 @@ void LocalDerivationGoal::initEnv() derivation, tell the builder, so that for instance `fetchurl' can skip checking the output. On older Nixes, this environment variable won't be set, so `fetchurl' will do the check. */ - if (derivationType.isFixed()) env["NIX_OUTPUT_CHECKED"] = "1"; + if (derivationType.isFixed()) + env["NIX_OUTPUT_CHECKED"] = "1"; /* *Only* if this is a fixed-output derivation, propagate the values of the environment variables specified in the @@ -1076,7 +1062,6 @@ void LocalDerivationGoal::initEnv() env["TERM"] = "xterm-256color"; } - void LocalDerivationGoal::writeStructuredAttrs() { if (auto structAttrsJson = parsedDrv->prepareStructuredAttrs(worker.store, inputPaths)) { @@ -1101,30 +1086,28 @@ void LocalDerivationGoal::writeStructuredAttrs() } } - static StorePath pathPartOfReq(const DerivedPath & req) { - return std::visit(overloaded { - [&](const DerivedPath::Opaque & bo) { - return bo.path; - }, - [&](const DerivedPath::Built & bfd) { - return bfd.drvPath; + return std::visit( + overloaded{ + [&](const DerivedPath::Opaque & bo) { return bo.path; }, + [&](const DerivedPath::Built & bfd) { return bfd.drvPath; }, }, - }, req.raw()); + req.raw()); } - bool LocalDerivationGoal::isAllowed(const DerivedPath & req) { return this->isAllowed(pathPartOfReq(req)); } - struct RestrictedStoreConfig : virtual LocalFSStoreConfig { using LocalFSStoreConfig::LocalFSStoreConfig; - const std::string name() { return "Restricted Store"; } + const std::string name() + { + return "Restricted Store"; + } }; /* A wrapper around LocalStore that only allows building/querying of @@ -1142,25 +1125,32 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo , RestrictedStoreConfig(params) , Store(params) , LocalFSStore(params) - , next(next), goal(goal) - { } + , next(next) + , goal(goal) + {} Path getRealStoreDir() override - { return next->realStoreDir; } + { + return next->realStoreDir; + } std::string getUri() override - { return next->getUri(); } + { + return next->getUri(); + } StorePathSet queryAllValidPaths() override { StorePathSet paths; - for (auto & p : goal.inputPaths) paths.insert(p); - for (auto & p : goal.addedPaths) paths.insert(p); + for (auto & p : goal.inputPaths) + paths.insert(p); + for (auto & p : goal.addedPaths) + paths.insert(p); return paths; } - void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept override + void queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept override { if (goal.isAllowed(path)) { try { @@ -1178,8 +1168,7 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo callback(nullptr); }; - void queryReferrers(const StorePath & path, StorePathSet & referrers) override - { } + void queryReferrers(const StorePath & path, StorePathSet & referrers) override {} std::map> queryPartialDerivationOutputMap(const StorePath & path) override { @@ -1189,7 +1178,9 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo } std::optional queryPathFromHashPart(const std::string & hashPart) override - { throw Error("queryPathFromHashPart"); } + { + throw Error("queryPathFromHashPart"); + } StorePath addToStore( std::string_view name, @@ -1199,10 +1190,15 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo PathFilter & filter, RepairFlag repair, const StorePathSet & references) override - { throw Error("addToStore"); } + { + throw Error("addToStore"); + } - void addToStore(const ValidPathInfo & info, Source & narSource, - RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs) override + void addToStore( + const ValidPathInfo & info, + Source & narSource, + RepairFlag repair = NoRepair, + CheckSigsFlag checkSigs = CheckSigs) override { next->addToStore(info, narSource, repair, checkSigs); goal.addDependency(info.path); @@ -1249,10 +1245,12 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo void registerDrvOutput(const Realisation & info) override // XXX: This should probably be allowed as a no-op if the realisation // corresponds to an allowed derivation - { throw Error("registerDrvOutput"); } + { + throw Error("registerDrvOutput"); + } - void queryRealisationUncached(const DrvOutput & id, - Callback> callback) noexcept override + void queryRealisationUncached( + const DrvOutput & id, Callback> callback) noexcept override // XXX: This should probably be allowed if the realisation corresponds to // an allowed derivation { @@ -1261,7 +1259,8 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo next->queryRealisation(id, std::move(callback)); } - void buildPaths(const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override + void + buildPaths(const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override { for (auto & result : buildPathsWithResults(paths, buildMode, evalStore)) if (!result.success()) @@ -1275,7 +1274,8 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo { assert(!evalStore); - if (buildMode != bmNormal) throw Error("unsupported build mode"); + if (buildMode != bmNormal) + throw Error("unsupported build mode"); StorePathSet newPaths; std::set newRealisations; @@ -1304,28 +1304,35 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo return results; } - BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, - BuildMode buildMode = bmNormal) override - { unsupported("buildDerivation"); } + BuildResult + buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode = bmNormal) override + { + unsupported("buildDerivation"); + } - void addTempRoot(const StorePath & path) override - { } + void addTempRoot(const StorePath & path) override {} - void addIndirectRoot(const Path & path) override - { } + void addIndirectRoot(const Path & path) override {} Roots findRoots(bool censor) override - { return Roots(); } + { + return Roots(); + } - void collectGarbage(const GCOptions & options, GCResults & results) override - { } + void collectGarbage(const GCOptions & options, GCResults & results) override {} void addSignatures(const StorePath & storePath, const StringSet & sigs) override - { unsupported("addSignatures"); } + { + unsupported("addSignatures"); + } - void queryMissing(const std::vector & targets, - StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown, - uint64_t & downloadSize, uint64_t & narSize) override + void queryMissing( + const std::vector & targets, + StorePathSet & willBuild, + StorePathSet & willSubstitute, + StorePathSet & unknown, + uint64_t & downloadSize, + uint64_t & narSize) override { /* This is slightly impure since it leaks information to the client about what paths will be built/substituted or are @@ -1339,18 +1346,20 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo unknown.insert(pathPartOfReq(req)); } - next->queryMissing(allowed, willBuild, willSubstitute, - unknown, downloadSize, narSize); + next->queryMissing(allowed, willBuild, willSubstitute, unknown, downloadSize, narSize); } virtual std::optional getBuildLog(const StorePath & path) override - { return std::nullopt; } + { + return std::nullopt; + } virtual void addBuildLog(const StorePath & path, std::string_view log) override - { unsupported("addBuildLog"); } + { + unsupported("addBuildLog"); + } }; - void LocalDerivationGoal::startDaemon() { settings.requireExperimentalFeature(Xp::RecursiveNix); @@ -1361,9 +1370,8 @@ void LocalDerivationGoal::startDaemon() params["root"] = getLocalStore().rootDir; params["state"] = "/no-such-path"; params["log"] = "/no-such-path"; - auto store = make_ref(params, - ref(std::dynamic_pointer_cast(worker.store.shared_from_this())), - *this); + auto store = make_ref( + params, ref(std::dynamic_pointer_cast(worker.store.shared_from_this())), *this); addedPaths.clear(); @@ -1376,18 +1384,18 @@ void LocalDerivationGoal::startDaemon() chownToBuilder(socketPath); daemonThread = std::thread([this, store]() { - while (true) { /* Accept a connection. */ struct sockaddr_un remoteAddr; socklen_t remoteAddrLen = sizeof(remoteAddr); - AutoCloseFD remote = accept(daemonSocket.get(), - (struct sockaddr *) &remoteAddr, &remoteAddrLen); + AutoCloseFD remote = accept(daemonSocket.get(), (struct sockaddr *) &remoteAddr, &remoteAddrLen); if (!remote) { - if (errno == EINTR || errno == EAGAIN) continue; - if (errno == EINVAL) break; + if (errno == EINTR || errno == EAGAIN) + continue; + if (errno == EINVAL) + break; throw SysError("accepting connection"); } @@ -1399,8 +1407,8 @@ void LocalDerivationGoal::startDaemon() FdSource from(remote.get()); FdSink to(remote.get()); try { - daemon::processConnection(store, from, to, - daemon::NotTrusted, daemon::Recursive, + daemon::processConnection( + store, from, to, daemon::NotTrusted, daemon::Recursive, [&](Store & store) { store.createUser("nobody", 65535); }); debug("terminated daemon connection"); } catch (SysError &) { @@ -1415,7 +1423,6 @@ void LocalDerivationGoal::startDaemon() }); } - void LocalDerivationGoal::stopDaemon() { if (daemonSocket && shutdown(daemonSocket.get(), SHUT_RDWR) == -1) @@ -1433,10 +1440,10 @@ void LocalDerivationGoal::stopDaemon() daemonSocket = -1; } - void LocalDerivationGoal::addDependency(const StorePath & path) { - if (isAllowed(path)) return; + if (isAllowed(path)) + return; addedPaths.insert(path); @@ -1446,109 +1453,111 @@ void LocalDerivationGoal::addDependency(const StorePath & path) debug("materialising '%s' in the sandbox", worker.store.printStorePath(path)); - #if __linux__ - - Path source = worker.store.Store::toRealPath(path); - Path target = chrootRootDir + worker.store.printStorePath(path); - debug("bind-mounting %s -> %s", target, source); - - if (pathExists(target)) - throw Error("store path '%s' already exists in the sandbox", worker.store.printStorePath(path)); +#if __linux__ - auto st = lstat(source); + Path source = worker.store.Store::toRealPath(path); + Path target = chrootRootDir + worker.store.printStorePath(path); + debug("bind-mounting %s -> %s", target, source); - if (S_ISDIR(st.st_mode)) { + if (pathExists(target)) + throw Error("store path '%s' already exists in the sandbox", worker.store.printStorePath(path)); - /* Bind-mount the path into the sandbox. This requires - entering its mount namespace, which is not possible - in multithreaded programs. So we do this in a - child process.*/ - Pid child(startProcess([&]() { + auto st = lstat(source); - if (usingUserNamespace && (setns(sandboxUserNamespace.get(), 0) == -1)) - throw SysError("entering sandbox user namespace"); + if (S_ISDIR(st.st_mode)) { - if (setns(sandboxMountNamespace.get(), 0) == -1) - throw SysError("entering sandbox mount namespace"); + /* Bind-mount the path into the sandbox. This requires + entering its mount namespace, which is not possible + in multithreaded programs. So we do this in a + child process.*/ + Pid child(startProcess([&]() { + if (usingUserNamespace && (setns(sandboxUserNamespace.get(), 0) == -1)) + throw SysError("entering sandbox user namespace"); - createDirs(target); + if (setns(sandboxMountNamespace.get(), 0) == -1) + throw SysError("entering sandbox mount namespace"); - if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1) - throw SysError("bind mount from '%s' to '%s' failed", source, target); + createDirs(target); - _exit(0); - })); + if (mount(source.c_str(), target.c_str(), "", MS_BIND, 0) == -1) + throw SysError("bind mount from '%s' to '%s' failed", source, target); - int status = child.wait(); - if (status != 0) - throw Error("could not add path '%s' to sandbox", worker.store.printStorePath(path)); + _exit(0); + })); - } else - linkOrCopy(source, target); + int status = child.wait(); + if (status != 0) + throw Error("could not add path '%s' to sandbox", worker.store.printStorePath(path)); - #else - throw Error("don't know how to make path '%s' (produced by a recursive Nix call) appear in the sandbox", - worker.store.printStorePath(path)); - #endif + } else + linkOrCopy(source, target); +#else + throw Error( + "don't know how to make path '%s' (produced by a recursive Nix call) appear in the sandbox", + worker.store.printStorePath(path)); +#endif } } void LocalDerivationGoal::chownToBuilder(const Path & path) { - if (!buildUser) return; + if (!buildUser) + return; if (chown(path.c_str(), buildUser->getUID(), buildUser->getGID()) == -1) throw SysError("cannot change ownership of '%1%'", path); } - void setupSeccomp() { #if __linux__ - if (!settings.filterSyscalls) return; + if (!settings.filterSyscalls) + return; #if HAVE_SECCOMP scmp_filter_ctx ctx; if (!(ctx = seccomp_init(SCMP_ACT_ALLOW))) throw SysError("unable to initialize seccomp mode 2"); - Finally cleanup([&]() { - seccomp_release(ctx); - }); + Finally cleanup([&]() { seccomp_release(ctx); }); - if (nativeSystem == "x86_64-linux" && - seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0) + if (nativeSystem == "x86_64-linux" && seccomp_arch_add(ctx, SCMP_ARCH_X86) != 0) throw SysError("unable to add 32-bit seccomp architecture"); - if (nativeSystem == "x86_64-linux" && - seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0) + if (nativeSystem == "x86_64-linux" && seccomp_arch_add(ctx, SCMP_ARCH_X32) != 0) throw SysError("unable to add X32 seccomp architecture"); - if (nativeSystem == "aarch64-linux" && - seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0) - printError("unable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes"); + if (nativeSystem == "aarch64-linux" && seccomp_arch_add(ctx, SCMP_ARCH_ARM) != 0) + printError( + "unable to add ARM seccomp architecture; this may result in spurious build failures if running 32-bit ARM processes"); /* Prevent builders from creating setuid/setgid binaries. */ - for (int perm : { S_ISUID, S_ISGID }) { - if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(chmod), 1, - SCMP_A1(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) != 0) + for (int perm : {S_ISUID, S_ISGID}) { + if (seccomp_rule_add( + ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(chmod), 1, + SCMP_A1(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) + != 0) throw SysError("unable to add seccomp rule"); - if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fchmod), 1, - SCMP_A1(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) != 0) + if (seccomp_rule_add( + ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fchmod), 1, + SCMP_A1(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) + != 0) throw SysError("unable to add seccomp rule"); - if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fchmodat), 1, - SCMP_A2(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) != 0) + if (seccomp_rule_add( + ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(fchmodat), 1, + SCMP_A2(SCMP_CMP_MASKED_EQ, (scmp_datum_t) perm, (scmp_datum_t) perm)) + != 0) throw SysError("unable to add seccomp rule"); } /* Prevent builders from creating EAs or ACLs. Not all filesystems support these, and they're not allowed in the Nix store because they're not representable in the NAR serialisation. */ - if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(setxattr), 0) != 0 || - seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(lsetxattr), 0) != 0 || - seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0) + if (seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(setxattr), 0) != 0 + || seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(lsetxattr), 0) != 0 + || seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0) throw SysError("unable to add seccomp rule"); if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, settings.allowNewPrivileges ? 0 : 1) != 0) @@ -1564,7 +1573,6 @@ void setupSeccomp() #endif } - void LocalDerivationGoal::runChild() { /* Warning: in the child we should absolutely not make any SQLite @@ -1577,7 +1585,8 @@ void LocalDerivationGoal::runChild() try { setupSeccomp(); } catch (...) { - if (buildUser) throw; + if (buildUser) + throw; } bool setUser = true; @@ -1588,7 +1597,8 @@ void LocalDerivationGoal::runChild() try { if (drv->isBuiltin() && drv->builder == "builtin:fetchurl") netrcData = readFile(settings.netrcFile); - } catch (SysError &) { } + } catch (SysError &) { + } #if __linux__ if (useChroot) { @@ -1604,7 +1614,8 @@ void LocalDerivationGoal::runChild() /* Initialise the loopback interface. */ AutoCloseFD fd(socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)); - if (!fd) throw SysError("cannot open IP socket"); + if (!fd) + throw SysError("cannot open IP socket"); struct ifreq ifr; strcpy(ifr.ifr_name, "lo"); @@ -1686,12 +1697,13 @@ void LocalDerivationGoal::runChild() /* N.B. it is realistic that these paths might not exist. It happens when testing Nix building fixed-output derivations within a pure derivation. */ - for (auto & path : { "/etc/resolv.conf", "/etc/services", "/etc/hosts" }) + for (auto & path : {"/etc/resolv.conf", "/etc/services", "/etc/hosts"}) if (pathExists(path)) ss.push_back(path); } - for (auto & i : ss) dirsInChroot.emplace(i, i); + for (auto & i : ss) + dirsInChroot.emplace(i, i); /* Bind-mount all the directories from the "host" filesystem that we want in the chroot @@ -1716,19 +1728,20 @@ void LocalDerivationGoal::runChild() }; for (auto & i : dirsInChroot) { - if (i.second.source == "/proc") continue; // backwards compatibility + if (i.second.source == "/proc") + continue; // backwards compatibility - #if HAVE_EMBEDDED_SANDBOX_SHELL +#if HAVE_EMBEDDED_SANDBOX_SHELL if (i.second.source == "__embedded_sandbox_shell__") { static unsigned char sh[] = { - #include "embedded-sandbox-shell.gen.hh" +#include "embedded-sandbox-shell.gen.hh" }; auto dst = chrootRootDir + i.first; createDirs(dirOf(dst)); writeFile(dst, std::string_view((const char *) sh, sizeof(sh))); chmod_(dst, 0555); } else - #endif +#endif doBind(i.second.source, chrootRootDir + i.first, i.second.optional); } @@ -1739,20 +1752,20 @@ void LocalDerivationGoal::runChild() /* Mount a new tmpfs on /dev/shm to ensure that whatever the builder puts in /dev/shm is cleaned up automatically. */ - if (pathExists("/dev/shm") && mount("none", (chrootRootDir + "/dev/shm").c_str(), "tmpfs", 0, - fmt("size=%s", settings.sandboxShmSize).c_str()) == -1) + if (pathExists("/dev/shm") + && mount( + "none", (chrootRootDir + "/dev/shm").c_str(), "tmpfs", 0, + fmt("size=%s", settings.sandboxShmSize).c_str()) + == -1) throw SysError("mounting /dev/shm"); /* Mount a new devpts on /dev/pts. Note that this requires the kernel to be compiled with CONFIG_DEVPTS_MULTIPLE_INSTANCES=y (which is the case if /dev/ptx/ptmx exists). */ - if (pathExists("/dev/pts/ptmx") && - !pathExists(chrootRootDir + "/dev/ptmx") - && !dirsInChroot.count("/dev/pts")) - { - if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == 0) - { + if (pathExists("/dev/pts/ptmx") && !pathExists(chrootRootDir + "/dev/ptmx") + && !dirsInChroot.count("/dev/pts")) { + if (mount("none", (chrootRootDir + "/dev/pts").c_str(), "devpts", 0, "newinstance,mode=0620") == 0) { createSymlink("/dev/pts/ptmx", chrootRootDir + "/dev/ptmx"); /* Make sure /dev/pts/ptmx is world-writable. With some @@ -1822,11 +1835,9 @@ void LocalDerivationGoal::runChild() struct utsname utsbuf; uname(&utsbuf); if ((drv->platform == "i686-linux" - && (settings.thisSystem == "x86_64-linux" - || (!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64")))) - || drv->platform == "armv7l-linux" - || drv->platform == "armv6l-linux") - { + && (settings.thisSystem == "x86_64-linux" + || (!strcmp(utsbuf.sysname, "Linux") && !strcmp(utsbuf.machine, "x86_64")))) + || drv->platform == "armv7l-linux" || drv->platform == "armv6l-linux") { if (personality(PER_LINUX32) == -1) throw SysError("cannot set 32-bit personality"); } @@ -1835,17 +1846,19 @@ void LocalDerivationGoal::runChild() builds that depend on the kernel version. */ if ((drv->platform == "i686-linux" || drv->platform == "x86_64-linux") && settings.impersonateLinux26) { int cur = personality(0xffffffff); - if (cur != -1) personality(cur | 0x0020000 /* == UNAME26 */); + if (cur != -1) + personality(cur | 0x0020000 /* == UNAME26 */); } /* Disable address space randomization for improved determinism. */ int cur = personality(0xffffffff); - if (cur != -1) personality(cur | ADDR_NO_RANDOMIZE); + if (cur != -1) + personality(cur | ADDR_NO_RANDOMIZE); #endif /* Disable core dumps by default. */ - struct rlimit limit = { 0, RLIM_INFINITY }; + struct rlimit limit = {0, RLIM_INFINITY}; setrlimit(RLIMIT_CORE, &limit); // FIXME: set other limits to deterministic values? @@ -1864,19 +1877,16 @@ void LocalDerivationGoal::runChild() if (setUser && buildUser) { /* Preserve supplementary groups of the build user, to allow admins to specify groups such as "kvm". */ - if (!buildUser->getSupplementaryGIDs().empty() && - setgroups(buildUser->getSupplementaryGIDs().size(), - buildUser->getSupplementaryGIDs().data()) == -1) + if (!buildUser->getSupplementaryGIDs().empty() + && setgroups(buildUser->getSupplementaryGIDs().size(), buildUser->getSupplementaryGIDs().data()) == -1) throw SysError("cannot set supplementary groups of build user"); - if (setgid(buildUser->getGID()) == -1 || - getgid() != buildUser->getGID() || - getegid() != buildUser->getGID()) + if (setgid(buildUser->getGID()) == -1 || getgid() != buildUser->getGID() + || getegid() != buildUser->getGID()) throw SysError("setgid failed"); - if (setuid(buildUser->getUID()) == -1 || - getuid() != buildUser->getUID() || - geteuid() != buildUser->getUID()) + if (setuid(buildUser->getUID()) == -1 || getuid() != buildUser->getUID() + || geteuid() != buildUser->getUID()) throw SysError("setuid failed"); } @@ -1923,7 +1933,8 @@ void LocalDerivationGoal::runChild() dirsInChroot[p] = p; } - /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be configurable */ + /* Violations will go to the syslog if you set this. Unfortunately the destination does not appear to be + * configurable */ if (settings.darwinLogSandboxViolations) { sandboxProfile += "(deny default)\n"; } else { @@ -1950,8 +1961,8 @@ void LocalDerivationGoal::runChild() for (auto & i : dirsInChroot) { if (i.first != i.second.source) throw Error( - "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", - i.first, i.second.source); + "can't map '%1%' to '%2%': mismatched impure paths not supported on Darwin", i.first, + i.second.source); std::string path = i.first; struct stat st; @@ -1987,12 +1998,14 @@ void LocalDerivationGoal::runChild() bool allowLocalNetworking = parsedDrv->getBoolAttr("__darwinAllowLocalNetworking"); - /* 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. */ + /* 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); /* They don't like trailing slashes on subpath directives */ - if (globalTmpDir.back() == '/') globalTmpDir.pop_back(); + if (globalTmpDir.back() == '/') + globalTmpDir.pop_back(); if (getEnv("_NIX_TEST_NO_SANDBOX") != "1") { builder = "/usr/bin/sandbox-exec"; @@ -2071,7 +2084,8 @@ void LocalDerivationGoal::runChild() posix_spawnattr_setbinpref_np(&attrp, 1, &cpu, NULL); } - posix_spawn(NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); + posix_spawn( + NULL, builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); #else execve(builder.c_str(), stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data()); #endif @@ -2087,7 +2101,6 @@ void LocalDerivationGoal::runChild() } } - DrvOutputs LocalDerivationGoal::registerOutputs() { /* When using a build hook, the build hook can register the output @@ -2116,16 +2129,17 @@ DrvOutputs LocalDerivationGoal::registerOutputs() output paths, and any paths that have been built via recursive Nix calls. */ StorePathSet referenceablePaths; - for (auto & p : inputPaths) referenceablePaths.insert(p); - for (auto & i : scratchOutputs) referenceablePaths.insert(i.second); - for (auto & p : addedPaths) referenceablePaths.insert(p); + for (auto & p : inputPaths) + referenceablePaths.insert(p); + for (auto & i : scratchOutputs) + referenceablePaths.insert(i.second); + for (auto & p : addedPaths) + referenceablePaths.insert(p); /* FIXME `needsHashRewrite` should probably be removed and we get to the real reason why we aren't using the chroot dir */ auto toRealPathChroot = [&](const Path & p) -> Path { - return useChroot && !needsHashRewrite() - ? chrootRootDir + p - : worker.store.toRealPath(p); + return useChroot && !needsHashRewrite() ? chrootRootDir + p : worker.store.toRealPath(p); }; /* Check whether the output paths were created, and make all @@ -2134,16 +2148,21 @@ DrvOutputs LocalDerivationGoal::registerOutputs() that are most definitely already installed, we just store their final name so we can also use it in rewrites. */ StringSet outputsToSort; - struct AlreadyRegistered { StorePath path; }; - struct PerhapsNeedToRegister { StorePathSet refs; }; + struct AlreadyRegistered + { + StorePath path; + }; + struct PerhapsNeedToRegister + { + StorePathSet refs; + }; std::map> outputReferencesIfUnregistered; std::map outputStats; for (auto & [outputName, _] : drv->outputs) { auto scratchOutput = get(scratchOutputs, outputName); if (!scratchOutput) throw BuildError( - "builder for '%s' has no scratch output for '%s'", - worker.store.printStorePath(drvPath), outputName); + "builder for '%s' has no scratch output for '%s'", worker.store.printStorePath(drvPath), outputName); auto actualPath = toRealPathChroot(worker.store.printStorePath(*scratchOutput)); outputsToSort.insert(outputName); @@ -2152,17 +2171,14 @@ DrvOutputs LocalDerivationGoal::registerOutputs() auto initialOutput = get(initialOutputs, outputName); if (!initialOutput) throw BuildError( - "builder for '%s' has no initial output for '%s'", - worker.store.printStorePath(drvPath), outputName); + "builder for '%s' has no initial output for '%s'", worker.store.printStorePath(drvPath), outputName); auto & initialInfo = *initialOutput; /* Don't register if already valid, and not checking */ - initialInfo.wanted = buildMode == bmCheck - || !(initialInfo.known && initialInfo.known->isValid()); + initialInfo.wanted = buildMode == bmCheck || !(initialInfo.known && initialInfo.known->isValid()); if (!initialInfo.wanted) { outputReferencesIfUnregistered.insert_or_assign( - outputName, - AlreadyRegistered { .path = initialInfo.known->path }); + outputName, AlreadyRegistered{.path = initialInfo.known->path}); continue; } @@ -2180,11 +2196,11 @@ DrvOutputs LocalDerivationGoal::registerOutputs() that means that someone else can have interfered with the build. Also, the output should be owned by the build user. */ - if ((!S_ISLNK(st.st_mode) && (st.st_mode & (S_IWGRP | S_IWOTH))) || - (buildUser && st.st_uid != buildUser->getUID())) + if ((!S_ISLNK(st.st_mode) && (st.st_mode & (S_IWGRP | S_IWOTH))) + || (buildUser && st.st_uid != buildUser->getUID())) throw BuildError( - "suspicious ownership or permission on '%s' for output '%s'; rejecting this build output", - actualPath, outputName); + "suspicious ownership or permission on '%s' for output '%s'; rejecting this build output", actualPath, + outputName); #endif /* Canonicalise first. This ensures that the path we're @@ -2198,34 +2214,33 @@ DrvOutputs LocalDerivationGoal::registerOutputs() NullSink blank; auto references = scanForReferences(blank, actualPath, referenceablePaths); - outputReferencesIfUnregistered.insert_or_assign( - outputName, - PerhapsNeedToRegister { .refs = references }); + outputReferencesIfUnregistered.insert_or_assign(outputName, PerhapsNeedToRegister{.refs = references}); outputStats.insert_or_assign(outputName, std::move(st)); } - auto sortedOutputNames = topoSort(outputsToSort, - {[&](const std::string & name) { + auto sortedOutputNames = topoSort( + outputsToSort, {[&](const std::string & name) { auto orifu = get(outputReferencesIfUnregistered, name); if (!orifu) throw BuildError( - "no output reference for '%s' in build of '%s'", - name, worker.store.printStorePath(drvPath)); - return std::visit(overloaded { - /* Since we'll use the already installed versions of these, we - can treat them as leaves and ignore any references they - have. */ - [&](const AlreadyRegistered &) { return StringSet {}; }, - [&](const PerhapsNeedToRegister & refs) { - StringSet referencedOutputs; - /* FIXME build inverted map up front so no quadratic waste here */ - for (auto & r : refs.refs) - for (auto & [o, p] : scratchOutputs) - if (r == p) - referencedOutputs.insert(o); - return referencedOutputs; + "no output reference for '%s' in build of '%s'", name, worker.store.printStorePath(drvPath)); + return std::visit( + overloaded{ + /* Since we'll use the already installed versions of these, we + can treat them as leaves and ignore any references they + have. */ + [&](const AlreadyRegistered &) { return StringSet{}; }, + [&](const PerhapsNeedToRegister & refs) { + StringSet referencedOutputs; + /* FIXME build inverted map up front so no quadratic waste here */ + for (auto & r : refs.refs) + for (auto & [o, p] : scratchOutputs) + if (r == p) + referencedOutputs.insert(o); + return referencedOutputs; + }, }, - }, *orifu); + *orifu); }}, {[&](const std::string & path, const std::string & parent) { // TODO with more -vvvv also show the temporary paths for manual inspection. @@ -2251,21 +2266,21 @@ DrvOutputs LocalDerivationGoal::registerOutputs() use. This is why the topological sort is essential to do first before this for loop. */ if (*scratchPath != finalStorePath) - outputRewrites[std::string { scratchPath->hashPart() }] = std::string { finalStorePath.hashPart() }; + outputRewrites[std::string{scratchPath->hashPart()}] = std::string{finalStorePath.hashPart()}; }; auto orifu = get(outputReferencesIfUnregistered, outputName); assert(orifu); - std::optional referencesOpt = std::visit(overloaded { - [&](const AlreadyRegistered & skippedFinalPath) -> std::optional { - finish(skippedFinalPath.path); - return std::nullopt; - }, - [&](const PerhapsNeedToRegister & r) -> std::optional { - return r.refs; + std::optional referencesOpt = std::visit( + overloaded{ + [&](const AlreadyRegistered & skippedFinalPath) -> std::optional { + finish(skippedFinalPath.path); + return std::nullopt; + }, + [&](const PerhapsNeedToRegister & r) -> std::optional { return r.refs; }, }, - }, *orifu); + *orifu); if (!referencesOpt) continue; @@ -2291,20 +2306,20 @@ DrvOutputs LocalDerivationGoal::registerOutputs() final path, therefore we look for a *non-rewritten self-reference, and use a bool rather try to solve the computationally intractable fixed point. */ - std::pair res { + std::pair res{ false, {}, }; for (auto & r : references) { auto name = r.name(); - auto origHash = std::string { r.hashPart() }; + auto origHash = std::string{r.hashPart()}; if (r == *scratchPath) { res.first = true; } else if (auto outputRewrite = get(outputRewrites, origHash)) { std::string newRef = *outputRewrite; newRef += '-'; newRef += name; - res.second.insert(StorePath { newRef }); + res.second.insert(StorePath{newRef}); } else { res.second.insert(r); } @@ -2315,9 +2330,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs() auto newInfoFromCA = [&](const DerivationOutput::CAFloating outputHash) -> ValidPathInfo { auto st = get(outputStats, outputName); if (!st) - throw BuildError( - "output path %1% without valid stats info", - actualPath); + throw BuildError("output path %1% without valid stats info", actualPath); if (outputHash.method == FileIngestionMethod::Flat) { /* The output path should be a regular file without execute permission. */ if (!S_ISREG(st->st_mode) || (st->st_mode & S_IXUSR) != 0) @@ -2328,8 +2341,8 @@ DrvOutputs LocalDerivationGoal::registerOutputs() } rewriteOutput(); /* FIXME optimize and deduplicate with addToStore */ - std::string oldHashPart { scratchPath->hashPart() }; - HashModuloSink caSink { outputHash.hashType, oldHashPart }; + std::string oldHashPart{scratchPath->hashPart()}; + HashModuloSink caSink{outputHash.hashType, oldHashPart}; switch (outputHash.method) { case FileIngestionMethod::Recursive: dumpPath(actualPath, caSink); @@ -2342,11 +2355,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs() auto refs = rewriteRefs(); auto finalPath = worker.store.makeFixedOutputPath( - outputHash.method, - got, - outputPathName(drv->name, outputName), - refs.second, - refs.first); + outputHash.method, got, outputPathName(drv->name, outputName), refs.second, refs.first); if (*scratchPath != finalPath) { // Also rewrite the output path auto source = sinkToSource([&](Sink & nextSink) { @@ -2363,13 +2372,13 @@ DrvOutputs LocalDerivationGoal::registerOutputs() } HashResult narHashAndSize = hashPath(htSHA256, actualPath); - ValidPathInfo newInfo0 { + ValidPathInfo newInfo0{ finalPath, narHashAndSize.first, }; newInfo0.narSize = narHashAndSize.second; - newInfo0.ca = FixedOutputHash { + newInfo0.ca = FixedOutputHash{ .method = outputHash.method, .hash = got, }; @@ -2381,69 +2390,67 @@ DrvOutputs LocalDerivationGoal::registerOutputs() return newInfo0; }; - ValidPathInfo newInfo = std::visit(overloaded { - - [&](const DerivationOutput::InputAddressed & output) { - /* input-addressed case */ - auto requiredFinalPath = output.path; - /* Preemptively add rewrite rule for final hash, as that is - what the NAR hash will use rather than normalized-self references */ - if (*scratchPath != requiredFinalPath) - outputRewrites.insert_or_assign( - std::string { scratchPath->hashPart() }, - std::string { requiredFinalPath.hashPart() }); - rewriteOutput(); - auto narHashAndSize = hashPath(htSHA256, actualPath); - ValidPathInfo newInfo0 { requiredFinalPath, narHashAndSize.first }; - newInfo0.narSize = narHashAndSize.second; - auto refs = rewriteRefs(); - newInfo0.references = refs.second; - if (refs.first) - newInfo0.references.insert(newInfo0.path); - return newInfo0; - }, - - [&](const DerivationOutput::CAFixed & dof) { - auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating { - .method = dof.hash.method, - .hashType = dof.hash.hash.type, - }); + ValidPathInfo newInfo = std::visit( + overloaded{ + + [&](const DerivationOutput::InputAddressed & output) { + /* input-addressed case */ + auto requiredFinalPath = output.path; + /* Preemptively add rewrite rule for final hash, as that is + what the NAR hash will use rather than normalized-self references */ + if (*scratchPath != requiredFinalPath) + outputRewrites.insert_or_assign( + std::string{scratchPath->hashPart()}, std::string{requiredFinalPath.hashPart()}); + rewriteOutput(); + auto narHashAndSize = hashPath(htSHA256, actualPath); + ValidPathInfo newInfo0{requiredFinalPath, narHashAndSize.first}; + newInfo0.narSize = narHashAndSize.second; + auto refs = rewriteRefs(); + newInfo0.references = refs.second; + if (refs.first) + newInfo0.references.insert(newInfo0.path); + return newInfo0; + }, - /* Check wanted hash */ - const Hash & wanted = dof.hash.hash; - assert(newInfo0.ca); - auto got = getContentAddressHash(*newInfo0.ca); - if (wanted != got) { - /* Throw an error after registering the path as - valid. */ - worker.hashMismatch = true; - delayedException = std::make_exception_ptr( - BuildError("hash mismatch in fixed-output derivation '%s':\n specified: %s\n got: %s", - worker.store.printStorePath(drvPath), - wanted.to_string(SRI, true), + [&](const DerivationOutput::CAFixed & dof) { + auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating{ + .method = dof.hash.method, + .hashType = dof.hash.hash.type, + }); + + /* Check wanted hash */ + const Hash & wanted = dof.hash.hash; + assert(newInfo0.ca); + auto got = getContentAddressHash(*newInfo0.ca); + if (wanted != got) { + /* Throw an error after registering the path as + valid. */ + worker.hashMismatch = true; + delayedException = std::make_exception_ptr(BuildError( + "hash mismatch in fixed-output derivation '%s':\n specified: %s\n got: %s", + worker.store.printStorePath(drvPath), wanted.to_string(SRI, true), got.to_string(SRI, true))); - } - return newInfo0; - }, + } + return newInfo0; + }, - [&](const DerivationOutput::CAFloating & dof) { - return newInfoFromCA(dof); - }, + [&](const DerivationOutput::CAFloating & dof) { return newInfoFromCA(dof); }, - [&](const DerivationOutput::Deferred &) -> ValidPathInfo { - // No derivation should reach that point without having been - // rewritten first - assert(false); - }, + [&](const DerivationOutput::Deferred &) -> ValidPathInfo { + // No derivation should reach that point without having been + // rewritten first + assert(false); + }, - [&](const DerivationOutput::Impure & doi) { - return newInfoFromCA(DerivationOutput::CAFloating { - .method = doi.method, - .hashType = doi.hashType, - }); - }, + [&](const DerivationOutput::Impure & doi) { + return newInfoFromCA(DerivationOutput::CAFloating{ + .method = doi.method, + .hashType = doi.hashType, + }); + }, - }, output->raw()); + }, + output->raw()); /* FIXME: set proper permissions in restorePath() so we don't have to do another traversal. */ @@ -2460,9 +2467,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs() PathLocks dynamicOutputLock; dynamicOutputLock.setDeletion(true); auto optFixedPath = output->path(worker.store, drv->name, outputName); - if (!optFixedPath || - worker.store.printStorePath(*optFixedPath) != finalDestPath) - { + if (!optFixedPath || worker.store.printStorePath(*optFixedPath) != finalDestPath) { assert(newInfo.ca); dynamicOutputLock.lockPaths({worker.store.toRealPath(finalDestPath)}); } @@ -2492,7 +2497,8 @@ DrvOutputs LocalDerivationGoal::registerOutputs() if (buildMode == bmCheck) { - if (!worker.store.isValidPath(newInfo.path)) continue; + if (!worker.store.isValidPath(newInfo.path)) + continue; ValidPathInfo oldInfo(*worker.store.queryPathInfo(newInfo.path)); if (newInfo.narHash != oldInfo.narHash) { worker.checkMismatch = true; @@ -2502,14 +2508,15 @@ DrvOutputs LocalDerivationGoal::registerOutputs() movePath(actualPath, dst); handleDiffHook( - buildUser ? buildUser->getUID() : getuid(), - buildUser ? buildUser->getGID() : getgid(), + buildUser ? buildUser->getUID() : getuid(), buildUser ? buildUser->getGID() : getgid(), finalDestPath, dst, worker.store.printStorePath(drvPath), tmpDir); - throw NotDeterministic("derivation '%s' may not be deterministic: output '%s' differs from '%s'", + throw NotDeterministic( + "derivation '%s' may not be deterministic: output '%s' differs from '%s'", worker.store.printStorePath(drvPath), worker.store.toRealPath(finalDestPath), dst); } else - throw NotDeterministic("derivation '%s' may not be deterministic: output '%s' differs", + throw NotDeterministic( + "derivation '%s' may not be deterministic: output '%s' differs", worker.store.printStorePath(drvPath), worker.store.toRealPath(finalDestPath)); } @@ -2572,17 +2579,17 @@ DrvOutputs LocalDerivationGoal::registerOutputs() buildResult.isNonDeterministic = true; Path prev = worker.store.printStorePath(i->second.path) + checkSuffix; bool prevExists = keepPreviousRound && pathExists(prev); - hintformat hint = prevExists - ? hintfmt("output '%s' of '%s' differs from '%s' from previous round", + hintformat hint = + prevExists ? hintfmt( + "output '%s' of '%s' differs from '%s' from previous round", worker.store.printStorePath(i->second.path), worker.store.printStorePath(drvPath), prev) - : hintfmt("output '%s' of '%s' differs from previous round", - worker.store.printStorePath(i->second.path), worker.store.printStorePath(drvPath)); + : hintfmt( + "output '%s' of '%s' differs from previous round", + worker.store.printStorePath(i->second.path), worker.store.printStorePath(drvPath)); handleDiffHook( - buildUser ? buildUser->getUID() : getuid(), - buildUser ? buildUser->getGID() : getgid(), - prev, worker.store.printStorePath(i->second.path), - worker.store.printStorePath(drvPath), tmpDir); + buildUser ? buildUser->getUID() : getuid(), buildUser ? buildUser->getGID() : getgid(), prev, + worker.store.printStorePath(i->second.path), worker.store.printStorePath(drvPath), tmpDir); if (settings.enforceDeterminism) throw NotDeterministic(hint); @@ -2647,16 +2654,8 @@ DrvOutputs LocalDerivationGoal::registerOutputs() for (auto & [outputName, newInfo] : infos) { auto oldinfo = get(initialOutputs, outputName); assert(oldinfo); - auto thisRealisation = Realisation { - .id = DrvOutput { - oldinfo->outputHash, - outputName - }, - .outPath = newInfo.path - }; - if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) - && drv->type().isPure()) - { + auto thisRealisation = Realisation{.id = DrvOutput{oldinfo->outputHash, outputName}, .outPath = newInfo.path}; + if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) && drv->type().isPure()) { signRealisation(thisRealisation); worker.store.registerDrvOutput(thisRealisation); } @@ -2672,7 +2671,6 @@ void LocalDerivationGoal::signRealisation(Realisation & realisation) getLocalStore().signRealisation(realisation); } - void LocalDerivationGoal::checkOutputs(const std::map & outputs) { std::map outputsByPath; @@ -2693,8 +2691,7 @@ void LocalDerivationGoal::checkOutputs(const std::map pathsLeft; @@ -2703,7 +2700,8 @@ void LocalDerivationGoal::checkOutputs(const std::map *checks.maxSize) - throw BuildError("path '%s' is too large at %d bytes; limit is %d bytes", - worker.store.printStorePath(info.path), info.narSize, *checks.maxSize); + throw BuildError( + "path '%s' is too large at %d bytes; limit is %d bytes", worker.store.printStorePath(info.path), + info.narSize, *checks.maxSize); if (checks.maxClosureSize) { uint64_t closureSize = getClosure(info.path).second; if (closureSize > *checks.maxClosureSize) - throw BuildError("closure of path '%s' is too large at %d bytes; limit is %d bytes", + throw BuildError( + "closure of path '%s' is too large at %d bytes; limit is %d bytes", worker.store.printStorePath(info.path), closureSize, *checks.maxClosureSize); } - auto checkRefs = [&](const std::optional & value, bool allowed, bool recursive) - { - if (!value) return; + auto checkRefs = [&](const std::optional & value, bool allowed, bool recursive) { + if (!value) + return; /* Parse a list of reference specifiers. Each element must either be a store path, or the symbolic name of the output @@ -2751,9 +2750,7 @@ void LocalDerivationGoal::checkOutputs(const std::mapbegin(); j != i->end(); ++j) { if (!j->is_string()) - throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, worker.store.printStorePath(drvPath)); + throw Error( + "attribute '%s' of derivation '%s' must be a list of strings", name, + worker.store.printStorePath(drvPath)); res.push_back(j->get()); } checks.disallowedRequisites = res; @@ -2832,7 +2832,6 @@ void LocalDerivationGoal::checkOutputs(const std::mapisBuiltin()) { printError("note: keeping build directory '%s'", tmpDir); chmod(tmpDir.c_str(), 0755); - } - else + } else deletePath(tmpDir); tmpDir = ""; } } - bool LocalDerivationGoal::isReadDesc(int fd) { - return (hook && DerivationGoal::isReadDesc(fd)) || - (!hook && fd == builderOut.readSide.get()); + return (hook && DerivationGoal::isReadDesc(fd)) || (!hook && fd == builderOut.readSide.get()); } - StorePath LocalDerivationGoal::makeFallbackPath(std::string_view outputName) { return worker.store.makeStorePath( - "rewrite:" + std::string(drvPath.to_string()) + ":name:" + std::string(outputName), - Hash(htSHA256), outputPathName(drv->name, outputName)); + "rewrite:" + std::string(drvPath.to_string()) + ":name:" + std::string(outputName), Hash(htSHA256), + outputPathName(drv->name, outputName)); } - StorePath LocalDerivationGoal::makeFallbackPath(const StorePath & path) { return worker.store.makeStorePath( - "rewrite:" + std::string(drvPath.to_string()) + ":" + std::string(path.to_string()), - Hash(htSHA256), path.name()); + "rewrite:" + std::string(drvPath.to_string()) + ":" + std::string(path.to_string()), Hash(htSHA256), + path.name()); } - } diff --git a/src/libstore/build/local-derivation-goal.hh b/src/libstore/build/local-derivation-goal.hh index d456e9cae979..e88e8180e320 100644 --- a/src/libstore/build/local-derivation-goal.hh +++ b/src/libstore/build/local-derivation-goal.hh @@ -48,12 +48,14 @@ struct LocalDerivationGoal : public DerivationGoal bool privateNetwork = false; /* Stuff we need to pass to initChild(). */ - struct ChrootPath { + struct ChrootPath + { Path source; bool optional; ChrootPath(Path source = "", bool optional = false) - : source(source), optional(optional) - { } + : source(source) + , optional(optional) + {} }; typedef map DirsInChroot; // maps target path to source path DirsInChroot dirsInChroot; @@ -92,8 +94,14 @@ struct LocalDerivationGoal : public DerivationGoal result. */ std::map prevInfos; - uid_t sandboxUid() { return usingUserNamespace ? 1000 : buildUser->getUID(); } - gid_t sandboxGid() { return usingUserNamespace ? 100 : buildUser->getGID(); } + uid_t sandboxUid() + { + return usingUserNamespace ? 1000 : buildUser->getUID(); + } + gid_t sandboxGid() + { + return usingUserNamespace ? 100 : buildUser->getGID(); + } const static Path homeDir; diff --git a/src/libstore/build/substitution-goal.cc b/src/libstore/build/substitution-goal.cc index 2af105b4d31a..b8f5d29eabe7 100644 --- a/src/libstore/build/substitution-goal.cc +++ b/src/libstore/build/substitution-goal.cc @@ -5,8 +5,9 @@ namespace nix { -PathSubstitutionGoal::PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional ca) - : Goal(worker, DerivedPath::Opaque { storePath }) +PathSubstitutionGoal::PathSubstitutionGoal( + const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional ca) + : Goal(worker, DerivedPath::Opaque{storePath}) , storePath(storePath) , repair(repair) , ca(ca) @@ -17,17 +18,12 @@ PathSubstitutionGoal::PathSubstitutionGoal(const StorePath & storePath, Worker & maintainExpectedSubstitutions = std::make_unique>(worker.expectedSubstitutions); } - PathSubstitutionGoal::~PathSubstitutionGoal() { cleanup(); } - -void PathSubstitutionGoal::done( - ExitCode result, - BuildResult::Status status, - std::optional errorMsg) +void PathSubstitutionGoal::done(ExitCode result, BuildResult::Status status, std::optional errorMsg) { buildResult.status = status; if (errorMsg) { @@ -37,13 +33,11 @@ void PathSubstitutionGoal::done( amDone(result); } - void PathSubstitutionGoal::work() { (this->*state)(); } - void PathSubstitutionGoal::init() { trace("init"); @@ -57,14 +51,14 @@ void PathSubstitutionGoal::init() } if (settings.readOnlyMode) - throw Error("cannot substitute path '%s' - no write access to the Nix store", worker.store.printStorePath(storePath)); + throw Error( + "cannot substitute path '%s' - no write access to the Nix store", worker.store.printStorePath(storePath)); subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list>(); tryNext(); } - void PathSubstitutionGoal::tryNext() { trace("trying next substituter"); @@ -79,9 +73,9 @@ void PathSubstitutionGoal::tryNext() In that case the calling derivation should just do a build. */ done( - substituterFailed ? ecFailed : ecNoSubstituters, - BuildResult::NoSubstituters, - fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath))); + substituterFailed ? ecFailed : ecNoSubstituters, BuildResult::NoSubstituters, + fmt("path '%s' is required, but there is no substituter that can build it", + worker.store.printStorePath(storePath))); if (substituterFailed) { worker.failedSubstitutions++; @@ -130,8 +124,9 @@ void PathSubstitutionGoal::tryNext() info2->path = storePath; info = info2; } else { - printError("asked '%s' for '%s' but got '%s'", - sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path)); + printError( + "asked '%s' for '%s' but got '%s'", sub->getUri(), worker.store.printStorePath(storePath), + sub->printStorePath(info->path)); tryNext(); return; } @@ -144,17 +139,17 @@ void PathSubstitutionGoal::tryNext() maintainExpectedDownload = narInfo && narInfo->fileSize - ? std::make_unique>(worker.expectedDownloadSize, narInfo->fileSize) - : nullptr; + ? std::make_unique>(worker.expectedDownloadSize, narInfo->fileSize) + : nullptr; worker.updateProgress(); /* Bail out early if this substituter lacks a valid signature. LocalStore::addToStore() also checks for this, but only after we've downloaded the path. */ - if (!sub->isTrusted && worker.store.pathInfoIsUntrusted(*info)) - { - warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'", + if (!sub->isTrusted && worker.store.pathInfoIsUntrusted(*info)) { + warn( + "ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'", worker.store.printStorePath(storePath), sub->getUri()); tryNext(); return; @@ -172,7 +167,6 @@ void PathSubstitutionGoal::tryNext() state = &PathSubstitutionGoal::referencesValid; } - void PathSubstitutionGoal::referencesValid() { trace("all references realised"); @@ -193,7 +187,6 @@ void PathSubstitutionGoal::referencesValid() worker.wakeUp(shared_from_this()); } - void PathSubstitutionGoal::tryToRun() { trace("trying to run"); @@ -222,8 +215,8 @@ void PathSubstitutionGoal::tryToRun() Activity act(*logger, actSubstitute, Logger::Fields{worker.store.printStorePath(storePath), sub->getUri()}); PushActivity pact(act.id); - copyStorePath(*sub, worker.store, - subPath ? *subPath : storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs); + copyStorePath( + *sub, worker.store, subPath ? *subPath : storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs); promise.set_value(); } catch (...) { @@ -236,7 +229,6 @@ void PathSubstitutionGoal::tryToRun() state = &PathSubstitutionGoal::finished; } - void PathSubstitutionGoal::finished() { trace("substitute finished"); @@ -289,18 +281,14 @@ void PathSubstitutionGoal::finished() done(ecSuccess, BuildResult::Substituted); } - -void PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data) -{ -} - +void PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data) {} void PathSubstitutionGoal::handleEOF(int fd) { - if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this()); + if (fd == outPipe.readSide.get()) + worker.wakeUp(shared_from_this()); } - void PathSubstitutionGoal::cleanup() { try { @@ -316,5 +304,4 @@ void PathSubstitutionGoal::cleanup() } } - } diff --git a/src/libstore/build/substitution-goal.hh b/src/libstore/build/substitution-goal.hh index a73f8e6669a8..21fdcf9d11f7 100644 --- a/src/libstore/build/substitution-goal.hh +++ b/src/libstore/build/substitution-goal.hh @@ -44,8 +44,8 @@ struct PathSubstitutionGoal : public Goal storePath when doing a repair. */ Path destPath; - std::unique_ptr> maintainExpectedSubstitutions, - maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload; + std::unique_ptr> maintainExpectedSubstitutions, maintainRunningSubstitutions, + maintainExpectedNar, maintainExpectedDownload; typedef void (PathSubstitutionGoal::*GoalState)(); GoalState state; @@ -53,16 +53,20 @@ struct PathSubstitutionGoal : public Goal /* Content address for recomputing store path */ std::optional ca; - void done( - ExitCode result, - BuildResult::Status status, - std::optional errorMsg = {}); + void done(ExitCode result, BuildResult::Status status, std::optional errorMsg = {}); public: - PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional ca = std::nullopt); + PathSubstitutionGoal( + const StorePath & storePath, + Worker & worker, + RepairFlag repair = NoRepair, + std::optional ca = std::nullopt); ~PathSubstitutionGoal(); - void timedOut(Error && ex) override { abort(); }; + void timedOut(Error && ex) override + { + abort(); + }; std::string key() override { diff --git a/src/libstore/build/worker.cc b/src/libstore/build/worker.cc index b192fbc778dc..ce029d4d1c0a 100644 --- a/src/libstore/build/worker.cc +++ b/src/libstore/build/worker.cc @@ -25,7 +25,6 @@ Worker::Worker(Store & store, Store & evalStore) checkMismatch = false; } - Worker::~Worker() { /* Explicitly get rid of all strong pointers now. After this all @@ -39,7 +38,6 @@ Worker::~Worker() assert(expectedNarSize == 0); } - std::shared_ptr Worker::makeDerivationGoalCommon( const StorePath & drvPath, const StringSet & wantedOutputs, @@ -57,30 +55,28 @@ std::shared_ptr Worker::makeDerivationGoalCommon( return goal; } - -std::shared_ptr Worker::makeDerivationGoal(const StorePath & drvPath, - const StringSet & wantedOutputs, BuildMode buildMode) +std::shared_ptr +Worker::makeDerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs, BuildMode buildMode) { return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr { return !dynamic_cast(&store) - ? std::make_shared(drvPath, wantedOutputs, *this, buildMode) - : std::make_shared(drvPath, wantedOutputs, *this, buildMode); + ? std::make_shared(drvPath, wantedOutputs, *this, buildMode) + : std::make_shared(drvPath, wantedOutputs, *this, buildMode); }); } - -std::shared_ptr Worker::makeBasicDerivationGoal(const StorePath & drvPath, - const BasicDerivation & drv, const StringSet & wantedOutputs, BuildMode buildMode) +std::shared_ptr Worker::makeBasicDerivationGoal( + const StorePath & drvPath, const BasicDerivation & drv, const StringSet & wantedOutputs, BuildMode buildMode) { return makeDerivationGoalCommon(drvPath, wantedOutputs, [&]() -> std::shared_ptr { return !dynamic_cast(&store) - ? std::make_shared(drvPath, drv, wantedOutputs, *this, buildMode) - : std::make_shared(drvPath, drv, wantedOutputs, *this, buildMode); + ? std::make_shared(drvPath, drv, wantedOutputs, *this, buildMode) + : std::make_shared(drvPath, drv, wantedOutputs, *this, buildMode); }); } - -std::shared_ptr Worker::makePathSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional ca) +std::shared_ptr +Worker::makePathSubstitutionGoal(const StorePath & path, RepairFlag repair, std::optional ca) { std::weak_ptr & goal_weak = substitutionGoals[path]; auto goal = goal_weak.lock(); // FIXME @@ -92,7 +88,8 @@ std::shared_ptr Worker::makePathSubstitutionGoal(const Sto return goal; } -std::shared_ptr Worker::makeDrvOutputSubstitutionGoal(const DrvOutput& id, RepairFlag repair, std::optional ca) +std::shared_ptr +Worker::makeDrvOutputSubstitutionGoal(const DrvOutput & id, RepairFlag repair, std::optional ca) { std::weak_ptr & goal_weak = drvOutputSubstitutionGoals[id]; auto goal = goal_weak.lock(); // FIXME @@ -108,17 +105,16 @@ template static void removeGoal(std::shared_ptr goal, std::map> & goalMap) { /* !!! inefficient */ - for (auto i = goalMap.begin(); - i != goalMap.end(); ) + for (auto i = goalMap.begin(); i != goalMap.end();) if (i->second.lock() == goal) { - auto j = i; ++j; + auto j = i; + ++j; goalMap.erase(i); i = j; - } - else ++i; + } else + ++i; } - void Worker::removeGoal(GoalPtr goal) { if (auto drvGoal = std::dynamic_pointer_cast(goal)) @@ -141,28 +137,25 @@ void Worker::removeGoal(GoalPtr goal) /* Wake up goals waiting for any goal to finish. */ for (auto & i : waitingForAnyGoal) { GoalPtr goal = i.lock(); - if (goal) wakeUp(goal); + if (goal) + wakeUp(goal); } waitingForAnyGoal.clear(); } - void Worker::wakeUp(GoalPtr goal) { goal->trace("woken up"); addToWeakGoals(awake, goal); } - unsigned Worker::getNrLocalBuilds() { return nrLocalBuilds; } - -void Worker::childStarted(GoalPtr goal, const std::set & fds, - bool inBuildSlot, bool respectTimeouts) +void Worker::childStarted(GoalPtr goal, const std::set & fds, bool inBuildSlot, bool respectTimeouts) { Child child; child.goal = goal; @@ -172,15 +165,15 @@ void Worker::childStarted(GoalPtr goal, const std::set & fds, child.inBuildSlot = inBuildSlot; child.respectTimeouts = respectTimeouts; children.emplace_back(child); - if (inBuildSlot) nrLocalBuilds++; + if (inBuildSlot) + nrLocalBuilds++; } - void Worker::childTerminated(Goal * goal, bool wakeSleepers) { - auto i = std::find_if(children.begin(), children.end(), - [&](const Child & child) { return child.goal2 == goal; }); - if (i == children.end()) return; + auto i = std::find_if(children.begin(), children.end(), [&](const Child & child) { return child.goal2 == goal; }); + if (i == children.end()) + return; if (i->inBuildSlot) { assert(nrLocalBuilds > 0); @@ -194,14 +187,14 @@ void Worker::childTerminated(Goal * goal, bool wakeSleepers) /* Wake up goals waiting for a build slot. */ for (auto & j : wantingToBuild) { GoalPtr goal = j.lock(); - if (goal) wakeUp(goal); + if (goal) + wakeUp(goal); } wantingToBuild.clear(); } } - void Worker::waitForBuildSlot(GoalPtr goal) { debug("wait for build slot"); @@ -211,21 +204,18 @@ void Worker::waitForBuildSlot(GoalPtr goal) addToWeakGoals(wantingToBuild, goal); } - void Worker::waitForAnyGoal(GoalPtr goal) { debug("wait for any goal"); addToWeakGoals(waitingForAnyGoal, goal); } - void Worker::waitForAWhile(GoalPtr goal) { debug("wait for a while"); addToWeakGoals(waitingForAWhile, goal); } - void Worker::run(const Goals & _topGoals) { std::vector topPaths; @@ -260,33 +250,36 @@ void Worker::run(const Goals & _topGoals) Goals awake2; for (auto & i : awake) { GoalPtr goal = i.lock(); - if (goal) awake2.insert(goal); + if (goal) + awake2.insert(goal); } awake.clear(); for (auto & goal : awake2) { checkInterrupt(); goal->work(); - if (topGoals.empty()) break; // stuff may have been cancelled + if (topGoals.empty()) + break; // stuff may have been cancelled } } - if (topGoals.empty()) break; + if (topGoals.empty()) + break; /* Wait for input. */ if (!children.empty() || !waitingForAWhile.empty()) waitForInput(); else { - if (awake.empty() && 0 == settings.maxBuildJobs) - { + if (awake.empty() && 0 == settings.maxBuildJobs) { if (getMachines().empty()) - throw Error("unable to start any build; either increase '--max-jobs' " - "or enable remote builds." - "\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html"); + throw Error( + "unable to start any build; either increase '--max-jobs' " + "or enable remote builds." + "\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html"); else - throw Error("unable to start any build; remote machines may not have " - "all required system features." - "\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html"); - + throw Error( + "unable to start any build; remote machines may not have " + "all required system features." + "\nhttps://nixos.org/manual/nix/stable/advanced-topics/distributed-builds.html"); } assert(!awake.empty()); } @@ -322,7 +315,8 @@ void Worker::waitForInput() // Periodicallty wake up to see if we need to run the garbage collector. nearest = before + std::chrono::seconds(10); for (auto & i : children) { - if (!i.respectTimeouts) continue; + if (!i.respectTimeouts) + continue; if (0 != settings.maxSilentTime) nearest = std::min(nearest, i.lastOutput + std::chrono::seconds(settings.maxSilentTime)); if (0 != settings.buildTimeout) @@ -337,11 +331,14 @@ void Worker::waitForInput() up after a few seconds at most. */ if (!waitingForAWhile.empty()) { useTimeout = true; - if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) lastWokenUp = before; - timeout = std::max(1L, - (long) std::chrono::duration_cast( - lastWokenUp + std::chrono::seconds(settings.pollInterval) - before).count()); - } else lastWokenUp = steady_time_point::min(); + if (lastWokenUp == steady_time_point::min() || lastWokenUp > before) + lastWokenUp = before; + timeout = std::max( + 1L, (long) std::chrono::duration_cast( + lastWokenUp + std::chrono::seconds(settings.pollInterval) - before) + .count()); + } else + lastWokenUp = steady_time_point::min(); if (useTimeout) vomit("sleeping %d seconds", timeout); @@ -353,14 +350,14 @@ void Worker::waitForInput() std::map fdToPollStatus; for (auto & i : children) { for (auto & j : i.fds) { - pollStatus.push_back((struct pollfd) { .fd = j, .events = POLLIN }); + pollStatus.push_back((struct pollfd){.fd = j, .events = POLLIN}); fdToPollStatus[j] = pollStatus.size() - 1; } } - if (poll(pollStatus.data(), pollStatus.size(), - useTimeout ? timeout * 1000 : -1) == -1) { - if (errno == EINTR) return; + if (poll(pollStatus.data(), pollStatus.size(), useTimeout ? timeout * 1000 : -1) == -1) { + if (errno == EINTR) + return; throw SysError("waiting for input"); } @@ -395,8 +392,7 @@ void Worker::waitForInput() if (errno != EINTR) throw SysError("%s: read failed", goal->getName()); } else { - printMsg(lvlVomit, "%1%: read %2% bytes", - goal->getName(), rd); + printMsg(lvlVomit, "%1%: read %2% bytes", goal->getName(), rd); std::string data((char *) buffer.data(), rd); j->lastOutput = after; goal->handleChildOutput(k, data); @@ -404,24 +400,16 @@ void Worker::waitForInput() } } - if (goal->exitCode == Goal::ecBusy && - 0 != settings.maxSilentTime && - j->respectTimeouts && - after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime)) - { - goal->timedOut(Error( - "%1% timed out after %2% seconds of silence", - goal->getName(), settings.maxSilentTime)); + if (goal->exitCode == Goal::ecBusy && 0 != settings.maxSilentTime && j->respectTimeouts + && after - j->lastOutput >= std::chrono::seconds(settings.maxSilentTime)) { + goal->timedOut( + Error("%1% timed out after %2% seconds of silence", goal->getName(), settings.maxSilentTime)); } - else if (goal->exitCode == Goal::ecBusy && - 0 != settings.buildTimeout && - j->respectTimeouts && - after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout)) - { - goal->timedOut(Error( - "%1% timed out after %2% seconds", - goal->getName(), settings.buildTimeout)); + else if ( + goal->exitCode == Goal::ecBusy && 0 != settings.buildTimeout && j->respectTimeouts + && after - j->timeStarted >= std::chrono::seconds(settings.buildTimeout)) { + goal->timedOut(Error("%1% timed out after %2% seconds", goal->getName(), settings.buildTimeout)); } } @@ -429,13 +417,13 @@ void Worker::waitForInput() lastWokenUp = after; for (auto & i : waitingForAWhile) { GoalPtr goal = i.lock(); - if (goal) wakeUp(goal); + if (goal) + wakeUp(goal); } waitingForAWhile.clear(); } } - unsigned int Worker::exitStatus() { /* @@ -449,13 +437,13 @@ unsigned int Worker::exitStatus() unsigned int mask = 0; bool buildFailure = permanentFailure || timedOut || hashMismatch; if (buildFailure) - mask |= 0x04; // 100 + mask |= 0x04; // 100 if (timedOut) - mask |= 0x01; // 101 + mask |= 0x01; // 101 if (hashMismatch) - mask |= 0x02; // 102 + mask |= 0x02; // 102 if (checkMismatch) { - mask |= 0x08; // 104 + mask |= 0x08; // 104 } if (mask) @@ -463,11 +451,11 @@ unsigned int Worker::exitStatus() return mask ? mask : 1; } - bool Worker::pathContentsGood(const StorePath & path) { auto i = pathContentsGoodCache.find(path); - if (i != pathContentsGoodCache.end()) return i->second; + if (i != pathContentsGoodCache.end()) + return i->second; printInfo("checking path '%s'...", store.printStorePath(path)); auto info = store.queryPathInfo(path); bool res; @@ -484,17 +472,17 @@ bool Worker::pathContentsGood(const StorePath & path) return res; } - void Worker::markContentsGood(const StorePath & path) { pathContentsGoodCache.insert_or_assign(path, true); } - -GoalPtr upcast_goal(std::shared_ptr subGoal) { +GoalPtr upcast_goal(std::shared_ptr subGoal) +{ return subGoal; } -GoalPtr upcast_goal(std::shared_ptr subGoal) { +GoalPtr upcast_goal(std::shared_ptr subGoal) +{ return subGoal; } diff --git a/src/libstore/build/worker.hh b/src/libstore/build/worker.hh index a1e036a96b50..ee58b0ddbbfc 100644 --- a/src/libstore/build/worker.hh +++ b/src/libstore/build/worker.hh @@ -30,7 +30,6 @@ GoalPtr upcast_goal(std::shared_ptr subGoal); typedef std::chrono::time_point steady_time_point; - /* A mapping used to remember for each child process to what goal it belongs, and file descriptors for receiving log data and output path creation commands. */ @@ -140,19 +139,23 @@ public: /* derivation goal */ private: std::shared_ptr makeDerivationGoalCommon( - const StorePath & drvPath, const StringSet & wantedOutputs, + const StorePath & drvPath, + const StringSet & wantedOutputs, std::function()> mkDrvGoal); public: - std::shared_ptr makeDerivationGoal( - const StorePath & drvPath, - const StringSet & wantedOutputs, BuildMode buildMode = bmNormal); + std::shared_ptr + makeDerivationGoal(const StorePath & drvPath, const StringSet & wantedOutputs, BuildMode buildMode = bmNormal); std::shared_ptr makeBasicDerivationGoal( - const StorePath & drvPath, const BasicDerivation & drv, - const StringSet & wantedOutputs, BuildMode buildMode = bmNormal); + const StorePath & drvPath, + const BasicDerivation & drv, + const StringSet & wantedOutputs, + BuildMode buildMode = bmNormal); /* substitution goal */ - std::shared_ptr makePathSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional ca = std::nullopt); - std::shared_ptr makeDrvOutputSubstitutionGoal(const DrvOutput & id, RepairFlag repair = NoRepair, std::optional ca = std::nullopt); + std::shared_ptr makePathSubstitutionGoal( + const StorePath & storePath, RepairFlag repair = NoRepair, std::optional ca = std::nullopt); + std::shared_ptr makeDrvOutputSubstitutionGoal( + const DrvOutput & id, RepairFlag repair = NoRepair, std::optional ca = std::nullopt); /* Remove a dead goal. */ void removeGoal(GoalPtr goal); @@ -167,8 +170,7 @@ public: /* Registers a running child process. `inBuildSlot' means that the process counts towards the jobs limit. */ - void childStarted(GoalPtr goal, const std::set & fds, - bool inBuildSlot, bool respectTimeouts); + void childStarted(GoalPtr goal, const std::set & fds, bool inBuildSlot, bool respectTimeouts); /* Unregisters a running child process. `wakeSleepers' should be false if there is no sense in waking up goals that are sleeping @@ -207,7 +209,8 @@ public: void updateProgress() { actDerivations.progress(doneBuilds, expectedBuilds + doneBuilds, runningBuilds, failedBuilds); - actSubstitutions.progress(doneSubstitutions, expectedSubstitutions + doneSubstitutions, runningSubstitutions, failedSubstitutions); + actSubstitutions.progress( + doneSubstitutions, expectedSubstitutions + doneSubstitutions, runningSubstitutions, failedSubstitutions); act.setExpected(actFileTransfer, expectedDownloadSize + doneDownloadSize); act.setExpected(actCopyPath, expectedNarSize + doneNarSize); } diff --git a/src/libstore/builtins/buildenv.cc b/src/libstore/builtins/buildenv.cc index 47458a388d48..e2e9dbd630b1 100644 --- a/src/libstore/builtins/buildenv.cc +++ b/src/libstore/builtins/buildenv.cc @@ -53,13 +53,9 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir, * Python package brings its own * `$out/lib/pythonX.Y/site-packages/easy-install.pth'.) */ - if (hasSuffix(srcFile, "/propagated-build-inputs") || - hasSuffix(srcFile, "/nix-support") || - hasSuffix(srcFile, "/perllocal.pod") || - hasSuffix(srcFile, "/info/dir") || - hasSuffix(srcFile, "/log") || - hasSuffix(srcFile, "/manifest.nix") || - hasSuffix(srcFile, "/manifest.json")) + if (hasSuffix(srcFile, "/propagated-build-inputs") || hasSuffix(srcFile, "/nix-support") + || hasSuffix(srcFile, "/perllocal.pod") || hasSuffix(srcFile, "/info/dir") || hasSuffix(srcFile, "/log") + || hasSuffix(srcFile, "/manifest.nix") || hasSuffix(srcFile, "/manifest.json")) continue; else if (S_ISDIR(srcSt.st_mode)) { @@ -93,12 +89,12 @@ static void createLinks(State & state, const Path & srcDir, const Path & dstDir, 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); + "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); if (prevPriority < priority) continue; if (unlink(dstFile.c_str()) == -1) @@ -122,16 +118,18 @@ void buildProfile(const Path & out, Packages && pkgs) std::set done, postponed; auto addPkg = [&](const Path & pkgDir, int priority) { - if (!done.insert(pkgDir).second) return; + if (!done.insert(pkgDir).second) + return; createLinks(state, pkgDir, out, priority); try { for (const auto & p : tokenizeString>( - readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n")) + readFile(pkgDir + "/nix-support/propagated-user-env-packages"), " \n")) if (!done.count(p)) postponed.insert(p); } catch (SysError & e) { - if (e.errNo != ENOENT && e.errNo != ENOTDIR) throw; + if (e.errNo != ENOENT && e.errNo != ENOTDIR) + throw; } }; @@ -166,7 +164,8 @@ void builtinBuildenv(const BasicDerivation & drv) { auto getAttr = [&](const std::string & name) { auto i = drv.env.find(name); - if (i == drv.env.end()) throw Error("attribute '%s' missing", name); + if (i == drv.env.end()) + throw Error("attribute '%s' missing", name); return i->second; }; @@ -179,11 +178,15 @@ void builtinBuildenv(const BasicDerivation & drv) auto derivations = tokenizeString(getAttr("derivations")); while (!derivations.empty()) { /* !!! We're trusting the caller to structure derivations env var correctly */ - auto active = derivations.front(); derivations.pop_front(); - auto priority = stoi(derivations.front()); derivations.pop_front(); - auto outputs = stoi(derivations.front()); derivations.pop_front(); + auto active = derivations.front(); + derivations.pop_front(); + auto priority = stoi(derivations.front()); + derivations.pop_front(); + auto outputs = stoi(derivations.front()); + derivations.pop_front(); for (auto n = 0; n < outputs; n++) { - auto path = derivations.front(); derivations.pop_front(); + auto path = derivations.front(); + derivations.pop_front(); pkgs.emplace_back(path, active != "false", priority); } } diff --git a/src/libstore/builtins/buildenv.hh b/src/libstore/builtins/buildenv.hh index 73c0f5f7fd3f..061f280c1362 100644 --- a/src/libstore/builtins/buildenv.hh +++ b/src/libstore/builtins/buildenv.hh @@ -5,11 +5,16 @@ namespace nix { -struct Package { +struct Package +{ Path path; bool active; int priority; - Package(const Path & path, bool active, int priority) : path{path}, active{active}, priority{priority} {} + Package(const Path & path, bool active, int priority) + : path{path} + , active{active} + , priority{priority} + {} }; typedef std::vector Packages; diff --git a/src/libstore/builtins/fetchurl.cc b/src/libstore/builtins/fetchurl.cc index 7d7924d77339..8b87aa71cf42 100644 --- a/src/libstore/builtins/fetchurl.cc +++ b/src/libstore/builtins/fetchurl.cc @@ -18,7 +18,8 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData) auto getAttr = [&](const std::string & name) { auto i = drv.env.find(name); - if (i == drv.env.end()) throw Error("attribute '%s' missing", name); + if (i == drv.env.end()) + throw Error("attribute '%s' missing", name); return i->second; }; @@ -31,17 +32,14 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData) auto fileTransfer = makeFileTransfer(); auto fetch = [&](const std::string & url) { - auto source = sinkToSource([&](Sink & sink) { - /* No need to do TLS verification, because we check the hash of the result anyway. */ FileTransferRequest request(url); request.verifyTLS = false; request.decompress = false; - auto decompressor = makeDecompressionSink( - unpack && hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink); + auto decompressor = makeDecompressionSink(unpack && hasSuffix(mainUrl, ".xz") ? "xz" : "none", sink); fileTransfer->download(std::move(request), *decompressor); decompressor->finish(); }); @@ -62,7 +60,8 @@ void builtinFetchurl(const BasicDerivation & drv, const std::string & netrcData) if (getAttr("outputHashMode") == "flat") for (auto hashedMirror : settings.hashedMirrors.get()) try { - if (!hasSuffix(hashedMirror, "/")) hashedMirror += '/'; + if (!hasSuffix(hashedMirror, "/")) + hashedMirror += '/'; std::optional ht = parseHashTypeOpt(getAttr("outputHashAlgo")); Hash h = newHashAllowEmpty(getAttr("outputHash"), ht); fetch(hashedMirror + printHashType(h.type) + "/" + h.to_string(Base16, false)); diff --git a/src/libstore/builtins/unpack-channel.cc b/src/libstore/builtins/unpack-channel.cc index 426d58a53a4a..52ab63ca9d93 100644 --- a/src/libstore/builtins/unpack-channel.cc +++ b/src/libstore/builtins/unpack-channel.cc @@ -7,7 +7,8 @@ void builtinUnpackChannel(const BasicDerivation & drv) { auto getAttr = [&](const std::string & name) { auto i = drv.env.find(name); - if (i == drv.env.end()) throw Error("attribute '%s' missing", name); + if (i == drv.env.end()) + throw Error("attribute '%s' missing", name); return i->second; }; diff --git a/src/libstore/content-address.cc b/src/libstore/content-address.cc index cf32ccdc461c..28c24f9484bb 100644 --- a/src/libstore/content-address.cc +++ b/src/libstore/content-address.cc @@ -23,33 +23,27 @@ std::string makeFileIngestionPrefix(const FileIngestionMethod m) std::string makeFixedOutputCA(FileIngestionMethod method, const Hash & hash) { - return "fixed:" - + makeFileIngestionPrefix(method) - + hash.to_string(Base32, true); + return "fixed:" + makeFileIngestionPrefix(method) + hash.to_string(Base32, true); } std::string renderContentAddress(ContentAddress ca) { - return std::visit(overloaded { - [](TextHash & th) { - return "text:" + th.hash.to_string(Base32, true); - }, - [](FixedOutputHash & fsh) { - return makeFixedOutputCA(fsh.method, fsh.hash); - } - }, ca); + return std::visit( + overloaded{ + [](TextHash & th) { return "text:" + th.hash.to_string(Base32, true); }, + [](FixedOutputHash & fsh) { return makeFixedOutputCA(fsh.method, fsh.hash); }}, + ca); } std::string renderContentAddressMethod(ContentAddressMethod cam) { - return std::visit(overloaded { - [](TextHashMethod & th) { - return std::string{"text:"} + printHashType(htSHA256); - }, - [](FixedOutputHashMethod & fshm) { - return "fixed:" + makeFileIngestionPrefix(fshm.fileIngestionMethod) + printHashType(fshm.hashType); - } - }, cam); + return std::visit( + overloaded{ + [](TextHashMethod & th) { return std::string{"text:"} + printHashType(htSHA256); }, + [](FixedOutputHashMethod & fshm) { + return "fixed:" + makeFileIngestionPrefix(fshm.fileIngestionMethod) + printHashType(fshm.hashType); + }}, + cam); } /* @@ -57,7 +51,7 @@ std::string renderContentAddressMethod(ContentAddressMethod cam) */ static ContentAddressMethod parseContentAddressMethodPrefix(std::string_view & rest) { - std::string_view wholeInput { rest }; + std::string_view wholeInput{rest}; std::string_view prefix; { @@ -67,7 +61,7 @@ static ContentAddressMethod parseContentAddressMethodPrefix(std::string_view & r prefix = *optPrefix; } - auto parseHashType_ = [&](){ + auto parseHashType_ = [&]() { auto hashTypeRaw = splitPrefixTo(rest, ':'); if (!hashTypeRaw) throw UsageError("content address hash must be in form ':', but found: %s", wholeInput); @@ -80,42 +74,44 @@ static ContentAddressMethod parseContentAddressMethodPrefix(std::string_view & r // No parsing of the ingestion method, "text" only support flat. HashType hashType = parseHashType_(); if (hashType != htSHA256) - throw Error("text content address hash should use %s, but instead uses %s", - printHashType(htSHA256), printHashType(hashType)); - return TextHashMethod {}; + throw Error( + "text content address hash should use %s, but instead uses %s", printHashType(htSHA256), + printHashType(hashType)); + return TextHashMethod{}; } else if (prefix == "fixed") { // Parse method auto method = FileIngestionMethod::Flat; if (splitPrefix(rest, "r:")) method = FileIngestionMethod::Recursive; HashType hashType = parseHashType_(); - return FixedOutputHashMethod { + return FixedOutputHashMethod{ .fileIngestionMethod = method, .hashType = std::move(hashType), }; } else - throw UsageError("content address prefix '%s' is unrecognized. Recogonized prefixes are 'text' or 'fixed'", prefix); + throw UsageError( + "content address prefix '%s' is unrecognized. Recogonized prefixes are 'text' or 'fixed'", prefix); } -ContentAddress parseContentAddress(std::string_view rawCa) { +ContentAddress parseContentAddress(std::string_view rawCa) +{ auto rest = rawCa; ContentAddressMethod caMethod = parseContentAddressMethodPrefix(rest); return std::visit( - overloaded { + overloaded{ [&](TextHashMethod & thm) { - return ContentAddress(TextHash { - .hash = Hash::parseNonSRIUnprefixed(rest, htSHA256) - }); + return ContentAddress(TextHash{.hash = Hash::parseNonSRIUnprefixed(rest, htSHA256)}); }, [&](FixedOutputHashMethod & fohMethod) { - return ContentAddress(FixedOutputHash { + return ContentAddress(FixedOutputHash{ .method = fohMethod.fileIngestionMethod, .hash = Hash::parseNonSRIUnprefixed(rest, std::move(fohMethod.hashType)), }); }, - }, caMethod); + }, + caMethod); } ContentAddressMethod parseContentAddressMethod(std::string_view caMethod) @@ -138,14 +134,9 @@ std::string renderContentAddress(std::optional ca) Hash getContentAddressHash(const ContentAddress & ca) { - return std::visit(overloaded { - [](const TextHash & th) { - return th.hash; - }, - [](const FixedOutputHash & fsh) { - return fsh.hash; - } - }, ca); + return std::visit( + overloaded{[](const TextHash & th) { return th.hash; }, [](const FixedOutputHash & fsh) { return fsh.hash; }}, + ca); } } diff --git a/src/libstore/content-address.hh b/src/libstore/content-address.hh index f6a6f5140048..8bf4a7c37748 100644 --- a/src/libstore/content-address.hh +++ b/src/libstore/content-address.hh @@ -5,17 +5,16 @@ namespace nix { -enum struct FileIngestionMethod : uint8_t { - Flat = false, - Recursive = true -}; +enum struct FileIngestionMethod : uint8_t { Flat = false, Recursive = true }; -struct TextHash { +struct TextHash +{ Hash hash; }; /// Pair of a hash, and how the file system was ingested -struct FixedOutputHash { +struct FixedOutputHash +{ FileIngestionMethod method; Hash hash; std::string printMethodAlgo() const; @@ -33,9 +32,10 @@ struct FixedOutputHash { makeFixedOutputPath() / addToStore(). */ typedef std::variant< - TextHash, // for paths computed by makeTextPath() / addTextToStore + TextHash, // for paths computed by makeTextPath() / addTextToStore FixedOutputHash // for path computed by makeFixedOutputPath -> ContentAddress; + > + ContentAddress; /* Compute the prefix to the hash algorithm which indicates how the files were ingested. */ @@ -59,16 +59,15 @@ Hash getContentAddressHash(const ContentAddress & ca); We only have one way to hash text with references, so this is single-value type is only useful in std::variant. */ -struct TextHashMethod { }; -struct FixedOutputHashMethod { - FileIngestionMethod fileIngestionMethod; - HashType hashType; +struct TextHashMethod +{}; +struct FixedOutputHashMethod +{ + FileIngestionMethod fileIngestionMethod; + HashType hashType; }; -typedef std::variant< - TextHashMethod, - FixedOutputHashMethod - > ContentAddressMethod; +typedef std::variant ContentAddressMethod; ContentAddressMethod parseContentAddressMethod(std::string_view rawCaMethod); diff --git a/src/libstore/crypto.cc b/src/libstore/crypto.cc index 1027469c9eee..cddd0a94a955 100644 --- a/src/libstore/crypto.cc +++ b/src/libstore/crypto.cc @@ -43,8 +43,7 @@ std::string SecretKey::signDetached(std::string_view data) const { unsigned char sig[crypto_sign_BYTES]; unsigned long long sigLen; - crypto_sign_detached(sig, &sigLen, (unsigned char *) data.data(), data.size(), - (unsigned char *) key.data()); + crypto_sign_detached(sig, &sigLen, (unsigned char *) data.data(), data.size(), (unsigned char *) key.data()); return name + ":" + base64Encode(std::string((char *) sig, sigLen)); } @@ -72,21 +71,22 @@ PublicKey::PublicKey(std::string_view s) throw Error("public key is not valid"); } -bool verifyDetached(const std::string & data, const std::string & sig, - const PublicKeys & publicKeys) +bool verifyDetached(const std::string & data, const std::string & sig, const PublicKeys & publicKeys) { auto ss = split(sig); auto key = publicKeys.find(std::string(ss.first)); - if (key == publicKeys.end()) return false; + if (key == publicKeys.end()) + return false; auto sig2 = base64Decode(ss.second); if (sig2.size() != crypto_sign_BYTES) throw Error("signature is not valid"); - return crypto_sign_verify_detached((unsigned char *) sig2.data(), - (unsigned char *) data.data(), data.size(), - (unsigned char *) key->second.key.data()) == 0; + return crypto_sign_verify_detached( + (unsigned char *) sig2.data(), (unsigned char *) data.data(), data.size(), + (unsigned char *) key->second.key.data()) + == 0; } PublicKeys getDefaultPublicKeys() diff --git a/src/libstore/crypto.hh b/src/libstore/crypto.hh index 03f85c103109..ac04fde18bd4 100644 --- a/src/libstore/crypto.hh +++ b/src/libstore/crypto.hh @@ -19,7 +19,9 @@ struct Key protected: Key(std::string_view name, std::string && key) - : name(name), key(std::move(key)) { } + : name(name) + , key(std::move(key)) + {} }; struct PublicKey; @@ -37,7 +39,8 @@ struct SecretKey : Key private: SecretKey(std::string_view name, std::string && key) - : Key(name, std::move(key)) { } + : Key(name, std::move(key)) + {} }; struct PublicKey : Key @@ -46,7 +49,8 @@ struct PublicKey : Key private: PublicKey(std::string_view name, std::string && key) - : Key(name, std::move(key)) { } + : Key(name, std::move(key)) + {} friend struct SecretKey; }; @@ -54,8 +58,7 @@ typedef std::map PublicKeys; /* Return true iff ‘sig’ is a correct signature over ‘data’ using one of the given public keys. */ -bool verifyDetached(const std::string & data, const std::string & sig, - const PublicKeys & publicKeys); +bool verifyDetached(const std::string & data, const std::string & sig, const PublicKeys & publicKeys); PublicKeys getDefaultPublicKeys(); diff --git a/src/libstore/daemon.cc b/src/libstore/daemon.cc index de69b50eec7a..deea49671d94 100644 --- a/src/libstore/daemon.cc +++ b/src/libstore/daemon.cc @@ -14,7 +14,7 @@ namespace nix::daemon { -Sink & operator << (Sink & sink, const Logger::Fields & fields) +Sink & operator<<(Sink & sink, const Logger::Fields & fields) { sink << fields.size(); for (auto & f : fields) { @@ -23,7 +23,8 @@ Sink & operator << (Sink & sink, const Logger::Fields & fields) sink << f.i; else if (f.type == Logger::Field::tString) sink << f.s; - else abort(); + else + abort(); } return sink; } @@ -46,7 +47,9 @@ struct TunnelLogger : public Logger unsigned int clientVersion; TunnelLogger(FdSink & to, unsigned int clientVersion) - : to(to), clientVersion(clientVersion) { } + : to(to) + , clientVersion(clientVersion) + {} void enqueueMsg(const std::string & s) { @@ -69,7 +72,8 @@ struct TunnelLogger : public Logger void log(Verbosity lvl, const FormatOrString & fs) override { - if (lvl > verbosity) return; + if (lvl > verbosity) + return; StringSink buf; buf << STDERR_NEXT << (fs.s + "\n"); @@ -78,7 +82,8 @@ struct TunnelLogger : public Logger void logEI(const ErrorInfo & ei) override { - if (ei.level > verbosity) return; + if (ei.level > verbosity) + return; std::stringstream oss; showErrorInfo(oss, ei, false); @@ -122,8 +127,13 @@ struct TunnelLogger : public Logger } } - void startActivity(ActivityId act, Verbosity lvl, ActivityType type, - const std::string & s, const Fields & fields, ActivityId parent) override + void startActivity( + ActivityId act, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Fields & fields, + ActivityId parent) override { if (GET_PROTOCOL_MINOR(clientVersion) < 20) { if (!s.empty()) @@ -138,7 +148,8 @@ struct TunnelLogger : public Logger void stopActivity(ActivityId act) override { - if (GET_PROTOCOL_MINOR(clientVersion) < 20) return; + if (GET_PROTOCOL_MINOR(clientVersion) < 20) + return; StringSink buf; buf << STDERR_STOP_ACTIVITY << act; enqueueMsg(buf.s); @@ -146,7 +157,8 @@ struct TunnelLogger : public Logger void result(ActivityId act, ResultType type, const Fields & fields) override { - if (GET_PROTOCOL_MINOR(clientVersion) < 20) return; + if (GET_PROTOCOL_MINOR(clientVersion) < 20) + return; StringSink buf; buf << STDERR_RESULT << act << type << fields; enqueueMsg(buf.s); @@ -156,8 +168,10 @@ struct TunnelLogger : public Logger struct TunnelSink : Sink { Sink & to; - TunnelSink(Sink & to) : to(to) { } - void operator () (std::string_view data) + TunnelSink(Sink & to) + : to(to) + {} + void operator()(std::string_view data) { to << STDERR_WRITE; writeString(data, to); @@ -168,13 +182,17 @@ struct TunnelSource : BufferedSource { Source & from; BufferedSink & to; - TunnelSource(Source & from, BufferedSink & to) : from(from), to(to) { } + TunnelSource(Source & from, BufferedSink & to) + : from(from) + , to(to) + {} size_t readUnbuffered(char * data, size_t len) override { to << STDERR_READ << len; to.flush(); size_t n = readString(data, len, from); - if (n == 0) throw EndOfFile("unexpected end-of-file"); + if (n == 0) + throw EndOfFile("unexpected end-of-file"); return n; } }; @@ -235,17 +253,16 @@ struct ClientSettings // the daemon, as that could cause some pretty weird stuff if (parseFeatures(tokenizeString(value)) != settings.experimentalFeatures.get()) debug("Ignoring the client-specified experimental features"); - } - else if (trusted - || name == settings.buildTimeout.name - || name == settings.buildRepeat.name - || name == "connect-timeout" - || (name == "builders" && value == "")) + } else if ( + trusted || name == settings.buildTimeout.name || name == settings.buildRepeat.name + || name == "connect-timeout" || (name == "builders" && value == "")) settings.set(name, value); else if (setSubstituters(settings.substituters)) ; else - debug("ignoring the client-specified setting '%s', because it is a restricted setting and you are not a trusted user", name); + debug( + "ignoring the client-specified setting '%s', because it is a restricted setting and you are not a trusted user", + name); } catch (UsageError & e) { warn(e.what()); } @@ -257,7 +274,7 @@ static std::vector readDerivedPaths(Store & store, unsigned int cli { std::vector reqs; if (GET_PROTOCOL_MINOR(clientVersion) >= 30) { - reqs = worker_proto::read(store, from, Phantom> {}); + reqs = worker_proto::read(store, from, Phantom>{}); } else { for (auto & s : readStrings(from)) reqs.push_back(parsePathWithOutputs(store, s).toDerivedPath()); @@ -265,9 +282,15 @@ static std::vector readDerivedPaths(Store & store, unsigned int cli return reqs; } -static void performOp(TunnelLogger * logger, ref store, - TrustedFlag trusted, RecursiveFlag recursive, unsigned int clientVersion, - Source & from, BufferedSink & to, unsigned int op) +static void performOp( + TunnelLogger * logger, + ref store, + TrustedFlag trusted, + RecursiveFlag recursive, + unsigned int clientVersion, + Source & from, + BufferedSink & to, + unsigned int op) { switch (op) { @@ -281,7 +304,7 @@ static void performOp(TunnelLogger * logger, ref store, } case wopQueryValidPaths: { - auto paths = worker_proto::read(*store, from, Phantom {}); + auto paths = worker_proto::read(*store, from, Phantom{}); SubstituteFlag substitute = NoSubstitute; if (GET_PROTOCOL_MINOR(clientVersion) >= 27) { @@ -310,7 +333,7 @@ static void performOp(TunnelLogger * logger, ref store, } case wopQuerySubstitutablePaths: { - auto paths = worker_proto::read(*store, from, Phantom {}); + auto paths = worker_proto::read(*store, from, Phantom{}); logger->startWork(); auto res = store->querySubstitutablePaths(paths); logger->stopWork(); @@ -341,7 +364,8 @@ static void performOp(TunnelLogger * logger, ref store, store->queryReferrers(path, paths); else if (op == wopQueryValidDerivers) paths = store->queryValidDerivers(path); - else paths = store->queryDerivationOutputs(path); + else + paths = store->queryDerivationOutputs(path); logger->stopWork(); worker_proto::write(*store, to, paths); break; @@ -387,7 +411,7 @@ static void performOp(TunnelLogger * logger, ref store, if (GET_PROTOCOL_MINOR(clientVersion) >= 25) { auto name = readString(from); auto camStr = readString(from); - auto refs = worker_proto::read(*store, from, Phantom {}); + auto refs = worker_proto::read(*store, from, Phantom{}); bool repairBool; from >> repairBool; auto repair = RepairFlag{repairBool}; @@ -398,18 +422,21 @@ static void performOp(TunnelLogger * logger, ref store, ContentAddressMethod contentAddressMethod = parseContentAddressMethod(camStr); FramedSource source(from); // TODO this is essentially RemoteStore::addCAToStore. Move it up to Store. - return std::visit(overloaded { - [&](TextHashMethod &) { - // We could stream this by changing Store - std::string contents = source.drain(); - auto path = store->addTextToStore(name, contents, refs, repair); - return store->queryPathInfo(path); + return std::visit( + overloaded{ + [&](TextHashMethod &) { + // We could stream this by changing Store + std::string contents = source.drain(); + auto path = store->addTextToStore(name, contents, refs, repair); + return store->queryPathInfo(path); + }, + [&](FixedOutputHashMethod & fohm) { + auto path = store->addToStoreFromDump( + source, name, fohm.fileIngestionMethod, fohm.hashType, repair, refs); + return store->queryPathInfo(path); + }, }, - [&](FixedOutputHashMethod & fohm) { - auto path = store->addToStoreFromDump(source, name, fohm.fileIngestionMethod, fohm.hashType, repair, refs); - return store->queryPathInfo(path); - }, - }, contentAddressMethod); + contentAddressMethod); }(); logger->stopWork(); @@ -424,8 +451,10 @@ static void performOp(TunnelLogger * logger, ref store, std::string hashAlgoRaw; from >> baseName >> fixed /* obsolete */ >> recursive >> hashAlgoRaw; if (recursive > (uint8_t) FileIngestionMethod::Recursive) - throw Error("unsupported FileIngestionMethod with value of %i; you may need to upgrade nix-daemon", recursive); - method = FileIngestionMethod { recursive }; + throw Error( + "unsupported FileIngestionMethod with value of %i; you may need to upgrade nix-daemon", + recursive); + method = FileIngestionMethod{recursive}; /* Compatibility hack. */ if (!fixed) { hashAlgoRaw = "sha256"; @@ -451,9 +480,10 @@ static void performOp(TunnelLogger * logger, ref store, /* Incrementally parse the NAR file, stripping the metadata, and streaming the sole file we expect into `saved`. */ - RetrieveRegularNARSink savedRegular { saved }; + RetrieveRegularNARSink savedRegular{saved}; parseDump(savedRegular, from); - if (!savedRegular.regular) throw Error("regular file expected"); + if (!savedRegular.regular) + throw Error("regular file expected"); } }); logger->startWork(); @@ -474,9 +504,7 @@ static void performOp(TunnelLogger * logger, ref store, logger->startWork(); { FramedSource source(from); - store->addMultipleToStore(source, - RepairFlag{repair}, - dontCheckSigs ? NoCheckSigs : CheckSigs); + store->addMultipleToStore(source, RepairFlag{repair}, dontCheckSigs ? NoCheckSigs : CheckSigs); } logger->stopWork(); break; @@ -485,7 +513,7 @@ static void performOp(TunnelLogger * logger, ref store, case wopAddTextToStore: { std::string suffix = readString(from); std::string s = readString(from); - auto refs = worker_proto::read(*store, from, Phantom {}); + auto refs = worker_proto::read(*store, from, Phantom{}); logger->startWork(); auto path = store->addTextToStore(suffix, s, refs, NoRepair); logger->stopWork(); @@ -507,11 +535,11 @@ static void performOp(TunnelLogger * logger, ref store, case wopImportPaths: { logger->startWork(); TunnelSource source(from, to); - auto paths = store->importPaths(source, - trusted ? NoCheckSigs : CheckSigs); + auto paths = store->importPaths(source, trusted ? NoCheckSigs : CheckSigs); logger->stopWork(); Strings paths2; - for (auto & i : paths) paths2.push_back(store->printStorePath(i)); + for (auto & i : paths) + paths2.push_back(store->printStorePath(i)); to << paths2; break; } @@ -612,7 +640,7 @@ static void performOp(TunnelLogger * logger, ref store, Derivation drv2; static_cast(drv2) = drv; - drvPath = writeDerivation(*store, Derivation { drv2 }); + drvPath = writeDerivation(*store, Derivation{drv2}); } auto res = store->buildDerivation(drvPath, drv, buildMode); @@ -687,7 +715,7 @@ static void performOp(TunnelLogger * logger, ref store, case wopCollectGarbage: { GCOptions options; options.action = (GCOptions::GCAction) readInt(from); - options.pathsToDelete = worker_proto::read(*store, from, Phantom {}); + options.pathsToDelete = worker_proto::read(*store, from, Phantom{}); from >> options.ignoreLiveness >> options.maxFreed; // obsolete fields readInt(from); @@ -755,11 +783,9 @@ static void performOp(TunnelLogger * logger, ref store, if (i == infos.end()) to << 0; else { - to << 1 - << (i->second.deriver ? store->printStorePath(*i->second.deriver) : ""); + to << 1 << (i->second.deriver ? store->printStorePath(*i->second.deriver) : ""); worker_proto::write(*store, to, i->second.references); - to << i->second.downloadSize - << i->second.narSize; + to << i->second.downloadSize << i->second.narSize; } break; } @@ -768,18 +794,17 @@ static void performOp(TunnelLogger * logger, ref store, SubstitutablePathInfos infos; StorePathCAMap pathsMap = {}; if (GET_PROTOCOL_MINOR(clientVersion) < 22) { - auto paths = worker_proto::read(*store, from, Phantom {}); + auto paths = worker_proto::read(*store, from, Phantom{}); for (auto & path : paths) pathsMap.emplace(path, std::nullopt); } else - pathsMap = worker_proto::read(*store, from, Phantom {}); + pathsMap = worker_proto::read(*store, from, Phantom{}); logger->startWork(); store->querySubstitutablePathInfos(pathsMap, infos); logger->stopWork(); to << infos.size(); for (auto & i : infos) { - to << store->printStorePath(i.first) - << (i.second.deriver ? store->printStorePath(*i.second.deriver) : ""); + to << store->printStorePath(i.first) << (i.second.deriver ? store->printStorePath(*i.second.deriver) : ""); worker_proto::write(*store, to, i.second.references); to << i.second.downloadSize << i.second.narSize; } @@ -801,7 +826,8 @@ static void performOp(TunnelLogger * logger, ref store, try { info = store->queryPathInfo(path); } catch (InvalidPath &) { - if (GET_PROTOCOL_MINOR(clientVersion) < 17) throw; + if (GET_PROTOCOL_MINOR(clientVersion) < 17) + throw; } logger->stopWork(); if (info) { @@ -859,10 +885,10 @@ static void performOp(TunnelLogger * logger, ref store, auto path = store->parseStorePath(readString(from)); auto deriver = readString(from); auto narHash = Hash::parseAny(readString(from), htSHA256); - ValidPathInfo info { path, narHash }; + ValidPathInfo info{path, narHash}; if (deriver != "") info.deriver = store->parseStorePath(deriver); - info.references = worker_proto::read(*store, from, Phantom {}); + info.references = worker_proto::read(*store, from, Phantom{}); from >> info.registrationTime >> info.narSize >> info.ultimate; info.sigs = readStrings(from); info.ca = parseContentAddressOpt(readString(from)); @@ -876,8 +902,7 @@ static void performOp(TunnelLogger * logger, ref store, logger->startWork(); { FramedSource source(from); - store->addToStore(info, source, (RepairFlag) repair, - dontCheckSigs ? NoCheckSigs : CheckSigs); + store->addToStore(info, source, (RepairFlag) repair, dontCheckSigs ? NoCheckSigs : CheckSigs); } logger->stopWork(); } @@ -888,7 +913,7 @@ static void performOp(TunnelLogger * logger, ref store, if (GET_PROTOCOL_MINOR(clientVersion) >= 21) source = std::make_unique(from, to); else { - TeeSource tee { from, saved }; + TeeSource tee{from, saved}; ParseSink ether; parseDump(ether, tee); source = std::make_unique(saved.s); @@ -897,8 +922,7 @@ static void performOp(TunnelLogger * logger, ref store, logger->startWork(); // FIXME: race if addToStore doesn't read source? - store->addToStore(info, *source, (RepairFlag) repair, - dontCheckSigs ? NoCheckSigs : CheckSigs); + store->addToStore(info, *source, (RepairFlag) repair, dontCheckSigs ? NoCheckSigs : CheckSigs); logger->stopWork(); } @@ -925,8 +949,7 @@ static void performOp(TunnelLogger * logger, ref store, if (GET_PROTOCOL_MINOR(clientVersion) < 31) { auto outputId = DrvOutput::parse(readString(from)); auto outputPath = StorePath(readString(from)); - store->registerDrvOutput(Realisation{ - .id = outputId, .outPath = outputPath}); + store->registerDrvOutput(Realisation{.id = outputId, .outPath = outputPath}); } else { auto realisation = worker_proto::read(*store, from, Phantom()); store->registerDrvOutput(realisation); @@ -942,11 +965,13 @@ static void performOp(TunnelLogger * logger, ref store, logger->stopWork(); if (GET_PROTOCOL_MINOR(clientVersion) < 31) { std::set outPaths; - if (info) outPaths.insert(info->outPath); + if (info) + outPaths.insert(info->outPath); worker_proto::write(*store, to, outPaths); } else { std::set realisations; - if (info) realisations.insert(*info); + if (info) + realisations.insert(*info); worker_proto::write(*store, to, realisations); } break; @@ -986,7 +1011,8 @@ void processConnection( /* Exchange the greeting. */ unsigned int magic = readInt(from); - if (magic != WORKER_MAGIC_1) throw Error("protocol mismatch"); + if (magic != WORKER_MAGIC_1) + throw Error("protocol mismatch"); to << WORKER_MAGIC_2 << PROTOCOL_VERSION; to.flush(); unsigned int clientVersion = readInt(from); @@ -1024,7 +1050,7 @@ void processConnection( try { /* If we can't accept clientVersion, then throw an error - *here* (not above). */ + *here* (not above). */ authHook(*store); tunnelLogger->stopWork(); @@ -1055,7 +1081,8 @@ void processConnection( happens, just send the error message and exit. */ bool errorAllowed = tunnelLogger->state_.lock()->canSendStderr; tunnelLogger->stopWork(&e); - if (!errorAllowed) throw; + if (!errorAllowed) + throw; } catch (std::bad_alloc & e) { auto ex = Error("Nix daemon out of memory"); tunnelLogger->stopWork(&ex); diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index fe99c3c5eb38..abc029275a9c 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -8,128 +8,93 @@ namespace nix { -std::optional DerivationOutput::path(const Store & store, std::string_view drvName, std::string_view outputName) const -{ - return std::visit(overloaded { - [](const DerivationOutput::InputAddressed & doi) -> std::optional { - return { doi.path }; - }, - [&](const DerivationOutput::CAFixed & dof) -> std::optional { - return { - dof.path(store, drvName, outputName) - }; - }, - [](const DerivationOutput::CAFloating & dof) -> std::optional { - return std::nullopt; - }, - [](const DerivationOutput::Deferred &) -> std::optional { - return std::nullopt; - }, - [](const DerivationOutput::Impure &) -> std::optional { - return std::nullopt; +std::optional +DerivationOutput::path(const Store & store, std::string_view drvName, std::string_view outputName) const +{ + return std::visit( + overloaded{ + [](const DerivationOutput::InputAddressed & doi) -> std::optional { return {doi.path}; }, + [&](const DerivationOutput::CAFixed & dof) -> std::optional { + return {dof.path(store, drvName, outputName)}; + }, + [](const DerivationOutput::CAFloating & dof) -> std::optional { return std::nullopt; }, + [](const DerivationOutput::Deferred &) -> std::optional { return std::nullopt; }, + [](const DerivationOutput::Impure &) -> std::optional { return std::nullopt; }, }, - }, raw()); + raw()); } - -StorePath DerivationOutput::CAFixed::path(const Store & store, std::string_view drvName, std::string_view outputName) const +StorePath +DerivationOutput::CAFixed::path(const Store & store, std::string_view drvName, std::string_view outputName) const { - return store.makeFixedOutputPath( - hash.method, hash.hash, - outputPathName(drvName, outputName)); + return store.makeFixedOutputPath(hash.method, hash.hash, outputPathName(drvName, outputName)); } - bool DerivationType::isCA() const { /* Normally we do the full `std::visit` to make sure we have exhaustively handled all variants, but so long as there is a variant called `ContentAddressed`, it must be the only one for which `isCA` is true for this to make sense!. */ - return std::visit(overloaded { - [](const InputAddressed & ia) { - return false; - }, - [](const ContentAddressed & ca) { - return true; - }, - [](const Impure &) { - return true; + return std::visit( + overloaded{ + [](const InputAddressed & ia) { return false; }, + [](const ContentAddressed & ca) { return true; }, + [](const Impure &) { return true; }, }, - }, raw()); + raw()); } bool DerivationType::isFixed() const { - return std::visit(overloaded { - [](const InputAddressed & ia) { - return false; + return std::visit( + overloaded{ + [](const InputAddressed & ia) { return false; }, + [](const ContentAddressed & ca) { return ca.fixed; }, + [](const Impure &) { return false; }, }, - [](const ContentAddressed & ca) { - return ca.fixed; - }, - [](const Impure &) { - return false; - }, - }, raw()); + raw()); } bool DerivationType::hasKnownOutputPaths() const { - return std::visit(overloaded { - [](const InputAddressed & ia) { - return !ia.deferred; - }, - [](const ContentAddressed & ca) { - return ca.fixed; + return std::visit( + overloaded{ + [](const InputAddressed & ia) { return !ia.deferred; }, + [](const ContentAddressed & ca) { return ca.fixed; }, + [](const Impure &) { return false; }, }, - [](const Impure &) { - return false; - }, - }, raw()); + raw()); } - bool DerivationType::isSandboxed() const { - return std::visit(overloaded { - [](const InputAddressed & ia) { - return true; + return std::visit( + overloaded{ + [](const InputAddressed & ia) { return true; }, + [](const ContentAddressed & ca) { return ca.sandboxed; }, + [](const Impure &) { return false; }, }, - [](const ContentAddressed & ca) { - return ca.sandboxed; - }, - [](const Impure &) { - return false; - }, - }, raw()); + raw()); } - bool DerivationType::isPure() const { - return std::visit(overloaded { - [](const InputAddressed & ia) { - return true; - }, - [](const ContentAddressed & ca) { - return true; - }, - [](const Impure &) { - return false; + return std::visit( + overloaded{ + [](const InputAddressed & ia) { return true; }, + [](const ContentAddressed & ca) { return true; }, + [](const Impure &) { return false; }, }, - }, raw()); + raw()); } - bool BasicDerivation::isBuiltin() const { return builder.substr(0, 8) == "builtin:"; } - -StorePath writeDerivation(Store & store, - const Derivation & drv, RepairFlag repair, bool readOnly) +StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair, bool readOnly) { auto references = drv.inputSrcs; for (auto & i : drv.inputDrvs) @@ -139,12 +104,10 @@ StorePath writeDerivation(Store & store, held during a garbage collection). */ auto suffix = std::string(drv.name) + drvExtension; auto contents = drv.unparse(store, false); - return readOnly || settings.readOnlyMode - ? store.computeStorePathForText(suffix, contents, references) - : store.addTextToStore(suffix, contents, references, repair); + return readOnly || settings.readOnlyMode ? store.computeStorePathForText(suffix, contents, references) + : store.addTextToStore(suffix, contents, references, repair); } - /* Read string `s' from stream `str'. */ static void expect(std::istream & str, std::string_view s) { @@ -154,7 +117,6 @@ static void expect(std::istream & str, std::string_view s) throw FormatError("expected string '%1%'", s); } - /* Read a C-style string from stream `str'. */ static std::string parseString(std::istream & str) { @@ -164,16 +126,21 @@ static std::string parseString(std::istream & str) while ((c = str.get()) != '"') if (c == '\\') { c = str.get(); - if (c == 'n') res += '\n'; - else if (c == 'r') res += '\r'; - else if (c == 't') res += '\t'; - else res += c; - } - else res += c; + if (c == 'n') + res += '\n'; + else if (c == 'r') + res += '\r'; + else if (c == 't') + res += '\t'; + else + res += c; + } else + res += c; return res; } -static void validatePath(std::string_view s) { +static void validatePath(std::string_view s) +{ if (s.size() == 0 || s[0] != '/') throw FormatError("bad path '%1%' in derivation", s); } @@ -185,7 +152,6 @@ static Path parsePath(std::istream & str) return s; } - static bool endOfList(std::istream & str) { if (str.peek() == ',') { @@ -199,7 +165,6 @@ static bool endOfList(std::istream & str) return false; } - static StringSet parseStrings(std::istream & str, bool arePaths) { StringSet res; @@ -208,9 +173,8 @@ static StringSet parseStrings(std::istream & str, bool arePaths) return res; } - -static DerivationOutput parseDerivationOutput(const Store & store, - std::string_view pathS, std::string_view hashAlgo, std::string_view hash) +static DerivationOutput +parseDerivationOutput(const Store & store, std::string_view pathS, std::string_view hashAlgo, std::string_view hash) { if (hashAlgo != "") { auto method = FileIngestionMethod::Flat; @@ -222,32 +186,33 @@ static DerivationOutput parseDerivationOutput(const Store & store, if (hash == "impure") { settings.requireExperimentalFeature(Xp::ImpureDerivations); assert(pathS == ""); - return DerivationOutput::Impure { + return DerivationOutput::Impure{ .method = std::move(method), .hashType = std::move(hashType), }; } else if (hash != "") { validatePath(pathS); - return DerivationOutput::CAFixed { - .hash = FixedOutputHash { - .method = std::move(method), - .hash = Hash::parseNonSRIUnprefixed(hash, hashType), - }, + return DerivationOutput::CAFixed{ + .hash = + FixedOutputHash{ + .method = std::move(method), + .hash = Hash::parseNonSRIUnprefixed(hash, hashType), + }, }; } else { settings.requireExperimentalFeature(Xp::CaDerivations); assert(pathS == ""); - return DerivationOutput::CAFloating { + return DerivationOutput::CAFloating{ .method = std::move(method), .hashType = std::move(hashType), }; } } else { if (pathS == "") { - return DerivationOutput::Deferred { }; + return DerivationOutput::Deferred{}; } validatePath(pathS); - return DerivationOutput::InputAddressed { + return DerivationOutput::InputAddressed{ .path = store.parseStorePath(pathS), }; } @@ -255,15 +220,17 @@ static DerivationOutput parseDerivationOutput(const Store & store, static DerivationOutput parseDerivationOutput(const Store & store, std::istringstream & str) { - expect(str, ","); const auto pathS = parseString(str); - expect(str, ","); const auto hashAlgo = parseString(str); - expect(str, ","); const auto hash = parseString(str); + expect(str, ","); + const auto pathS = parseString(str); + expect(str, ","); + const auto hashAlgo = parseString(str); + expect(str, ","); + const auto hash = parseString(str); expect(str, ")"); return parseDerivationOutput(store, pathS, hashAlgo, hash); } - Derivation parseDerivation(const Store & store, std::string && s, std::string_view name) { Derivation drv; @@ -274,7 +241,8 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi /* Parse the list of outputs. */ while (!endOfList(str)) { - expect(str, "("); std::string id = parseString(str); + expect(str, "("); + std::string id = parseString(str); auto output = parseDerivationOutput(store, str); drv.outputs.emplace(std::move(id), std::move(output)); } @@ -289,9 +257,12 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi expect(str, ")"); } - expect(str, ",["); drv.inputSrcs = store.parseStorePathSet(parseStrings(str, true)); - expect(str, ","); drv.platform = parseString(str); - expect(str, ","); drv.builder = parseString(str); + expect(str, ",["); + drv.inputSrcs = store.parseStorePathSet(parseStrings(str, true)); + expect(str, ","); + drv.platform = parseString(str); + expect(str, ","); + drv.builder = parseString(str); /* Parse the builder arguments. */ expect(str, ",["); @@ -301,8 +272,10 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi /* Parse the environment variables. */ expect(str, ",["); while (!endOfList(str)) { - expect(str, "("); auto name = parseString(str); - expect(str, ","); auto value = parseString(str); + expect(str, "("); + auto name = parseString(str); + expect(str, ","); + auto value = parseString(str); expect(str, ")"); drv.env[name] = value; } @@ -311,7 +284,6 @@ Derivation parseDerivation(const Store & store, std::string && s, std::string_vi return drv; } - static void printString(std::string & res, std::string_view s) { boost::container::small_vector buffer; @@ -320,16 +292,24 @@ static void printString(std::string & res, std::string_view s) char * p = buf; *p++ = '"'; for (auto c : s) - if (c == '\"' || c == '\\') { *p++ = '\\'; *p++ = c; } - else if (c == '\n') { *p++ = '\\'; *p++ = 'n'; } - else if (c == '\r') { *p++ = '\\'; *p++ = 'r'; } - else if (c == '\t') { *p++ = '\\'; *p++ = 't'; } - else *p++ = c; + if (c == '\"' || c == '\\') { + *p++ = '\\'; + *p++ = c; + } else if (c == '\n') { + *p++ = '\\'; + *p++ = 'n'; + } else if (c == '\r') { + *p++ = '\\'; + *p++ = 'r'; + } else if (c == '\t') { + *p++ = '\\'; + *p++ = 't'; + } else + *p++ = c; *p++ = '"'; res.append(buf, p - buf); } - static void printUnquotedString(std::string & res, std::string_view s) { res += '"'; @@ -337,35 +317,38 @@ static void printUnquotedString(std::string & res, std::string_view s) res += '"'; } - template static void printStrings(std::string & res, ForwardIterator i, ForwardIterator j) { res += '['; bool first = true; - for ( ; i != j; ++i) { - if (first) first = false; else res += ','; + for (; i != j; ++i) { + if (first) + first = false; + else + res += ','; printString(res, *i); } res += ']'; } - template static void printUnquotedStrings(std::string & res, ForwardIterator i, ForwardIterator j) { res += '['; bool first = true; - for ( ; i != j; ++i) { - if (first) first = false; else res += ','; + for (; i != j; ++i) { + if (first) + first = false; + else + res += ','; printUnquotedString(res, *i); } res += ']'; } - -std::string Derivation::unparse(const Store & store, bool maskOutputs, - std::map * actualInputs) const +std::string +Derivation::unparse(const Store & store, bool maskOutputs, std::map * actualInputs) const { std::string s; s.reserve(65536); @@ -373,36 +356,56 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs, bool first = true; for (auto & i : outputs) { - if (first) first = false; else s += ','; - s += '('; printUnquotedString(s, i.first); - std::visit(overloaded { - [&](const DerivationOutput::InputAddressed & doi) { - s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(doi.path)); - s += ','; printUnquotedString(s, ""); - s += ','; printUnquotedString(s, ""); - }, - [&](const DerivationOutput::CAFixed & dof) { - s += ','; printUnquotedString(s, maskOutputs ? "" : store.printStorePath(dof.path(store, name, i.first))); - s += ','; printUnquotedString(s, dof.hash.printMethodAlgo()); - s += ','; printUnquotedString(s, dof.hash.hash.to_string(Base16, false)); - }, - [&](const DerivationOutput::CAFloating & dof) { - s += ','; printUnquotedString(s, ""); - s += ','; printUnquotedString(s, makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)); - s += ','; printUnquotedString(s, ""); - }, - [&](const DerivationOutput::Deferred &) { - s += ','; printUnquotedString(s, ""); - s += ','; printUnquotedString(s, ""); - s += ','; printUnquotedString(s, ""); - }, - [&](const DerivationOutputImpure & doi) { - // FIXME - s += ','; printUnquotedString(s, ""); - s += ','; printUnquotedString(s, makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); - s += ','; printUnquotedString(s, "impure"); - } - }, i.second.raw()); + if (first) + first = false; + else + s += ','; + s += '('; + printUnquotedString(s, i.first); + std::visit( + overloaded{ + [&](const DerivationOutput::InputAddressed & doi) { + s += ','; + printUnquotedString(s, maskOutputs ? "" : store.printStorePath(doi.path)); + s += ','; + printUnquotedString(s, ""); + s += ','; + printUnquotedString(s, ""); + }, + [&](const DerivationOutput::CAFixed & dof) { + s += ','; + printUnquotedString(s, maskOutputs ? "" : store.printStorePath(dof.path(store, name, i.first))); + s += ','; + printUnquotedString(s, dof.hash.printMethodAlgo()); + s += ','; + printUnquotedString(s, dof.hash.hash.to_string(Base16, false)); + }, + [&](const DerivationOutput::CAFloating & dof) { + s += ','; + printUnquotedString(s, ""); + s += ','; + printUnquotedString(s, makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)); + s += ','; + printUnquotedString(s, ""); + }, + [&](const DerivationOutput::Deferred &) { + s += ','; + printUnquotedString(s, ""); + s += ','; + printUnquotedString(s, ""); + s += ','; + printUnquotedString(s, ""); + }, + [&](const DerivationOutputImpure & doi) { + // FIXME + s += ','; + printUnquotedString(s, ""); + s += ','; + printUnquotedString(s, makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); + s += ','; + printUnquotedString(s, "impure"); + }}, + i.second.raw()); s += ')'; } @@ -410,16 +413,26 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs, first = true; if (actualInputs) { for (auto & i : *actualInputs) { - if (first) first = false; else s += ','; - s += '('; printUnquotedString(s, i.first); - s += ','; printUnquotedStrings(s, i.second.begin(), i.second.end()); + if (first) + first = false; + else + s += ','; + s += '('; + printUnquotedString(s, i.first); + s += ','; + printUnquotedStrings(s, i.second.begin(), i.second.end()); s += ')'; } } else { for (auto & i : inputDrvs) { - if (first) first = false; else s += ','; - s += '('; printUnquotedString(s, store.printStorePath(i.first)); - s += ','; printUnquotedStrings(s, i.second.begin(), i.second.end()); + if (first) + first = false; + else + s += ','; + s += '('; + printUnquotedString(s, store.printStorePath(i.first)); + s += ','; + printUnquotedStrings(s, i.second.begin(), i.second.end()); s += ')'; } } @@ -428,16 +441,24 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs, auto paths = store.printStorePathSet(inputSrcs); // FIXME: slow printUnquotedStrings(s, paths.begin(), paths.end()); - s += ','; printUnquotedString(s, platform); - s += ','; printString(s, builder); - s += ','; printStrings(s, args.begin(), args.end()); + s += ','; + printUnquotedString(s, platform); + s += ','; + printString(s, builder); + s += ','; + printStrings(s, args.begin(), args.end()); s += ",["; first = true; for (auto & i : env) { - if (first) first = false; else s += ','; - s += '('; printString(s, i.first); - s += ','; printString(s, maskOutputs && outputs.count(i.first) ? "" : i.second); + if (first) + first = false; + else + s += ','; + s += '('; + printString(s, i.first); + s += ','; + printString(s, maskOutputs && outputs.count(i.first) ? "" : i.second); s += ')'; } @@ -446,16 +467,15 @@ std::string Derivation::unparse(const Store & store, bool maskOutputs, return s; } - // FIXME: remove bool isDerivation(const std::string & fileName) { return hasSuffix(fileName, drvExtension); } - -std::string outputPathName(std::string_view drvName, std::string_view outputName) { - std::string res { drvName }; +std::string outputPathName(std::string_view drvName, std::string_view outputName) +{ + std::string res{drvName}; if (outputName != "out") { res += "-"; res += outputName; @@ -463,106 +483,75 @@ std::string outputPathName(std::string_view drvName, std::string_view outputName return res; } - DerivationType BasicDerivation::type() const { - std::set - inputAddressedOutputs, - fixedCAOutputs, - floatingCAOutputs, - deferredIAOutputs, + std::set inputAddressedOutputs, fixedCAOutputs, floatingCAOutputs, deferredIAOutputs, impureOutputs; std::optional floatingHashType; for (auto & i : outputs) { - std::visit(overloaded { - [&](const DerivationOutput::InputAddressed &) { - inputAddressedOutputs.insert(i.first); - }, - [&](const DerivationOutput::CAFixed &) { - fixedCAOutputs.insert(i.first); - }, - [&](const DerivationOutput::CAFloating & dof) { - floatingCAOutputs.insert(i.first); - if (!floatingHashType) { - floatingHashType = dof.hashType; - } else { - if (*floatingHashType != dof.hashType) - throw Error("all floating outputs must use the same hash type"); - } - }, - [&](const DerivationOutput::Deferred &) { - deferredIAOutputs.insert(i.first); - }, - [&](const DerivationOutput::Impure &) { - impureOutputs.insert(i.first); + std::visit( + overloaded{ + [&](const DerivationOutput::InputAddressed &) { inputAddressedOutputs.insert(i.first); }, + [&](const DerivationOutput::CAFixed &) { fixedCAOutputs.insert(i.first); }, + [&](const DerivationOutput::CAFloating & dof) { + floatingCAOutputs.insert(i.first); + if (!floatingHashType) { + floatingHashType = dof.hashType; + } else { + if (*floatingHashType != dof.hashType) + throw Error("all floating outputs must use the same hash type"); + } + }, + [&](const DerivationOutput::Deferred &) { deferredIAOutputs.insert(i.first); }, + [&](const DerivationOutput::Impure &) { impureOutputs.insert(i.first); }, }, - }, i.second.raw()); + i.second.raw()); } - if (inputAddressedOutputs.empty() - && fixedCAOutputs.empty() - && floatingCAOutputs.empty() - && deferredIAOutputs.empty() - && impureOutputs.empty()) + if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() + && deferredIAOutputs.empty() && impureOutputs.empty()) throw Error("must have at least one output"); - if (!inputAddressedOutputs.empty() - && fixedCAOutputs.empty() - && floatingCAOutputs.empty() - && deferredIAOutputs.empty() - && impureOutputs.empty()) - return DerivationType::InputAddressed { + if (!inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() + && deferredIAOutputs.empty() && impureOutputs.empty()) + return DerivationType::InputAddressed{ .deferred = false, }; - if (inputAddressedOutputs.empty() - && !fixedCAOutputs.empty() - && floatingCAOutputs.empty() - && deferredIAOutputs.empty() - && impureOutputs.empty()) - { + if (inputAddressedOutputs.empty() && !fixedCAOutputs.empty() && floatingCAOutputs.empty() + && deferredIAOutputs.empty() && impureOutputs.empty()) { if (fixedCAOutputs.size() > 1) // FIXME: Experimental feature? throw Error("only one fixed output is allowed for now"); if (*fixedCAOutputs.begin() != "out") throw Error("single fixed output must be named \"out\""); - return DerivationType::ContentAddressed { + return DerivationType::ContentAddressed{ .sandboxed = false, .fixed = true, }; } - if (inputAddressedOutputs.empty() - && fixedCAOutputs.empty() - && !floatingCAOutputs.empty() - && deferredIAOutputs.empty() - && impureOutputs.empty()) - return DerivationType::ContentAddressed { + if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && !floatingCAOutputs.empty() + && deferredIAOutputs.empty() && impureOutputs.empty()) + return DerivationType::ContentAddressed{ .sandboxed = true, .fixed = false, }; - if (inputAddressedOutputs.empty() - && fixedCAOutputs.empty() - && floatingCAOutputs.empty() - && !deferredIAOutputs.empty() - && impureOutputs.empty()) - return DerivationType::InputAddressed { + if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() + && !deferredIAOutputs.empty() && impureOutputs.empty()) + return DerivationType::InputAddressed{ .deferred = true, }; - if (inputAddressedOutputs.empty() - && fixedCAOutputs.empty() - && floatingCAOutputs.empty() - && deferredIAOutputs.empty() - && !impureOutputs.empty()) - return DerivationType::Impure { }; + if (inputAddressedOutputs.empty() && fixedCAOutputs.empty() && floatingCAOutputs.empty() + && deferredIAOutputs.empty() && !impureOutputs.empty()) + return DerivationType::Impure{}; throw Error("can't mix derivation output types"); } - Sync drvHashes; /* pathDerivationModulo and hashDerivationModulo are mutually recursive @@ -580,10 +569,7 @@ static const DrvHash pathDerivationModulo(Store & store, const StorePath & drvPa return h->second; } } - auto h = hashDerivationModulo( - store, - store.readInvalidDerivation(drvPath), - false); + auto h = hashDerivationModulo(store, store.readInvalidDerivation(drvPath), false); // Cache it drvHashes.lock()->insert_or_assign(drvPath, h); return h; @@ -615,13 +601,12 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut std::map outputHashes; for (const auto & i : drv.outputs) { auto & dof = std::get(i.second.raw()); - auto hash = hashString(htSHA256, "fixed:out:" - + dof.hash.printMethodAlgo() + ":" - + dof.hash.hash.to_string(Base16, false) + ":" - + store.printStorePath(dof.path(store, drv.name, i.first))); + auto hash = hashString( + htSHA256, "fixed:out:" + dof.hash.printMethodAlgo() + ":" + dof.hash.hash.to_string(Base16, false) + ":" + + store.printStorePath(dof.path(store, drv.name, i.first))); outputHashes.insert_or_assign(i.first, std::move(hash)); } - return DrvHash { + return DrvHash{ .hashes = outputHashes, .kind = DrvHash::Kind::Regular, }; @@ -631,27 +616,24 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut std::map outputHashes; for (const auto & [outputName, _] : drv.outputs) outputHashes.insert_or_assign(outputName, impureOutputHash); - return DrvHash { + return DrvHash{ .hashes = outputHashes, .kind = DrvHash::Kind::Deferred, }; } - auto kind = std::visit(overloaded { - [](const DerivationType::InputAddressed & ia) { - /* This might be a "pesimistically" deferred output, so we don't - "taint" the kind yet. */ - return DrvHash::Kind::Regular; - }, - [](const DerivationType::ContentAddressed & ca) { - return ca.fixed - ? DrvHash::Kind::Regular - : DrvHash::Kind::Deferred; - }, - [](const DerivationType::Impure &) -> DrvHash::Kind { - assert(false); - } - }, drv.type().raw()); + auto kind = std::visit( + overloaded{ + [](const DerivationType::InputAddressed & ia) { + /* This might be a "pesimistically" deferred output, so we don't + "taint" the kind yet. */ + return DrvHash::Kind::Regular; + }, + [](const DerivationType::ContentAddressed & ca) { + return ca.fixed ? DrvHash::Kind::Regular : DrvHash::Kind::Deferred; + }, + [](const DerivationType::Impure &) -> DrvHash::Kind { assert(false); }}, + drv.type().raw()); std::map inputs2; for (auto & [drvPath, inputOutputs0] : drv.inputDrvs) { @@ -675,25 +657,22 @@ DrvHash hashDerivationModulo(Store & store, const Derivation & drv, bool maskOut outputHashes.insert_or_assign(outputName, hash); } - return DrvHash { + return DrvHash{ .hashes = outputHashes, .kind = kind, }; } - std::map staticOutputHashes(Store & store, const Derivation & drv) { return hashDerivationModulo(store, drv, true).hashes; } - bool wantOutput(const std::string & output, const std::set & wanted) { return wanted.empty() || wanted.find(output) != wanted.end(); } - static DerivationOutput readDerivationOutput(Source & in, const Store & store) { const auto pathS = readString(in); @@ -715,11 +694,8 @@ DerivationOutputsAndOptPaths BasicDerivation::outputsAndOptPaths(const Store & s { DerivationOutputsAndOptPaths outsAndOptPaths; for (auto output : outputs) - outsAndOptPaths.insert(std::make_pair( - output.first, - std::make_pair(output.second, output.second.path(store, name, output.first)) - ) - ); + outsAndOptPaths.insert( + std::make_pair(output.first, std::make_pair(output.second, output.second.path(store, name, output.first)))); return outsAndOptPaths; } @@ -732,7 +708,6 @@ std::string_view BasicDerivation::nameFromPath(const StorePath & drvPath) return nameWithSuffix; } - Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv, std::string_view name) { drv.name = name; @@ -745,7 +720,7 @@ Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv, drv.outputs.emplace(std::move(name), std::move(output)); } - drv.inputSrcs = worker_proto::read(store, in, Phantom {}); + drv.inputSrcs = worker_proto::read(store, in, Phantom{}); in >> drv.platform >> drv.builder; drv.args = readStrings(in); @@ -759,39 +734,34 @@ Source & readDerivation(Source & in, const Store & store, BasicDerivation & drv, return in; } - void writeDerivation(Sink & out, const Store & store, const BasicDerivation & drv) { out << drv.outputs.size(); for (auto & i : drv.outputs) { out << i.first; - std::visit(overloaded { - [&](const DerivationOutput::InputAddressed & doi) { - out << store.printStorePath(doi.path) - << "" - << ""; - }, - [&](const DerivationOutput::CAFixed & dof) { - out << store.printStorePath(dof.path(store, drv.name, i.first)) - << dof.hash.printMethodAlgo() - << dof.hash.hash.to_string(Base16, false); - }, - [&](const DerivationOutput::CAFloating & dof) { - out << "" - << (makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)) - << ""; - }, - [&](const DerivationOutput::Deferred &) { - out << "" - << "" - << ""; - }, - [&](const DerivationOutput::Impure & doi) { - out << "" - << (makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)) - << "impure"; + std::visit( + overloaded{ + [&](const DerivationOutput::InputAddressed & doi) { + out << store.printStorePath(doi.path) << "" + << ""; + }, + [&](const DerivationOutput::CAFixed & dof) { + out << store.printStorePath(dof.path(store, drv.name, i.first)) << dof.hash.printMethodAlgo() + << dof.hash.hash.to_string(Base16, false); + }, + [&](const DerivationOutput::CAFloating & dof) { + out << "" << (makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)) << ""; + }, + [&](const DerivationOutput::Deferred &) { + out << "" + << "" + << ""; + }, + [&](const DerivationOutput::Impure & doi) { + out << "" << (makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)) << "impure"; + }, }, - }, i.second.raw()); + i.second.raw()); } worker_proto::write(store, out, drv.inputSrcs); out << drv.platform << drv.builder << drv.args; @@ -800,7 +770,6 @@ void writeDerivation(Sink & out, const Store & store, const BasicDerivation & dr out << i.first << i.second; } - std::string hashPlaceholder(const std::string_view outputName) { // FIXME: memoize? @@ -811,11 +780,11 @@ std::string downstreamPlaceholder(const Store & store, const StorePath & drvPath { auto drvNameWithExtension = drvPath.name(); auto drvName = drvNameWithExtension.substr(0, drvNameWithExtension.size() - 4); - auto clearText = "nix-upstream-output:" + std::string { drvPath.hashPart() } + ":" + outputPathName(drvName, outputName); + auto clearText = + "nix-upstream-output:" + std::string{drvPath.hashPart()} + ":" + outputPathName(drvName, outputName); return "/" + hashString(htSHA256, clearText).to_string(Base32, false); } - static void rewriteDerivation(Store & store, BasicDerivation & drv, const StringMap & rewrites) { for (auto & rewrite : rewrites) { @@ -840,16 +809,15 @@ static void rewriteDerivation(Store & store, BasicDerivation & drv, const String if (std::holds_alternative(output.raw())) { auto h = get(hashModulo.hashes, outputName); if (!h) - throw Error("derivation '%s' output '%s' has no hash (derivations.cc/rewriteDerivation)", - drv.name, outputName); + throw Error( + "derivation '%s' output '%s' has no hash (derivations.cc/rewriteDerivation)", drv.name, outputName); auto outPath = store.makeOutputPath(outputName, *h, drv.name); drv.env[outputName] = store.printStorePath(outPath); - output = DerivationOutput::InputAddressed { + output = DerivationOutput::InputAddressed{ .path = std::move(outPath), }; } } - } std::optional Derivation::tryResolve(Store & store) const @@ -865,24 +833,22 @@ std::optional Derivation::tryResolve(Store & store) const } std::optional Derivation::tryResolve( - Store & store, - const std::map, StorePath> & inputDrvOutputs) const + Store & store, const std::map, StorePath> & inputDrvOutputs) const { - BasicDerivation resolved { *this }; + BasicDerivation resolved{*this}; // Input paths that we'll want to rewrite in the derivation StringMap inputRewrites; for (auto & [inputDrv, inputOutputs] : inputDrvs) { for (auto & outputName : inputOutputs) { - if (auto actualPath = get(inputDrvOutputs, { inputDrv, outputName })) { + if (auto actualPath = get(inputDrvOutputs, {inputDrv, outputName})) { inputRewrites.emplace( - downstreamPlaceholder(store, inputDrv, outputName), - store.printStorePath(*actualPath)); + downstreamPlaceholder(store, inputDrv, outputName), store.printStorePath(*actualPath)); resolved.inputSrcs.insert(*actualPath); } else { - warn("output '%s' of input '%s' missing, aborting the resolving", - outputName, + warn( + "output '%s' of input '%s' missing, aborting the resolving", outputName, store.printStorePath(inputDrv)); return {}; } diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index af198a76732f..8a36ce7c7ec7 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -10,10 +10,8 @@ #include #include - namespace nix { - /* Abstract syntax of derivations. */ /* The traditional non-fixed-output derivation type. */ @@ -43,7 +41,8 @@ struct DerivationOutputCAFloating /* Input-addressed output which depends on a (CA) derivation whose hash isn't * known yet. */ -struct DerivationOutputDeferred {}; +struct DerivationOutputDeferred +{}; /* Impure output which is moved to a content-addressed location (like CAFloating) but isn't registered as a realization. @@ -60,8 +59,8 @@ typedef std::variant< DerivationOutputCAFixed, DerivationOutputCAFloating, DerivationOutputDeferred, - DerivationOutputImpure -> _DerivationOutputRaw; + DerivationOutputImpure> + _DerivationOutputRaw; struct DerivationOutput : _DerivationOutputRaw { @@ -79,7 +78,8 @@ struct DerivationOutput : _DerivationOutputRaw interface provided by BasicDerivation::outputsAndOptPaths */ std::optional path(const Store & store, std::string_view drvName, std::string_view outputName) const; - inline const Raw & raw() const { + inline const Raw & raw() const + { return static_cast(*this); } }; @@ -90,32 +90,31 @@ typedef std::map DerivationOutputs; also contains, for each output, the (optional) store path in which it would be written. To calculate values of these types, see the corresponding functions in BasicDerivation */ -typedef std::map>> - DerivationOutputsAndOptPaths; +typedef std::map>> DerivationOutputsAndOptPaths; /* For inputs that are sub-derivations, we specify exactly which output IDs we are interested in. */ typedef std::map DerivationInputs; -struct DerivationType_InputAddressed { +struct DerivationType_InputAddressed +{ bool deferred; }; -struct DerivationType_ContentAddressed { +struct DerivationType_ContentAddressed +{ bool sandboxed; bool fixed; }; -struct DerivationType_Impure { -}; +struct DerivationType_Impure +{}; -typedef std::variant< - DerivationType_InputAddressed, - DerivationType_ContentAddressed, - DerivationType_Impure -> _DerivationTypeRaw; +typedef std::variant + _DerivationTypeRaw; -struct DerivationType : _DerivationTypeRaw { +struct DerivationType : _DerivationTypeRaw +{ using Raw = _DerivationTypeRaw; using Raw::Raw; using InputAddressed = DerivationType_InputAddressed; @@ -149,7 +148,8 @@ struct DerivationType : _DerivationTypeRaw { */ bool hasKnownOutputPaths() const; - inline const Raw & raw() const { + inline const Raw & raw() const + { return static_cast(*this); } }; @@ -157,7 +157,7 @@ struct DerivationType : _DerivationTypeRaw { struct BasicDerivation { DerivationOutputs outputs; /* keyed on symbolic IDs */ - StorePathSet inputSrcs; /* inputs that are sources */ + StorePathSet inputSrcs; /* inputs that are sources */ std::string platform; Path builder; Strings args; @@ -165,7 +165,7 @@ struct BasicDerivation std::string name; BasicDerivation() = default; - virtual ~BasicDerivation() { }; + virtual ~BasicDerivation(){}; bool isBuiltin() const; @@ -188,8 +188,8 @@ struct Derivation : BasicDerivation DerivationInputs inputDrvs; /* inputs that are sub-derivations */ /* Print a derivation. */ - std::string unparse(const Store & store, bool maskOutputs, - std::map * actualInputs = nullptr) const; + std::string + unparse(const Store & store, bool maskOutputs, std::map * actualInputs = nullptr) const; /* Return the underlying basic derivation but with these changes: @@ -202,23 +202,22 @@ struct Derivation : BasicDerivation /* Like the above, but instead of querying the Nix database for realisations, uses a given mapping from input derivation paths + output names to actual output store paths. */ - std::optional tryResolve( - Store & store, - const std::map, StorePath> & inputDrvOutputs) const; + std::optional + tryResolve(Store & store, const std::map, StorePath> & inputDrvOutputs) const; Derivation() = default; - Derivation(const BasicDerivation & bd) : BasicDerivation(bd) { } - Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { } + Derivation(const BasicDerivation & bd) + : BasicDerivation(bd) + {} + Derivation(BasicDerivation && bd) + : BasicDerivation(std::move(bd)) + {} }; - class Store; /* Write a derivation to the Nix store, and return its path. */ -StorePath writeDerivation(Store & store, - const Derivation & drv, - RepairFlag repair = NoRepair, - bool readOnly = false); +StorePath writeDerivation(Store & store, const Derivation & drv, RepairFlag repair = NoRepair, bool readOnly = false); /* Read a derivation from a file. */ Derivation parseDerivation(const Store & store, std::string && s, std::string_view name); @@ -233,13 +232,13 @@ bool isDerivation(const std::string & fileName); the output name is "out". */ std::string outputPathName(std::string_view drvName, std::string_view outputName); - // The hashes modulo of a derivation. // // Each output is given a hash, although in practice only the content-addressed // derivations (fixed-output or not) will have a different hash for each // output. -struct DrvHash { +struct DrvHash +{ std::map hashes; enum struct Kind : bool { @@ -253,7 +252,7 @@ struct DrvHash { Kind kind; }; -void operator |= (DrvHash::Kind & self, const DrvHash::Kind & other) noexcept; +void operator|=(DrvHash::Kind & self, const DrvHash::Kind & other) noexcept; /* Returns hashes with the details of fixed-output subderivations expunged. diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc index 44587ae789f3..e36718054288 100644 --- a/src/libstore/derived-path.cc +++ b/src/libstore/derived-path.cc @@ -8,31 +8,32 @@ namespace nix { -nlohmann::json DerivedPath::Opaque::toJSON(ref store) const { +nlohmann::json DerivedPath::Opaque::toJSON(ref store) const +{ nlohmann::json res; res["path"] = store->printStorePath(path); return res; } -nlohmann::json DerivedPath::Built::toJSON(ref store) const { +nlohmann::json DerivedPath::Built::toJSON(ref store) const +{ nlohmann::json res; res["drvPath"] = store->printStorePath(drvPath); // Fallback for the input-addressed derivation case: We expect to always be // able to print the output paths, so let’s do it const auto knownOutputs = store->queryPartialDerivationOutputMap(drvPath); - for (const auto& output : outputs) { + for (const auto & output : outputs) { auto knownOutput = get(knownOutputs, output); - res["outputs"][output] = (knownOutput && *knownOutput) - ? store->printStorePath(**knownOutput) - : nullptr; + res["outputs"][output] = (knownOutput && *knownOutput) ? store->printStorePath(**knownOutput) : nullptr; } return res; } -nlohmann::json BuiltPath::Built::toJSON(ref store) const { +nlohmann::json BuiltPath::Built::toJSON(ref store) const +{ nlohmann::json res; res["drvPath"] = store->printStorePath(drvPath); - for (const auto& [output, path] : outputs) { + for (const auto & [output, path] : outputs) { res["outputs"][output] = store->printStorePath(path); } return res; @@ -49,45 +50,44 @@ StorePathSet BuiltPath::outPaths() const res.insert(path); return res; }, - }, raw() - ); + }, + raw()); } template -nlohmann::json stuffToJSON(const std::vector & ts, ref store) { +nlohmann::json stuffToJSON(const std::vector & ts, ref store) +{ auto res = nlohmann::json::array(); for (const T & t : ts) { - std::visit([&res, store](const auto & t) { - res.push_back(t.toJSON(store)); - }, t.raw()); + std::visit([&res, store](const auto & t) { res.push_back(t.toJSON(store)); }, t.raw()); } return res; } nlohmann::json derivedPathsWithHintsToJSON(const BuiltPaths & buildables, ref store) -{ return stuffToJSON(buildables, store); } +{ + return stuffToJSON(buildables, store); +} nlohmann::json derivedPathsToJSON(const DerivedPaths & paths, ref store) -{ return stuffToJSON(paths, store); } - +{ + return stuffToJSON(paths, store); +} -std::string DerivedPath::Opaque::to_string(const Store & store) const { +std::string DerivedPath::Opaque::to_string(const Store & store) const +{ return store.printStorePath(path); } -std::string DerivedPath::Built::to_string(const Store & store) const { - return store.printStorePath(drvPath) - + "!" - + (outputs.empty() ? std::string { "*" } : concatStringsSep(",", outputs)); +std::string DerivedPath::Built::to_string(const Store & store) const +{ + return store.printStorePath(drvPath) + "!" + (outputs.empty() ? std::string{"*"} : concatStringsSep(",", outputs)); } std::string DerivedPath::to_string(const Store & store) const { - return std::visit( - [&](const auto & req) { return req.to_string(store); }, - this->raw()); + return std::visit([&](const auto & req) { return req.to_string(store); }, this->raw()); } - DerivedPath::Opaque DerivedPath::Opaque::parse(const Store & store, std::string_view s) { return {store.parseStorePath(s)}; @@ -108,9 +108,8 @@ DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_vi DerivedPath DerivedPath::parse(const Store & store, std::string_view s) { size_t n = s.find("!"); - return n == s.npos - ? (DerivedPath) DerivedPath::Opaque::parse(store, s) - : (DerivedPath) DerivedPath::Built::parse(store, s); + return n == s.npos ? (DerivedPath) DerivedPath::Opaque::parse(store, s) + : (DerivedPath) DerivedPath::Built::parse(store, s); } RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const @@ -120,20 +119,17 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const overloaded{ [&](const BuiltPath::Opaque & p) { res.insert(p.path); }, [&](const BuiltPath::Built & p) { - auto drvHashes = - staticOutputHashes(store, store.readDerivation(p.drvPath)); - for (auto& [outputName, outputPath] : p.outputs) { - if (settings.isExperimentalFeatureEnabled( - Xp::CaDerivations)) { + auto drvHashes = staticOutputHashes(store, store.readDerivation(p.drvPath)); + for (auto & [outputName, outputPath] : p.outputs) { + if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { auto drvOutput = get(drvHashes, outputName); if (!drvOutput) throw Error( "the derivation '%s' has unrealised output '%s' (derived-path.cc/toRealisedPaths)", store.printStorePath(p.drvPath), outputName); - auto thisRealisation = store.queryRealisation( - DrvOutput{*drvOutput, outputName}); - assert(thisRealisation); // We’ve built it, so we must - // have the realisation + auto thisRealisation = store.queryRealisation(DrvOutput{*drvOutput, outputName}); + assert(thisRealisation); // We’ve built it, so we must + // have the realisation res.insert(*thisRealisation); } else { res.insert(outputPath); diff --git a/src/libstore/derived-path.hh b/src/libstore/derived-path.hh index 24a0ae773592..d2881be29dba 100644 --- a/src/libstore/derived-path.hh +++ b/src/libstore/derived-path.hh @@ -19,15 +19,18 @@ class Store; * cannot be simplified further. Since they are opaque, they cannot be * built, but they can fetched. */ -struct DerivedPathOpaque { +struct DerivedPathOpaque +{ StorePath path; nlohmann::json toJSON(ref store) const; std::string to_string(const Store & store) const; static DerivedPathOpaque parse(const Store & store, std::string_view); - bool operator < (const DerivedPathOpaque & b) const - { return path < b.path; } + bool operator<(const DerivedPathOpaque & b) const + { + return path < b.path; + } }; /** @@ -42,7 +45,8 @@ struct DerivedPathOpaque { * evaluate to single values. Perhaps this should have just a single * output name. */ -struct DerivedPathBuilt { +struct DerivedPathBuilt +{ StorePath drvPath; std::set outputs; @@ -50,14 +54,13 @@ struct DerivedPathBuilt { static DerivedPathBuilt parse(const Store & store, std::string_view); nlohmann::json toJSON(ref store) const; - bool operator < (const DerivedPathBuilt & b) const - { return std::make_pair(drvPath, outputs) < std::make_pair(b.drvPath, b.outputs); } + bool operator<(const DerivedPathBuilt & b) const + { + return std::make_pair(drvPath, outputs) < std::make_pair(b.drvPath, b.outputs); + } }; -using _DerivedPathRaw = std::variant< - DerivedPathOpaque, - DerivedPathBuilt ->; +using _DerivedPathRaw = std::variant; /** * A "derived path" is a very simple sort of expression that evaluates @@ -69,14 +72,16 @@ using _DerivedPathRaw = std::variant< * - built, in which case it is a pair of a derivation path and an * output name. */ -struct DerivedPath : _DerivedPathRaw { +struct DerivedPath : _DerivedPathRaw +{ using Raw = _DerivedPathRaw; using Raw::Raw; using Opaque = DerivedPathOpaque; using Built = DerivedPathBuilt; - inline const Raw & raw() const { + inline const Raw & raw() const + { return static_cast(*this); } @@ -89,7 +94,8 @@ struct DerivedPath : _DerivedPathRaw { * * See 'BuiltPath' for more an explanation. */ -struct BuiltPathBuilt { +struct BuiltPathBuilt +{ StorePath drvPath; std::map outputs; @@ -97,35 +103,33 @@ struct BuiltPathBuilt { static BuiltPathBuilt parse(const Store & store, std::string_view); }; -using _BuiltPathRaw = std::variant< - DerivedPath::Opaque, - BuiltPathBuilt ->; +using _BuiltPathRaw = std::variant; /** * A built path. Similar to a `DerivedPath`, but enriched with the corresponding * output path(s). */ -struct BuiltPath : _BuiltPathRaw { +struct BuiltPath : _BuiltPathRaw +{ using Raw = _BuiltPathRaw; using Raw::Raw; using Opaque = DerivedPathOpaque; using Built = BuiltPathBuilt; - inline const Raw & raw() const { + inline const Raw & raw() const + { return static_cast(*this); } StorePathSet outPaths() const; RealisedPath::Set toRealisedPaths(Store & store) const; - }; typedef std::vector DerivedPaths; typedef std::vector BuiltPaths; nlohmann::json derivedPathsWithHintsToJSON(const BuiltPaths & buildables, ref store); -nlohmann::json derivedPathsToJSON(const DerivedPaths & , ref store); +nlohmann::json derivedPathsToJSON(const DerivedPaths &, ref store); } diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc index b4fbe0b702ca..dc1104f41854 100644 --- a/src/libstore/dummy-store.cc +++ b/src/libstore/dummy-store.cc @@ -3,59 +3,70 @@ namespace nix { -struct DummyStoreConfig : virtual StoreConfig { +struct DummyStoreConfig : virtual StoreConfig +{ using StoreConfig::StoreConfig; - const std::string name() override { return "Dummy Store"; } + const std::string name() override + { + return "Dummy Store"; + } }; struct DummyStore : public virtual DummyStoreConfig, public virtual Store { DummyStore(const std::string scheme, const std::string uri, const Params & params) : DummyStore(params) - { } + {} DummyStore(const Params & params) : StoreConfig(params) , DummyStoreConfig(params) , Store(params) - { } + {} std::string getUri() override { return *uriSchemes().begin(); } - void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept override + void queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept override { callback(nullptr); } - static std::set uriSchemes() { + static std::set uriSchemes() + { return {"dummy"}; } std::optional queryPathFromHashPart(const std::string & hashPart) override - { unsupported("queryPathFromHashPart"); } + { + unsupported("queryPathFromHashPart"); + } - void addToStore(const ValidPathInfo & info, Source & source, - RepairFlag repair, CheckSigsFlag checkSigs) override - { unsupported("addToStore"); } + void addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override + { + unsupported("addToStore"); + } StorePath addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) override - { unsupported("addTextToStore"); } + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) override + { + unsupported("addTextToStore"); + } void narFromPath(const StorePath & path, Sink & sink) override - { unsupported("narFromPath"); } + { + unsupported("narFromPath"); + } - void queryRealisationUncached(const DrvOutput &, - Callback> callback) noexcept override - { callback(nullptr); } + void + queryRealisationUncached(const DrvOutput &, Callback> callback) noexcept override + { + callback(nullptr); + } }; static RegisterStoreImplementation regDummyStore; diff --git a/src/libstore/export-import.cc b/src/libstore/export-import.cc index 9875da909066..4b15eb5c6b93 100644 --- a/src/libstore/export-import.cc +++ b/src/libstore/export-import.cc @@ -13,13 +13,13 @@ void Store::exportPaths(const StorePathSet & paths, Sink & sink) std::reverse(sorted.begin(), sorted.end()); std::string doneLabel("paths exported"); - //logger->incExpected(doneLabel, sorted.size()); + // logger->incExpected(doneLabel, sorted.size()); for (auto & path : sorted) { - //Activity act(*logger, lvlInfo, format("exporting path '%s'") % path); + // Activity act(*logger, lvlInfo, format("exporting path '%s'") % path); sink << 1; exportPath(path, sink); - //logger->incProgress(doneLabel); + // logger->incProgress(doneLabel); } sink << 0; @@ -39,16 +39,13 @@ void Store::exportPath(const StorePath & path, Sink & sink) Don't complain if the stored hash is zero (unknown). */ Hash hash = hashSink.currentHash().first; if (hash != info->narHash && info->narHash != Hash(info->narHash.type)) - throw Error("hash of path '%s' has changed from '%s' to '%s'!", - printStorePath(path), info->narHash.to_string(Base32, true), hash.to_string(Base32, true)); + throw Error( + "hash of path '%s' has changed from '%s' to '%s'!", printStorePath(path), + info->narHash.to_string(Base32, true), hash.to_string(Base32, true)); - teeSink - << exportMagic - << printStorePath(path); + teeSink << exportMagic << printStorePath(path); worker_proto::write(*this, teeSink, info->references); - teeSink - << (info->deriver ? printStorePath(*info->deriver) : "") - << 0; + teeSink << (info->deriver ? printStorePath(*info->deriver) : "") << 0; } StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs) @@ -56,12 +53,14 @@ StorePaths Store::importPaths(Source & source, CheckSigsFlag checkSigs) StorePaths res; while (true) { auto n = readNum(source); - if (n == 0) break; - if (n != 1) throw Error("input doesn't look like something created by 'nix-store --export'"); + if (n == 0) + break; + if (n != 1) + throw Error("input doesn't look like something created by 'nix-store --export'"); /* Extract the NAR from the source. */ StringSink saved; - TeeSource tee { source, saved }; + TeeSource tee{source, saved}; ParseSink ether; parseDump(ether, tee); @@ -71,13 +70,13 @@ 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, format("importing path '%s'") % info.path); - auto references = worker_proto::read(*this, source, Phantom {}); + auto references = worker_proto::read(*this, source, Phantom{}); auto deriver = readString(source); auto narHash = hashString(htSHA256, saved.s); - ValidPathInfo info { path, narHash }; + ValidPathInfo info{path, narHash}; if (deriver != "") info.deriver = parseStorePath(deriver); info.references = references; diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc index 8454ad7d2a4f..7953e1c50564 100644 --- a/src/libstore/filetransfer.cc +++ b/src/libstore/filetransfer.cc @@ -74,7 +74,7 @@ struct curlFileTransfer : public FileTransfer curl_off_t writtenToSink = 0; - inline static const std::set successfulStatuses {200, 201, 204, 206, 304, 0 /* other protocol */}; + inline static const std::set successfulStatuses{200, 201, 204, 206, 304, 0 /* other protocol */}; /* Get the HTTP status code, or 0 for other protocols. */ long getHTTPStatus() { @@ -86,14 +86,18 @@ struct curlFileTransfer : public FileTransfer return httpStatus; } - TransferItem(curlFileTransfer & fileTransfer, + TransferItem( + curlFileTransfer & fileTransfer, const FileTransferRequest & request, Callback && callback) : fileTransfer(fileTransfer) , request(request) - , act(*logger, lvlTalkative, actFileTransfer, - fmt(request.data ? "uploading '%s'" : "downloading '%s'", request.uri), - {request.uri}, request.parentAct) + , act(*logger, + lvlTalkative, + actFileTransfer, + fmt(request.data ? "uploading '%s'" : "downloading '%s'", request.uri), + {request.uri}, + request.parentAct) , callback(std::move(callback)) , finalSink([this](std::string_view data) { if (this->request.dataCallback) { @@ -107,13 +111,13 @@ struct curlFileTransfer : public FileTransfer } } else this->result.data.append(data); - }) + }) { if (!request.expectedETag.empty()) requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str()); if (!request.mimeType.empty()) requestHeaders = curl_slist_append(requestHeaders, ("Content-Type: " + request.mimeType).c_str()); - for (auto it = request.headers.begin(); it != request.headers.end(); ++it){ + for (auto it = request.headers.begin(); it != request.headers.end(); ++it) { requestHeaders = curl_slist_append(requestHeaders, fmt("%s: %s", it->first, it->second).c_str()); } } @@ -125,7 +129,8 @@ struct curlFileTransfer : public FileTransfer curl_multi_remove_handle(fileTransfer.curlm, req); curl_easy_cleanup(req); } - if (requestHeaders) curl_slist_free_all(requestHeaders); + if (requestHeaders) + curl_slist_free_all(requestHeaders); try { if (!done) fail(FileTransferError(Interrupted, {}, "download of '%s' was interrupted", request.uri)); @@ -161,12 +166,12 @@ struct curlFileTransfer : public FileTransfer if (!decompressionSink) { decompressionSink = makeDecompressionSink(encoding, finalSink); - if (! successfulStatuses.count(getHTTPStatus())) { + if (!successfulStatuses.count(getHTTPStatus())) { // In this case we want to construct a TeeSink, to keep // the response around (which we figure won't be big // like an actual download should be) to improve error // messages. - errorSink = StringSink { }; + errorSink = StringSink{}; } } @@ -234,9 +239,9 @@ struct curlFileTransfer : public FileTransfer int progressCallback(double dltotal, double dlnow) { try { - act.progress(dlnow, dltotal); + act.progress(dlnow, dltotal); } catch (nix::Interrupted &) { - assert(_isInterrupted); + assert(_isInterrupted); } return _isInterrupted; } @@ -254,7 +259,7 @@ struct curlFileTransfer : public FileTransfer } size_t readOffset = 0; - size_t readCallback(char *buffer, size_t size, size_t nitems) + size_t readCallback(char * buffer, size_t size, size_t nitems) { if (readOffset == request.data->length()) return 0; @@ -265,14 +270,15 @@ struct curlFileTransfer : public FileTransfer return count; } - static size_t readCallbackWrapper(char *buffer, size_t size, size_t nitems, void * userp) + static size_t readCallbackWrapper(char * buffer, size_t size, size_t nitems, void * userp) { return ((TransferItem *) userp)->readCallback(buffer, size, nitems); } void init() { - if (!req) req = curl_easy_init(); + if (!req) + req = curl_easy_init(); curl_easy_reset(req); @@ -285,18 +291,20 @@ struct curlFileTransfer : public FileTransfer curl_easy_setopt(req, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(req, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(req, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(req, CURLOPT_USERAGENT, - ("curl/" LIBCURL_VERSION " Nix/" + nixVersion + - (fileTransferSettings.userAgentSuffix != "" ? " " + fileTransferSettings.userAgentSuffix.get() : "")).c_str()); - #if LIBCURL_VERSION_NUM >= 0x072b00 + curl_easy_setopt( + req, CURLOPT_USERAGENT, + ("curl/" LIBCURL_VERSION " Nix/" + nixVersion + + (fileTransferSettings.userAgentSuffix != "" ? " " + fileTransferSettings.userAgentSuffix.get() : "")) + .c_str()); +#if LIBCURL_VERSION_NUM >= 0x072b00 curl_easy_setopt(req, CURLOPT_PIPEWAIT, 1); - #endif - #if LIBCURL_VERSION_NUM >= 0x072f00 +#endif +#if LIBCURL_VERSION_NUM >= 0x072f00 if (fileTransferSettings.enableHttp2) curl_easy_setopt(req, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); else curl_easy_setopt(req, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); - #endif +#endif curl_easy_setopt(req, CURLOPT_WRITEFUNCTION, TransferItem::writeCallbackWrapper); curl_easy_setopt(req, CURLOPT_WRITEDATA, this); curl_easy_setopt(req, CURLOPT_HEADERFUNCTION, TransferItem::headerCallbackWrapper); @@ -353,8 +361,9 @@ struct curlFileTransfer : public FileTransfer if (effectiveUriCStr) result.effectiveUri = effectiveUriCStr; - debug("finished %s of '%s'; curl status = %d, HTTP status = %d, body = %d bytes", - request.verb(), request.uri, code, httpStatus, result.bodySize); + debug( + "finished %s of '%s'; curl status = %d, HTTP status = %d, body = %d bytes", request.verb(), request.uri, + code, httpStatus, result.bodySize); if (decompressionSink) { try { @@ -372,8 +381,7 @@ struct curlFileTransfer : public FileTransfer if (writeException) failEx(writeException); - else if (code == CURLE_OK && successfulStatuses.count(httpStatus)) - { + else if (code == CURLE_OK && successfulStatuses.count(httpStatus)) { result.cached = httpStatus == 304; // In 2021, GitHub responds to If-None-Match with 304, @@ -411,24 +419,24 @@ struct curlFileTransfer : public FileTransfer } else { // Don't bother retrying on certain cURL errors either switch (code) { - case CURLE_FAILED_INIT: - case CURLE_URL_MALFORMAT: - case CURLE_NOT_BUILT_IN: - case CURLE_REMOTE_ACCESS_DENIED: - case CURLE_FILE_COULDNT_READ_FILE: - case CURLE_FUNCTION_NOT_FOUND: - case CURLE_ABORTED_BY_CALLBACK: - case CURLE_BAD_FUNCTION_ARGUMENT: - case CURLE_INTERFACE_FAILED: - case CURLE_UNKNOWN_OPTION: - case CURLE_SSL_CACERT_BADFILE: - case CURLE_TOO_MANY_REDIRECTS: - case CURLE_WRITE_ERROR: - case CURLE_UNSUPPORTED_PROTOCOL: - err = Misc; - break; - default: // Shut up warnings - break; + case CURLE_FAILED_INIT: + case CURLE_URL_MALFORMAT: + case CURLE_NOT_BUILT_IN: + case CURLE_REMOTE_ACCESS_DENIED: + case CURLE_FILE_COULDNT_READ_FILE: + case CURLE_FUNCTION_NOT_FOUND: + case CURLE_ABORTED_BY_CALLBACK: + case CURLE_BAD_FUNCTION_ARGUMENT: + case CURLE_INTERFACE_FAILED: + case CURLE_UNKNOWN_OPTION: + case CURLE_SSL_CACERT_BADFILE: + case CURLE_TOO_MANY_REDIRECTS: + case CURLE_WRITE_ERROR: + case CURLE_UNSUPPORTED_PROTOCOL: + err = Misc; + break; + default: // Shut up warnings + break; } } @@ -438,38 +446,31 @@ struct curlFileTransfer : public FileTransfer if (errorSink) response = std::move(errorSink->s); auto exc = - code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted - ? FileTransferError(Interrupted, std::move(response), "%s of '%s' was interrupted", request.verb(), request.uri) - : httpStatus != 0 - ? FileTransferError(err, - std::move(response), - "unable to %s '%s': HTTP error %d%s", - request.verb(), request.uri, httpStatus, - code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code))) - : FileTransferError(err, - std::move(response), - "unable to %s '%s': %s (%d)", - request.verb(), request.uri, curl_easy_strerror(code), code); + code == CURLE_ABORTED_BY_CALLBACK && _isInterrupted ? FileTransferError( + Interrupted, std::move(response), "%s of '%s' was interrupted", request.verb(), request.uri) + : httpStatus != 0 ? FileTransferError( + err, std::move(response), "unable to %s '%s': HTTP error %d%s", request.verb(), request.uri, + httpStatus, code == CURLE_OK ? "" : fmt(" (curl error: %s)", curl_easy_strerror(code))) + : FileTransferError( + err, std::move(response), "unable to %s '%s': %s (%d)", request.verb(), + request.uri, curl_easy_strerror(code), code); /* If this is a transient error, then maybe retry the download after a while. If we're writing to a sink, we can only retry if the server supports ranged requests. */ - if (err == Transient - && attempt < request.tries - && (!this->request.dataCallback - || writtenToSink == 0 - || (acceptRanges && encoding.empty()))) - { - int ms = request.baseRetryTimeMs * std::pow(2.0f, attempt - 1 + std::uniform_real_distribution<>(0.0, 0.5)(fileTransfer.mt19937)); + if (err == Transient && attempt < request.tries + && (!this->request.dataCallback || writtenToSink == 0 || (acceptRanges && encoding.empty()))) { + int ms = request.baseRetryTimeMs + * std::pow( + 2.0f, attempt - 1 + std::uniform_real_distribution<>(0.0, 0.5)(fileTransfer.mt19937)); if (writtenToSink) warn("%s; retrying from offset %d in %d ms", exc.what(), writtenToSink, ms); else warn("%s; retrying in %d ms", exc.what(), ms); embargo = std::chrono::steady_clock::now() + std::chrono::milliseconds(ms); fileTransfer.enqueueItem(shared_from_this()); - } - else + } else fail(exc); } } @@ -477,13 +478,17 @@ struct curlFileTransfer : public FileTransfer struct State { - struct EmbargoComparator { - bool operator() (const std::shared_ptr & i1, const std::shared_ptr & i2) { + struct EmbargoComparator + { + bool operator()(const std::shared_ptr & i1, const std::shared_ptr & i2) + { return i1->embargo > i2->embargo; } }; bool quit = false; - std::priority_queue, std::vector>, EmbargoComparator> incoming; + std:: + priority_queue, std::vector>, EmbargoComparator> + incoming; }; Sync state_; @@ -503,13 +508,12 @@ struct curlFileTransfer : public FileTransfer curlm = curl_multi_init(); - #if LIBCURL_VERSION_NUM >= 0x072b00 // Multiplex requires >= 7.43.0 +#if LIBCURL_VERSION_NUM >= 0x072b00 // Multiplex requires >= 7.43.0 curl_multi_setopt(curlm, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); - #endif - #if LIBCURL_VERSION_NUM >= 0x071e00 // Max connections requires >= 7.30.0 - curl_multi_setopt(curlm, CURLMOPT_MAX_TOTAL_CONNECTIONS, - fileTransferSettings.httpConnections.get()); - #endif +#endif +#if LIBCURL_VERSION_NUM >= 0x071e00 // Max connections requires >= 7.30.0 + curl_multi_setopt(curlm, CURLMOPT_MAX_TOTAL_CONNECTIONS, fileTransferSettings.httpConnections.get()); +#endif wakeupPipe.create(); fcntl(wakeupPipe.readSide.get(), F_SETFL, O_NONBLOCK); @@ -523,7 +527,8 @@ struct curlFileTransfer : public FileTransfer workerThread.join(); - if (curlm) curl_multi_cleanup(curlm); + if (curlm) + curl_multi_cleanup(curlm); } void stopWorkerThread() @@ -539,9 +544,7 @@ struct curlFileTransfer : public FileTransfer void workerThreadMain() { /* Cause this thread to be notified on SIGINT. */ - auto callback = createInterruptCallback([&]() { - stopWorkerThread(); - }); + auto callback = createInterruptCallback([&]() { stopWorkerThread(); }); unshareFilesystem(); @@ -581,10 +584,11 @@ struct curlFileTransfer : public FileTransfer extraFDs[0].events = CURL_WAIT_POLLIN; extraFDs[0].revents = 0; long maxSleepTimeMs = items.empty() ? 10000 : 100; - auto sleepTimeMs = - nextWakeup != std::chrono::steady_clock::time_point() - ? std::max(0, (int) std::chrono::duration_cast(nextWakeup - std::chrono::steady_clock::now()).count()) - : maxSleepTimeMs; + auto sleepTimeMs = nextWakeup != std::chrono::steady_clock::time_point() ? std::max( + 0, (int) std::chrono::duration_cast( + nextWakeup - std::chrono::steady_clock::now()) + .count()) + : maxSleepTimeMs; vomit("download thread waiting for %d ms", sleepTimeMs); mc = curl_multi_wait(curlm, extraFDs, 1, sleepTimeMs, &numfds); if (mc != CURLM_OK) @@ -613,8 +617,7 @@ struct curlFileTransfer : public FileTransfer incoming.push_back(item); state->incoming.pop(); } else { - if (nextWakeup == std::chrono::steady_clock::time_point() - || item->embargo < nextWakeup) + if (nextWakeup == std::chrono::steady_clock::time_point() || item->embargo < nextWakeup) nextWakeup = item->embargo; break; } @@ -645,16 +648,15 @@ struct curlFileTransfer : public FileTransfer { auto state(state_.lock()); - while (!state->incoming.empty()) state->incoming.pop(); + while (!state->incoming.empty()) + state->incoming.pop(); state->quit = true; } } void enqueueItem(std::shared_ptr item) { - if (item->request.data - && !hasPrefix(item->request.uri, "http://") - && !hasPrefix(item->request.uri, "https://")) + if (item->request.data && !hasPrefix(item->request.uri, "http://") && !hasPrefix(item->request.uri, "https://")) throw nix::Error("uploading to '%s' is not supported", item->request.uri); { @@ -672,8 +674,8 @@ struct curlFileTransfer : public FileTransfer auto [path, params] = splitUriAndParams(uri); auto slash = path.find('/', 5); // 5 is the length of "s3://" prefix - if (slash == std::string::npos) - throw nix::Error("bad S3 URI '%s'", path); + if (slash == std::string::npos) + throw nix::Error("bad S3 URI '%s'", path); std::string bucketName(path, 5, slash - 5); std::string key(path, slash + 1); @@ -682,8 +684,7 @@ struct curlFileTransfer : public FileTransfer } #endif - void enqueueFileTransfer(const FileTransferRequest & request, - Callback callback) override + void enqueueFileTransfer(const FileTransferRequest & request, Callback callback) override { /* Ugly hack to support s3:// URIs. */ if (hasPrefix(request.uri, "s3://")) { @@ -709,7 +710,9 @@ struct curlFileTransfer : public FileTransfer #else throw nix::Error("cannot download '%s' because Nix is not built with S3 support", request.uri); #endif - } catch (...) { callback.rethrow(); } + } catch (...) { + callback.rethrow(); + } return; } @@ -740,14 +743,13 @@ ref makeFileTransfer() std::future FileTransfer::enqueueFileTransfer(const FileTransferRequest & request) { auto promise = std::make_shared>(); - enqueueFileTransfer(request, - {[promise](std::future fut) { - try { - promise->set_value(fut.get()); - } catch (...) { - promise->set_exception(std::current_exception()); - } - }}); + enqueueFileTransfer(request, {[promise](std::future fut) { + try { + promise->set_value(fut.get()); + } catch (...) { + promise->set_exception(std::current_exception()); + } + }}); return promise->get_future(); } @@ -772,7 +774,8 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink) Therefore we use a buffer to communicate data between the download thread and the calling thread. */ - struct State { + struct State + { bool quit = false; std::exception_ptr exc; std::string data; @@ -790,10 +793,10 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink) }); request.dataCallback = [_state](std::string_view data) { - auto state(_state->lock()); - if (state->quit) return; + if (state->quit) + return; /* If the buffer is full, then go to sleep until the calling thread wakes us up (i.e. when it has removed data from the @@ -811,18 +814,17 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink) state->avail.notify_one(); }; - enqueueFileTransfer(request, - {[_state](std::future fut) { - auto state(_state->lock()); - state->quit = true; - try { - fut.get(); - } catch (...) { - state->exc = std::current_exception(); - } - state->avail.notify_one(); - state->request.notify_one(); - }}); + enqueueFileTransfer(request, {[_state](std::future fut) { + auto state(_state->lock()); + state->quit = true; + try { + fut.get(); + } catch (...) { + state->exc = std::current_exception(); + } + state->avail.notify_one(); + state->request.notify_one(); + }}); while (true) { checkInterrupt(); @@ -837,7 +839,8 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink) while (state->data.empty()) { if (state->quit) { - if (state->exc) std::rethrow_exception(state->exc); + if (state->exc) + std::rethrow_exception(state->exc); return; } @@ -858,8 +861,11 @@ void FileTransfer::download(FileTransferRequest && request, Sink & sink) } template -FileTransferError::FileTransferError(FileTransfer::Error error, std::optional response, const Args & ... args) - : Error(args...), error(error), response(response) +FileTransferError::FileTransferError( + FileTransfer::Error error, std::optional response, const Args &... args) + : Error(args...) + , error(error) + , response(response) { const auto hf = hintfmt(args...); // FIXME: Due to https://github.com/NixOS/nix/issues/3841 we don't know how @@ -873,12 +879,14 @@ FileTransferError::FileTransferError(FileTransfer::Error error, std::optional enableHttp2{this, true, "http2", - "Whether to enable HTTP/2 support."}; + Setting enableHttp2{this, true, "http2", "Whether to enable HTTP/2 support."}; - Setting userAgentSuffix{this, "", "user-agent-suffix", - "String appended to the user agent in HTTP requests."}; + Setting userAgentSuffix{ + this, "", "user-agent-suffix", "String appended to the user agent in HTTP requests."}; Setting httpConnections{ - this, 25, "http-connections", + this, + 25, + "http-connections", R"( The maximum number of parallel TCP connections used to fetch files from binary caches and by other downloads. It defaults @@ -42,8 +43,8 @@ struct FileTransferSettings : Config timeout's duration. )"}; - Setting tries{this, 5, "download-attempts", - "How often Nix will attempt to download a file before giving up."}; + Setting tries{ + this, 5, "download-attempts", "How often Nix will attempt to download a file before giving up."}; }; extern FileTransferSettings fileTransferSettings; @@ -64,7 +65,9 @@ struct FileTransferRequest std::function dataCallback; FileTransferRequest(std::string_view uri) - : uri(uri), parentAct(getCurActivity()) { } + : uri(uri) + , parentAct(getCurActivity()) + {} std::string verb() { @@ -85,13 +88,12 @@ class Store; struct FileTransfer { - virtual ~FileTransfer() { } + virtual ~FileTransfer() {} /* Enqueue a data transfer request, returning a future to the result of the download. The future may throw a FileTransferError exception. */ - virtual void enqueueFileTransfer(const FileTransferRequest & request, - Callback callback) = 0; + virtual void enqueueFileTransfer(const FileTransferRequest & request, Callback callback) = 0; std::future enqueueFileTransfer(const FileTransferRequest & request); @@ -122,7 +124,7 @@ public: std::optional response; // intentionally optional template - FileTransferError(FileTransfer::Error error, std::optional response, const Args & ... args); + FileTransferError(FileTransfer::Error error, std::optional response, const Args &... args); }; bool isUri(std::string_view s); diff --git a/src/libstore/fs-accessor.hh b/src/libstore/fs-accessor.hh index c825e84f2d70..bf1d84356979 100644 --- a/src/libstore/fs-accessor.hh +++ b/src/libstore/fs-accessor.hh @@ -14,12 +14,12 @@ public: struct Stat { Type type = tMissing; - uint64_t fileSize = 0; // regular files only + uint64_t fileSize = 0; // regular files only bool isExecutable = false; // regular files only - uint64_t narOffset = 0; // regular files only + uint64_t narOffset = 0; // regular files only }; - virtual ~FSAccessor() { } + virtual ~FSAccessor() {} virtual Stat stat(const Path & path) = 0; diff --git a/src/libstore/gc-store.hh b/src/libstore/gc-store.hh index b3cbbad74472..d879b1104126 100644 --- a/src/libstore/gc-store.hh +++ b/src/libstore/gc-store.hh @@ -2,13 +2,10 @@ #include "store-api.hh" - namespace nix { - typedef std::unordered_map> Roots; - struct GCOptions { /* Garbage collector operation: @@ -46,7 +43,6 @@ struct GCOptions uint64_t maxFreed{std::numeric_limits::max()}; }; - struct GCResults { /* Depending on the action, the GC roots, or the paths that would @@ -58,7 +54,6 @@ struct GCResults uint64_t bytesFreed = 0; }; - struct GcStore : public virtual Store { inline static std::string operationName = "Garbage collection"; diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index d58ed78b149a..67f7b3a5bf84 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -23,28 +23,23 @@ namespace nix { - static std::string gcSocketPath = "/gc-socket/socket"; static std::string gcRootsDir = "gcroots"; - static void makeSymlink(const Path & link, const Path & target) { /* Create directories up to `gcRoot'. */ createDirs(dirOf(link)); /* Create the new symlink. */ - Path tempLink = (format("%1%.tmp-%2%-%3%") - % link % getpid() % random()).str(); + Path tempLink = (format("%1%.tmp-%2%-%3%") % link % getpid() % random()).str(); createSymlink(target, tempLink); /* Atomically replace the old one. */ if (rename(tempLink.c_str(), link.c_str()) == -1) - throw SysError("cannot rename '%1%' to '%2%'", - tempLink , link); + throw SysError("cannot rename '%1%' to '%2%'", tempLink, link); } - void LocalStore::addIndirectRoot(const Path & path) { std::string hash = hashString(htSHA1, path).to_string(Base32, false); @@ -52,15 +47,15 @@ void LocalStore::addIndirectRoot(const Path & path) makeSymlink(realRoot, path); } - Path LocalFSStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot) { Path gcRoot(canonPath(_gcRoot)); if (isInStore(gcRoot)) throw Error( - "creating a garbage collector root (%1%) in the Nix store is forbidden " - "(are you running nix-build inside the store?)", gcRoot); + "creating a garbage collector root (%1%) in the Nix store is forbidden " + "(are you running nix-build inside the store?)", + gcRoot); /* Register this root with the garbage collector, if it's running. This should be superfluous since the caller should @@ -78,7 +73,6 @@ Path LocalFSStore::addPermRoot(const StorePath & storePath, const Path & _gcRoot return gcRoot; } - void LocalStore::addTempRoot(const StorePath & path) { auto state(_state.lock()); @@ -102,19 +96,19 @@ void LocalStore::addTempRoot(const StorePath & path) struct stat st; if (fstat(state->fdTempRoots.get(), &st) == -1) throw SysError("statting '%1%'", fnTempRoots); - if (st.st_size == 0) break; + if (st.st_size == 0) + break; /* The garbage collector deleted this file before we could get a lock. (It won't delete the file after we get a lock.) Try again. */ } - } if (!state->fdGCLock) state->fdGCLock = openGCLock(); - restart: +restart: FdLock gcLock(state->fdGCLock.get(), ltRead, false, ""); if (!gcLock.acquired) { @@ -167,10 +161,8 @@ void LocalStore::addTempRoot(const StorePath & path) writeFull(state->fdTempRoots.get(), s); } - static std::string censored = "{censored}"; - void LocalStore::findTempRoots(Roots & tempRoots, bool censor) { /* Read the `temproots' directory for per-process temporary root @@ -189,7 +181,8 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) AutoCloseFD fd(open(path.c_str(), O_CLOEXEC | O_RDWR, 0666)); if (!fd) { /* It's okay if the file has disappeared. */ - if (errno == ENOENT) continue; + if (errno == ENOENT) + continue; throw SysError("opening temporary roots file '%1%'", path); } @@ -218,7 +211,6 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) } } - void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) { auto foundRoot = [&](const Path & path, const Path & target) { @@ -228,7 +220,8 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) roots[std::move(storePath)].emplace(path); else printInfo("skipping invalid root from '%1%' to '%2%'", path, target); - } catch (BadStorePath &) { } + } catch (BadStorePath &) { + } }; try { @@ -256,9 +249,11 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) } } else { struct stat st2 = lstat(target); - if (!S_ISLNK(st2.st_mode)) return; + if (!S_ISLNK(st2.st_mode)) + return; Path target2 = readLink(target); - if (isInStore(target2)) foundRoot(target, target2); + if (isInStore(target2)) + foundRoot(target, target2); } } } @@ -280,7 +275,6 @@ void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) } } - void LocalStore::findRootsNoTemp(Roots & roots, bool censor) { /* Process direct roots in {gcroots,profiles}. */ @@ -293,7 +287,6 @@ void LocalStore::findRootsNoTemp(Roots & roots, bool censor) findRuntimeRoots(roots, censor); } - Roots LocalStore::findRoots(bool censor) { Roots roots; @@ -325,8 +318,7 @@ static void readProcLink(const std::string & file, UncheckedRoots & roots) goto try_again; } if (res > 0 && buf[0] == '/') - roots[std::string(static_cast(buf), res)] - .emplace(file); + roots[std::string(static_cast(buf), res)].emplace(file); } static std::string quoteRegexChars(const std::string & raw) @@ -360,7 +352,7 @@ 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/exe", ent->d_name), unchecked); readProcLink(fmt("/proc/%s/cwd", ent->d_name), unchecked); auto fdStr = fmt("/proc/%s/fd", ent->d_name); @@ -394,7 +386,8 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor) auto envFile = fmt("/proc/%s/environ", ent->d_name); auto envString = readFile(envFile); auto env_end = std::sregex_iterator{}; - for (auto i = std::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; i != env_end; ++i) + for (auto i = std::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; + i != env_end; ++i) unchecked[i->str()].emplace(envFile); } catch (SysError & e) { if (errno == ENOENT || errno == EACCES || errno == ESRCH) @@ -415,7 +408,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor) try { std::regex lsofRegex(R"(^n(/.*)$)"); auto lsofLines = - tokenizeString>(runProgram(LSOF, true, { "-n", "-w", "-F", "n" }), "\n"); + tokenizeString>(runProgram(LSOF, true, {"-n", "-w", "-F", "n"}), "\n"); for (const auto & line : lsofLines) { std::smatch match; if (std::regex_match(line, match, lsofRegex)) @@ -434,22 +427,24 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor) #endif for (auto & [target, links] : unchecked) { - if (!isInStore(target)) continue; + if (!isInStore(target)) + continue; try { auto path = toStorePath(target).first; - if (!isValidPath(path)) continue; + if (!isValidPath(path)) + continue; debug("got additional root '%1%'", printStorePath(path)); if (censor) roots[path].insert(censored); else roots[path].insert(links.begin(), links.end()); - } catch (BadStorePath &) { } + } catch (BadStorePath &) { + } } } - -struct GCLimitReached { }; - +struct GCLimitReached +{}; void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) { @@ -510,7 +505,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) debug("GC roots server shutting down"); while (true) { auto item = remove_begin(*connections.lock()); - if (!item) break; + if (!item) + break; auto & [fd, thread] = *item; shutdown(fd, SHUT_RDWR); thread.join(); @@ -532,7 +528,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) /* Accept a new connection. */ assert(fds[1].revents & POLLIN); AutoCloseFD fdClient = accept(fdServer.get(), nullptr, nullptr); - if (!fdClient) continue; + if (!fdClient) + continue; debug("GC roots server accepted new client"); @@ -593,7 +590,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) Finally stopServer([&]() { writeFull(shutdownPipe.writeSide.get(), "x", false); wakeup.notify_all(); - if (serverThread.joinable()) serverThread.join(); + if (serverThread.joinable()) + serverThread.join(); }); /* Find the roots. Since we've grabbed the GC lock, the set of @@ -603,7 +601,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) if (!options.ignoreLiveness) findRootsNoTemp(rootMap, true); - for (auto & i : rootMap) roots.insert(i.first); + for (auto & i : rootMap) + roots.insert(i.first); /* Read the temporary roots created before we acquired the global GC root. Any new roots will be sent to our socket. */ @@ -616,8 +615,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) /* Helper function that deletes a path from the store and throws GCLimitReached if we've deleted enough garbage. */ - auto deleteFromStore = [&](std::string_view baseName) - { + auto deleteFromStore = [&](std::string_view baseName) { Path path = storeDir + "/" + std::string(baseName); Path realPath = realStoreDir + "/" + std::string(baseName); @@ -672,19 +670,21 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) /* If we've previously deleted this path, we don't have to handle it again. */ - if (dead.count(*path)) continue; + if (dead.count(*path)) + continue; - auto markAlive = [&]() - { + auto markAlive = [&]() { alive.insert(*path); alive.insert(start); try { StorePathSet closure; - computeFSClosure(*path, closure, + computeFSClosure( + *path, closure, /* flipDirection */ false, gcKeepOutputs, gcKeepDerivations); for (auto & p : closure) alive.insert(p); - } catch (InvalidPath &) { } + } catch (InvalidPath &) { + } }; /* If this is a root, bail out. */ @@ -693,8 +693,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) return markAlive(); } - if (options.action == GCOptions::gcDeleteSpecific - && !options.pathsToDelete.count(*path)) + if (options.action == GCOptions::gcDeleteSpecific && !options.pathsToDelete.count(*path)) return; { @@ -724,9 +723,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) derivation, then visit the derivation outputs. */ if (gcKeepDerivations && path->isDerivation()) { for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(*path)) - if (maybeOutPath && - isValidPath(*maybeOutPath) && - queryPathInfo(*maybeOutPath)->deriver == *path) + if (maybeOutPath && isValidPath(*maybeOutPath) + && queryPathInfo(*maybeOutPath)->deriver == *path) enqueue(*maybeOutPath); } @@ -740,7 +738,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) } for (auto & path : topoSortPaths(visited)) { - if (!dead.insert(path).second) continue; + if (!dead.insert(path).second) + continue; if (shouldDelete) { invalidatePathChecked(path); deleteFromStore(path.to_string()); @@ -776,7 +775,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) try { AutoCloseDir dir(opendir(realStoreDir.get().c_str())); - if (!dir) throw SysError("opening directory '%1%'", realStoreDir); + if (!dir) + throw SysError("opening directory '%1%'", realStoreDir); /* Read the store and delete all paths that are invalid or unreachable. We don't use readDirectory() here so that @@ -787,13 +787,13 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) while (errno = 0, dirent = readdir(dir.get())) { checkInterrupt(); std::string name = dirent->d_name; - if (name == "." || name == ".." || name == linksName) continue; + if (name == "." || name == ".." || name == linksName) + continue; if (auto storePath = maybeParseStorePath(storeDir + "/" + name)) deleteReferrersClosure(*storePath); else deleteFromStore(name); - } } catch (GCLimitReached & e) { } @@ -820,7 +820,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) printInfo("deleting unused links..."); AutoCloseDir dir(opendir(linksDir.c_str())); - if (!dir) throw SysError("opening directory '%1%'", linksDir); + if (!dir) + throw SysError("opening directory '%1%'", linksDir); int64_t actualSize = 0, unsharedSize = 0; @@ -828,7 +829,8 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) while (errno = 0, dirent = readdir(dir.get())) { checkInterrupt(); std::string name = dirent->d_name; - if (name == "." || name == "..") continue; + if (name == "." || name == "..") + continue; Path path = linksDir + "/" + name; auto st = lstat(path); @@ -853,15 +855,15 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) throw SysError("statting '%1%'", linksDir); int64_t overhead = st.st_blocks * 512ULL; - printInfo("note: currently hard linking saves %.2f MiB", + printInfo( + "note: currently hard linking saves %.2f MiB", ((unsharedSize - actualSize - overhead) / (1024.0 * 1024.0))); } /* While we're at it, vacuum the database. */ - //if (options.action == GCOptions::gcDeleteDead) vacuumDB(); + // if (options.action == GCOptions::gcDeleteDead) vacuumDB(); } - void LocalStore::autoGC(bool sync) { static auto fakeFreeSpaceFile = getEnv("_NIX_TEST_FREE_SPACE_FILE"); @@ -890,15 +892,18 @@ void LocalStore::autoGC(bool sync) auto now = std::chrono::steady_clock::now(); - if (now < state->lastGCCheck + std::chrono::seconds(settings.minFreeCheckInterval)) return; + if (now < state->lastGCCheck + std::chrono::seconds(settings.minFreeCheckInterval)) + return; auto avail = getAvail(); state->lastGCCheck = now; - if (avail >= settings.minFree || avail >= settings.maxFree) return; + if (avail >= settings.minFree || avail >= settings.maxFree) + return; - if (avail > state->availAfterGC * 0.97) return; + if (avail > state->availAfterGC * 0.97) + return; state->gcRunning = true; @@ -906,7 +911,6 @@ void LocalStore::autoGC(bool sync) future = state->gcFuture = promise.get_future().share(); std::thread([promise{std::move(promise)}, this, avail, getAvail]() mutable { - try { /* Wake up any threads waiting for the auto-GC to finish. */ @@ -933,14 +937,13 @@ void LocalStore::autoGC(bool sync) // future, but we don't really care. ignoreException(); } - }).detach(); } - sync: +sync: // Wait for the future outside of the state lock. - if (sync) future.get(); + if (sync) + future.get(); } - } diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 0f2ca4b15cad..f9d9cfd39e7e 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -13,10 +13,8 @@ #include - namespace nix { - /* The default location of the daemon socket, relative to nixStateDir. The socket is in a directory to allow you to control access to the Nix daemon by setting the mode/ownership of the directory @@ -46,7 +44,8 @@ Settings::Settings() caFile = getEnv("NIX_SSL_CERT_FILE").value_or(getEnv("SSL_CERT_FILE").value_or("")); if (caFile == "") { - for (auto & fn : {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"}) + for (auto & fn : + {"/etc/ssl/certs/ca-certificates.crt", "/nix/var/nix/profiles/default/etc/ssl/certs/ca-bundle.crt"}) if (pathExists(fn)) { caFile = fn; break; @@ -68,7 +67,8 @@ Settings::Settings() /* chroot-like behavior from Apple's sandbox */ #if __APPLE__ - sandboxPaths = tokenizeString("/System/Library/Frameworks /System/Library/PrivateFrameworks /bin/sh /bin/bash /private/tmp /private/var/tmp /usr/lib"); + sandboxPaths = tokenizeString( + "/System/Library/Frameworks /System/Library/PrivateFrameworks /bin/sh /bin/bash /private/tmp /private/var/tmp /usr/lib"); allowedImpureHostPrefixes = tokenizeString("/System/Library /usr/lib /dev /bin/sh"); #endif @@ -92,7 +92,6 @@ void loadConfFile() if (nixConfEnv.has_value()) { globalConfig.applyConfig(nixConfEnv.value(), "NIX_CONFIG"); } - } std::vector getUserConfigFiles() @@ -124,10 +123,10 @@ StringSet Settings::getDefaultSystemFeatures() actually require anything special on the machines. */ StringSet features{"nixos-test", "benchmark", "big-parallel"}; - #if __linux__ +#if __linux__ if (access("/dev/kvm", R_OK | W_OK) == 0) features.insert("kvm"); - #endif +#endif return features; } @@ -148,8 +147,8 @@ 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 (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") @@ -183,58 +182,67 @@ bool Settings::isWSL1() const std::string nixVersion = PACKAGE_VERSION; -NLOHMANN_JSON_SERIALIZE_ENUM(SandboxMode, { - {SandboxMode::smEnabled, true}, - {SandboxMode::smRelaxed, "relaxed"}, - {SandboxMode::smDisabled, false}, -}); +NLOHMANN_JSON_SERIALIZE_ENUM( + SandboxMode, + { + {SandboxMode::smEnabled, true}, + {SandboxMode::smRelaxed, "relaxed"}, + {SandboxMode::smDisabled, false}, + }); -template<> void BaseSetting::set(const std::string & str, bool append) +template<> +void BaseSetting::set(const std::string & str, bool append) { - if (str == "true") value = smEnabled; - else if (str == "relaxed") value = smRelaxed; - else if (str == "false") value = smDisabled; - else throw UsageError("option '%s' has invalid value '%s'", name, str); + if (str == "true") + value = smEnabled; + else if (str == "relaxed") + value = smRelaxed; + else if (str == "false") + value = smDisabled; + else + throw UsageError("option '%s' has invalid value '%s'", name, str); } -template<> bool BaseSetting::isAppendable() +template<> +bool BaseSetting::isAppendable() { return false; } -template<> std::string BaseSetting::to_string() const +template<> +std::string BaseSetting::to_string() const { - if (value == smEnabled) return "true"; - else if (value == smRelaxed) return "relaxed"; - else if (value == smDisabled) return "false"; - else abort(); + if (value == smEnabled) + return "true"; + else if (value == smRelaxed) + return "relaxed"; + else if (value == smDisabled) + return "false"; + else + abort(); } -template<> void BaseSetting::convertToArg(Args & args, const std::string & category) +template<> +void BaseSetting::convertToArg(Args & args, const std::string & category) { - args.addFlag({ - .longName = name, - .description = "Enable sandboxing.", - .category = category, - .handler = {[=]() { override(smEnabled); }} - }); - args.addFlag({ - .longName = "no-" + name, - .description = "Disable sandboxing.", - .category = category, - .handler = {[=]() { override(smDisabled); }} - }); - args.addFlag({ - .longName = "relaxed-" + name, - .description = "Enable sandboxing, but allow builds to disable it.", - .category = category, - .handler = {[=]() { override(smRelaxed); }} - }); + args.addFlag({.longName = name, .description = "Enable sandboxing.", .category = category, .handler = {[=]() { + override(smEnabled); + }}}); + args.addFlag( + {.longName = "no-" + name, .description = "Disable sandboxing.", .category = category, .handler = {[=]() { + override(smDisabled); + }}}); + args.addFlag( + {.longName = "relaxed-" + name, + .description = "Enable sandboxing, but allow builds to disable it.", + .category = category, + .handler = {[=]() { override(smRelaxed); }}}); } void MaxBuildJobsSetting::set(const std::string & str, bool append) { - if (str == "auto") value = std::max(1U, std::thread::hardware_concurrency()); + if (str == "auto") + value = std::max(1U, std::thread::hardware_concurrency()); else { if (auto n = string2Int(str)) value = *n; @@ -243,15 +251,14 @@ void MaxBuildJobsSetting::set(const std::string & str, bool append) } } - void PluginFilesSetting::set(const std::string & str, bool append) { if (pluginsLoaded) - throw UsageError("plugin-files set after plugins were loaded, you may need to move the flag before the subcommand"); + throw UsageError( + "plugin-files set after plugins were loaded, you may need to move the flag before the subcommand"); BaseSetting::set(str, append); } - void initPlugins() { assert(!settings.pluginFiles.pluginsLoaded); @@ -269,8 +276,7 @@ void initPlugins() for (const auto & file : pluginFiles) { /* handle is purposefully leaked as there may be state in the DSO needed by the action of the plugin. */ - void *handle = - dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL); + void * handle = dlopen(file.c_str(), RTLD_LAZY | RTLD_LOCAL); if (!handle) throw Error("could not dynamically open plugin file '%s': %s", file, dlerror()); } diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index d7f351166ad7..6f8101f3c3ca 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -16,7 +16,8 @@ typedef enum { smEnabled, smRelaxed, smDisabled } SandboxMode; struct MaxBuildJobsSetting : public BaseSetting { - MaxBuildJobsSetting(Config * options, + MaxBuildJobsSetting( + Config * options, unsigned int def, const std::string & name, const std::string & description, @@ -33,7 +34,8 @@ struct PluginFilesSetting : public BaseSetting { bool pluginsLoaded = false; - PluginFilesSetting(Config * options, + PluginFilesSetting( + Config * options, const Paths & def, const std::string & name, const std::string & description, @@ -46,7 +48,8 @@ struct PluginFilesSetting : public BaseSetting void set(const std::string & str, bool append = false) override; }; -class Settings : public Config { +class Settings : public Config +{ unsigned int getDefaultCores(); @@ -88,17 +91,18 @@ public: /* File name of the socket the daemon listens to. */ Path nixDaemonSocketFile; - Setting storeUri{this, getEnv("NIX_REMOTE").value_or("auto"), "store", - "The default Nix store to use."}; + Setting storeUri{ + this, getEnv("NIX_REMOTE").value_or("auto"), "store", "The default Nix store to use."}; - Setting keepFailed{this, false, "keep-failed", - "Whether to keep temporary directories of failed builds."}; + Setting keepFailed{this, false, "keep-failed", "Whether to keep temporary directories of failed builds."}; - Setting keepGoing{this, false, "keep-going", - "Whether to keep building derivations when another build fails."}; + Setting keepGoing{ + this, false, "keep-going", "Whether to keep building derivations when another build fails."}; Setting tryFallback{ - this, false, "fallback", + this, + false, + "fallback", R"( If set to `true`, Nix will fall back to building from source if a binary substitute fails. This is equivalent to the `--fallback` @@ -109,12 +113,15 @@ public: /* Whether to show build log output in real time. */ bool verboseBuild = true; - Setting logLines{this, 10, "log-lines", + Setting logLines{ + this, 10, "log-lines", "The number of lines of the tail of " "the log to show if a build fails."}; MaxBuildJobsSetting maxBuildJobs{ - this, 1, "max-jobs", + this, + 1, + "max-jobs", R"( This option defines the maximum number of jobs that Nix will try to build in parallel. The default is `1`. The special value `auto` @@ -126,11 +133,8 @@ public: )", {"build-max-jobs"}}; - Setting buildCores{ - this, - getDefaultCores(), - "cores", - R"( + Setting buildCores{this, getDefaultCores(), "cores", + R"( Sets the value of the `NIX_BUILD_CORES` environment variable in the invocation of builders. Builders can use this variable at their discretion to control the maximum amount of parallelism. For @@ -139,8 +143,7 @@ public: `-jN` flag to GNU Make. It can be overridden using the `--cores` command line switch and defaults to `1`. The value `0` means that the builder should use all available CPU cores in the system. - )", - {"build-cores"}, false}; + )", {"build-cores"}, false}; /* Read-only mode. Don't copy stuff to the store, don't change the database. */ @@ -164,7 +167,9 @@ public: )"}; Setting maxSilentTime{ - this, 0, "max-silent-time", + this, + 0, + "max-silent-time", R"( This option defines the maximum number of seconds that a builder can go without producing any data on standard output or standard error. @@ -179,7 +184,9 @@ public: {"build-max-silent-time"}}; Setting buildTimeout{ - this, 0, "timeout", + this, + 0, + "timeout", R"( This option defines the maximum number of seconds that a builder can run. This is useful (for instance in an automated build system) to @@ -192,8 +199,8 @@ public: )", {"build-timeout"}}; - PathSetting buildHook{this, true, "", "build-hook", - "The path of the helper program that executes builds to remote machines."}; + PathSetting buildHook{ + this, true, "", "build-hook", "The path of the helper program that executes builds to remote machines."}; Setting builders{ this, "@" + nixConfDir + "/machines", "builders", @@ -214,8 +221,8 @@ public: this computer and the remote build host is slow. )"}; - Setting reservedSize{this, 8 * 1024 * 1024, "gc-reserved-space", - "Amount of reserved disk space for the garbage collector."}; + Setting reservedSize{ + this, 8 * 1024 * 1024, "gc-reserved-space", "Amount of reserved disk space for the garbage collector."}; Setting fsyncMetadata{ this, true, "fsync-metadata", @@ -226,14 +233,15 @@ public: default is `true`. )"}; - Setting useSQLiteWAL{this, !isWSL1(), "use-sqlite-wal", - "Whether SQLite should use WAL mode."}; + Setting useSQLiteWAL{this, !isWSL1(), "use-sqlite-wal", "Whether SQLite should use WAL mode."}; - Setting syncBeforeRegistering{this, false, "sync-before-registering", - "Whether to call `sync()` before registering a path as valid."}; + Setting syncBeforeRegistering{ + this, false, "sync-before-registering", "Whether to call `sync()` before registering a path as valid."}; Setting useSubstitutes{ - this, true, "substitute", + this, + true, + "substitute", R"( If set to `true` (default), Nix will use binary substitutes if available. This option can be disabled to force building from @@ -275,12 +283,17 @@ public: multi-user settings with untrusted users. )"}; - Setting impersonateLinux26{this, false, "impersonate-linux-26", + Setting impersonateLinux26{ + this, + false, + "impersonate-linux-26", "Whether to impersonate a Linux 2.6 machine on newer kernels.", {"build-impersonate-linux-26"}}; Setting keepLog{ - this, true, "keep-build-log", + this, + true, + "keep-build-log", R"( If set to `true` (the default), Nix will write the build log of a derivation (i.e. the standard output and error of its builder) to @@ -290,7 +303,9 @@ public: {"build-keep-log"}}; Setting compressLog{ - this, true, "compress-build-log", + this, + true, + "compress-build-log", R"( If set to `true` (the default), build logs written to `/nix/var/log/nix/drvs` will be compressed on the fly using bzip2. @@ -299,7 +314,9 @@ public: {"build-compress-log"}}; Setting maxLogSize{ - this, 0, "max-build-log-size", + this, + 0, + "max-build-log-size", R"( This option defines the maximum number of bytes that a builder can write to its stdout/stderr. If the builder exceeds this limit, it’s @@ -312,11 +329,12 @@ public: stderr. Hack to prevent Hydra logs from being polluted. */ bool printRepeatedBuilds = true; - Setting pollInterval{this, 5, "build-poll-interval", - "How often (in seconds) to poll for locks."}; + Setting pollInterval{this, 5, "build-poll-interval", "How often (in seconds) to poll for locks."}; Setting gcKeepOutputs{ - this, false, "keep-outputs", + this, + false, + "keep-outputs", R"( If `true`, the garbage collector will keep the outputs of non-garbage derivations. If `false` (default), outputs will be @@ -332,7 +350,9 @@ public: {"gc-keep-outputs"}}; Setting gcKeepDerivations{ - this, true, "keep-derivations", + this, + true, + "keep-derivations", R"( If `true` (default), the garbage collector will keep the derivations from which non-garbage store paths were built. If `false`, they will @@ -358,7 +378,9 @@ public: )"}; Setting envKeepDerivations{ - this, false, "keep-env-derivations", + this, + false, + "keep-env-derivations", R"( If `false` (default), derivations are not stored in Nix user environments. That is, the derivations of any build-time-only @@ -381,15 +403,17 @@ public: /* Whether to lock the Nix client and worker to the same CPU. */ bool lockCPU; - Setting sandboxMode{ + Setting sandboxMode + { this, - #if __linux__ - smEnabled - #else - smDisabled - #endif - , "sandbox", - R"( +#if __linux__ + smEnabled +#else + smDisabled +#endif + , + "sandbox", + R"( If set to `true`, builds will be performed in a *sandboxed environment*, i.e., they’re isolated from the normal file system hierarchy and will only see their dependencies in the Nix store, @@ -414,10 +438,15 @@ public: The default is `true` on Linux and `false` on all other platforms. )", - {"build-use-chroot", "build-use-sandbox"}}; + { + "build-use-chroot", "build-use-sandbox" + } + }; Setting sandboxPaths{ - this, {}, "sandbox-paths", + this, + {}, + "sandbox-paths", R"( A list of paths bind-mounted into Nix sandbox environments. You can use the syntax `target=source` to mount a path in a different @@ -432,11 +461,13 @@ public: )", {"build-chroot-dirs", "build-sandbox-paths"}}; - Setting sandboxFallback{this, true, "sandbox-fallback", - "Whether to disable sandboxing when the kernel doesn't allow it."}; + Setting sandboxFallback{ + this, true, "sandbox-fallback", "Whether to disable sandboxing when the kernel doesn't allow it."}; Setting buildRepeat{ - this, 0, "repeat", + this, + 0, + "repeat", R"( How many times to repeat builds to check whether they are deterministic. The default value is 0. If the value is non-zero, @@ -458,15 +489,18 @@ public: is `50%`. )"}; - Setting sandboxBuildDir{this, "/build", "sandbox-build-dir", - "The build directory inside the sandbox."}; + Setting sandboxBuildDir{this, "/build", "sandbox-build-dir", "The build directory inside the sandbox."}; #endif - Setting allowedImpureHostPrefixes{this, {}, "allowed-impure-host-deps", + Setting allowedImpureHostPrefixes{ + this, + {}, + "allowed-impure-host-deps", "Which prefixes to allow derivations to ask for access to (primarily for Darwin)."}; #if __APPLE__ - Setting darwinLogSandboxViolations{this, false, "darwin-log-sandbox-violations", + Setting darwinLogSandboxViolations{ + this, false, "darwin-log-sandbox-violations", "Whether to log Darwin sandbox access violations to the system log."}; #endif @@ -529,7 +563,9 @@ public: {"binary-cache-public-keys"}}; Setting secretKeyFiles{ - this, {}, "secret-key-files", + this, + {}, + "secret-key-files", R"( A whitespace-separated list of files containing secret (private) keys. These are used to sign locally-built paths. They can be @@ -582,7 +618,9 @@ public: platform and generate incompatible code, so you may wish to cross-check the results of using this option against proper natively-built versions of your derivations. - )", {}, false}; + )", + {}, + false}; Setting systemFeatures{ this, @@ -602,7 +640,9 @@ public: This setting by default includes `kvm` if `/dev/kvm` is accessible, and the pseudo-features `nixos-test`, `benchmark` and `big-parallel` that are used in Nixpkgs to route builds to specific machines. - )", {}, false}; + )", + {}, + false}; Setting substituters{ this, @@ -617,7 +657,9 @@ public: {"binary-caches"}}; Setting trustedSubstituters{ - this, {}, "trusted-substituters", + this, + {}, + "trusted-substituters", R"( A list of URLs of substituters, separated by whitespace. These are not used by default, but can be enabled by users of the Nix daemon @@ -628,7 +670,9 @@ public: {"trusted-binary-caches"}}; Setting trustedUsers{ - this, {"root"}, "trusted-users", + this, + {"root"}, + "trusted-users", R"( A list of names of users (separated by whitespace) that have additional rights when connecting to the Nix daemon, such as the @@ -669,7 +713,9 @@ public: /* ?Who we trust to use the daemon in safe ways */ Setting allowedUsers{ - this, {"*"}, "allowed-users", + this, + {"*"}, + "allowed-users", R"( A list of names of users (separated by whitespace) that are allowed to connect to the Nix daemon. As with the `trusted-users` option, @@ -679,8 +725,8 @@ public: Note that trusted users are always allowed to connect. )"}; - Setting printMissing{this, true, "print-missing", - "Whether to print what paths need to be built or downloaded."}; + Setting printMissing{ + this, true, "print-missing", "Whether to print what paths need to be built or downloaded."}; Setting preBuildHook{ this, "", "pre-build-hook", @@ -799,7 +845,9 @@ public: )"}; Setting ignoredAcls{ - this, {"security.selinux", "system.nfs4_acl", "security.csm"}, "ignored-acls", + this, + {"security.selinux", "system.nfs4_acl", "security.csm"}, + "ignored-acls", R"( A list of ACLs that should be ignored, normally Nix attempts to remove all ACLs from files and directories in the Nix store, but @@ -809,7 +857,9 @@ public: #endif Setting hashedMirrors{ - this, {}, "hashed-mirrors", + this, + {}, + "hashed-mirrors", R"( A list of web servers used by `builtins.fetchurl` to obtain files by hash. The default is `http://tarballs.nixos.org/`. Given a hash type @@ -848,11 +898,13 @@ public: infinity (i.e. delete all garbage). )"}; - Setting minFreeCheckInterval{this, 5, "min-free-check-interval", - "Number of seconds between checking free disk space."}; + Setting minFreeCheckInterval{ + this, 5, "min-free-check-interval", "Number of seconds between checking free disk space."}; PluginFilesSetting pluginFiles{ - this, {}, "plugin-files", + this, + {}, + "plugin-files", R"( A list of plugin files to be loaded by Nix. Each of these files will be dlopened by Nix, allowing them to affect execution through static @@ -877,15 +929,15 @@ public: are loaded as plugins (non-recursively). )"}; - Setting> experimentalFeatures{this, {}, "experimental-features", - "Experimental Nix features to enable."}; + Setting> experimentalFeatures{ + this, {}, "experimental-features", "Experimental Nix features to enable."}; bool isExperimentalFeatureEnabled(const ExperimentalFeature &); void requireExperimentalFeature(const ExperimentalFeature &); - Setting narBufferSize{this, 32 * 1024 * 1024, "nar-buffer-size", - "Maximum size of NARs before spilling them to disk."}; + Setting narBufferSize{ + this, 32 * 1024 * 1024, "nar-buffer-size", "Maximum size of NARs before spilling them to disk."}; Setting allowSymlinkedStore{ this, false, "allow-symlinked-store", @@ -901,7 +953,6 @@ public: )"}; }; - // FIXME: don't use a global variable. extern Settings settings; diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc index 73bcd6e817da..da5f56b543e6 100644 --- a/src/libstore/http-binary-cache-store.cc +++ b/src/libstore/http-binary-cache-store.cc @@ -12,7 +12,10 @@ struct HttpBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig { using BinaryCacheStoreConfig::BinaryCacheStoreConfig; - const std::string name() override { return "Http Binary Cache Store"; } + const std::string name() override + { + return "Http Binary Cache Store"; + } }; class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public virtual BinaryCacheStore @@ -31,10 +34,7 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v public: - HttpBinaryCacheStore( - const std::string & scheme, - const Path & _cacheUri, - const Params & params) + HttpBinaryCacheStore(const std::string & scheme, const Path & _cacheUri, const Params & params) : StoreConfig(params) , BinaryCacheStoreConfig(params) , HttpBinaryCacheStoreConfig(params) @@ -73,7 +73,8 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v { static bool forceHttp = getEnv("_NIX_FORCE_HTTP") == "1"; auto ret = std::set({"http", "https"}); - if (forceHttp) ret.insert("file"); + if (forceHttp) + ret.insert("file"); return ret; } @@ -93,7 +94,8 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v void checkEnabled() { auto state(_state.lock()); - if (state->enabled) return; + if (state->enabled) + return; if (std::chrono::steady_clock::now() > state->disabledUntil) { state->enabled = true; debug("re-enabling binary cache '%s'", getUri()); @@ -121,7 +123,8 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v } } - void upsertFile(const std::string & path, + void upsertFile( + const std::string & path, std::shared_ptr> istream, const std::string & mimeType) override { @@ -139,9 +142,8 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v { return FileTransferRequest( hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://") - ? path - : cacheUri + "/" + path); - + ? path + : cacheUri + "/" + path); } void getFile(const std::string & path, Sink & sink) override @@ -158,8 +160,7 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v } } - void getFile(const std::string & path, - Callback> callback) noexcept override + void getFile(const std::string & path, Callback> callback) noexcept override { try { checkEnabled(); @@ -172,21 +173,20 @@ class HttpBinaryCacheStore : public virtual HttpBinaryCacheStoreConfig, public v auto callbackPtr = std::make_shared(std::move(callback)); - getFileTransfer()->enqueueFileTransfer(request, - {[callbackPtr, this](std::future result) { - try { - (*callbackPtr)(std::move(result.get().data)); - } catch (FileTransferError & e) { - if (e.error == FileTransfer::NotFound || e.error == FileTransfer::Forbidden) - return (*callbackPtr)({}); - maybeDisable(); - callbackPtr->rethrow(); - } catch (...) { - callbackPtr->rethrow(); - } - }}); + getFileTransfer()->enqueueFileTransfer(request, {[callbackPtr, this](std::future result) { + try { + (*callbackPtr)(std::move(result.get().data)); + } catch (FileTransferError & e) { + if (e.error == FileTransfer::NotFound + || e.error == FileTransfer::Forbidden) + return (*callbackPtr)({}); + maybeDisable(); + callbackPtr->rethrow(); + } catch (...) { + callbackPtr->rethrow(); + } + }}); } - }; static RegisterStoreImplementation regHttpBinaryCacheStore; diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc index dd34b19c6832..2c92466dabbe 100644 --- a/src/libstore/legacy-ssh-store.cc +++ b/src/libstore/legacy-ssh-store.cc @@ -15,14 +15,21 @@ namespace nix { struct LegacySSHStoreConfig : virtual StoreConfig { using StoreConfig::StoreConfig; - const Setting maxConnections{(StoreConfig*) this, 1, "max-connections", "maximum number of concurrent SSH connections"}; - const Setting sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"}; - const Setting sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"}; - const Setting compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"}; - const Setting remoteProgram{(StoreConfig*) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"}; - const Setting remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"}; - - const std::string name() override { return "Legacy SSH Store"; } + const Setting maxConnections{ + (StoreConfig *) this, 1, "max-connections", "maximum number of concurrent SSH connections"}; + const Setting sshKey{(StoreConfig *) this, "", "ssh-key", "path to an SSH private key"}; + const Setting sshPublicHostKey{ + (StoreConfig *) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"}; + const Setting compress{(StoreConfig *) this, false, "compress", "whether to compress the connection"}; + const Setting remoteProgram{ + (StoreConfig *) this, "nix-store", "remote-program", "path to the nix-store executable on the remote system"}; + const Setting remoteStore{ + (StoreConfig *) this, "", "remote-store", "URI of the store on the remote system"}; + + const std::string name() override + { + return "Legacy SSH Store"; + } }; struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Store @@ -30,7 +37,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor // Hack for getting remote build log output. // Intentionally not in `LegacySSHStoreConfig` so that it doesn't appear in // the documentation - const Setting logFD{(StoreConfig*) this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"}; + const Setting logFD{(StoreConfig *) this, -1, "log-fd", "file descriptor to which SSH's stderr is connected"}; struct Connection { @@ -47,7 +54,10 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor SSHMaster master; - static std::set uriSchemes() { return {"ssh"}; } + static std::set uriSchemes() + { + return {"ssh"}; + } LegacySSHStore(const std::string & scheme, const std::string & host, const Params & params) : StoreConfig(params) @@ -55,20 +65,18 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor , Store(params) , host(host) , connections(make_ref>( - std::max(1, (int) maxConnections), - [this]() { return openConnection(); }, - [](const ref & r) { return r->good; } - )) + std::max(1, (int) maxConnections), + [this]() { return openConnection(); }, + [](const ref & r) { return r->good; })) , master( - host, - sshKey, - sshPublicHostKey, - // Use SSH master only if using more than 1 connection. - connections->capacity() > 1, - compress, - logFD) - { - } + host, + sshKey, + sshPublicHostKey, + // Use SSH master only if using more than 1 connection. + connections->capacity() > 1, + compress, + logFD) + {} ref openConnection() { @@ -94,8 +102,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor close it. */ conn->sshConn->in.close(); auto msg = conn->from.drain(); - throw Error("'nix-store --serve' protocol mismatch from '%s', got '%s'", - host, chomp(saved.s + msg)); + throw Error("'nix-store --serve' protocol mismatch from '%s', got '%s'", host, chomp(saved.s + msg)); } conn->remoteVersion = readInt(conn->from); if (GET_PROTOCOL_MAJOR(conn->remoteVersion) != 0x200) @@ -113,8 +120,8 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor return *uriSchemes().begin() + "://" + host; } - void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept override + void queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept override { try { auto conn(connections->get()); @@ -128,7 +135,8 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor conn->to.flush(); auto p = readString(conn->from); - if (p.empty()) return callback(nullptr); + if (p.empty()) + return callback(nullptr); auto path2 = parseStorePath(p); assert(path == path2); /* Hash will be set below. FIXME construct ValidPathInfo at end. */ @@ -138,7 +146,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor auto deriver = readString(conn->from); if (deriver != "") info->deriver = parseStorePath(deriver); - info->references = worker_proto::read(*this, conn->from, Phantom {}); + info->references = worker_proto::read(*this, conn->from, Phantom{}); readLongLong(conn->from); // download size info->narSize = readLongLong(conn->from); @@ -155,11 +163,12 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor assert(s == ""); callback(std::move(info)); - } catch (...) { callback.rethrow(); } + } catch (...) { + callback.rethrow(); + } } - void addToStore(const ValidPathInfo & info, Source & source, - RepairFlag repair, CheckSigsFlag checkSigs) override + void addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override { debug("adding path '%s' to remote host '%s'", printStorePath(info.path), host); @@ -167,18 +176,11 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 5) { - conn->to - << cmdAddToStoreNar - << printStorePath(info.path) - << (info.deriver ? printStorePath(*info.deriver) : "") - << info.narHash.to_string(Base16, false); + conn->to << cmdAddToStoreNar << printStorePath(info.path) + << (info.deriver ? printStorePath(*info.deriver) : "") << info.narHash.to_string(Base16, false); worker_proto::write(*this, conn->to, info.references); - conn->to - << info.registrationTime - << info.narSize - << info.ultimate - << info.sigs - << renderContentAddress(info.ca); + conn->to << info.registrationTime << info.narSize << info.ultimate << info.sigs + << renderContentAddress(info.ca); try { copyNAR(source, conn->to); } catch (...) { @@ -189,25 +191,17 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor } else { - conn->to - << cmdImportPaths - << 1; + conn->to << cmdImportPaths << 1; try { copyNAR(source, conn->to); } catch (...) { conn->good = false; throw; } - conn->to - << exportMagic - << printStorePath(info.path); + conn->to << exportMagic << printStorePath(info.path); worker_proto::write(*this, conn->to, info.references); - conn->to - << (info.deriver ? printStorePath(*info.deriver) : "") - << 0 - << 0; + conn->to << (info.deriver ? printStorePath(*info.deriver) : "") << 0 << 0; conn->to.flush(); - } if (readInt(conn->from) != 1) @@ -224,7 +218,9 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor } std::optional queryPathFromHashPart(const std::string & hashPart) override - { unsupported("queryPathFromHashPart"); } + { + unsupported("queryPathFromHashPart"); + } StorePath addToStore( std::string_view name, @@ -234,29 +230,25 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor PathFilter & filter, RepairFlag repair, const StorePathSet & references) override - { unsupported("addToStore"); } + { + unsupported("addToStore"); + } StorePath addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) override - { unsupported("addTextToStore"); } + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) override + { + unsupported("addTextToStore"); + } private: void putBuildSettings(Connection & conn) { - conn.to - << settings.maxSilentTime - << settings.buildTimeout; + conn.to << settings.maxSilentTime << settings.buildTimeout; if (GET_PROTOCOL_MINOR(conn.remoteVersion) >= 2) - conn.to - << settings.maxLogSize; + conn.to << settings.maxLogSize; if (GET_PROTOCOL_MINOR(conn.remoteVersion) >= 3) - conn.to - << settings.buildRepeat - << settings.enforceDeterminism; + conn.to << settings.buildRepeat << settings.enforceDeterminism; if (GET_PROTOCOL_MINOR(conn.remoteVersion) >= 7) { conn.to << ((int) settings.keepFailed); @@ -265,33 +257,31 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor public: - BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, - BuildMode buildMode) override + BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode) override { auto conn(connections->get()); - conn->to - << cmdBuildDerivation - << printStorePath(drvPath); + conn->to << cmdBuildDerivation << printStorePath(drvPath); writeDerivation(conn->to, *this, drv); putBuildSettings(*conn); conn->to.flush(); - BuildResult status { .path = DerivedPath::Built { .drvPath = drvPath } }; + BuildResult status{.path = DerivedPath::Built{.drvPath = drvPath}}; status.status = (BuildResult::Status) readInt(conn->from); conn->from >> status.errorMsg; if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 3) conn->from >> status.timesBuilt >> status.isNonDeterministic >> status.startTime >> status.stopTime; if (GET_PROTOCOL_MINOR(conn->remoteVersion) >= 6) { - status.builtOutputs = worker_proto::read(*this, conn->from, Phantom {}); + status.builtOutputs = worker_proto::read(*this, conn->from, Phantom{}); } return status; } - void buildPaths(const std::vector & drvPaths, BuildMode buildMode, std::shared_ptr evalStore) override + void buildPaths( + const std::vector & drvPaths, BuildMode buildMode, std::shared_ptr evalStore) override { if (evalStore && evalStore.get() != this) throw Error("building on an SSH store is incompatible with '--eval-store'"); @@ -302,14 +292,16 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor Strings ss; for (auto & p : drvPaths) { auto sOrDrvPath = StorePathWithOutputs::tryFromDerivedPath(p); - std::visit(overloaded { - [&](const StorePathWithOutputs & s) { - ss.push_back(s.to_string(*this)); + std::visit( + overloaded{ + [&](const StorePathWithOutputs & s) { ss.push_back(s.to_string(*this)); }, + [&](const StorePath & drvPath) { + throw Error( + "wanted to fetch '%s' but the legacy ssh protocol doesn't support merely substituting drv files via the build paths command. It would build them instead. Try using ssh-ng://", + printStorePath(drvPath)); + }, }, - [&](const StorePath & drvPath) { - throw Error("wanted to fetch '%s' but the legacy ssh protocol doesn't support merely substituting drv files via the build paths command. It would build them instead. Try using ssh-ng://", printStorePath(drvPath)); - }, - }, sOrDrvPath); + sOrDrvPath); } conn->to << ss; @@ -317,7 +309,7 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor conn->to.flush(); - BuildResult result { .path = DerivedPath::Opaque { StorePath::dummy } }; + BuildResult result{.path = DerivedPath::Opaque{StorePath::dummy}}; result.status = (BuildResult::Status) readInt(conn->from); if (!result.success()) { @@ -327,11 +319,16 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor } void ensurePath(const StorePath & path) override - { unsupported("ensurePath"); } + { + unsupported("ensurePath"); + } - void computeFSClosure(const StorePathSet & paths, - StorePathSet & out, bool flipDirection = false, - bool includeOutputs = false, bool includeDerivers = false) override + void computeFSClosure( + const StorePathSet & paths, + StorePathSet & out, + bool flipDirection = false, + bool includeOutputs = false, + bool includeDerivers = false) override { if (flipDirection || includeDerivers) { Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers); @@ -340,29 +337,24 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor auto conn(connections->get()); - conn->to - << cmdQueryClosure - << includeOutputs; + conn->to << cmdQueryClosure << includeOutputs; worker_proto::write(*this, conn->to, paths); conn->to.flush(); - for (auto & i : worker_proto::read(*this, conn->from, Phantom {})) + for (auto & i : worker_proto::read(*this, conn->from, Phantom{})) out.insert(i); } - StorePathSet queryValidPaths(const StorePathSet & paths, - SubstituteFlag maybeSubstitute = NoSubstitute) override + StorePathSet queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute = NoSubstitute) override { auto conn(connections->get()); - conn->to - << cmdQueryValidPaths - << false // lock - << maybeSubstitute; + conn->to << cmdQueryValidPaths << false // lock + << maybeSubstitute; worker_proto::write(*this, conn->to, paths); conn->to.flush(); - return worker_proto::read(*this, conn->from, Phantom {}); + return worker_proto::read(*this, conn->from, Phantom{}); } void connect() override @@ -376,10 +368,12 @@ struct LegacySSHStore : public virtual LegacySSHStoreConfig, public virtual Stor return conn->remoteVersion; } - void queryRealisationUncached(const DrvOutput &, - Callback> callback) noexcept override + void + queryRealisationUncached(const DrvOutput &, Callback> callback) noexcept override // TODO: Implement - { unsupported("queryRealisation"); } + { + unsupported("queryRealisation"); + } }; static RegisterStoreImplementation regLegacySSHStore; diff --git a/src/libstore/local-binary-cache-store.cc b/src/libstore/local-binary-cache-store.cc index ba4416f6d8e3..56e3f6f2027e 100644 --- a/src/libstore/local-binary-cache-store.cc +++ b/src/libstore/local-binary-cache-store.cc @@ -10,7 +10,10 @@ struct LocalBinaryCacheStoreConfig : virtual BinaryCacheStoreConfig { using BinaryCacheStoreConfig::BinaryCacheStoreConfig; - const std::string name() override { return "Local Binary Cache Store"; } + const std::string name() override + { + return "Local Binary Cache Store"; + } }; class LocalBinaryCacheStore : public virtual LocalBinaryCacheStoreConfig, public virtual BinaryCacheStore @@ -21,18 +24,14 @@ class LocalBinaryCacheStore : public virtual LocalBinaryCacheStoreConfig, public public: - LocalBinaryCacheStore( - const std::string scheme, - const Path & binaryCacheDir, - const Params & params) + LocalBinaryCacheStore(const std::string scheme, const Path & binaryCacheDir, const Params & params) : StoreConfig(params) , BinaryCacheStoreConfig(params) , LocalBinaryCacheStoreConfig(params) , Store(params) , BinaryCacheStore(params) , binaryCacheDir(binaryCacheDir) - { - } + {} void init() override; @@ -47,7 +46,8 @@ class LocalBinaryCacheStore : public virtual LocalBinaryCacheStoreConfig, public bool fileExists(const std::string & path) override; - void upsertFile(const std::string & path, + void upsertFile( + const std::string & path, std::shared_ptr> istream, const std::string & mimeType) override { @@ -78,17 +78,14 @@ class LocalBinaryCacheStore : public virtual LocalBinaryCacheStoreConfig, public StorePathSet paths; for (auto & entry : readDirectory(binaryCacheDir)) { - if (entry.name.size() != 40 || - !hasSuffix(entry.name, ".narinfo")) + if (entry.name.size() != 40 || !hasSuffix(entry.name, ".narinfo")) continue; - paths.insert(parseStorePath( - storeDir + "/" + entry.name.substr(0, entry.name.size() - 8) - + "-" + MissingName)); + paths.insert( + parseStorePath(storeDir + "/" + entry.name.substr(0, entry.name.size() - 8) + "-" + MissingName)); } return paths; } - }; void LocalBinaryCacheStore::init() diff --git a/src/libstore/local-fs-store.cc b/src/libstore/local-fs-store.cc index c5ae7536f25f..325740e3a3c3 100644 --- a/src/libstore/local-fs-store.cc +++ b/src/libstore/local-fs-store.cc @@ -10,14 +10,15 @@ namespace nix { LocalFSStore::LocalFSStore(const Params & params) : Store(params) -{ -} +{} struct LocalStoreAccessor : public FSAccessor { ref store; - LocalStoreAccessor(ref store) : store(store) { } + LocalStoreAccessor(ref store) + : store(store) + {} Path toRealPath(const Path & path, bool requireValidPath = true) { @@ -33,7 +34,8 @@ struct LocalStoreAccessor : public FSAccessor struct stat st; if (lstat(realPath.c_str(), &st)) { - if (errno == ENOENT || errno == ENOTDIR) return {Type::tMissing, 0, false}; + if (errno == ENOENT || errno == ENOTDIR) + return {Type::tMissing, 0, false}; throw SysError("getting status of '%1%'", path); } @@ -41,11 +43,10 @@ struct LocalStoreAccessor : public FSAccessor throw Error("file '%1%' has unsupported type", path); return { - S_ISREG(st.st_mode) ? Type::tRegular : - S_ISLNK(st.st_mode) ? Type::tSymlink : - Type::tDirectory, - S_ISREG(st.st_mode) ? (uint64_t) st.st_size : 0, - S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}; + S_ISREG(st.st_mode) ? Type::tRegular + : S_ISLNK(st.st_mode) ? Type::tSymlink + : Type::tDirectory, + S_ISREG(st.st_mode) ? (uint64_t) st.st_size : 0, S_ISREG(st.st_mode) && st.st_mode & S_IXUSR}; } StringSet readDirectory(const Path & path) override @@ -74,8 +75,7 @@ struct LocalStoreAccessor : public FSAccessor ref LocalFSStore::getFSAccessor() { - return make_ref(ref( - std::dynamic_pointer_cast(shared_from_this()))); + return make_ref(ref(std::dynamic_pointer_cast(shared_from_this()))); } void LocalFSStore::narFromPath(const StorePath & path, Sink & sink) @@ -94,7 +94,8 @@ std::optional LocalFSStore::getBuildLog(const StorePath & path_) if (!path.isDerivation()) { try { auto info = queryPathInfo(path); - if (!info->deriver) return std::nullopt; + if (!info->deriver) + return std::nullopt; path = *info->deriver; } catch (InvalidPath &) { return std::nullopt; @@ -105,10 +106,8 @@ std::optional LocalFSStore::getBuildLog(const StorePath & path_) for (int j = 0; j < 2; j++) { - Path logPath = - j == 0 - ? fmt("%s/%s/%s/%s", logDir, drvsLogDir, baseName.substr(0, 2), baseName.substr(2)) - : fmt("%s/%s/%s", logDir, drvsLogDir, baseName); + Path logPath = j == 0 ? fmt("%s/%s/%s/%s", logDir, drvsLogDir, baseName.substr(0, 2), baseName.substr(2)) + : fmt("%s/%s/%s", logDir, drvsLogDir, baseName); Path logBz2Path = logPath + ".bz2"; if (pathExists(logPath)) @@ -117,9 +116,9 @@ std::optional LocalFSStore::getBuildLog(const StorePath & path_) else if (pathExists(logBz2Path)) { try { return decompress("bzip2", readFile(logBz2Path)); - } catch (Error &) { } + } catch (Error &) { + } } - } return std::nullopt; diff --git a/src/libstore/local-fs-store.hh b/src/libstore/local-fs-store.hh index e6fb3201a496..d5a98e3ef688 100644 --- a/src/libstore/local-fs-store.hh +++ b/src/libstore/local-fs-store.hh @@ -12,23 +12,22 @@ struct LocalFSStoreConfig : virtual StoreConfig // FIXME: the (StoreConfig*) cast works around a bug in gcc that causes // it to omit the call to the Setting constructor. Clang works fine // either way. - const PathSetting rootDir{(StoreConfig*) this, true, "", - "root", "directory prefixed to all other paths"}; - const PathSetting stateDir{(StoreConfig*) this, false, - rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir, - "state", "directory where Nix will store state"}; - const PathSetting logDir{(StoreConfig*) this, false, - rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir, - "log", "directory where Nix will store state"}; - const PathSetting realStoreDir{(StoreConfig*) this, false, - rootDir != "" ? rootDir + "/nix/store" : storeDir, "real", + const PathSetting rootDir{(StoreConfig *) this, true, "", "root", "directory prefixed to all other paths"}; + const PathSetting stateDir{ + (StoreConfig *) this, false, rootDir != "" ? rootDir + "/nix/var/nix" : settings.nixStateDir, "state", + "directory where Nix will store state"}; + const PathSetting logDir{ + (StoreConfig *) this, false, rootDir != "" ? rootDir + "/nix/var/log/nix" : settings.nixLogDir, "log", + "directory where Nix will store state"}; + const PathSetting realStoreDir{ + (StoreConfig *) this, false, rootDir != "" ? rootDir + "/nix/store" : storeDir, "real", "physical path to the Nix store"}; }; class LocalFSStore : public virtual LocalFSStoreConfig, - public virtual Store, - public virtual GcStore, - public virtual LogStore + public virtual Store, + public virtual GcStore, + public virtual LogStore { public: @@ -42,7 +41,10 @@ public: /* Register a permanent GC root. */ Path addPermRoot(const StorePath & storePath, const Path & gcRoot); - virtual Path getRealStoreDir() { return realStoreDir; } + virtual Path getRealStoreDir() + { + return realStoreDir; + } Path toRealPath(const Path & storePath) override { @@ -51,7 +53,6 @@ public: } std::optional getBuildLog(const StorePath & path) override; - }; } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index eba3b0fa5e60..f4546b066528 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -41,10 +41,10 @@ #include - namespace nix { -struct LocalStore::State::Stmts { +struct LocalStore::State::Stmts +{ /* Some precompiled SQLite statements. */ SQLiteStmt RegisterValidPath; SQLiteStmt UpdatePathInfo; @@ -79,14 +79,14 @@ int getSchema(Path schemaPath) return curSchema; } -void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd) +void migrateCASchema(SQLite & db, Path schemaPath, AutoCloseFD & lockFd) { const int nixCASchemaVersion = 4; int curCASchema = getSchema(schemaPath); if (curCASchema != nixCASchemaVersion) { if (curCASchema > nixCASchemaVersion) { - throw Error("current Nix store ca-schema is version %1%, but I only support %2%", - curCASchema, nixCASchemaVersion); + throw Error( + "current Nix store ca-schema is version %1%, but I only support %2%", curCASchema, nixCASchemaVersion); } if (!lockFile(lockFd.get(), ltWrite, false)) { @@ -96,7 +96,7 @@ void migrateCASchema(SQLite& db, Path schemaPath, AutoCloseFD& lockFd) if (curCASchema == 0) { static const char schema[] = - #include "ca-specific-schema.sql.gen.hh" +#include "ca-specific-schema.sql.gen.hh" ; db.exec(schema); curCASchema = nixCASchemaVersion; @@ -209,7 +209,8 @@ LocalStore::LocalStore(const Params & params) struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); if (!gr) - printError("warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup); + printError( + "warning: the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup); else { struct stat st; if (stat(realStoreDir.get().c_str(), &st)) @@ -232,9 +233,9 @@ LocalStore::LocalStore(const Params & params) st = lstat(path); if (S_ISLNK(st.st_mode)) throw Error( - "the path '%1%' is a symlink; " - "this is not allowed for the Nix store and its parent directories", - path); + "the path '%1%' is a symlink; " + "this is not allowed for the Nix store and its parent directories", + path); path = dirOf(path); } } @@ -245,9 +246,7 @@ LocalStore::LocalStore(const Params & params) before doing a garbage collection. */ try { struct stat st; - if (stat(reservedPath.c_str(), &st) == -1 || - st.st_size != settings.reservedSize) - { + if (stat(reservedPath.c_str(), &st) == -1 || st.st_size != settings.reservedSize) { AutoCloseFD fd = open(reservedPath.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, 0600); int res = -1; #if HAVE_POSIX_FALLOCATE @@ -275,8 +274,7 @@ LocalStore::LocalStore(const Params & params) upgrade. */ int curSchema = getSchema(); if (curSchema > nixSchemaVersion) - throw Error("current Nix store schema is version %1%, but I only support %2%", - curSchema, nixSchemaVersion); + throw Error("current Nix store schema is version %1%, but I only support %2%", curSchema, nixSchemaVersion); else if (curSchema == 0) { /* new store */ curSchema = nixSchemaVersion; @@ -306,7 +304,9 @@ LocalStore::LocalStore(const Params & params) have performed the upgrade already. */ curSchema = getSchema(); - if (curSchema < 7) { upgradeStore7(); } + if (curSchema < 7) { + upgradeStore7(); + } openDB(*state, false); @@ -334,46 +334,48 @@ LocalStore::LocalStore(const Params & params) lockFile(globalLock.get(), ltRead, true); } - else openDB(*state, false); + else + openDB(*state, false); if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { migrateCASchema(state->db, dbDir + "/ca-schema", globalLock); } /* Prepare SQL statements. */ - state->stmts->RegisterValidPath.create(state->db, + state->stmts->RegisterValidPath.create( + state->db, "insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate, sigs, ca) values (?, ?, ?, ?, ?, ?, ?, ?);"); - state->stmts->UpdatePathInfo.create(state->db, - "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ?, ca = ? where path = ?;"); - state->stmts->AddReference.create(state->db, - "insert or replace into Refs (referrer, reference) values (?, ?);"); - state->stmts->QueryPathInfo.create(state->db, + state->stmts->UpdatePathInfo.create( + state->db, "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ?, ca = ? where path = ?;"); + state->stmts->AddReference.create(state->db, "insert or replace into Refs (referrer, reference) values (?, ?);"); + state->stmts->QueryPathInfo.create( + state->db, "select id, hash, registrationTime, deriver, narSize, ultimate, sigs, ca from ValidPaths where path = ?;"); - state->stmts->QueryReferences.create(state->db, - "select path from Refs join ValidPaths on reference = id where referrer = ?;"); - state->stmts->QueryReferrers.create(state->db, + state->stmts->QueryReferences.create( + state->db, "select path from Refs join ValidPaths on reference = id where referrer = ?;"); + state->stmts->QueryReferrers.create( + state->db, "select path from Refs join ValidPaths on referrer = id where reference = (select id from ValidPaths where path = ?);"); - state->stmts->InvalidatePath.create(state->db, - "delete from ValidPaths where path = ?;"); - state->stmts->AddDerivationOutput.create(state->db, - "insert or replace into DerivationOutputs (drv, id, path) values (?, ?, ?);"); - state->stmts->QueryValidDerivers.create(state->db, - "select v.id, v.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where d.path = ?;"); - state->stmts->QueryDerivationOutputs.create(state->db, - "select id, path from DerivationOutputs where drv = ?;"); + state->stmts->InvalidatePath.create(state->db, "delete from ValidPaths where path = ?;"); + state->stmts->AddDerivationOutput.create( + state->db, "insert or replace into DerivationOutputs (drv, id, path) values (?, ?, ?);"); + state->stmts->QueryValidDerivers.create( + state->db, "select v.id, v.path from DerivationOutputs d join ValidPaths v on d.drv = v.id where d.path = ?;"); + state->stmts->QueryDerivationOutputs.create(state->db, "select id, path from DerivationOutputs where drv = ?;"); // Use "path >= ?" with limit 1 rather than "path like '?%'" to // ensure efficient lookup. - state->stmts->QueryPathFromHashPart.create(state->db, - "select path from ValidPaths where path >= ? limit 1;"); + state->stmts->QueryPathFromHashPart.create(state->db, "select path from ValidPaths where path >= ? limit 1;"); state->stmts->QueryValidPaths.create(state->db, "select path from ValidPaths"); if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { - state->stmts->RegisterRealisedOutput.create(state->db, + state->stmts->RegisterRealisedOutput.create( + state->db, R"( insert into Realisations (drvPath, outputName, outputPath, signatures) values (?, ?, (select id from ValidPaths where path = ?), ?) ; )"); - state->stmts->UpdateRealisedOutput.create(state->db, + state->stmts->UpdateRealisedOutput.create( + state->db, R"( update Realisations set signatures = ? @@ -382,27 +384,31 @@ LocalStore::LocalStore(const Params & params) outputName = ? ; )"); - state->stmts->QueryRealisedOutput.create(state->db, + state->stmts->QueryRealisedOutput.create( + state->db, R"( select Realisations.id, Output.path, Realisations.signatures from Realisations inner join ValidPaths as Output on Output.id = Realisations.outputPath where drvPath = ? and outputName = ? ; )"); - state->stmts->QueryAllRealisedOutputs.create(state->db, + state->stmts->QueryAllRealisedOutputs.create( + state->db, R"( select outputName, Output.path from Realisations inner join ValidPaths as Output on Output.id = Realisations.outputPath where drvPath = ? ; )"); - state->stmts->QueryRealisationReferences.create(state->db, + state->stmts->QueryRealisationReferences.create( + state->db, R"( select drvPath, outputName from Realisations join RealisationsRefs on realisationReference = Realisations.id where referrer = ?; )"); - state->stmts->AddRealisationReference.create(state->db, + state->stmts->AddRealisationReference.create( + state->db, R"( insert or replace into RealisationsRefs (referrer, realisationReference) values ( @@ -412,7 +418,6 @@ LocalStore::LocalStore(const Params & params) } } - AutoCloseFD LocalStore::openGCLock() { Path fnGCLock = stateDir + "/gc.lock"; @@ -422,7 +427,6 @@ AutoCloseFD LocalStore::openGCLock() return fdGCLock; } - LocalStore::~LocalStore() { std::shared_future future; @@ -449,15 +453,15 @@ LocalStore::~LocalStore() } } - std::string LocalStore::getUri() { return "local"; } - int LocalStore::getSchema() -{ return nix::getSchema(schemaPath); } +{ + return nix::getSchema(schemaPath); +} void LocalStore::openDB(State & state, bool create) { @@ -500,8 +504,8 @@ void LocalStore::openDB(State & state, bool create) SQLiteError::throw_(db, "querying journal mode"); prevMode = std::string((const char *) sqlite3_column_text(stmt, 0)); } - if (prevMode != mode && - sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK) + if (prevMode != mode + && sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK) SQLiteError::throw_(db, "setting journal mode"); /* Increase the auto-checkpoint interval to 40000 pages. This @@ -519,13 +523,13 @@ void LocalStore::openDB(State & state, bool create) } } - /* To improve purity, users may want to make the Nix store a read-only bind mount. So make the Nix store writable for this process. */ void LocalStore::makeStoreWritable() { #if __linux__ - if (getuid() != 0) return; + if (getuid() != 0) + return; /* Check if /nix/store is on a read-only mount. */ struct statvfs stat; if (statvfs(realStoreDir.get().c_str(), &stat) != 0) @@ -538,10 +542,8 @@ void LocalStore::makeStoreWritable() #endif } - const time_t mtimeStore = 1; /* 1 second into the epoch */ - static void canonicaliseTimestampAndPermissions(const Path & path, const struct stat & st) { if (!S_ISLNK(st.st_mode)) { @@ -550,13 +552,10 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const struct mode_t mode = st.st_mode & ~S_IFMT; if (mode != 0444 && mode != 0555) { - mode = (st.st_mode & S_IFMT) - | 0444 - | (st.st_mode & S_IXUSR ? 0111 : 0); + mode = (st.st_mode & S_IFMT) | 0444 | (st.st_mode & S_IXUSR ? 0111 : 0); if (chmod(path.c_str(), mode) == -1) throw SysError("changing mode of '%1%' to %2$o", path, mode); } - } if (st.st_mtime != mtimeStore) { @@ -567,22 +566,19 @@ static void canonicaliseTimestampAndPermissions(const Path & path, const struct times[1].tv_usec = 0; #if HAVE_LUTIMES if (lutimes(path.c_str(), times) == -1) - if (errno != ENOSYS || - (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1)) + if (errno != ENOSYS || (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1)) #else if (!S_ISLNK(st.st_mode) && utimes(path.c_str(), times) == -1) #endif - throw SysError("changing modification time of '%1%'", path); + throw SysError("changing modification time of '%1%'", path); } } - void canonicaliseTimestampAndPermissions(const Path & path) { canonicaliseTimestampAndPermissions(path, lstat(path)); } - static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSeen & inodesSeen) { checkInterrupt(); @@ -616,12 +612,13 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe if ((eaSize = llistxattr(path.c_str(), eaBuf.data(), eaBuf.size())) < 0) throw SysError("querying extended attributes of '%s'", path); - for (auto & eaName: tokenizeString(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) { - if (settings.ignoredAcls.get().count(eaName)) continue; + for (auto & eaName : tokenizeString(std::string(eaBuf.data(), eaSize), std::string("\000", 1))) { + if (settings.ignoredAcls.get().count(eaName)) + continue; if (lremovexattr(path.c_str(), eaName.c_str()) == -1) throw SysError("removing extended attribute '%s' from '%s'", eaName, path); } - } + } #endif /* Fail if the file is not owned by the build user. This prevents @@ -634,7 +631,9 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe if (S_ISDIR(st.st_mode) || !inodesSeen.count(Inode(st.st_dev, st.st_ino))) throw BuildError("invalid ownership on file '%1%'", path); mode_t mode = st.st_mode & ~S_IFMT; - assert(S_ISLNK(st.st_mode) || (st.st_uid == geteuid() && (mode == 0444 || mode == 0555) && st.st_mtime == mtimeStore)); + assert( + S_ISLNK(st.st_mode) + || (st.st_uid == geteuid() && (mode == 0444 || mode == 0555) && st.st_mtime == mtimeStore)); return; } @@ -653,11 +652,9 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe #if HAVE_LCHOWN if (lchown(path.c_str(), geteuid(), getegid()) == -1) #else - if (!S_ISLNK(st.st_mode) && - chown(path.c_str(), geteuid(), getegid()) == -1) + if (!S_ISLNK(st.st_mode) && chown(path.c_str(), geteuid(), getegid()) == -1) #endif - throw SysError("changing owner of '%1%' to %2%", - path, geteuid()); + throw SysError("changing owner of '%1%' to %2%", path, geteuid()); } if (S_ISDIR(st.st_mode)) { @@ -667,7 +664,6 @@ static void canonicalisePathMetaData_(const Path & path, uid_t fromUid, InodesSe } } - void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & inodesSeen) { canonicalisePathMetaData_(path, fromUid, inodesSeen); @@ -682,29 +678,26 @@ void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & ino } } - void canonicalisePathMetaData(const Path & path, uid_t fromUid) { InodesSeen inodesSeen; canonicalisePathMetaData(path, fromUid, inodesSeen); } - void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv) { assert(drvPath.isDerivation()); std::string drvName(drvPath.name()); drvName = drvName.substr(0, drvName.size() - drvExtension.size()); - auto envHasRightPath = [&](const StorePath & actual, const std::string & varName) - { + auto envHasRightPath = [&](const StorePath & actual, const std::string & varName) { auto j = drv.env.find(varName); if (j == drv.env.end() || parseStorePath(j->second) != actual) - throw Error("derivation '%s' has incorrect environment variable '%s', should be '%s'", - printStorePath(drvPath), varName, printStorePath(actual)); + throw Error( + "derivation '%s' has incorrect environment variable '%s', should be '%s'", printStorePath(drvPath), + varName, printStorePath(actual)); }; - // Don't need the answer, but do this anyways to assert is proper // combination. The code below is more general and naturally allows // combinations that are currently prohibited. @@ -712,36 +705,40 @@ void LocalStore::checkDerivationOutputs(const StorePath & drvPath, const Derivat std::optional hashesModulo; for (auto & i : drv.outputs) { - std::visit(overloaded { - [&](const DerivationOutput::InputAddressed & doia) { - if (!hashesModulo) { - // somewhat expensive so we do lazily - hashesModulo = hashDerivationModulo(*this, drv, true); - } - auto currentOutputHash = get(hashesModulo->hashes, i.first); - if (!currentOutputHash) - throw Error("derivation '%s' has unexpected output '%s' (local-store / hashesModulo) named '%s'", - printStorePath(drvPath), printStorePath(doia.path), i.first); - StorePath recomputed = makeOutputPath(i.first, *currentOutputHash, drvName); - if (doia.path != recomputed) - throw Error("derivation '%s' has incorrect output '%s', should be '%s'", - printStorePath(drvPath), printStorePath(doia.path), printStorePath(recomputed)); - envHasRightPath(doia.path, i.first); - }, - [&](const DerivationOutput::CAFixed & dof) { - StorePath path = makeFixedOutputPath(dof.hash.method, dof.hash.hash, drvName); - envHasRightPath(path, i.first); - }, - [&](const DerivationOutput::CAFloating &) { - /* Nothing to check */ - }, - [&](const DerivationOutput::Deferred &) { - /* Nothing to check */ - }, - [&](const DerivationOutput::Impure &) { - /* Nothing to check */ + std::visit( + overloaded{ + [&](const DerivationOutput::InputAddressed & doia) { + if (!hashesModulo) { + // somewhat expensive so we do lazily + hashesModulo = hashDerivationModulo(*this, drv, true); + } + auto currentOutputHash = get(hashesModulo->hashes, i.first); + if (!currentOutputHash) + throw Error( + "derivation '%s' has unexpected output '%s' (local-store / hashesModulo) named '%s'", + printStorePath(drvPath), printStorePath(doia.path), i.first); + StorePath recomputed = makeOutputPath(i.first, *currentOutputHash, drvName); + if (doia.path != recomputed) + throw Error( + "derivation '%s' has incorrect output '%s', should be '%s'", printStorePath(drvPath), + printStorePath(doia.path), printStorePath(recomputed)); + envHasRightPath(doia.path, i.first); + }, + [&](const DerivationOutput::CAFixed & dof) { + StorePath path = makeFixedOutputPath(dof.hash.method, dof.hash.hash, drvName); + envHasRightPath(path, i.first); + }, + [&](const DerivationOutput::CAFloating &) { + /* Nothing to check */ + }, + [&](const DerivationOutput::Deferred &) { + /* Nothing to check */ + }, + [&](const DerivationOutput::Impure &) { + /* Nothing to check */ + }, }, - }, i.second.raw()); + i.second.raw()); } } @@ -762,84 +759,64 @@ void LocalStore::registerDrvOutput(const Realisation & info) if (auto oldR = queryRealisation_(*state, info.id)) { if (info.isCompatibleWith(*oldR)) { auto combinedSignatures = oldR->signatures; - combinedSignatures.insert(info.signatures.begin(), - info.signatures.end()); - state->stmts->UpdateRealisedOutput.use() - (concatStringsSep(" ", combinedSignatures)) - (info.id.strHash()) - (info.id.outputName) + combinedSignatures.insert(info.signatures.begin(), info.signatures.end()); + state->stmts->UpdateRealisedOutput + .use()(concatStringsSep(" ", combinedSignatures))(info.id.strHash())(info.id.outputName) .exec(); } else { - throw Error("Trying to register a realisation of '%s', but we already " - "have another one locally.\n" - "Local: %s\n" - "Remote: %s", - info.id.to_string(), - printStorePath(oldR->outPath), - printStorePath(info.outPath) - ); + throw Error( + "Trying to register a realisation of '%s', but we already " + "have another one locally.\n" + "Local: %s\n" + "Remote: %s", + info.id.to_string(), printStorePath(oldR->outPath), printStorePath(info.outPath)); } } else { - state->stmts->RegisterRealisedOutput.use() - (info.id.strHash()) - (info.id.outputName) - (printStorePath(info.outPath)) - (concatStringsSep(" ", info.signatures)) + state->stmts->RegisterRealisedOutput + .use()(info.id.strHash())(info.id.outputName)(printStorePath(info.outPath))( + concatStringsSep(" ", info.signatures)) .exec(); } for (auto & [outputId, depPath] : info.dependentRealisations) { auto localRealisation = queryRealisationCore_(*state, outputId); if (!localRealisation) - throw Error("unable to register the derivation '%s' as it " - "depends on the non existent '%s'", + throw Error( + "unable to register the derivation '%s' as it " + "depends on the non existent '%s'", info.id.to_string(), outputId.to_string()); if (localRealisation->second.outPath != depPath) - throw Error("unable to register the derivation '%s' as it " - "depends on a realisation of '%s' that doesn’t" - "match what we have locally", + throw Error( + "unable to register the derivation '%s' as it " + "depends on a realisation of '%s' that doesn’t" + "match what we have locally", info.id.to_string(), outputId.to_string()); - state->stmts->AddRealisationReference.use() - (info.id.strHash()) - (info.id.outputName) - (outputId.strHash()) - (outputId.outputName) + state->stmts->AddRealisationReference + .use()(info.id.strHash())(info.id.outputName)(outputId.strHash())(outputId.outputName) .exec(); } }); } void LocalStore::cacheDrvOutputMapping( - State & state, - const uint64_t deriver, - const std::string & outputName, - const StorePath & output) + State & state, const uint64_t deriver, const std::string & outputName, const StorePath & output) { - retrySQLite([&]() { - state.stmts->AddDerivationOutput.use() - (deriver) - (outputName) - (printStorePath(output)) - .exec(); - }); + retrySQLite( + [&]() { state.stmts->AddDerivationOutput.use()(deriver)(outputName) (printStorePath(output)).exec(); }); } - -uint64_t LocalStore::addValidPath(State & state, - const ValidPathInfo & info, bool checkOutputs) +uint64_t LocalStore::addValidPath(State & state, const ValidPathInfo & info, bool checkOutputs) { if (info.ca.has_value() && !info.isContentAddressed(*this)) - throw Error("cannot add path '%s' to the Nix store because it claims to be content-addressed but isn't", + throw Error( + "cannot add path '%s' to the Nix store because it claims to be content-addressed but isn't", printStorePath(info.path)); - state.stmts->RegisterValidPath.use() - (printStorePath(info.path)) - (info.narHash.to_string(Base16, true)) - (info.registrationTime == 0 ? time(0) : info.registrationTime) - (info.deriver ? printStorePath(*info.deriver) : "", (bool) info.deriver) - (info.narSize, info.narSize != 0) - (info.ultimate ? 1 : 0, info.ultimate) - (concatStringsSep(" ", info.sigs), !info.sigs.empty()) - (renderContentAddress(info.ca), (bool) info.ca) + state.stmts->RegisterValidPath + .use()(printStorePath(info.path))(info.narHash.to_string(Base16, true))( + info.registrationTime == 0 ? time(0) : info.registrationTime)( + info.deriver ? printStorePath(*info.deriver) : "", + (bool) info.deriver)(info.narSize, info.narSize != 0)(info.ultimate ? 1 : 0, info.ultimate)( + concatStringsSep(" ", info.sigs), !info.sigs.empty())(renderContentAddress(info.ca), (bool) info.ca) .exec(); uint64_t id = state.db.getLastInsertedRowId(); @@ -855,7 +832,8 @@ uint64_t LocalStore::addValidPath(State & state, derivations). Note that if this throws an error, then the DB transaction is rolled back, so the path validity registration above is undone. */ - if (checkOutputs) checkDerivationOutputs(info.path, drv); + if (checkOutputs) + checkDerivationOutputs(info.path, drv); for (auto & i : drv.outputsAndOptPaths(*this)) { /* Floating CA derivations have indeterminate output paths until @@ -867,16 +845,16 @@ uint64_t LocalStore::addValidPath(State & state, { auto state_(Store::state.lock()); - state_->pathInfoCache.upsert(std::string(info.path.to_string()), - PathInfoCacheValue{ .value = std::make_shared(info) }); + state_->pathInfoCache.upsert( + std::string(info.path.to_string()), + PathInfoCacheValue{.value = std::make_shared(info)}); } return id; } - -void LocalStore::queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept +void LocalStore::queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept { try { callback(retrySQLite>([&]() { @@ -884,10 +862,11 @@ void LocalStore::queryPathInfoUncached(const StorePath & path, return queryPathInfoInternal(*state, path); })); - } catch (...) { callback.rethrow(); } + } catch (...) { + callback.rethrow(); + } } - std::shared_ptr LocalStore::queryPathInfoInternal(State & state, const StorePath & path) { /* Get the path info. */ @@ -912,7 +891,8 @@ std::shared_ptr LocalStore::queryPathInfoInternal(State & s info->registrationTime = useQueryPathInfo.getInt(2); auto s = (const char *) sqlite3_column_text(state.stmts->QueryPathInfo, 3); - if (s) info->deriver = parseStorePath(s); + if (s) + info->deriver = parseStorePath(s); /* Note that narSize = NULL yields 0. */ info->narSize = useQueryPathInfo.getInt(4); @@ -920,10 +900,12 @@ std::shared_ptr LocalStore::queryPathInfoInternal(State & s info->ultimate = useQueryPathInfo.getInt(5) == 1; s = (const char *) sqlite3_column_text(state.stmts->QueryPathInfo, 6); - if (s) info->sigs = tokenizeString(s, " "); + if (s) + info->sigs = tokenizeString(s, " "); s = (const char *) sqlite3_column_text(state.stmts->QueryPathInfo, 7); - if (s) info->ca = parseContentAddressOpt(s); + if (s) + info->ca = parseContentAddressOpt(s); /* Get the references. */ auto useQueryReferences(state.stmts->QueryReferences.use()(info->id)); @@ -934,21 +916,16 @@ std::shared_ptr LocalStore::queryPathInfoInternal(State & s return info; } - /* Update path info in the database. */ void LocalStore::updatePathInfo(State & state, const ValidPathInfo & info) { - state.stmts->UpdatePathInfo.use() - (info.narSize, info.narSize != 0) - (info.narHash.to_string(Base16, true)) - (info.ultimate ? 1 : 0, info.ultimate) - (concatStringsSep(" ", info.sigs), !info.sigs.empty()) - (renderContentAddress(info.ca), (bool) info.ca) - (printStorePath(info.path)) + state.stmts->UpdatePathInfo + .use()(info.narSize, info.narSize != 0)(info.narHash.to_string(Base16, true))( + info.ultimate ? 1 : 0, info.ultimate)(concatStringsSep(" ", info.sigs), !info.sigs.empty())( + renderContentAddress(info.ca), (bool) info.ca)(printStorePath(info.path)) .exec(); } - uint64_t LocalStore::queryValidPathId(State & state, const StorePath & path) { auto use(state.stmts->QueryPathInfo.use()(printStorePath(path))); @@ -957,13 +934,11 @@ uint64_t LocalStore::queryValidPathId(State & state, const StorePath & path) return use.getInt(0); } - bool LocalStore::isValidPath_(State & state, const StorePath & path) { return state.stmts->QueryPathInfo.use()(printStorePath(path)).next(); } - bool LocalStore::isValidPathUncached(const StorePath & path) { return retrySQLite([&]() { @@ -972,28 +947,27 @@ bool LocalStore::isValidPathUncached(const StorePath & path) }); } - StorePathSet LocalStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute) { StorePathSet res; for (auto & i : paths) - if (isValidPath(i)) res.insert(i); + if (isValidPath(i)) + res.insert(i); return res; } - StorePathSet LocalStore::queryAllValidPaths() { return retrySQLite([&]() { auto state(_state.lock()); auto use(state->stmts->QueryValidPaths.use()); StorePathSet res; - while (use.next()) res.insert(parseStorePath(use.getStr(0))); + while (use.next()) + res.insert(parseStorePath(use.getStr(0))); return res; }); } - void LocalStore::queryReferrers(State & state, const StorePath & path, StorePathSet & referrers) { auto useQueryReferrers(state.stmts->QueryReferrers.use()(printStorePath(path))); @@ -1002,7 +976,6 @@ void LocalStore::queryReferrers(State & state, const StorePath & path, StorePath referrers.insert(parseStorePath(useQueryReferrers.getStr(0))); } - void LocalStore::queryReferrers(const StorePath & path, StorePathSet & referrers) { return retrySQLite([&]() { @@ -1011,7 +984,6 @@ void LocalStore::queryReferrers(const StorePath & path, StorePathSet & referrers }); } - StorePathSet LocalStore::queryValidDerivers(const StorePath & path) { return retrySQLite([&]() { @@ -1027,9 +999,7 @@ StorePathSet LocalStore::queryValidDerivers(const StorePath & path) }); } - -std::map> -LocalStore::queryPartialDerivationOutputMap(const StorePath & path_) +std::map> LocalStore::queryPartialDerivationOutputMap(const StorePath & path_) { auto path = path_; auto outputs = retrySQLite>>([&]() { @@ -1039,8 +1009,7 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path_) drvId = queryValidPathId(*state, path); auto use(state->stmts->QueryDerivationOutputs.use()(drvId)); while (use.next()) - outputs.insert_or_assign( - use.getStr(0), parseStorePath(use.getStr(1))); + outputs.insert_or_assign(use.getStr(0), parseStorePath(use.getStr(1))); return outputs; }); @@ -1050,7 +1019,7 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path_) auto drv = readInvalidDerivation(path); auto drvHashes = staticOutputHashes(*this, drv); - for (auto& [outputName, hash] : drvHashes) { + for (auto & [outputName, hash] : drvHashes) { auto realisation = queryRealisation(DrvOutput{hash, outputName}); if (realisation) outputs.insert_or_assign(outputName, realisation->outPath); @@ -1063,7 +1032,8 @@ LocalStore::queryPartialDerivationOutputMap(const StorePath & path_) std::optional LocalStore::queryPathFromHashPart(const std::string & hashPart) { - if (hashPart.size() != StorePath::HashLen) throw Error("invalid hash part"); + if (hashPart.size() != StorePath::HashLen) + throw Error("invalid hash part"); Path prefix = storeDir + "/" + hashPart; @@ -1072,7 +1042,8 @@ std::optional LocalStore::queryPathFromHashPart(const std::string & h auto useQueryPathFromHashPart(state->stmts->QueryPathFromHashPart.use()(prefix)); - if (!useQueryPathFromHashPart.next()) return {}; + if (!useQueryPathFromHashPart.next()) + return {}; const char * s = (const char *) sqlite3_column_text(state->stmts->QueryPathFromHashPart, 0); if (s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0) @@ -1081,10 +1052,10 @@ std::optional LocalStore::queryPathFromHashPart(const std::string & h }); } - StorePathSet LocalStore::querySubstitutablePaths(const StorePathSet & paths) { - if (!settings.useSubstitutes) return StorePathSet(); + if (!settings.useSubstitutes) + return StorePathSet(); StorePathSet remaining; for (auto & i : paths) @@ -1093,9 +1064,12 @@ StorePathSet LocalStore::querySubstitutablePaths(const StorePathSet & paths) StorePathSet res; for (auto & sub : getDefaultSubstituters()) { - if (remaining.empty()) break; - if (sub->storeDir != storeDir) continue; - if (!sub->wantMassQuery) continue; + if (remaining.empty()) + break; + if (sub->storeDir != storeDir) + continue; + if (!sub->wantMassQuery) + continue; auto valid = sub->queryValidPaths(remaining); @@ -1112,11 +1086,11 @@ StorePathSet LocalStore::querySubstitutablePaths(const StorePathSet & paths) return res; } - // FIXME: move this, it's not specific to LocalStore. void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, SubstitutablePathInfos & infos) { - if (!settings.useSubstitutes) return; + if (!settings.useSubstitutes) + return; for (auto & sub : getDefaultSubstituters()) { for (auto & path : paths) { if (infos.count(path.first)) @@ -1131,8 +1105,11 @@ void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, Subst if (sub->storeDir == storeDir) assert(subPath == path.first); if (subPath != path.first) - debug("replaced path '%s' with '%s' for substituter '%s'", printStorePath(path.first), sub->printStorePath(subPath), sub->getUri()); - } else if (sub->storeDir != storeDir) continue; + debug( + "replaced path '%s' with '%s' for substituter '%s'", printStorePath(path.first), + sub->printStorePath(subPath), sub->getUri()); + } else if (sub->storeDir != storeDir) + continue; debug("checking substituter '%s' for path '%s'", sub->getUri(), sub->printStorePath(subPath)); try { @@ -1141,13 +1118,10 @@ void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, Subst if (sub->storeDir != storeDir && !(info->isContentAddressed(*sub) && info->references.empty())) continue; - auto narInfo = std::dynamic_pointer_cast( - std::shared_ptr(info)); - infos.insert_or_assign(path.first, SubstitutablePathInfo{ - info->deriver, - info->references, - narInfo ? narInfo->fileSize : 0, - info->narSize}); + auto narInfo = std::dynamic_pointer_cast(std::shared_ptr(info)); + infos.insert_or_assign( + path.first, SubstitutablePathInfo{ + info->deriver, info->references, narInfo ? narInfo->fileSize : 0, info->narSize}); } catch (InvalidPath &) { } catch (SubstituterDisabled &) { } catch (Error & e) { @@ -1160,20 +1134,19 @@ void LocalStore::querySubstitutablePathInfos(const StorePathCAMap & paths, Subst } } - void LocalStore::registerValidPath(const ValidPathInfo & info) { registerValidPaths({{info.path, info}}); } - void LocalStore::registerValidPaths(const ValidPathInfos & infos) { /* SQLite will fsync by default, but the new valid paths may not be fsync-ed. So some may want to fsync them before registering the validity, at the expense of some speed of the path registering operation. */ - if (settings.syncBeforeRegistering) sync(); + if (settings.syncBeforeRegistering) + sync(); return retrySQLite([&]() { auto state(_state.lock()); @@ -1202,31 +1175,27 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) for (auto & [_, i] : infos) if (i.path.isDerivation()) { // FIXME: inefficient; we already loaded the derivation in addValidPath(). - checkDerivationOutputs(i.path, - readInvalidDerivation(i.path)); + checkDerivationOutputs(i.path, readInvalidDerivation(i.path)); } /* Do a topological sort of the paths. This will throw an error if a cycle is detected and roll back the transaction. Cycles can only occur when a derivation has multiple outputs. */ - topoSort(paths, - {[&](const StorePath & path) { + topoSort( + paths, {[&](const StorePath & path) { auto i = infos.find(path); return i == infos.end() ? StorePathSet() : i->second.references; }}, {[&](const StorePath & path, const StorePath & parent) { return BuildError( - "cycle detected in the references of '%s' from '%s'", - printStorePath(path), - printStorePath(parent)); + "cycle detected in the references of '%s' from '%s'", printStorePath(path), printStorePath(parent)); }}); txn.commit(); }); } - /* Invalidate a path. The caller is responsible for checking that there are no referrers. */ void LocalStore::invalidatePath(State & state, const StorePath & path) @@ -1262,8 +1231,7 @@ bool LocalStore::realisationIsUntrusted(const Realisation & realisation) return requireSigs && !realisation.checkSignatures(getPublicKeys()); } -void LocalStore::addToStore(const ValidPathInfo & info, Source & source, - RepairFlag repair, CheckSigsFlag checkSigs) +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)); @@ -1290,40 +1258,38 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source, of the NAR. */ HashSink hashSink(htSHA256); - TeeSource wrapperSource { source, hashSink }; + TeeSource wrapperSource{source, hashSink}; restorePath(realPath, wrapperSource); auto hashResult = hashSink.finish(); if (hashResult.first != info.narHash) - throw Error("hash mismatch importing path '%s';\n specified: %s\n got: %s", - printStorePath(info.path), info.narHash.to_string(Base32, true), hashResult.first.to_string(Base32, true)); + throw Error( + "hash mismatch importing path '%s';\n specified: %s\n got: %s", printStorePath(info.path), + info.narHash.to_string(Base32, true), hashResult.first.to_string(Base32, true)); if (hashResult.second != info.narSize) - throw Error("size mismatch importing path '%s';\n specified: %s\n got: %s", - printStorePath(info.path), info.narSize, hashResult.second); + throw Error( + "size mismatch importing path '%s';\n specified: %s\n got: %s", printStorePath(info.path), + info.narSize, hashResult.second); if (info.ca) { if (auto foHash = std::get_if(&*info.ca)) { - auto actualFoHash = hashCAPath( - foHash->method, - foHash->hash.type, - info.path - ); + auto actualFoHash = hashCAPath(foHash->method, foHash->hash.type, info.path); if (foHash->hash != actualFoHash.hash) { - throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s", - printStorePath(info.path), - foHash->hash.to_string(Base32, true), + throw Error( + "ca hash mismatch importing path '%s';\n specified: %s\n got: %s", + printStorePath(info.path), foHash->hash.to_string(Base32, true), actualFoHash.hash.to_string(Base32, true)); } } if (auto textHash = std::get_if(&*info.ca)) { auto actualTextHash = hashString(htSHA256, readFile(realPath)); if (textHash->hash != actualTextHash) { - throw Error("ca hash mismatch importing path '%s';\n specified: %s\n got: %s", - printStorePath(info.path), - textHash->hash.to_string(Base32, true), + throw Error( + "ca hash mismatch importing path '%s';\n specified: %s\n got: %s", + printStorePath(info.path), textHash->hash.to_string(Base32, true), actualTextHash.to_string(Base32, true)); } } @@ -1342,13 +1308,17 @@ void LocalStore::addToStore(const ValidPathInfo & info, Source & source, } } - -StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name, - FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) +StorePath LocalStore::addToStoreFromDump( + Source & source0, + std::string_view name, + FileIngestionMethod method, + HashType hashAlgo, + RepairFlag repair, + const StorePathSet & references) { /* For computing the store path. */ auto hashSink = std::make_unique(hashAlgo); - TeeSource source { source0, *hashSink }; + TeeSource source{source0, *hashSink}; /* Read the source path into memory, but only if it's up to narBufferSize bytes. If it's larger, write it to a temporary @@ -1369,9 +1339,7 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name auto want = std::min(chunkSize, settings.narBufferSize - oldSize); dump.resize(oldSize + want); auto got = 0; - Finally cleanup([&]() { - dump.resize(oldSize + got); - }); + Finally cleanup([&]() { dump.resize(oldSize + got); }); try { got = source.read(dump.data() + oldSize, want); } catch (EndOfFile &) { @@ -1385,8 +1353,8 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name if (!inMemory) { /* Drain what we pulled so far, and then keep on pulling */ - StringSource dumpSource { dump }; - ChainSource bothSource { dumpSource, source }; + StringSource dumpSource{dump}; + ChainSource bothSource{dumpSource, source}; auto tempDir = createTempDir(realStoreDir, "add"); delTempDir = std::make_unique(tempDir); @@ -1422,7 +1390,7 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name autoGC(); if (inMemory) { - StringSource dumpSource { dump }; + StringSource dumpSource{dump}; /* Restore from the NAR in memory. */ if (method == FileIngestionMethod::Recursive) restorePath(realPath, dumpSource); @@ -1436,9 +1404,9 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name /* For computing the nar hash. In recursive SHA-256 mode, this is the same as the store hash, so no need to do it again. */ - auto narHash = std::pair { hash, size }; + auto narHash = std::pair{hash, size}; if (method != FileIngestionMethod::Recursive || hashAlgo != htSHA256) { - HashSink narSink { htSHA256 }; + HashSink narSink{htSHA256}; dumpPath(realPath, narSink); narHash = narSink.finish(); } @@ -1447,10 +1415,10 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name optimisePath(realPath, repair); - ValidPathInfo info { dstPath, narHash.first }; + ValidPathInfo info{dstPath, narHash.first}; info.narSize = narHash.second; info.references = references; - info.ca = FixedOutputHash { .method = method, .hash = hash }; + info.ca = FixedOutputHash{.method = method, .hash = hash}; registerValidPath(info); } @@ -1460,11 +1428,8 @@ StorePath LocalStore::addToStoreFromDump(Source & source0, std::string_view name return dstPath; } - StorePath LocalStore::addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, RepairFlag repair) + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) { auto hash = hashString(htSHA256, s); auto dstPath = makeTextPath(name, hash, references); @@ -1493,10 +1458,10 @@ StorePath LocalStore::addTextToStore( optimisePath(realPath, repair); - ValidPathInfo info { dstPath, narHash }; + ValidPathInfo info{dstPath, narHash}; info.narSize = sink.s.size(); info.references = references; - info.ca = TextHash { .hash = hash }; + info.ca = TextHash{.hash = hash}; registerValidPath(info); } @@ -1506,7 +1471,6 @@ StorePath LocalStore::addTextToStore( return dstPath; } - /* Create a temporary directory in the store that won't be garbage-collected. */ Path LocalStore::createTempDirInStore() @@ -1522,7 +1486,6 @@ Path LocalStore::createTempDirInStore() return tmpDir; } - void LocalStore::invalidatePathChecked(const StorePath & path) { retrySQLite([&]() { @@ -1531,11 +1494,12 @@ void LocalStore::invalidatePathChecked(const StorePath & path) SQLiteTxn txn(state->db); if (isValidPath_(*state, path)) { - StorePathSet referrers; queryReferrers(*state, path, referrers); + StorePathSet referrers; + queryReferrers(*state, path, referrers); referrers.erase(path); /* ignore self-references */ if (!referrers.empty()) - throw PathInUse("cannot delete path '%s' because it is in use by %s", - printStorePath(path), showPaths(referrers)); + throw PathInUse( + "cannot delete path '%s' because it is in use by %s", printStorePath(path), showPaths(referrers)); invalidatePath(*state, path); } @@ -1543,7 +1507,6 @@ void LocalStore::invalidatePathChecked(const StorePath & path) }); } - bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) { printInfo(format("reading the Nix store...")); @@ -1556,7 +1519,8 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) FdLock gcLock(fdGCLock.get(), ltRead, true, "waiting for the big garbage collector lock..."); StringSet store; - for (auto & i : readDirectory(realStoreDir)) store.insert(i.name); + for (auto & i : readDirectory(realStoreDir)) + store.insert(i.name); /* Check whether all valid paths actually exist. */ printInfo("checking path existence..."); @@ -1577,8 +1541,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) Path linkPath = linksDir + "/" + link.name; std::string hash = hashPath(htSHA256, linkPath).first.to_string(Base32, false); if (hash != link.name) { - printError("link '%s' was modified! expected hash '%s', got '%s'", - linkPath, link.name, hash); + printError("link '%s' was modified! expected hash '%s', got '%s'", linkPath, link.name, hash); if (repair) { if (unlink(linkPath.c_str()) == 0) printInfo("removed link '%s'", linkPath); @@ -1596,7 +1559,8 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) for (auto & i : validPaths) { try { - auto info = std::const_pointer_cast(std::shared_ptr(queryPathInfo(i))); + auto info = + std::const_pointer_cast(std::shared_ptr(queryPathInfo(i))); /* Check the content hash (optionally - slow). */ printMsg(lvlTalkative, "checking contents of '%s'", printStorePath(i)); @@ -1607,9 +1571,13 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) auto current = hashSink.finish(); if (info->narHash != nullHash && info->narHash != current.first) { - printError("path '%s' was modified! expected hash '%s', got '%s'", - printStorePath(i), info->narHash.to_string(Base32, true), current.first.to_string(Base32, true)); - if (repair) repairPath(i); else errors = true; + printError( + "path '%s' was modified! expected hash '%s', got '%s'", printStorePath(i), + info->narHash.to_string(Base32, true), current.first.to_string(Base32, true)); + if (repair) + repairPath(i); + else + errors = true; } else { bool update = false; @@ -1632,7 +1600,6 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) auto state(_state.lock()); updatePathInfo(*state, *info); } - } } catch (Error & e) { @@ -1650,13 +1617,18 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair) return errors; } - -void LocalStore::verifyPath(const Path & pathS, const StringSet & store, - PathSet & done, StorePathSet & validPaths, RepairFlag repair, bool & errors) +void LocalStore::verifyPath( + const Path & pathS, + const StringSet & store, + PathSet & done, + StorePathSet & validPaths, + RepairFlag repair, + bool & errors) { checkInterrupt(); - if (!done.insert(pathS).second) return; + if (!done.insert(pathS).second) + return; if (!isStorePath(pathS)) { printError("path '%s' is not in the Nix store", pathS); @@ -1669,7 +1641,8 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store, /* Check any referrers first. If we can invalidate them first, then we can invalidate this path as well. */ bool canInvalidate = true; - StorePathSet referrers; queryReferrers(path, referrers); + StorePathSet referrers; + queryReferrers(path, referrers); for (auto & i : referrers) if (i != path) { verifyPath(printStorePath(i), store, done, validPaths, repair, errors); @@ -1690,7 +1663,8 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store, logWarning(e.info()); errors = true; } - else errors = true; + else + errors = true; } return; @@ -1699,13 +1673,11 @@ void LocalStore::verifyPath(const Path & pathS, const StringSet & store, validPaths.insert(std::move(path)); } - unsigned int LocalStore::getProtocol() { return PROTOCOL_VERSION; } - #if defined(FS_IOC_SETFLAGS) && defined(FS_IOC_GETFLAGS) && defined(FS_IMMUTABLE_FL) static void makeMutable(const Path & path) @@ -1714,7 +1686,8 @@ static void makeMutable(const Path & path) auto st = lstat(path); - if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) return; + if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) + return; if (S_ISDIR(st.st_mode)) { for (auto & i : readDirectory(path)) @@ -1726,7 +1699,8 @@ static void makeMutable(const Path & path) security hole). */ AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC); if (fd == -1) { - if (errno == ELOOP) return; // it's a symlink + if (errno == ELOOP) + return; // it's a symlink throw SysError("opening file '%1%'", path); } @@ -1734,37 +1708,37 @@ static void makeMutable(const Path & path) /* Silently ignore errors getting/setting the immutable flag so that we work correctly on filesystems that don't support it. */ - if (ioctl(fd, FS_IOC_GETFLAGS, &flags)) return; + if (ioctl(fd, FS_IOC_GETFLAGS, &flags)) + return; old = flags; flags &= ~FS_IMMUTABLE_FL; - if (old == flags) return; - if (ioctl(fd, FS_IOC_SETFLAGS, &flags)) return; + if (old == flags) + return; + if (ioctl(fd, FS_IOC_SETFLAGS, &flags)) + return; } /* Upgrade from schema 6 (Nix 0.15) to schema 7 (Nix >= 1.3). */ void LocalStore::upgradeStore7() { - if (getuid() != 0) return; + if (getuid() != 0) + return; printInfo("removing immutable bits from the Nix store (this may take a while)..."); makeMutable(realStoreDir); } #else -void LocalStore::upgradeStore7() -{ -} +void LocalStore::upgradeStore7() {} #endif - void LocalStore::vacuumDB() { auto state(_state.lock()); state->db.exec("vacuum"); } - void LocalStore::addSignatures(const StorePath & storePath, const StringSet & sigs) { retrySQLite([&]() { @@ -1782,7 +1756,6 @@ void LocalStore::addSignatures(const StorePath & storePath, const StringSet & si }); } - void LocalStore::signRealisation(Realisation & realisation) { // FIXME: keep secret keys in memory. @@ -1807,13 +1780,10 @@ void LocalStore::signPathInfo(ValidPathInfo & info) } } - void LocalStore::createUser(const std::string & userName, uid_t userId) { - for (auto & dir : { - fmt("%s/profiles/per-user/%s", stateDir, userName), - fmt("%s/gcroots/per-user/%s", stateDir, userName) - }) { + for (auto & dir : + {fmt("%s/profiles/per-user/%s", stateDir, userName), fmt("%s/gcroots/per-user/%s", stateDir, userName)}) { createDirs(dir); if (chmod(dir.c_str(), 0755) == -1) throw SysError("changing permissions of directory '%s'", dir); @@ -1822,34 +1792,25 @@ void LocalStore::createUser(const std::string & userName, uid_t userId) } } -std::optional> LocalStore::queryRealisationCore_( - LocalStore::State & state, - const DrvOutput & id) +std::optional> +LocalStore::queryRealisationCore_(LocalStore::State & state, const DrvOutput & id) { - auto useQueryRealisedOutput( - state.stmts->QueryRealisedOutput.use() - (id.strHash()) - (id.outputName)); + auto useQueryRealisedOutput(state.stmts->QueryRealisedOutput.use()(id.strHash())(id.outputName)); if (!useQueryRealisedOutput.next()) return std::nullopt; auto realisationDbId = useQueryRealisedOutput.getInt(0); auto outputPath = parseStorePath(useQueryRealisedOutput.getStr(1)); - auto signatures = - tokenizeString(useQueryRealisedOutput.getStr(2)); - - return {{ - realisationDbId, - Realisation{ - .id = id, - .outPath = outputPath, - .signatures = signatures, - } - }}; + auto signatures = tokenizeString(useQueryRealisedOutput.getStr(2)); + + return { + {realisationDbId, Realisation{ + .id = id, + .outPath = outputPath, + .signatures = signatures, + }}}; } -std::optional LocalStore::queryRealisation_( - LocalStore::State & state, - const DrvOutput & id) +std::optional LocalStore::queryRealisation_(LocalStore::State & state, const DrvOutput & id) { auto maybeCore = queryRealisationCore_(state, id); if (!maybeCore) @@ -1857,11 +1818,9 @@ std::optional LocalStore::queryRealisation_( auto [realisationDbId, res] = *maybeCore; std::map dependentRealisations; - auto useRealisationRefs( - state.stmts->QueryRealisationReferences.use() - (realisationDbId)); + auto useRealisationRefs(state.stmts->QueryRealisationReferences.use()(realisationDbId)); while (useRealisationRefs.next()) { - auto depId = DrvOutput { + auto depId = DrvOutput{ Hash::parseAnyPrefixed(useRealisationRefs.getStr(0)), useRealisationRefs.getStr(1), }; @@ -1873,21 +1832,19 @@ std::optional LocalStore::queryRealisation_( res.dependentRealisations = dependentRealisations; - return { res }; + return {res}; } -void LocalStore::queryRealisationUncached(const DrvOutput & id, - Callback> callback) noexcept +void LocalStore::queryRealisationUncached( + const DrvOutput & id, Callback> callback) noexcept { try { - auto maybeRealisation - = retrySQLite>([&]() { - auto state(_state.lock()); - return queryRealisation_(*state, id); - }); + auto maybeRealisation = retrySQLite>([&]() { + auto state(_state.lock()); + return queryRealisation_(*state, id); + }); if (maybeRealisation) - callback( - std::make_shared(maybeRealisation.value())); + callback(std::make_shared(maybeRealisation.value())); else callback(nullptr); @@ -1896,21 +1853,16 @@ void LocalStore::queryRealisationUncached(const DrvOutput & id, } } -FixedOutputHash LocalStore::hashCAPath( - const FileIngestionMethod & method, const HashType & hashType, - const StorePath & path) +FixedOutputHash +LocalStore::hashCAPath(const FileIngestionMethod & method, const HashType & hashType, const StorePath & path) { return hashCAPath(method, hashType, Store::toRealPath(path), path.hashPart()); } FixedOutputHash LocalStore::hashCAPath( - const FileIngestionMethod & method, - const HashType & hashType, - const Path & path, - const std::string_view pathHash -) + const FileIngestionMethod & method, const HashType & hashType, const Path & path, const std::string_view pathHash) { - HashModuloSink caSink ( hashType, std::string(pathHash) ); + HashModuloSink caSink(hashType, std::string(pathHash)); switch (method) { case FileIngestionMethod::Recursive: dumpPath(path, caSink); @@ -1934,7 +1886,8 @@ void LocalStore::addBuildLog(const StorePath & drvPath, std::string_view log) auto logPath = fmt("%s/%s/%s/%s.bz2", logDir, drvsLogDir, baseName.substr(0, 2), baseName.substr(2)); - if (pathExists(logPath)) return; + if (pathExists(logPath)) + return; createDirs(dirOf(logPath)); @@ -1951,5 +1904,4 @@ std::optional LocalStore::getVersion() return nixVersion; } - -} // namespace nix +} // namespace nix diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 70d225be320f..b054be3342fd 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -14,17 +14,14 @@ #include #include - namespace nix { - /* Nix store and database schema version. Version 1 (or 0) was Nix <= 0.7. Version 2 was Nix 0.8 and 0.9. Version 3 is Nix 0.10. Version 4 is Nix 0.11. Version 5 is Nix 0.12-0.16. Version 6 is Nix 1.0. Version 7 is Nix 1.3. Version 10 is 2.0. */ const int nixSchemaVersion = 10; - struct OptimiseStats { unsigned long filesLinked = 0; @@ -36,14 +33,16 @@ struct LocalStoreConfig : virtual LocalFSStoreConfig { using LocalFSStoreConfig::LocalFSStoreConfig; - Setting requireSigs{(StoreConfig*) this, - settings.requireSigs, - "require-sigs", "whether store paths should have a trusted signature on import"}; + Setting requireSigs{ + (StoreConfig *) this, settings.requireSigs, "require-sigs", + "whether store paths should have a trusted signature on import"}; - const std::string name() override { return "Local Store"; } + const std::string name() override + { + return "Local Store"; + } }; - class LocalStore : public virtual LocalStoreConfig, public virtual LocalFSStore, public virtual GcStore { private: @@ -118,13 +117,12 @@ public: bool isValidPathUncached(const StorePath & path) override; - StorePathSet queryValidPaths(const StorePathSet & paths, - SubstituteFlag maybeSubstitute = NoSubstitute) override; + StorePathSet queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute = NoSubstitute) override; StorePathSet queryAllValidPaths() override; - void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept override; + void queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept override; void queryReferrers(const StorePath & path, StorePathSet & referrers) override; @@ -136,23 +134,23 @@ public: StorePathSet querySubstitutablePaths(const StorePathSet & paths) override; - void querySubstitutablePathInfos(const StorePathCAMap & paths, - SubstitutablePathInfos & infos) override; + void querySubstitutablePathInfos(const StorePathCAMap & paths, SubstitutablePathInfos & infos) override; bool pathInfoIsUntrusted(const ValidPathInfo &) override; - bool realisationIsUntrusted(const Realisation & ) override; + bool realisationIsUntrusted(const Realisation &) override; - void addToStore(const ValidPathInfo & info, Source & source, - RepairFlag repair, CheckSigsFlag checkSigs) override; + void addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override; - StorePath addToStoreFromDump(Source & dump, std::string_view name, - FileIngestionMethod method, HashType hashAlgo, RepairFlag repair, const StorePathSet & references) override; + StorePath addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method, + HashType hashAlgo, + RepairFlag repair, + const StorePathSet & references) override; StorePath addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) override; + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) override; void addTempRoot(const StorePath & path) override; @@ -209,15 +207,12 @@ public: void registerDrvOutput(const Realisation & info) override; void registerDrvOutput(const Realisation & info, CheckSigsFlag checkSigs) override; void cacheDrvOutputMapping( - State & state, - const uint64_t deriver, - const std::string & outputName, - const StorePath & output); + State & state, const uint64_t deriver, const std::string & outputName, const StorePath & output); std::optional queryRealisation_(State & state, const DrvOutput & id); std::optional> queryRealisationCore_(State & state, const DrvOutput & id); - void queryRealisationUncached(const DrvOutput&, - Callback> callback) noexcept override; + void queryRealisationUncached( + const DrvOutput &, Callback> callback) noexcept override; std::optional getVersion() override; @@ -238,8 +233,13 @@ private: /* Delete a path from the Nix store. */ void invalidatePathChecked(const StorePath & path); - void verifyPath(const Path & path, const StringSet & store, - PathSet & done, StorePathSet & validPaths, RepairFlag repair, bool & errors); + void verifyPath( + const Path & path, + const StringSet & store, + PathSet & done, + StorePathSet & validPaths, + RepairFlag repair, + bool & errors); std::shared_ptr queryPathInfoInternal(State & state, const StorePath & path); @@ -264,7 +264,8 @@ private: InodeHash loadInodeHash(); Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash); - void optimisePath_(Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash, RepairFlag repair); + void + optimisePath_(Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash, RepairFlag repair); // Internal versions that are not wrapped in retry_sqlite. bool isValidPath_(State & state, const StorePath & path); @@ -278,17 +279,13 @@ private: void createUser(const std::string & userName, uid_t userId) override; // XXX: Make a generic `Store` method - FixedOutputHash hashCAPath( - const FileIngestionMethod & method, - const HashType & hashType, - const StorePath & path); + FixedOutputHash hashCAPath(const FileIngestionMethod & method, const HashType & hashType, const StorePath & path); FixedOutputHash hashCAPath( const FileIngestionMethod & method, const HashType & hashType, const Path & path, - const std::string_view pathHash - ); + const std::string_view pathHash); void addBuildLog(const StorePath & drvPath, std::string_view log) override; @@ -298,11 +295,9 @@ private: friend struct DerivationGoal; }; - typedef std::pair Inode; typedef std::set InodesSeen; - /* "Fix", or canonicalise, the meta-data of the files in a store path after it has been built. In particular: - the last modification date on each file is set to 1 (i.e., diff --git a/src/libstore/lock.cc b/src/libstore/lock.cc index fa718f55d017..8e5a1b4a1f50 100644 --- a/src/libstore/lock.cc +++ b/src/libstore/lock.cc @@ -16,26 +16,26 @@ UserLock::UserLock() createDirs(settings.nixStateDir + "/userpool"); } -bool UserLock::findFreeUser() { - if (enabled()) return true; +bool UserLock::findFreeUser() +{ + if (enabled()) + return true; /* Get the members of the build-users-group. */ struct group * gr = getgrnam(settings.buildUsersGroup.get().c_str()); if (!gr) - throw Error("the group '%1%' specified in 'build-users-group' does not exist", - settings.buildUsersGroup); + throw Error("the group '%1%' specified in 'build-users-group' does not exist", settings.buildUsersGroup); gid = gr->gr_gid; /* Copy the result of getgrnam. */ Strings users; - for (char * * p = gr->gr_mem; *p; ++p) { + for (char ** p = gr->gr_mem; *p; ++p) { debug("found build user '%1%'", *p); users.push_back(*p); } if (users.empty()) - throw Error("the build users group '%1%' has no members", - settings.buildUsersGroup); + throw Error("the build users group '%1%' has no members", settings.buildUsersGroup); /* Find a user account that isn't currently in use for another build. */ @@ -44,9 +44,7 @@ bool UserLock::findFreeUser() { struct passwd * pw = getpwnam(i.c_str()); if (!pw) - throw Error("the user '%1%' in the group '%2%' does not exist", - i, settings.buildUsersGroup); - + throw Error("the user '%1%' in the group '%2%' does not exist", i, settings.buildUsersGroup); fnUserLock = (format("%1%/userpool/%2%") % settings.nixStateDir % pw->pw_uid).str(); @@ -61,8 +59,7 @@ bool UserLock::findFreeUser() { /* Sanity check... */ if (uid == getuid() || uid == geteuid()) - throw Error("the Nix user should not be a member of '%1%'", - settings.buildUsersGroup); + throw Error("the Nix user should not be a member of '%1%'", settings.buildUsersGroup); #if __linux__ /* Get the list of supplementary groups of this build user. This @@ -70,21 +67,18 @@ bool UserLock::findFreeUser() { int ngroups = 32; // arbitrary initial guess supplementaryGIDs.resize(ngroups); - int err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(), - &ngroups); + int err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(), &ngroups); // Our initial size of 32 wasn't sufficient, the correct size has // been stored in ngroups, so we try again. if (err == -1) { supplementaryGIDs.resize(ngroups); - err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(), - &ngroups); + err = getgrouplist(pw->pw_name, pw->pw_gid, supplementaryGIDs.data(), &ngroups); } // If it failed once more, then something must be broken. if (err == -1) - throw Error("failed to get list of supplementary groups for '%1%'", - pw->pw_name); + throw Error("failed to get list of supplementary groups for '%1%'", pw->pw_name); // Finally, trim back the GID list to its real size supplementaryGIDs.resize(ngroups); diff --git a/src/libstore/lock.hh b/src/libstore/lock.hh index 3d29a7b5ba7d..45ec3b6b369d 100644 --- a/src/libstore/lock.hh +++ b/src/libstore/lock.hh @@ -23,15 +23,31 @@ public: void kill(); - std::string getUser() { return user; } - uid_t getUID() { assert(uid); return uid; } - uid_t getGID() { assert(gid); return gid; } - std::vector getSupplementaryGIDs() { return supplementaryGIDs; } + std::string getUser() + { + return user; + } + uid_t getUID() + { + assert(uid); + return uid; + } + uid_t getGID() + { + assert(gid); + return gid; + } + std::vector getSupplementaryGIDs() + { + return supplementaryGIDs; + } bool findFreeUser(); - bool enabled() { return isEnabled; } - + bool enabled() + { + return isEnabled; + } }; } diff --git a/src/libstore/log-store.hh b/src/libstore/log-store.hh index ff1b92e174a1..1fe89998400f 100644 --- a/src/libstore/log-store.hh +++ b/src/libstore/log-store.hh @@ -2,7 +2,6 @@ #include "store-api.hh" - namespace nix { struct LogStore : public virtual Store diff --git a/src/libstore/machines.cc b/src/libstore/machines.cc index e87f469800dc..034b32aabf78 100644 --- a/src/libstore/machines.cc +++ b/src/libstore/machines.cc @@ -7,53 +7,45 @@ namespace nix { -Machine::Machine(decltype(storeUri) storeUri, +Machine::Machine( + decltype(storeUri) storeUri, decltype(systemTypes) systemTypes, decltype(sshKey) sshKey, decltype(maxJobs) maxJobs, decltype(speedFactor) speedFactor, decltype(supportedFeatures) supportedFeatures, decltype(mandatoryFeatures) mandatoryFeatures, - decltype(sshPublicHostKey) sshPublicHostKey) : - storeUri( + decltype(sshPublicHostKey) sshPublicHostKey) + : storeUri( // Backwards compatibility: if the URI is schemeless, is not a path, // and is not one of the special store connection words, prepend // ssh://. - storeUri.find("://") != std::string::npos - || storeUri.find("/") != std::string::npos - || storeUri == "auto" - || storeUri == "daemon" - || storeUri == "local" - || hasPrefix(storeUri, "auto?") - || hasPrefix(storeUri, "daemon?") - || hasPrefix(storeUri, "local?") - || hasPrefix(storeUri, "?") - ? storeUri - : "ssh://" + storeUri), - systemTypes(systemTypes), - sshKey(sshKey), - maxJobs(maxJobs), - speedFactor(std::max(1U, speedFactor)), - supportedFeatures(supportedFeatures), - mandatoryFeatures(mandatoryFeatures), - sshPublicHostKey(sshPublicHostKey) + storeUri.find("://") != std::string::npos || storeUri.find("/") != std::string::npos || storeUri == "auto" + || storeUri == "daemon" || storeUri == "local" || hasPrefix(storeUri, "auto?") + || hasPrefix(storeUri, "daemon?") || hasPrefix(storeUri, "local?") || hasPrefix(storeUri, "?") + ? storeUri + : "ssh://" + storeUri) + , systemTypes(systemTypes) + , sshKey(sshKey) + , maxJobs(maxJobs) + , speedFactor(std::max(1U, speedFactor)) + , supportedFeatures(supportedFeatures) + , mandatoryFeatures(mandatoryFeatures) + , sshPublicHostKey(sshPublicHostKey) {} bool Machine::allSupported(const std::set & features) const { - return std::all_of(features.begin(), features.end(), - [&](const std::string & feature) { - return supportedFeatures.count(feature) || - mandatoryFeatures.count(feature); - }); + return std::all_of(features.begin(), features.end(), [&](const std::string & feature) { + return supportedFeatures.count(feature) || mandatoryFeatures.count(feature); + }); } bool Machine::mandatoryMet(const std::set & features) const { - return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(), - [&](const std::string & feature) { - return features.count(feature); - }); + return std::all_of(mandatoryFeatures.begin(), mandatoryFeatures.end(), [&](const std::string & feature) { + return features.count(feature); + }); } ref Machine::openStore() const @@ -75,7 +67,8 @@ ref Machine::openStore() const auto & fs = storeParams["system-features"]; auto append = [&](auto feats) { for (auto & f : feats) { - if (fs.size() > 0) fs += ' '; + if (fs.size() > 0) + fs += ' '; fs += f; } }; @@ -92,7 +85,8 @@ static std::vector expandBuilderLines(const std::string & builders) for (auto line : tokenizeString>(builders, "\n;")) { trim(line); line.erase(std::find(line.begin(), line.end(), '#'), line.end()); - if (line.empty()) continue; + if (line.empty()) + continue; if (line[0] == '@') { const std::string path = trim(std::string(line, 1)); @@ -126,7 +120,9 @@ static Machine parseBuilderLine(const std::string & line) auto parseUnsignedIntField = [&](size_t fieldIndex) { const auto result = string2Int(tokens[fieldIndex]); if (!result) { - throw FormatError("bad machine specification: failed to convert column #%lu in a row: '%s' to 'unsigned int'", fieldIndex, line); + throw FormatError( + "bad machine specification: failed to convert column #%lu in a row: '%s' to 'unsigned int'", fieldIndex, + line); } return result.value(); }; @@ -136,24 +132,27 @@ static Machine parseBuilderLine(const std::string & line) try { base64Decode(str); } catch (const Error & e) { - throw FormatError("bad machine specification: a column #%lu in a row: '%s' is not valid base64 string: %s", fieldIndex, line, e.what()); + throw FormatError( + "bad machine specification: a column #%lu in a row: '%s' is not valid base64 string: %s", fieldIndex, + line, e.what()); } return str; }; if (!isSet(0)) - throw FormatError("bad machine specification: store URL was not found at the first column of a row: '%s'", line); + throw FormatError( + "bad machine specification: store URL was not found at the first column of a row: '%s'", line); return { tokens[0], - isSet(1) ? tokenizeString>(tokens[1], ",") : std::vector{settings.thisSystem}, + isSet(1) ? tokenizeString>(tokens[1], ",") + : std::vector{settings.thisSystem}, isSet(2) ? tokens[2] : "", isSet(3) ? parseUnsignedIntField(3) : 1U, isSet(4) ? parseUnsignedIntField(4) : 1U, isSet(5) ? tokenizeString>(tokens[5], ",") : std::set{}, isSet(6) ? tokenizeString>(tokens[6], ",") : std::set{}, - isSet(7) ? ensureBase64(7) : "" - }; + isSet(7) ? ensureBase64(7) : ""}; } static Machines parseBuilderLines(const std::vector & builders) diff --git a/src/libstore/machines.hh b/src/libstore/machines.hh index 834626de9cf0..c291f59a457e 100644 --- a/src/libstore/machines.hh +++ b/src/libstore/machines.hh @@ -6,7 +6,8 @@ namespace nix { class Store; -struct Machine { +struct Machine +{ const std::string storeUri; const std::vector systemTypes; @@ -22,7 +23,8 @@ struct Machine { bool mandatoryMet(const std::set & features) const; - Machine(decltype(storeUri) storeUri, + Machine( + decltype(storeUri) storeUri, decltype(systemTypes) systemTypes, decltype(sshKey) sshKey, decltype(maxJobs) maxJobs, diff --git a/src/libstore/make-content-addressed.cc b/src/libstore/make-content-addressed.cc index 64d172918a54..09eefc624478 100644 --- a/src/libstore/make-content-addressed.cc +++ b/src/libstore/make-content-addressed.cc @@ -3,10 +3,7 @@ namespace nix { -std::map makeContentAddressed( - Store & srcStore, - Store & dstStore, - const StorePathSet & storePaths) +std::map makeContentAddressed(Store & srcStore, Store & dstStore, const StorePathSet & storePaths) { StorePathSet closure; srcStore.computeFSClosure(storePaths, closure); @@ -59,11 +56,12 @@ std::map makeContentAddressed( rsink2(sink.s); rsink2.flush(); - ValidPathInfo info { dstPath, hashString(htSHA256, sink2.s) }; + ValidPathInfo info{dstPath, hashString(htSHA256, sink2.s)}; info.references = std::move(references); - if (hasSelfReference) info.references.insert(info.path); + if (hasSelfReference) + info.references.insert(info.path); info.narSize = sink.s.size(); - info.ca = FixedOutputHash { + info.ca = FixedOutputHash{ .method = FileIngestionMethod::Recursive, .hash = narModuloHash, }; diff --git a/src/libstore/make-content-addressed.hh b/src/libstore/make-content-addressed.hh index c4a66ed414cb..0e7ea6c02f4d 100644 --- a/src/libstore/make-content-addressed.hh +++ b/src/libstore/make-content-addressed.hh @@ -4,9 +4,7 @@ namespace nix { -std::map makeContentAddressed( - Store & srcStore, - Store & dstStore, - const StorePathSet & storePaths); +std::map +makeContentAddressed(Store & srcStore, Store & dstStore, const StorePathSet & storePaths); } diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index fb985c97bc4d..5c481602738b 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -11,41 +11,43 @@ namespace nix { -void Store::computeFSClosure(const StorePathSet & startPaths, - StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers) +void Store::computeFSClosure( + const StorePathSet & startPaths, + StorePathSet & paths_, + bool flipDirection, + bool includeOutputs, + bool includeDerivers) { std::function(const StorePath & path, std::future> &)> queryDeps; if (flipDirection) - queryDeps = [&](const StorePath& path, - std::future> & fut) { + queryDeps = [&](const StorePath & path, std::future> & fut) { StorePathSet res; StorePathSet referrers; queryReferrers(path, referrers); - for (auto& ref : referrers) + for (auto & ref : referrers) if (ref != path) res.insert(ref); if (includeOutputs) - for (auto& i : queryValidDerivers(path)) + for (auto & i : queryValidDerivers(path)) res.insert(i); if (includeDerivers && path.isDerivation()) - for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path)) + for (auto & [_, maybeOutPath] : queryPartialDerivationOutputMap(path)) if (maybeOutPath && isValidPath(*maybeOutPath)) res.insert(*maybeOutPath); return res; }; else - queryDeps = [&](const StorePath& path, - std::future> & fut) { + queryDeps = [&](const StorePath & path, std::future> & fut) { StorePathSet res; auto info = fut.get(); - for (auto& ref : info->references) + for (auto & ref : info->references) if (ref != path) res.insert(ref); if (includeOutputs && path.isDerivation()) - for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path)) + for (auto & [_, maybeOutPath] : queryPartialDerivationOutputMap(path)) if (maybeOutPath && isValidPath(*maybeOutPath)) res.insert(*maybeOutPath); @@ -56,33 +58,29 @@ void Store::computeFSClosure(const StorePathSet & startPaths, computeClosure( startPaths, paths_, - [&](const StorePath& path, - std::function>&)> - processEdges) { + [&](const StorePath & path, std::function> &)> processEdges) { std::promise> promise; - std::function>)> - getDependencies = - [&](std::future> fut) { - try { - promise.set_value(queryDeps(path, fut)); - } catch (...) { - promise.set_exception(std::current_exception()); - } - }; + std::function>)> getDependencies = + [&](std::future> fut) { + try { + promise.set_value(queryDeps(path, fut)); + } catch (...) { + promise.set_exception(std::current_exception()); + } + }; queryPathInfo(path, getDependencies); processEdges(promise); }); } -void Store::computeFSClosure(const StorePath & startPath, - StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers) +void Store::computeFSClosure( + const StorePath & startPath, StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers) { StorePathSet paths; paths.insert(startPath); computeFSClosure(paths, paths_, flipDirection, includeOutputs, includeDerivers); } - std::optional getDerivationCA(const BasicDerivation & drv) { auto out = drv.outputs.find("out"); @@ -93,9 +91,13 @@ std::optional getDerivationCA(const BasicDerivation & drv) return std::nullopt; } -void Store::queryMissing(const std::vector & targets, - StorePathSet & willBuild_, StorePathSet & willSubstitute_, StorePathSet & unknown_, - uint64_t & downloadSize_, uint64_t & narSize_) +void Store::queryMissing( + const std::vector & targets, + StorePathSet & willBuild_, + StorePathSet & willSubstitute_, + StorePathSet & unknown_, + uint64_t & downloadSize_, + uint64_t & narSize_) { Activity act(*logger, lvlDebug, actUnknown, "querying info about missing paths"); @@ -107,7 +109,7 @@ void Store::queryMissing(const std::vector & targets, struct State { std::unordered_set done; - StorePathSet & unknown, & willSubstitute, & willBuild; + StorePathSet &unknown, &willSubstitute, &willBuild; uint64_t & downloadSize; uint64_t & narSize; }; @@ -117,7 +119,9 @@ void Store::queryMissing(const std::vector & targets, size_t left; bool done = false; StorePathSet outPaths; - DrvState(size_t left) : left(left) { } + DrvState(size_t left) + : left(left) + {} }; Sync state_(State{{}, unknown_, willSubstitute_, willBuild_, downloadSize_, narSize_}); @@ -131,13 +135,13 @@ void Store::queryMissing(const std::vector & targets, } for (auto & i : drv.inputDrvs) - pool.enqueue(std::bind(doPath, DerivedPath::Built { i.first, i.second })); + pool.enqueue(std::bind(doPath, DerivedPath::Built{i.first, i.second})); }; - auto checkOutput = [&]( - const StorePath & drvPath, ref drv, const StorePath & outPath, ref> drvState_) - { - if (drvState_->lock()->done) return; + auto checkOutput = [&](const StorePath & drvPath, ref drv, const StorePath & outPath, + ref> drvState_) { + if (drvState_->lock()->done) + return; SubstitutablePathInfos infos; querySubstitutablePathInfos({{outPath, getDerivationCA(*drv)}}, infos); @@ -148,86 +152,89 @@ void Store::queryMissing(const std::vector & targets, } else { { auto drvState(drvState_->lock()); - if (drvState->done) return; + if (drvState->done) + return; assert(drvState->left); drvState->left--; drvState->outPaths.insert(outPath); if (!drvState->left) { for (auto & path : drvState->outPaths) - pool.enqueue(std::bind(doPath, DerivedPath::Opaque { path } )); + pool.enqueue(std::bind(doPath, DerivedPath::Opaque{path})); } } } }; doPath = [&](const DerivedPath & req) { - { auto state(state_.lock()); - if (!state->done.insert(req.to_string(*this)).second) return; - } - - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - if (!isValidPath(bfd.drvPath)) { - // FIXME: we could try to substitute the derivation. - auto state(state_.lock()); - state->unknown.insert(bfd.drvPath); - return; - } - - StorePathSet invalid; - /* true for regular derivations, and CA derivations for which we - have a trust mapping for all wanted outputs. */ - auto knownOutputPaths = true; - for (auto & [outputName, pathOpt] : queryPartialDerivationOutputMap(bfd.drvPath)) { - if (!pathOpt) { - knownOutputPaths = false; - break; - } - if (wantOutput(outputName, bfd.outputs) && !isValidPath(*pathOpt)) - invalid.insert(*pathOpt); - } - if (knownOutputPaths && invalid.empty()) return; - - auto drv = make_ref(derivationFromPath(bfd.drvPath)); - ParsedDerivation parsedDrv(StorePath(bfd.drvPath), *drv); - - if (knownOutputPaths && settings.useSubstitutes && parsedDrv.substitutesAllowed()) { - auto drvState = make_ref>(DrvState(invalid.size())); - for (auto & output : invalid) - pool.enqueue(std::bind(checkOutput, bfd.drvPath, drv, output, drvState)); - } else - mustBuildDrv(bfd.drvPath, *drv); - - }, - [&](const DerivedPath::Opaque & bo) { - - if (isValidPath(bo.path)) return; - - SubstitutablePathInfos infos; - querySubstitutablePathInfos({{bo.path, std::nullopt}}, infos); - - if (infos.empty()) { - auto state(state_.lock()); - state->unknown.insert(bo.path); + if (!state->done.insert(req.to_string(*this)).second) return; - } - - auto info = infos.find(bo.path); - assert(info != infos.end()); - - { - auto state(state_.lock()); - state->willSubstitute.insert(bo.path); - state->downloadSize += info->second.downloadSize; - state->narSize += info->second.narSize; - } + } - for (auto & ref : info->second.references) - pool.enqueue(std::bind(doPath, DerivedPath::Opaque { ref })); - }, - }, req.raw()); + std::visit( + overloaded{ + [&](const DerivedPath::Built & bfd) { + if (!isValidPath(bfd.drvPath)) { + // FIXME: we could try to substitute the derivation. + auto state(state_.lock()); + state->unknown.insert(bfd.drvPath); + return; + } + + StorePathSet invalid; + /* true for regular derivations, and CA derivations for which we + have a trust mapping for all wanted outputs. */ + auto knownOutputPaths = true; + for (auto & [outputName, pathOpt] : queryPartialDerivationOutputMap(bfd.drvPath)) { + if (!pathOpt) { + knownOutputPaths = false; + break; + } + if (wantOutput(outputName, bfd.outputs) && !isValidPath(*pathOpt)) + invalid.insert(*pathOpt); + } + if (knownOutputPaths && invalid.empty()) + return; + + auto drv = make_ref(derivationFromPath(bfd.drvPath)); + ParsedDerivation parsedDrv(StorePath(bfd.drvPath), *drv); + + if (knownOutputPaths && settings.useSubstitutes && parsedDrv.substitutesAllowed()) { + auto drvState = make_ref>(DrvState(invalid.size())); + for (auto & output : invalid) + pool.enqueue(std::bind(checkOutput, bfd.drvPath, drv, output, drvState)); + } else + mustBuildDrv(bfd.drvPath, *drv); + }, + [&](const DerivedPath::Opaque & bo) { + if (isValidPath(bo.path)) + return; + + SubstitutablePathInfos infos; + querySubstitutablePathInfos({{bo.path, std::nullopt}}, infos); + + if (infos.empty()) { + auto state(state_.lock()); + state->unknown.insert(bo.path); + return; + } + + auto info = infos.find(bo.path); + assert(info != infos.end()); + + { + auto state(state_.lock()); + state->willSubstitute.insert(bo.path); + state->downloadSize += info->second.downloadSize; + state->narSize += info->second.narSize; + } + + for (auto & ref : info->second.references) + pool.enqueue(std::bind(doPath, DerivedPath::Opaque{ref})); + }, + }, + req.raw()); }; for (auto & path : targets) @@ -236,11 +243,10 @@ void Store::queryMissing(const std::vector & targets, pool.process(); } - StorePaths Store::topoSortPaths(const StorePathSet & paths) { - return topoSort(paths, - {[&](const StorePath & path) { + return topoSort( + paths, {[&](const StorePath & path) { try { return queryPathInfo(path)->references; } catch (InvalidPath &) { @@ -249,15 +255,12 @@ StorePaths Store::topoSortPaths(const StorePathSet & paths) }}, {[&](const StorePath & path, const StorePath & parent) { return BuildError( - "cycle detected in the references of '%s' from '%s'", - printStorePath(path), - printStorePath(parent)); + "cycle detected in the references of '%s' from '%s'", printStorePath(path), printStorePath(parent)); }}); } -std::map drvOutputReferences( - const std::set & inputRealisations, - const StorePathSet & pathReferences) +std::map +drvOutputReferences(const std::set & inputRealisations, const StorePathSet & pathReferences) { std::map res; @@ -270,28 +273,20 @@ std::map drvOutputReferences( return res; } -std::map drvOutputReferences( - Store & store, - const Derivation & drv, - const StorePath & outputPath) +std::map drvOutputReferences(Store & store, const Derivation & drv, const StorePath & outputPath) { std::set inputRealisations; for (const auto & [inputDrv, outputNames] : drv.inputDrvs) { - const auto outputHashes = - staticOutputHashes(store, store.readDerivation(inputDrv)); + const auto outputHashes = staticOutputHashes(store, store.readDerivation(inputDrv)); for (const auto & outputName : outputNames) { auto outputHash = get(outputHashes, outputName); if (!outputHash) throw Error( - "output '%s' of derivation '%s' isn't realised", outputName, - store.printStorePath(inputDrv)); - auto thisRealisation = store.queryRealisation( - DrvOutput{*outputHash, outputName}); + "output '%s' of derivation '%s' isn't realised", outputName, store.printStorePath(inputDrv)); + auto thisRealisation = store.queryRealisation(DrvOutput{*outputHash, outputName}); if (!thisRealisation) - throw Error( - "output '%s' of derivation '%s' isn't built", outputName, - store.printStorePath(inputDrv)); + throw Error("output '%s' of derivation '%s' isn't built", outputName, store.printStorePath(inputDrv)); inputRealisations.insert(*thisRealisation); } } diff --git a/src/libstore/names.cc b/src/libstore/names.cc index 277aabf0f930..fed1454f4168 100644 --- a/src/libstore/names.cc +++ b/src/libstore/names.cc @@ -3,28 +3,25 @@ #include - namespace nix { - struct Regex { std::regex regex; }; - DrvName::DrvName() { name = ""; } - /* Parse a derivation name. The `name' part of a derivation name is everything up to but not including the first dash *not* followed by a letter. The `version' part is the rest (excluding the separating dash). E.g., `apache-httpd-2.0.48' is parsed to (`apache-httpd', '2.0.48'). */ -DrvName::DrvName(std::string_view s) : hits(0) +DrvName::DrvName(std::string_view s) + : hits(0) { name = fullName = std::string(s); for (unsigned int i = 0; i < s.size(); ++i) { @@ -37,10 +34,7 @@ DrvName::DrvName(std::string_view s) : hits(0) } } - -DrvName::~DrvName() -{ } - +DrvName::~DrvName() {} bool DrvName::matches(const DrvName & n) { @@ -49,27 +43,30 @@ bool DrvName::matches(const DrvName & n) regex = std::make_unique(); regex->regex = std::regex(name, std::regex::extended); } - if (!std::regex_match(n.name, regex->regex)) return false; + if (!std::regex_match(n.name, regex->regex)) + return false; } - if (version != "" && version != n.version) return false; + if (version != "" && version != n.version) + return false; return true; } - -std::string_view nextComponent(std::string_view::const_iterator & p, - const std::string_view::const_iterator end) +std::string_view nextComponent(std::string_view::const_iterator & p, const std::string_view::const_iterator end) { /* Skip any dots and dashes (component separators). */ - while (p != end && (*p == '.' || *p == '-')) ++p; + while (p != end && (*p == '.' || *p == '-')) + ++p; - if (p == end) return ""; + if (p == end) + return ""; /* If the first character is a digit, consume the longest sequence of digits. Otherwise, consume the longest sequence of non-digit, non-separator characters. */ auto s = p; if (isdigit(*p)) - while (p != end && isdigit(*p)) p++; + while (p != end && isdigit(*p)) + p++; else while (p != end && (!isdigit(*p) && *p != '.' && *p != '-')) p++; @@ -77,23 +74,28 @@ std::string_view nextComponent(std::string_view::const_iterator & p, return {s, size_t(p - s)}; } - static bool componentsLT(const std::string_view c1, const std::string_view c2) { auto n1 = string2Int(c1); auto n2 = string2Int(c2); - if (n1 && n2) return *n1 < *n2; - else if (c1 == "" && n2) return true; - else if (c1 == "pre" && c2 != "pre") return true; - else if (c2 == "pre") return false; + if (n1 && n2) + return *n1 < *n2; + else if (c1 == "" && n2) + return true; + else if (c1 == "pre" && c2 != "pre") + return true; + else if (c2 == "pre") + return false; /* Assume that `2.3a' < `2.3.1'. */ - else if (n2) return true; - else if (n1) return false; - else return c1 < c2; + else if (n2) + return true; + else if (n1) + return false; + else + return c1 < c2; } - int compareVersions(const std::string_view v1, const std::string_view v2) { auto p1 = v1.begin(); @@ -102,14 +104,15 @@ int compareVersions(const std::string_view v1, const std::string_view v2) while (p1 != v1.end() || p2 != v2.end()) { auto c1 = nextComponent(p1, v1.end()); auto c2 = nextComponent(p2, v2.end()); - if (componentsLT(c1, c2)) return -1; - else if (componentsLT(c2, c1)) return 1; + if (componentsLT(c1, c2)) + return -1; + else if (componentsLT(c2, c1)) + return 1; } return 0; } - DrvNames drvNamesFromArgs(const Strings & opArgs) { DrvNames result; @@ -118,5 +121,4 @@ DrvNames drvNamesFromArgs(const Strings & opArgs) return result; } - } diff --git a/src/libstore/names.hh b/src/libstore/names.hh index 3977fc6cc9bb..4dfb1bc8f566 100644 --- a/src/libstore/names.hh +++ b/src/libstore/names.hh @@ -27,8 +27,7 @@ private: typedef std::list DrvNames; -std::string_view nextComponent(std::string_view::const_iterator & p, - const std::string_view::const_iterator end); +std::string_view nextComponent(std::string_view::const_iterator & p, const std::string_view::const_iterator end); int compareVersions(const std::string_view v1, const std::string_view v2); DrvNames drvNamesFromArgs(const Strings & opArgs); diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc index 72d41cc943fe..990618e49c7b 100644 --- a/src/libstore/nar-accessor.cc +++ b/src/libstore/nar-accessor.cc @@ -46,13 +46,15 @@ struct NarAccessor : public FSAccessor uint64_t pos = 0; NarIndexer(NarAccessor & acc, Source & source) - : acc(acc), source(source) - { } + : acc(acc) + , source(source) + {} void createMember(const Path & path, NarMember member) { size_t level = std::count(path.begin(), path.end(), '/'); - while (parents.size() > level) parents.pop(); + while (parents.size() > level) + parents.pop(); if (parents.empty()) { acc.root = std::move(member); @@ -87,13 +89,11 @@ struct NarAccessor : public FSAccessor parents.top()->start = pos; } - void receiveContents(std::string_view data) override - { } + void receiveContents(std::string_view data) override {} void createSymlink(const Path & path, const std::string & target) override { - createMember(path, - NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); + createMember(path, NarMember{FSAccessor::Type::tSymlink, false, 0, 0, target}); } size_t read(char * data, size_t len) override @@ -104,7 +104,8 @@ struct NarAccessor : public FSAccessor } }; - NarAccessor(std::string && _nar) : nar(_nar) + NarAccessor(std::string && _nar) + : nar(_nar) { StringSource source(*nar); NarIndexer indexer(*this, source); @@ -141,7 +142,8 @@ struct NarAccessor : public FSAccessor } else if (type == "symlink") { member.type = FSAccessor::Type::tSymlink; member.target = v.value("target", ""); - } else return; + } else + return; }; json v = json::parse(listing); @@ -153,10 +155,11 @@ struct NarAccessor : public FSAccessor Path canon = path == "" ? "" : canonPath(path); NarMember * current = &root; auto end = path.end(); - for (auto it = path.begin(); it != end; ) { + for (auto it = path.begin(); it != end;) { // because it != end, the remaining component is non-empty so we need // a directory - if (current->type != FSAccessor::Type::tDirectory) return nullptr; + if (current->type != FSAccessor::Type::tDirectory) + return nullptr; // skip slash (canonPath above ensures that this is always a slash) assert(*it == '/'); @@ -165,7 +168,8 @@ struct NarAccessor : public FSAccessor // lookup current component auto next = std::find(it, end, '/'); auto child = current->children.find(std::string(it, next)); - if (child == current->children.end()) return nullptr; + if (child == current->children.end()) + return nullptr; current = &child->second; it = next; @@ -174,7 +178,8 @@ struct NarAccessor : public FSAccessor return current; } - NarMember & get(const Path & path) { + NarMember & get(const Path & path) + { auto result = find(path); if (result == nullptr) throw Error("NAR file does not contain path '%1%'", path); @@ -209,7 +214,8 @@ struct NarAccessor : public FSAccessor if (i.type != FSAccessor::Type::tRegular) throw Error("path '%1%' inside NAR file is not a regular file", path); - if (getNarBytes) return getNarBytes(i.start, i.size); + if (getNarBytes) + return getNarBytes(i.start, i.size); assert(nar); return std::string(*nar, i.start, i.size); @@ -234,14 +240,12 @@ ref makeNarAccessor(Source & source) return make_ref(source); } -ref makeLazyNarAccessor(const std::string & listing, - GetNarBytes getNarBytes) +ref makeLazyNarAccessor(const std::string & listing, GetNarBytes getNarBytes) { return make_ref(listing, getNarBytes); } -void listNar(JSONPlaceholder & res, ref accessor, - const Path & path, bool recurse) +void listNar(JSONPlaceholder & res, ref accessor, const Path & path, bool recurse) { auto st = accessor->stat(path); diff --git a/src/libstore/nar-accessor.hh b/src/libstore/nar-accessor.hh index c2241a04c00f..651bae3d343b 100644 --- a/src/libstore/nar-accessor.hh +++ b/src/libstore/nar-accessor.hh @@ -20,15 +20,12 @@ ref makeNarAccessor(Source & source); inside the NAR. */ typedef std::function GetNarBytes; -ref makeLazyNarAccessor( - const std::string & listing, - GetNarBytes getNarBytes); +ref makeLazyNarAccessor(const std::string & listing, GetNarBytes getNarBytes); class JSONPlaceholder; /* Write a JSON representation of the contents of a NAR (except file contents). */ -void listNar(JSONPlaceholder & res, ref accessor, - const Path & path, bool recurse); +void listNar(JSONPlaceholder & res, ref accessor, const Path & path, bool recurse); } diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc index 9dd81ddfb959..2428f0b90848 100644 --- a/src/libstore/nar-info-disk-cache.cc +++ b/src/libstore/nar-info-disk-cache.cc @@ -73,9 +73,8 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache struct State { SQLite db; - SQLiteStmt insertCache, queryCache, insertNAR, insertMissingNAR, - queryNAR, insertRealisation, insertMissingRealisation, - queryRealisation, purgeCache; + SQLiteStmt insertCache, queryCache, insertNAR, insertMissingNAR, queryNAR, insertRealisation, + insertMissingRealisation, queryRealisation, purgeCache; std::map caches; }; @@ -94,35 +93,41 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache state->db.exec(schema); - state->insertCache.create(state->db, + state->insertCache.create( + state->db, "insert or replace into BinaryCaches(url, timestamp, storeDir, wantMassQuery, priority) values (?, ?, ?, ?, ?)"); - state->queryCache.create(state->db, - "select id, storeDir, wantMassQuery, priority from BinaryCaches where url = ?"); + state->queryCache.create( + state->db, "select id, storeDir, wantMassQuery, priority from BinaryCaches where url = ?"); - state->insertNAR.create(state->db, + state->insertNAR.create( + state->db, "insert or replace into NARs(cache, hashPart, namePart, url, compression, fileHash, fileSize, narHash, " "narSize, refs, deriver, sigs, ca, timestamp, present) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)"); - state->insertMissingNAR.create(state->db, - "insert or replace into NARs(cache, hashPart, timestamp, present) values (?, ?, ?, 0)"); + state->insertMissingNAR.create( + state->db, "insert or replace into NARs(cache, hashPart, timestamp, present) values (?, ?, ?, 0)"); - state->queryNAR.create(state->db, + state->queryNAR.create( + state->db, "select present, namePart, url, compression, fileHash, fileSize, narHash, narSize, refs, deriver, sigs, ca from NARs where cache = ? and hashPart = ? and ((present = 0 and timestamp > ?) or (present = 1 and timestamp > ?))"); - state->insertRealisation.create(state->db, + state->insertRealisation.create( + state->db, R"( insert or replace into Realisations(cache, outputId, content, timestamp) values (?, ?, ?, ?) )"); - state->insertMissingRealisation.create(state->db, + state->insertMissingRealisation.create( + state->db, R"( insert or replace into Realisations(cache, outputId, timestamp) values (?, ?, ?) )"); - state->queryRealisation.create(state->db, + state->queryRealisation.create( + state->db, R"( select content from Realisations where cache = ? and outputId = ? and @@ -138,20 +143,21 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache auto queryLastPurge_(queryLastPurge.use()); if (!queryLastPurge_.next() || queryLastPurge_.getInt(0) < now - purgeInterval) { - SQLiteStmt(state->db, + SQLiteStmt( + state->db, "delete from NARs where ((present = 0 and timestamp < ?) or (present = 1 and timestamp < ?))") .use() // 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)) + (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)); - SQLiteStmt(state->db, - "insert or replace into LastPurge(dummy, value) values ('', ?)") - .use()(now).exec(); + SQLiteStmt(state->db, "insert or replace into LastPurge(dummy, value) values ('', ?)") + .use()(now) + .exec(); } }); } @@ -159,7 +165,8 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache Cache & getCache(State & state, const std::string & uri) { auto i = state.caches.find(uri); - if (i == state.caches.end()) abort(); + if (i == state.caches.end()) + abort(); return i->second; } @@ -170,7 +177,7 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache // FIXME: race - state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority).exec(); + state->insertCache.use()(uri)(time(0))(storeDir) (wantMassQuery) (priority).exec(); assert(sqlite3_changes(state->db) == 1); state->caches[uri] = Cache{(int) sqlite3_last_insert_rowid(state->db), storeDir, wantMassQuery, priority}; }); @@ -186,99 +193,88 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache auto queryCache(state->queryCache.use()(uri)); if (!queryCache.next()) return std::nullopt; - state->caches.emplace(uri, - Cache{(int) queryCache.getInt(0), queryCache.getStr(1), queryCache.getInt(2) != 0, (int) queryCache.getInt(3)}); + state->caches.emplace( + uri, Cache{ + (int) queryCache.getInt(0), queryCache.getStr(1), queryCache.getInt(2) != 0, + (int) queryCache.getInt(3)}); } auto & cache(getCache(*state, uri)); - return CacheInfo { - .wantMassQuery = cache.wantMassQuery, - .priority = cache.priority - }; + return CacheInfo{.wantMassQuery = cache.wantMassQuery, .priority = cache.priority}; }); } - std::pair> lookupNarInfo( - const std::string & uri, const std::string & hashPart) override + std::pair> + lookupNarInfo(const std::string & uri, const std::string & hashPart) override { return retrySQLite>>( [&]() -> std::pair> { - auto state(_state.lock()); - - auto & cache(getCache(*state, uri)); - - auto now = time(0); - - auto queryNAR(state->queryNAR.use() - (cache.id) - (hashPart) - (now - settings.ttlNegativeNarInfoCache) - (now - settings.ttlPositiveNarInfoCache)); - - if (!queryNAR.next()) - return {oUnknown, 0}; - - if (!queryNAR.getInt(0)) - return {oInvalid, 0}; - - auto namePart = queryNAR.getStr(1); - auto narInfo = make_ref( - StorePath(hashPart + "-" + namePart), - Hash::parseAnyPrefixed(queryNAR.getStr(6))); - narInfo->url = queryNAR.getStr(2); - narInfo->compression = queryNAR.getStr(3); - if (!queryNAR.isNull(4)) - narInfo->fileHash = Hash::parseAnyPrefixed(queryNAR.getStr(4)); - narInfo->fileSize = queryNAR.getInt(5); - narInfo->narSize = queryNAR.getInt(7); - for (auto & r : tokenizeString(queryNAR.getStr(8), " ")) - narInfo->references.insert(StorePath(r)); - if (!queryNAR.isNull(9)) - narInfo->deriver = StorePath(queryNAR.getStr(9)); - for (auto & sig : tokenizeString(queryNAR.getStr(10), " ")) - narInfo->sigs.insert(sig); - narInfo->ca = parseContentAddressOpt(queryNAR.getStr(11)); - - return {oValid, narInfo}; - }); + auto state(_state.lock()); + + auto & cache(getCache(*state, uri)); + + auto now = time(0); + + auto queryNAR(state->queryNAR.use()(cache.id)(hashPart) (now - settings.ttlNegativeNarInfoCache)( + now - settings.ttlPositiveNarInfoCache)); + + if (!queryNAR.next()) + return {oUnknown, 0}; + + if (!queryNAR.getInt(0)) + return {oInvalid, 0}; + + auto namePart = queryNAR.getStr(1); + auto narInfo = + make_ref(StorePath(hashPart + "-" + namePart), Hash::parseAnyPrefixed(queryNAR.getStr(6))); + narInfo->url = queryNAR.getStr(2); + narInfo->compression = queryNAR.getStr(3); + if (!queryNAR.isNull(4)) + narInfo->fileHash = Hash::parseAnyPrefixed(queryNAR.getStr(4)); + narInfo->fileSize = queryNAR.getInt(5); + narInfo->narSize = queryNAR.getInt(7); + for (auto & r : tokenizeString(queryNAR.getStr(8), " ")) + narInfo->references.insert(StorePath(r)); + if (!queryNAR.isNull(9)) + narInfo->deriver = StorePath(queryNAR.getStr(9)); + for (auto & sig : tokenizeString(queryNAR.getStr(10), " ")) + narInfo->sigs.insert(sig); + narInfo->ca = parseContentAddressOpt(queryNAR.getStr(11)); + + return {oValid, narInfo}; + }); } - std::pair> lookupRealisation( - const std::string & uri, const DrvOutput & id) override + std::pair> + lookupRealisation(const std::string & uri, const DrvOutput & id) override { return retrySQLite>>( [&]() -> std::pair> { - auto state(_state.lock()); + auto state(_state.lock()); - auto & cache(getCache(*state, uri)); + auto & cache(getCache(*state, uri)); - auto now = time(0); + auto now = time(0); - auto queryRealisation(state->queryRealisation.use() - (cache.id) - (id.to_string()) - (now - settings.ttlNegativeNarInfoCache) - (now - settings.ttlPositiveNarInfoCache)); + auto queryRealisation(state->queryRealisation.use()(cache.id)(id.to_string())( + now - settings.ttlNegativeNarInfoCache)(now - settings.ttlPositiveNarInfoCache)); - if (!queryRealisation.next()) - return {oUnknown, 0}; + if (!queryRealisation.next()) + return {oUnknown, 0}; - if (queryRealisation.isNull(0)) - return {oInvalid, 0}; + if (queryRealisation.isNull(0)) + return {oInvalid, 0}; - auto realisation = - std::make_shared(Realisation::fromJSON( - nlohmann::json::parse(queryRealisation.getStr(0)), - "Local disk cache")); + auto realisation = std::make_shared( + Realisation::fromJSON(nlohmann::json::parse(queryRealisation.getStr(0)), "Local disk cache")); - return {oValid, realisation}; - }); + return {oValid, realisation}; + }); } void upsertNarInfo( - const std::string & uri, const std::string & hashPart, - std::shared_ptr info) override + const std::string & uri, const std::string & hashPart, std::shared_ptr info) override { retrySQLite([&]() { auto state(_state.lock()); @@ -289,63 +285,44 @@ class NarInfoDiskCacheImpl : public NarInfoDiskCache auto narInfo = std::dynamic_pointer_cast(info); - //assert(hashPart == storePathToHash(info->path)); - - state->insertNAR.use() - (cache.id) - (hashPart) - (std::string(info->path.name())) - (narInfo ? narInfo->url : "", narInfo != 0) - (narInfo ? narInfo->compression : "", narInfo != 0) - (narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(Base32, true) : "", narInfo && narInfo->fileHash) - (narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize) - (info->narHash.to_string(Base32, true)) - (info->narSize) - (concatStringsSep(" ", info->shortRefs())) - (info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver) - (concatStringsSep(" ", info->sigs)) - (renderContentAddress(info->ca)) - (time(0)).exec(); + // assert(hashPart == storePathToHash(info->path)); + + state->insertNAR + .use()(cache.id)(hashPart) (std::string(info->path.name()))( + narInfo ? narInfo->url : "", narInfo != 0)(narInfo ? narInfo->compression : "", narInfo != 0)( + narInfo && narInfo->fileHash ? narInfo->fileHash->to_string(Base32, true) : "", + narInfo + && narInfo->fileHash)(narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize)( + info->narHash.to_string(Base32, true))(info->narSize)(concatStringsSep(" ", info->shortRefs()))( + info->deriver ? std::string(info->deriver->to_string()) : "", (bool) info->deriver)( + concatStringsSep(" ", info->sigs))(renderContentAddress(info->ca))(time(0)) + .exec(); } else { - state->insertMissingNAR.use() - (cache.id) - (hashPart) - (time(0)).exec(); + state->insertMissingNAR.use()(cache.id)(hashPart) (time(0)).exec(); } }); } - void upsertRealisation( - const std::string & uri, - const Realisation & realisation) override + void upsertRealisation(const std::string & uri, const Realisation & realisation) override { retrySQLite([&]() { auto state(_state.lock()); auto & cache(getCache(*state, uri)); - state->insertRealisation.use() - (cache.id) - (realisation.id.to_string()) - (realisation.toJSON().dump()) - (time(0)).exec(); + state->insertRealisation.use()(cache.id)(realisation.id.to_string())(realisation.toJSON().dump())(time(0)) + .exec(); }); - } - virtual void upsertAbsentRealisation( - const std::string & uri, - const DrvOutput & id) override + virtual void upsertAbsentRealisation(const std::string & uri, const DrvOutput & id) override { retrySQLite([&]() { auto state(_state.lock()); auto & cache(getCache(*state, uri)); - state->insertMissingRealisation.use() - (cache.id) - (id.to_string()) - (time(0)).exec(); + state->insertMissingRealisation.use()(cache.id)(id.to_string())(time(0)).exec(); }); } }; diff --git a/src/libstore/nar-info-disk-cache.hh b/src/libstore/nar-info-disk-cache.hh index 2dcaa76a4903..93c125bb0057 100644 --- a/src/libstore/nar-info-disk-cache.hh +++ b/src/libstore/nar-info-disk-cache.hh @@ -11,10 +11,9 @@ class NarInfoDiskCache public: typedef enum { oValid, oInvalid, oUnknown } Outcome; - virtual ~NarInfoDiskCache() { } + virtual ~NarInfoDiskCache() {} - virtual void createCache(const std::string & uri, const Path & storeDir, - bool wantMassQuery, int priority) = 0; + virtual void createCache(const std::string & uri, const Path & storeDir, bool wantMassQuery, int priority) = 0; struct CacheInfo { @@ -24,21 +23,16 @@ public: virtual std::optional cacheExists(const std::string & uri) = 0; - virtual std::pair> lookupNarInfo( - const std::string & uri, const std::string & hashPart) = 0; - - virtual void upsertNarInfo( - const std::string & uri, const std::string & hashPart, - std::shared_ptr info) = 0; - - virtual void upsertRealisation( - const std::string & uri, - const Realisation & realisation) = 0; - virtual void upsertAbsentRealisation( - const std::string & uri, - const DrvOutput & id) = 0; - virtual std::pair> lookupRealisation( - const std::string & uri, const DrvOutput & id) = 0; + virtual std::pair> + lookupNarInfo(const std::string & uri, const std::string & hashPart) = 0; + + virtual void + upsertNarInfo(const std::string & uri, const std::string & hashPart, std::shared_ptr info) = 0; + + virtual void upsertRealisation(const std::string & uri, const Realisation & realisation) = 0; + virtual void upsertAbsentRealisation(const std::string & uri, const DrvOutput & id) = 0; + virtual std::pair> + lookupRealisation(const std::string & uri, const DrvOutput & id) = 0; }; /* Return a singleton cache object that can be used concurrently by diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc index 071d8355e5c0..1a71721df04b 100644 --- a/src/libstore/nar-info.cc +++ b/src/libstore/nar-info.cc @@ -7,9 +7,7 @@ namespace nix { NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & whence) : ValidPathInfo(StorePath(StorePath::dummy), Hash(Hash::dummy)) // FIXME: hack { - auto corrupt = [&]() { - return Error("NAR info file '%1%' is corrupt", whence); - }; + auto corrupt = [&]() { return Error("NAR info file '%1%' is corrupt", whence); }; auto parseHashField = [&](const std::string & s) { try { @@ -26,20 +24,21 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & while (pos < s.size()) { size_t colon = s.find(':', pos); - if (colon == std::string::npos) throw corrupt(); + if (colon == std::string::npos) + throw corrupt(); std::string name(s, pos, colon - pos); size_t eol = s.find('\n', colon + 2); - if (eol == std::string::npos) throw corrupt(); + if (eol == std::string::npos) + throw corrupt(); std::string value(s, colon + 2, eol - colon - 2); if (name == "StorePath") { path = store.parseStorePath(value); havePath = true; - } - else if (name == "URL") + } else if (name == "URL") url = value; else if (name == "Compression") compression = value; @@ -47,32 +46,31 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & fileHash = parseHashField(value); else if (name == "FileSize") { auto n = string2Int(value); - if (!n) throw corrupt(); + if (!n) + throw corrupt(); fileSize = *n; - } - else if (name == "NarHash") { + } else if (name == "NarHash") { narHash = parseHashField(value); haveNarHash = true; - } - else if (name == "NarSize") { + } else if (name == "NarSize") { auto n = string2Int(value); - if (!n) throw corrupt(); + if (!n) + throw corrupt(); narSize = *n; - } - else if (name == "References") { + } else if (name == "References") { auto refs = tokenizeString(value, " "); - if (!references.empty()) throw corrupt(); + if (!references.empty()) + throw corrupt(); for (auto & r : refs) references.insert(StorePath(r)); - } - else if (name == "Deriver") { + } else if (name == "Deriver") { if (value != "unknown-deriver") deriver = StorePath(value); - } - else if (name == "Sig") + } else if (name == "Sig") sigs.insert(value); else if (name == "CA") { - if (ca) throw corrupt(); + if (ca) + throw corrupt(); // FIXME: allow blank ca or require skipping field? ca = parseContentAddressOpt(value); } @@ -80,9 +78,11 @@ NarInfo::NarInfo(const Store & store, const std::string & s, const std::string & pos = eol + 1; } - if (compression == "") compression = "bzip2"; + if (compression == "") + compression = "bzip2"; - if (!havePath || !haveNarHash || url.empty() || narSize == 0) throw corrupt(); + if (!havePath || !haveNarHash || url.empty() || narSize == 0) + throw corrupt(); } std::string NarInfo::to_string(const Store & store) const diff --git a/src/libstore/nar-info.hh b/src/libstore/nar-info.hh index 01683ec731ac..f60138dc4f7f 100644 --- a/src/libstore/nar-info.hh +++ b/src/libstore/nar-info.hh @@ -16,8 +16,12 @@ struct NarInfo : ValidPathInfo uint64_t fileSize = 0; NarInfo() = delete; - NarInfo(StorePath && path, Hash narHash) : ValidPathInfo(std::move(path), narHash) { } - NarInfo(const ValidPathInfo & info) : ValidPathInfo(info) { } + NarInfo(StorePath && path, Hash narHash) + : ValidPathInfo(std::move(path), narHash) + {} + NarInfo(const ValidPathInfo & info) + : ValidPathInfo(info) + {} NarInfo(const Store & store, const std::string & s, const std::string & whence); std::string to_string(const Store & store) const; diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 8af9b1dde288..f3b9b0ac3697 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -11,10 +11,8 @@ #include #include - namespace nix { - static void makeWritable(const Path & path) { auto st = lstat(path); @@ -22,30 +20,32 @@ static void makeWritable(const Path & path) throw SysError("changing writability of '%1%'", path); } - struct MakeReadOnly { Path path; - MakeReadOnly(const PathView path) : path(path) { } + MakeReadOnly(const PathView path) + : path(path) + {} ~MakeReadOnly() { try { /* This will make the path read-only. */ - if (path != "") canonicaliseTimestampAndPermissions(path); + if (path != "") + canonicaliseTimestampAndPermissions(path); } catch (...) { ignoreException(); } } }; - LocalStore::InodeHash LocalStore::loadInodeHash() { debug("loading hash inodes in memory"); InodeHash inodeHash; AutoCloseDir dir(opendir(linksDir.c_str())); - if (!dir) throw SysError("opening directory '%1%'", linksDir); + if (!dir) + throw SysError("opening directory '%1%'", linksDir); struct dirent * dirent; while (errno = 0, dirent = readdir(dir.get())) { /* sic */ @@ -53,20 +53,21 @@ LocalStore::InodeHash LocalStore::loadInodeHash() // We don't care if we hit non-hash files, anything goes inodeHash.insert(dirent->d_ino); } - if (errno) throw SysError("reading directory '%1%'", linksDir); + if (errno) + throw SysError("reading directory '%1%'", linksDir); printMsg(lvlTalkative, format("loaded %1% hash inodes") % inodeHash.size()); return inodeHash; } - Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash) { Strings names; AutoCloseDir dir(opendir(path.c_str())); - if (!dir) throw SysError("opening directory '%1%'", path); + if (!dir) + throw SysError("opening directory '%1%'", path); struct dirent * dirent; while (errno = 0, dirent = readdir(dir.get())) { /* sic */ @@ -78,17 +79,18 @@ Strings LocalStore::readDirectoryIgnoringInodes(const Path & path, const InodeHa } std::string name = dirent->d_name; - if (name == "." || name == "..") continue; + if (name == "." || name == "..") + continue; names.push_back(name); } - if (errno) throw SysError("reading directory '%1%'", path); + if (errno) + throw SysError("reading directory '%1%'", path); return names; } - -void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats, - const Path & path, InodeHash & inodeHash, RepairFlag repair) +void LocalStore::optimisePath_( + Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash, RepairFlag repair) { checkInterrupt(); @@ -100,8 +102,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats, *.app/Contents/Resources/\*.lproj seem to be the only paths affected. See https://github.com/NixOS/nix/issues/1443 for more discussion. */ - if (std::regex_search(path, std::regex("\\.app/Contents/.+$"))) - { + if (std::regex_search(path, std::regex("\\.app/Contents/.+$"))) { debug(format("'%1%' is not allowed to be linked in macOS") % path); return; } @@ -119,7 +120,8 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats, #if CAN_LINK_SYMLINK && !S_ISLNK(st.st_mode) #endif - ) return; + ) + return; /* Sometimes SNAFUs can cause files in the Nix store to be modified, in particular when running programs as root under @@ -154,13 +156,12 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats, /* Maybe delete the link, if it has been corrupted. */ if (pathExists(linkPath)) { auto stLink = lstat(linkPath); - if (st.st_size != stLink.st_size - || (repair && hash != hashPath(htSHA256, linkPath).first)) - { + if (st.st_size != stLink.st_size || (repair && hash != hashPath(htSHA256, linkPath).first)) { // XXX: Consider overwriting linkPath with our valid version. warn("removing corrupted link '%s'", linkPath); - warn("There may be more corrupted paths." - "\nYou should run `nix-store --verify --check-contents --repair` to fix them all"); + warn( + "There may be more corrupted paths." + "\nYou should run `nix-store --verify --check-contents --repair` to fix them all"); unlink(linkPath.c_str()); } } @@ -207,14 +208,14 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats, permissions). */ const Path dirOfPath(dirOf(path)); bool mustToggle = dirOfPath != realStoreDir.get(); - if (mustToggle) makeWritable(dirOfPath); + if (mustToggle) + makeWritable(dirOfPath); /* When we're done, make the directory read-only again and reset its timestamp back to 0. */ MakeReadOnly makeReadOnly(mustToggle ? dirOfPath : ""); - Path tempLink = (format("%1%/.tmp-link-%2%-%3%") - % realStoreDir % getpid() % random()).str(); + Path tempLink = (format("%1%/.tmp-link-%2%-%3%") % realStoreDir % getpid() % random()).str(); if (link(linkPath.c_str(), tempLink.c_str()) == -1) { if (errno == EMLINK) { @@ -251,7 +252,6 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats, act->result(resFileLinked, st.st_size, st.st_blocks); } - void LocalStore::optimiseStore(OptimiseStats & stats) { Activity act(*logger, actOptimiseStore); @@ -265,7 +265,8 @@ void LocalStore::optimiseStore(OptimiseStats & stats) for (auto & i : paths) { addTempRoot(i); - if (!isValidPath(i)) continue; /* path was GC'ed, probably */ + if (!isValidPath(i)) + continue; /* path was GC'ed, probably */ { Activity act(*logger, lvlTalkative, actUnknown, fmt("optimising path '%s'", printStorePath(i))); optimisePath_(&act, stats, realStoreDir + "/" + std::string(i.to_string()), inodeHash, NoRepair); @@ -281,9 +282,7 @@ void LocalStore::optimiseStore() optimiseStore(stats); - printInfo("%s freed by hard-linking %d files", - showBytes(stats.bytesFreed), - stats.filesLinked); + printInfo("%s freed by hard-linking %d files", showBytes(stats.bytesFreed), stats.filesLinked); } void LocalStore::optimisePath(const Path & path, RepairFlag repair) @@ -291,8 +290,8 @@ void LocalStore::optimisePath(const Path & path, RepairFlag repair) OptimiseStats stats; InodeHash inodeHash; - if (settings.autoOptimiseStore) optimisePath_(nullptr, stats, path, inodeHash, repair); + if (settings.autoOptimiseStore) + optimisePath_(nullptr, stats, path, inodeHash, repair); } - } diff --git a/src/libstore/parsed-derivations.cc b/src/libstore/parsed-derivations.cc index f2288a04ed81..5755aff86f84 100644 --- a/src/libstore/parsed-derivations.cc +++ b/src/libstore/parsed-derivations.cc @@ -7,7 +7,8 @@ namespace nix { ParsedDerivation::ParsedDerivation(const StorePath & drvPath, BasicDerivation & drv) - : drvPath(drvPath), drv(drv) + : drvPath(drvPath) + , drv(drv) { /* Parse the __json attribute, if any. */ auto jsonAttr = drv.env.find("__json"); @@ -20,7 +21,7 @@ ParsedDerivation::ParsedDerivation(const StorePath & drvPath, BasicDerivation & } } -ParsedDerivation::~ParsedDerivation() { } +ParsedDerivation::~ParsedDerivation() {} std::optional ParsedDerivation::getStringAttr(const std::string & name) const { @@ -74,7 +75,8 @@ std::optional ParsedDerivation::getStringsAttr(const std::string & name Strings res; for (auto j = i->begin(); j != i->end(); ++j) { if (!j->is_string()) - throw Error("attribute '%s' of derivation '%s' must be a list of strings", name, drvPath.to_string()); + throw Error( + "attribute '%s' of derivation '%s' must be a list of strings", name, drvPath.to_string()); res.push_back(j->get()); } return res; @@ -100,17 +102,16 @@ StringSet ParsedDerivation::getRequiredSystemFeatures() const bool ParsedDerivation::canBuildLocally(Store & localStore) const { - if (drv.platform != settings.thisSystem.get() - && !settings.extraPlatforms.get().count(drv.platform) + if (drv.platform != settings.thisSystem.get() && !settings.extraPlatforms.get().count(drv.platform) && !drv.isBuiltin()) return false; - if (settings.maxBuildJobs.get() == 0 - && !drv.isBuiltin()) + if (settings.maxBuildJobs.get() == 0 && !drv.isBuiltin()) return false; for (auto & feature : getRequiredSystemFeatures()) - if (!localStore.systemFeatures.get().count(feature)) return false; + if (!localStore.systemFeatures.get().count(feature)) + return false; return true; } @@ -130,7 +131,8 @@ static std::regex shVarName("[A-Za-z_][A-Za-z0-9_]*"); std::optional ParsedDerivation::prepareStructuredAttrs(Store & store, const StorePathSet & inputPaths) { auto structuredAttrs = getStructuredAttrs(); - if (!structuredAttrs) return std::nullopt; + if (!structuredAttrs) + return std::nullopt; auto json = *structuredAttrs; @@ -150,8 +152,7 @@ std::optional ParsedDerivation::prepareStructuredAttrs(Store & s StorePathSet storePaths; for (auto & p : *i) storePaths.insert(store.parseStorePath(p.get())); - store.pathInfoToJSON(jsonRoot, - store.exportReferences(storePaths, inputPaths), false, true); + store.pathInfoToJSON(jsonRoot, store.exportReferences(storePaths, inputPaths), false, true); } json[i.key()] = nlohmann::json::parse(str.str()); // urgh } @@ -191,7 +192,8 @@ std::string writeStructuredAttrsShell(const nlohmann::json & json) for (auto & [key, value] : json.items()) { - if (!std::regex_match(key, shVarName)) continue; + if (!std::regex_match(key, shVarName)) + continue; auto s = handleSimpleType(value); if (s) @@ -203,8 +205,12 @@ std::string writeStructuredAttrsShell(const nlohmann::json & json) for (auto & value2 : value) { auto s3 = handleSimpleType(value2); - if (!s3) { good = false; break; } - s2 += *s3; s2 += ' '; + if (!s3) { + good = false; + break; + } + s2 += *s3; + s2 += ' '; } if (good) @@ -217,7 +223,10 @@ std::string writeStructuredAttrsShell(const nlohmann::json & json) for (auto & [key2, value2] : value.items()) { auto s3 = handleSimpleType(value2); - if (!s3) { good = false; break; } + if (!s3) { + good = false; + break; + } s2 += fmt("[%s]=%s ", shellEscape(key2), *s3); } diff --git a/src/libstore/path-info.cc b/src/libstore/path-info.cc index fda55b2b6183..86d2ede6941f 100644 --- a/src/libstore/path-info.cc +++ b/src/libstore/path-info.cc @@ -13,8 +13,9 @@ ValidPathInfo ValidPathInfo::read(Source & source, const Store & store, unsigned auto deriver = readString(source); auto narHash = Hash::parseAny(readString(source), htSHA256); ValidPathInfo info(path, narHash); - if (deriver != "") info.deriver = store.parseStorePath(deriver); - info.references = worker_proto::read(store, source, Phantom {}); + if (deriver != "") + info.deriver = store.parseStorePath(deriver); + info.references = worker_proto::read(store, source, Phantom{}); source >> info.registrationTime >> info.narSize; if (format >= 16) { source >> info.ultimate; @@ -24,22 +25,15 @@ ValidPathInfo ValidPathInfo::read(Source & source, const Store & store, unsigned return info; } -void ValidPathInfo::write( - Sink & sink, - const Store & store, - unsigned int format, - bool includePath) const +void ValidPathInfo::write(Sink & sink, const Store & store, unsigned int format, bool includePath) const { if (includePath) sink << store.printStorePath(path); - sink << (deriver ? store.printStorePath(*deriver) : "") - << narHash.to_string(Base16, false); + sink << (deriver ? store.printStorePath(*deriver) : "") << narHash.to_string(Base16, false); worker_proto::write(store, sink, references); sink << registrationTime << narSize; if (format >= 16) { - sink << ultimate - << sigs - << renderContentAddress(ca); + sink << ultimate << sigs << renderContentAddress(ca); } } diff --git a/src/libstore/path-info.hh b/src/libstore/path-info.hh index b4b54e593c15..2d0d1798c6c5 100644 --- a/src/libstore/path-info.hh +++ b/src/libstore/path-info.hh @@ -10,21 +10,18 @@ namespace nix { - class Store; - struct SubstitutablePathInfo { std::optional deriver; StorePathSet references; uint64_t downloadSize; /* 0 = unknown or inapplicable */ - uint64_t narSize; /* 0 = unknown */ + uint64_t narSize; /* 0 = unknown */ }; typedef std::map SubstitutablePathInfos; - struct ValidPathInfo { StorePath path; @@ -34,7 +31,7 @@ struct ValidPathInfo StorePathSet references; time_t registrationTime = 0; uint64_t narSize = 0; // 0 = unknown - uint64_t id; // internal use only + uint64_t id; // internal use only /* Whether the path is ultimately trusted, that is, it's a derivation output that was built locally. */ @@ -60,12 +57,9 @@ struct ValidPathInfo */ std::optional ca; - bool operator == (const ValidPathInfo & i) const + bool operator==(const ValidPathInfo & i) const { - return - path == i.path - && narHash == i.narHash - && references == i.references; + return path == i.path && narHash == i.narHash && references == i.references; } /* Return a fingerprint of the store path to be used in binary @@ -101,10 +95,14 @@ struct ValidPathInfo ValidPathInfo(const ValidPathInfo & other) = default; - ValidPathInfo(StorePath && path, Hash narHash) : path(std::move(path)), narHash(narHash) { }; - ValidPathInfo(const StorePath & path, Hash narHash) : path(path), narHash(narHash) { }; + ValidPathInfo(StorePath && path, Hash narHash) + : path(std::move(path)) + , narHash(narHash){}; + ValidPathInfo(const StorePath & path, Hash narHash) + : path(path) + , narHash(narHash){}; - virtual ~ValidPathInfo() { } + virtual ~ValidPathInfo() {} static ValidPathInfo read(Source & source, const Store & store, unsigned int format); static ValidPathInfo read(Source & source, const Store & store, unsigned int format, StorePath && path); diff --git a/src/libstore/path-with-outputs.cc b/src/libstore/path-with-outputs.cc index d6d67ea05b9b..fda40861135d 100644 --- a/src/libstore/path-with-outputs.cc +++ b/src/libstore/path-with-outputs.cc @@ -8,67 +8,63 @@ namespace nix { std::string StorePathWithOutputs::to_string(const Store & store) const { - return outputs.empty() - ? store.printStorePath(path) - : store.printStorePath(path) + "!" + concatStringsSep(",", outputs); + return outputs.empty() ? store.printStorePath(path) + : store.printStorePath(path) + "!" + concatStringsSep(",", outputs); } - DerivedPath StorePathWithOutputs::toDerivedPath() const { if (!outputs.empty() || path.isDerivation()) - return DerivedPath::Built { path, outputs }; + return DerivedPath::Built{path, outputs}; else - return DerivedPath::Opaque { path }; + return DerivedPath::Opaque{path}; } - std::vector toDerivedPaths(const std::vector ss) { std::vector reqs; - for (auto & s : ss) reqs.push_back(s.toDerivedPath()); + for (auto & s : ss) + reqs.push_back(s.toDerivedPath()); return reqs; } - std::variant StorePathWithOutputs::tryFromDerivedPath(const DerivedPath & p) { - return std::visit(overloaded { - [&](const DerivedPath::Opaque & bo) -> std::variant { - if (bo.path.isDerivation()) { - // drv path gets interpreted as "build", not "get drv file itself" - return bo.path; - } - return StorePathWithOutputs { bo.path }; - }, - [&](const DerivedPath::Built & bfd) -> std::variant { - return StorePathWithOutputs { bfd.drvPath, bfd.outputs }; + return std::visit( + overloaded{ + [&](const DerivedPath::Opaque & bo) -> std::variant { + if (bo.path.isDerivation()) { + // drv path gets interpreted as "build", not "get drv file itself" + return bo.path; + } + return StorePathWithOutputs{bo.path}; + }, + [&](const DerivedPath::Built & bfd) -> std::variant { + return StorePathWithOutputs{bfd.drvPath, bfd.outputs}; + }, }, - }, p.raw()); + p.raw()); } - std::pair parsePathWithOutputs(std::string_view s) { size_t n = s.find("!"); - return n == s.npos - ? std::make_pair(s, std::set()) - : std::make_pair(((std::string_view) s).substr(0, n), - tokenizeString>(((std::string_view) s).substr(n + 1), ",")); + return n == s.npos ? std::make_pair(s, std::set()) + : std::make_pair( + ((std::string_view) s).substr(0, n), + tokenizeString>(((std::string_view) s).substr(n + 1), ",")); } - StorePathWithOutputs parsePathWithOutputs(const Store & store, std::string_view pathWithOutputs) { auto [path, outputs] = parsePathWithOutputs(pathWithOutputs); - return StorePathWithOutputs { store.parseStorePath(path), std::move(outputs) }; + return StorePathWithOutputs{store.parseStorePath(path), std::move(outputs)}; } - StorePathWithOutputs followLinksToStorePathWithOutputs(const Store & store, std::string_view pathWithOutputs) { auto [path, outputs] = parsePathWithOutputs(pathWithOutputs); - return StorePathWithOutputs { store.followLinksToStorePath(path), std::move(outputs) }; + return StorePathWithOutputs{store.followLinksToStorePath(path), std::move(outputs)}; } std::pair parseOutputsSpec(const std::string & s) diff --git a/src/libstore/path-with-outputs.hh b/src/libstore/path-with-outputs.hh index 0cb5eb2231c0..7cbee6f81022 100644 --- a/src/libstore/path-with-outputs.hh +++ b/src/libstore/path-with-outputs.hh @@ -35,12 +35,20 @@ StorePathWithOutputs followLinksToStorePathWithOutputs(const Store & store, std: typedef std::set OutputNames; -struct AllOutputs { - bool operator < (const AllOutputs & _) const { return false; } +struct AllOutputs +{ + bool operator<(const AllOutputs & _) const + { + return false; + } }; -struct DefaultOutputs { - bool operator < (const DefaultOutputs & _) const { return false; } +struct DefaultOutputs +{ + bool operator<(const DefaultOutputs & _) const + { + return false; + } }; typedef std::variant OutputsSpec; diff --git a/src/libstore/path.cc b/src/libstore/path.cc index 392db225e25e..187e005bf4aa 100644 --- a/src/libstore/path.cc +++ b/src/libstore/path.cc @@ -11,10 +11,8 @@ static void checkName(std::string_view path, std::string_view name) if (name.size() > 211) throw BadStorePath("store path '%s' has a name longer than 211 characters", path); for (auto c : name) - if (!((c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || c == '+' || c == '-' || c == '.' || c == '_' || c == '?' || c == '=')) + if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '+' || c == '-' + || c == '.' || c == '_' || c == '?' || c == '=')) throw BadStorePath("store path '%s' contains illegal character '%s'", path, c); } @@ -24,8 +22,7 @@ StorePath::StorePath(std::string_view _baseName) if (baseName.size() < HashLen + 1) throw BadStorePath("'%s' is too short to be a valid store path", baseName); for (auto c : hashPart()) - if (c == 'e' || c == 'o' || c == 'u' || c == 't' - || !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))) + if (c == 'e' || c == 'o' || c == 'u' || c == 't' || !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z'))) throw BadStorePath("store path '%s' contains illegal base-32 character '%s'", baseName, c); checkName(baseName, name()); } @@ -75,7 +72,8 @@ bool Store::isStorePath(std::string_view path) const StorePathSet Store::parseStorePathSet(const PathSet & paths) const { StorePathSet res; - for (auto & i : paths) res.insert(parseStorePath(i)); + for (auto & i : paths) + res.insert(parseStorePath(i)); return res; } @@ -87,7 +85,8 @@ std::string Store::printStorePath(const StorePath & path) const PathSet Store::printStorePathSet(const StorePathSet & paths) const { PathSet res; - for (auto & i : paths) res.insert(printStorePath(i)); + for (auto & i : paths) + res.insert(printStorePath(i)); return res; } diff --git a/src/libstore/path.hh b/src/libstore/path.hh index 77fd0f8dce22..20fe6d4fd604 100644 --- a/src/libstore/path.hh +++ b/src/libstore/path.hh @@ -28,17 +28,17 @@ public: return baseName; } - bool operator < (const StorePath & other) const + bool operator<(const StorePath & other) const { return baseName < other.baseName; } - bool operator == (const StorePath & other) const + bool operator==(const StorePath & other) const { return baseName == other.baseName; } - bool operator != (const StorePath & other) const + bool operator!=(const StorePath & other) const { return baseName != other.baseName; } @@ -75,10 +75,12 @@ const std::string drvExtension = ".drv"; namespace std { -template<> struct hash { +template<> +struct hash +{ std::size_t operator()(const nix::StorePath & path) const noexcept { - return * (std::size_t *) path.to_string().data(); + return *(std::size_t *) path.to_string().data(); } }; diff --git a/src/libstore/pathlocks.cc b/src/libstore/pathlocks.cc index 42023cd0a437..26e47a82131a 100644 --- a/src/libstore/pathlocks.cc +++ b/src/libstore/pathlocks.cc @@ -10,10 +10,8 @@ #include #include - namespace nix { - AutoCloseFD openLockFile(const Path & path, bool create) { AutoCloseFD fd; @@ -25,7 +23,6 @@ AutoCloseFD openLockFile(const Path & path, bool create) return fd; } - void deleteLockFile(const Path & path, int fd) { /* Get rid of the lock file. Have to be careful not to introduce @@ -38,14 +35,17 @@ void deleteLockFile(const Path & path, int fd) file is an optimisation, not a necessity. */ } - bool lockFile(int fd, LockType lockType, bool wait) { int type; - if (lockType == ltRead) type = LOCK_SH; - else if (lockType == ltWrite) type = LOCK_EX; - else if (lockType == ltNone) type = LOCK_UN; - else abort(); + if (lockType == ltRead) + type = LOCK_SH; + else if (lockType == ltWrite) + type = LOCK_EX; + else if (lockType == ltNone) + type = LOCK_UN; + else + abort(); if (wait) { while (flock(fd, type) != 0) { @@ -58,7 +58,8 @@ bool lockFile(int fd, LockType lockType, bool wait) } else { while (flock(fd, type | LOCK_NB) != 0) { checkInterrupt(); - if (errno == EWOULDBLOCK) return false; + if (errno == EWOULDBLOCK) + return false; if (errno != EINTR) throw SysError("acquiring/releasing lock"); } @@ -67,12 +68,9 @@ bool lockFile(int fd, LockType lockType, bool wait) return true; } - PathLocks::PathLocks() : deletePaths(false) -{ -} - +{} PathLocks::PathLocks(const PathSet & paths, const std::string & waitMsg) : deletePaths(false) @@ -80,9 +78,7 @@ PathLocks::PathLocks(const PathSet & paths, const std::string & waitMsg) lockPaths(paths, waitMsg); } - -bool PathLocks::lockPaths(const PathSet & paths, - const std::string & waitMsg, bool wait) +bool PathLocks::lockPaths(const PathSet & paths, const std::string & waitMsg, bool wait) { assert(fds.empty()); @@ -108,7 +104,8 @@ bool PathLocks::lockPaths(const PathSet & paths, /* Acquire an exclusive lock. */ if (!lockFile(fd.get(), ltWrite, false)) { if (wait) { - if (waitMsg != "") printError(waitMsg); + if (waitMsg != "") + printError(waitMsg); lockFile(fd.get(), ltWrite, true); } else { /* Failed to lock this path; release all other @@ -142,7 +139,6 @@ bool PathLocks::lockPaths(const PathSet & paths, return true; } - PathLocks::~PathLocks() { try { @@ -152,16 +148,14 @@ PathLocks::~PathLocks() } } - void PathLocks::unlock() { for (auto & i : fds) { - if (deletePaths) deleteLockFile(i.second, i.first); + if (deletePaths) + deleteLockFile(i.second, i.first); if (close(i.first) == -1) - printError( - "error (ignored): cannot close lock file on '%1%'", - i.second); + printError("error (ignored): cannot close lock file on '%1%'", i.second); debug(format("lock released on '%1%'") % i.second); } @@ -169,13 +163,11 @@ void PathLocks::unlock() fds.clear(); } - void PathLocks::setDeletion(bool deletePaths) { this->deletePaths = deletePaths; } - FdLock::FdLock(int fd, LockType lockType, bool wait, std::string_view waitMsg) : fd(fd) { @@ -188,5 +180,4 @@ FdLock::FdLock(int fd, LockType lockType, bool wait, std::string_view waitMsg) acquired = lockFile(fd, lockType, false); } - } diff --git a/src/libstore/pathlocks.hh b/src/libstore/pathlocks.hh index 5e3a734b4379..4b893039a09b 100644 --- a/src/libstore/pathlocks.hh +++ b/src/libstore/pathlocks.hh @@ -25,11 +25,8 @@ private: public: PathLocks(); - PathLocks(const PathSet & paths, - const std::string & waitMsg = ""); - bool lockPaths(const PathSet & _paths, - const std::string & waitMsg = "", - bool wait = true); + PathLocks(const PathSet & paths, const std::string & waitMsg = ""); + bool lockPaths(const PathSet & _paths, const std::string & waitMsg = "", bool wait = true); ~PathLocks(); void unlock(); void setDeletion(bool deletePaths); diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index 3e4188188f69..4e967b413c8c 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -9,26 +9,24 @@ #include #include - namespace nix { - /* Parse a generation name of the format `--link'. */ static std::optional parseName(const std::string & profileName, const std::string & name) { - if (name.substr(0, profileName.size() + 1) != profileName + "-") return {}; + if (name.substr(0, profileName.size() + 1) != profileName + "-") + return {}; auto s = name.substr(profileName.size() + 1); auto p = s.find("-link"); - if (p == std::string::npos) return {}; + if (p == std::string::npos) + return {}; if (auto n = string2Int(s.substr(0, p))) return *n; else return {}; } - - std::pair> findGenerations(Path profile) { Generations gens; @@ -39,36 +37,21 @@ std::pair> findGenerations(Path pro for (auto & i : readDirectory(profileDir)) { if (auto n = parseName(profileName, i.name)) { auto path = profileDir + "/" + i.name; - gens.push_back({ - .number = *n, - .path = path, - .creationTime = lstat(path).st_mtime - }); + gens.push_back({.number = *n, .path = path, .creationTime = lstat(path).st_mtime}); } } - gens.sort([](const Generation & a, const Generation & b) - { - return a.number < b.number; - }); - - return { - gens, - pathExists(profile) - ? parseName(profileName, readLink(profile)) - : std::nullopt - }; -} + gens.sort([](const Generation & a, const Generation & b) { return a.number < b.number; }); + return {gens, pathExists(profile) ? parseName(profileName, readLink(profile)) : std::nullopt}; +} -static void makeName(const Path & profile, GenerationNumber num, - Path & outLink) +static void makeName(const Path & profile, GenerationNumber num, Path & outLink) { Path prefix = (format("%1%-%2%") % profile % num).str(); outLink = prefix + "-link"; } - Path createGeneration(ref store, Path profile, StorePath outPath) { /* The new generation number should be higher than old the @@ -107,14 +90,12 @@ Path createGeneration(ref store, Path profile, StorePath outPath) return generation; } - static void removeFile(const Path & path) { if (remove(path.c_str()) == -1) throw SysError("cannot unlink '%1%'", path); } - void deleteGeneration(const Path & profile, GenerationNumber gen) { Path generation; @@ -122,7 +103,6 @@ void deleteGeneration(const Path & profile, GenerationNumber gen) removeFile(generation); } - static void deleteGeneration2(const Path & profile, GenerationNumber gen, bool dryRun) { if (dryRun) @@ -133,7 +113,6 @@ static void deleteGeneration2(const Path & profile, GenerationNumber gen, bool d } } - void deleteGenerations(const Path & profile, const std::set & gensToDelete, bool dryRun) { PathLocks lock; @@ -145,7 +124,8 @@ void deleteGenerations(const Path & profile, const std::set & throw Error("cannot delete current version of profile %1%'", profile); for (auto & i : gens) { - if (!gensToDelete.count(i.number)) continue; + if (!gensToDelete.count(i.number)) + continue; deleteGeneration2(profile, i.number, dryRun); } } @@ -185,7 +165,6 @@ void deleteOldGenerations(const Path & profile, bool dryRun) deleteGeneration2(profile, i.number, dryRun); } - void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun) { PathLocks lock; @@ -208,7 +187,6 @@ void deleteGenerationsOlderThan(const Path & profile, time_t t, bool dryRun) } } - void deleteGenerationsOlderThan(const Path & profile, std::string_view timeSpec, bool dryRun) { if (timeSpec.empty() || timeSpec[timeSpec.size() - 1] != 'd') @@ -226,20 +204,16 @@ void deleteGenerationsOlderThan(const Path & profile, std::string_view timeSpec, deleteGenerationsOlderThan(profile, oldTime, dryRun); } - void switchLink(Path link, Path target) { /* Hacky. */ - if (dirOf(target) == dirOf(link)) target = baseNameOf(target); + if (dirOf(target) == dirOf(link)) + target = baseNameOf(target); replaceSymlink(target, link); } - -void switchGeneration( - const Path & profile, - std::optional dstGen, - bool dryRun) +void switchGeneration(const Path & profile, std::optional dstGen, bool dryRun) { PathLocks lock; lockProfile(lock, profile); @@ -248,8 +222,7 @@ void switchGeneration( std::optional dst; for (auto & i : gens) - if ((!dstGen && i.number < curGen) || - (dstGen && i.number == *dstGen)) + if ((!dstGen && i.number < curGen) || (dstGen && i.number == *dstGen)) dst = i; if (!dst) { @@ -261,34 +234,31 @@ void switchGeneration( notice("switching profile from version %d to %d", curGen.value_or(0), dst->number); - if (dryRun) return; + if (dryRun) + return; switchLink(profile, dst->path); } - void lockProfile(PathLocks & lock, const Path & profile) { lock.lockPaths({profile}, (format("waiting for lock on profile '%1%'") % profile).str()); lock.setDeletion(true); } - std::string optimisticLockProfile(const Path & profile) { return pathExists(profile) ? readLink(profile) : ""; } - Path getDefaultProfile() { Path profileLink = getHome() + "/.nix-profile"; try { if (!pathExists(profileLink)) { replaceSymlink( - getuid() == 0 - ? settings.nixStateDir + "/profiles/default" - : fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName()), + getuid() == 0 ? settings.nixStateDir + "/profiles/default" + : fmt("%s/profiles/per-user/%s/profile", settings.nixStateDir, getUserName()), profileLink); } return absPath(readLink(profileLink), dirOf(profileLink)); @@ -297,5 +267,4 @@ Path getDefaultProfile() } } - } diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh index 408ca039cfbd..f846f4291b2c 100644 --- a/src/libstore/profiles.hh +++ b/src/libstore/profiles.hh @@ -5,12 +5,10 @@ #include - namespace nix { class StorePath; - typedef uint64_t GenerationNumber; struct Generation @@ -22,7 +20,6 @@ struct Generation typedef std::list Generations; - /* Returns the list of currently present generations for the specified profile, sorted by generation number. Also returns the number of the current generation. */ @@ -48,10 +45,7 @@ void switchLink(Path link, Path target); /* Roll back a profile to the specified generation, or to the most recent one older than the current. */ -void switchGeneration( - const Path & profile, - std::optional dstGen, - bool dryRun); +void switchGeneration(const Path & profile, std::optional dstGen, bool dryRun); /* Ensure exclusive access to a profile. Any command that modifies the profile first acquires this lock. */ diff --git a/src/libstore/realisation.cc b/src/libstore/realisation.cc index d63ec5ea2a71..9ee8e0a08888 100644 --- a/src/libstore/realisation.cc +++ b/src/libstore/realisation.cc @@ -7,18 +7,20 @@ namespace nix { MakeError(InvalidDerivationOutputId, Error); -DrvOutput DrvOutput::parse(const std::string &strRep) { +DrvOutput DrvOutput::parse(const std::string & strRep) +{ size_t n = strRep.find("!"); if (n == strRep.npos) throw InvalidDerivationOutputId("Invalid derivation output id %s", strRep); return DrvOutput{ .drvHash = Hash::parseAnyPrefixed(strRep.substr(0, n)), - .outputName = strRep.substr(n+1), + .outputName = strRep.substr(n + 1), }; } -std::string DrvOutput::to_string() const { +std::string DrvOutput::to_string() const +{ return strHash() + "!" + outputName; } @@ -31,23 +33,20 @@ std::set Realisation::closure(Store & store, const std::set & startOutputs, std::set & res) { - auto getDeps = [&](const Realisation& current) -> std::set { + auto getDeps = [&](const Realisation & current) -> std::set { std::set res; - for (auto& [currentDep, _] : current.dependentRealisations) { + for (auto & [currentDep, _] : current.dependentRealisations) { if (auto currentRealisation = store.queryRealisation(currentDep)) res.insert(*currentRealisation); else - throw Error( - "Unrealised derivation '%s'", currentDep.to_string()); + throw Error("Unrealised derivation '%s'", currentDep.to_string()); } return res; }; computeClosure( startOutputs, res, - [&](const Realisation& current, - std::function>&)> - processEdges) { + [&](const Realisation & current, std::function> &)> processEdges) { std::promise> promise; try { auto res = getDeps(current); @@ -59,7 +58,8 @@ void Realisation::closure(Store & store, const std::set & startOutp }); } -nlohmann::json Realisation::toJSON() const { +nlohmann::json Realisation::toJSON() const +{ auto jsonDependentRealisations = nlohmann::json::object(); for (auto & [depId, depOutPath] : dependentRealisations) jsonDependentRealisations.emplace(depId.to_string(), depOutPath.to_string()); @@ -71,9 +71,8 @@ nlohmann::json Realisation::toJSON() const { }; } -Realisation Realisation::fromJSON( - const nlohmann::json& json, - const std::string& whence) { +Realisation Realisation::fromJSON(const nlohmann::json & json, const std::string & whence) +{ auto getOptionalField = [&](std::string fieldName) -> std::optional { auto fieldIterator = json.find(fieldName); if (fieldIterator == json.end()) @@ -84,16 +83,14 @@ Realisation Realisation::fromJSON( if (auto field = getOptionalField(fieldName)) return *field; else - throw Error( - "Drv output info file '%1%' is corrupt, missing field %2%", - whence, fieldName); + throw Error("Drv output info file '%1%' is corrupt, missing field %2%", whence, fieldName); }; StringSet signatures; if (auto signaturesIterator = json.find("signatures"); signaturesIterator != json.end()) signatures.insert(signaturesIterator->begin(), signaturesIterator->end()); - std::map dependentRealisations; + std::map dependentRealisations; if (auto jsonDependencies = json.find("dependentRealisations"); jsonDependencies != json.end()) for (auto & [jsonDepId, jsonDepOutPath] : jsonDependencies->get>()) dependentRealisations.insert({DrvOutput::parse(jsonDepId), StorePath(jsonDepOutPath)}); @@ -136,13 +133,14 @@ size_t Realisation::checkSignatures(const PublicKeys & publicKeys) const return good; } -StorePath RealisedPath::path() const { +StorePath RealisedPath::path() const +{ return std::visit([](auto && arg) { return arg.getPath(); }, raw); } bool Realisation::isCompatibleWith(const Realisation & other) const { - assert (id == other.id); + assert(id == other.id); if (outPath == other.outPath) { if (dependentRealisations.empty() != other.dependentRealisations.empty()) { warn( @@ -158,27 +156,24 @@ bool Realisation::isCompatibleWith(const Realisation & other) const return false; } -void RealisedPath::closure( - Store& store, - const RealisedPath::Set& startPaths, - RealisedPath::Set& ret) +void RealisedPath::closure(Store & store, const RealisedPath::Set & startPaths, RealisedPath::Set & ret) { // FIXME: This only builds the store-path closure, not the real realisation // closure StorePathSet initialStorePaths, pathsClosure; - for (auto& path : startPaths) + for (auto & path : startPaths) initialStorePaths.insert(path.path()); store.computeFSClosure(initialStorePaths, pathsClosure); ret.insert(startPaths.begin(), startPaths.end()); ret.insert(pathsClosure.begin(), pathsClosure.end()); } -void RealisedPath::closure(Store& store, RealisedPath::Set & ret) const +void RealisedPath::closure(Store & store, RealisedPath::Set & ret) const { RealisedPath::closure(store, {*this}, ret); } -RealisedPath::Set RealisedPath::closure(Store& store) const +RealisedPath::Set RealisedPath::closure(Store & store) const { RealisedPath::Set ret; closure(store, ret); diff --git a/src/libstore/realisation.hh b/src/libstore/realisation.hh index 9070a6ee21d4..2a32e59ec57d 100644 --- a/src/libstore/realisation.hh +++ b/src/libstore/realisation.hh @@ -7,7 +7,8 @@ namespace nix { -struct DrvOutput { +struct DrvOutput +{ // The hash modulo of the derivation Hash drvHash; std::string outputName; @@ -15,14 +16,17 @@ struct DrvOutput { std::string to_string() const; std::string strHash() const - { return drvHash.to_string(Base16, true); } + { + return drvHash.to_string(Base16, true); + } static DrvOutput parse(const std::string &); GENERATE_CMP(DrvOutput, me->drvHash, me->outputName); }; -struct Realisation { +struct Realisation +{ DrvOutput id; StorePath outPath; @@ -37,7 +41,7 @@ struct Realisation { std::map dependentRealisations; nlohmann::json toJSON() const; - static Realisation fromJSON(const nlohmann::json& json, const std::string& whence); + static Realisation fromJSON(const nlohmann::json & json, const std::string & whence); std::string fingerprint() const; void sign(const SecretKey &); @@ -49,26 +53,33 @@ struct Realisation { bool isCompatibleWith(const Realisation & other) const; - StorePath getPath() const { return outPath; } + StorePath getPath() const + { + return outPath; + } GENERATE_CMP(Realisation, me->id, me->outPath); }; typedef std::map DrvOutputs; -struct OpaquePath { +struct OpaquePath +{ StorePath path; - StorePath getPath() const { return path; } + StorePath getPath() const + { + return path; + } GENERATE_CMP(OpaquePath, me->path); }; - /** * A store path with all the history of how it went into the store */ -struct RealisedPath { +struct RealisedPath +{ /* * A path is either the result of the realisation of a derivation or * an opaque blob that has been directly added to the store @@ -78,17 +89,21 @@ struct RealisedPath { using Set = std::set; - RealisedPath(StorePath path) : raw(OpaquePath{path}) {} - RealisedPath(Realisation r) : raw(r) {} + RealisedPath(StorePath path) + : raw(OpaquePath{path}) + {} + RealisedPath(Realisation r) + : raw(r) + {} /** * Get the raw store path associated to this */ StorePath path() const; - void closure(Store& store, Set& ret) const; - static void closure(Store& store, const Set& startPaths, Set& ret); - Set closure(Store& store) const; + void closure(Store & store, Set & ret) const; + static void closure(Store & store, const Set & startPaths, Set & ret); + Set closure(Store & store) const; GENERATE_CMP(RealisedPath, me->raw); }; diff --git a/src/libstore/references.cc b/src/libstore/references.cc index 34dce092cb2f..dc6146d855b7 100644 --- a/src/libstore/references.cc +++ b/src/libstore/references.cc @@ -7,27 +7,22 @@ #include #include - namespace nix { - static size_t refLength = 32; /* characters */ - -static void search( - std::string_view s, - StringSet & hashes, - StringSet & seen) +static void search(std::string_view s, StringSet & hashes, StringSet & seen) { static std::once_flag initialised; static bool isBase32[256]; - std::call_once(initialised, [](){ - for (unsigned int i = 0; i < 256; ++i) isBase32[i] = false; + std::call_once(initialised, []() { + for (unsigned int i = 0; i < 256; ++i) + isBase32[i] = false; for (unsigned int i = 0; i < base32Chars.size(); ++i) isBase32[(unsigned char) base32Chars[i]] = true; }); - for (size_t i = 0; i + refLength <= s.size(); ) { + for (size_t i = 0; i + refLength <= s.size();) { int j; bool match = true; for (j = refLength - 1; j >= 0; --j) @@ -36,19 +31,18 @@ static void search( match = false; break; } - if (!match) continue; + 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(format("found reference to '%1%' at offset '%2%'") % ref % i); seen.insert(ref); } ++i; } } - -void RefScanSink::operator () (std::string_view data) +void RefScanSink::operator()(std::string_view data) { /* It's possible that a reference spans the previous and current fragment, so search in the concatenation of the tail of the @@ -66,21 +60,15 @@ void RefScanSink::operator () (std::string_view data) tail.append(data.data() + data.size() - tailLen, tailLen); } - -std::pair scanForReferences( - const std::string & path, - const StorePathSet & refs) +std::pair scanForReferences(const std::string & path, const StorePathSet & refs) { - HashSink hashSink { htSHA256 }; + HashSink hashSink{htSHA256}; auto found = scanForReferences(hashSink, path, refs); auto hash = hashSink.finish(); return std::pair(found, hash); } -StorePathSet scanForReferences( - Sink & toTee, - const Path & path, - const StorePathSet & refs) +StorePathSet scanForReferences(Sink & toTee, const Path & path, const StorePathSet & refs) { StringSet hashes; std::map backMap; @@ -94,7 +82,7 @@ StorePathSet scanForReferences( /* Look for the hashes in the NAR dump of the path. */ RefScanSink refsSink(std::move(hashes)); - TeeSink sink { refsSink, toTee }; + TeeSink sink{refsSink, toTee}; dumpPath(path, sink); /* Map the hashes found back to their store paths. */ @@ -108,14 +96,15 @@ StorePathSet scanForReferences( return found; } - RewritingSink::RewritingSink(const std::string & from, const std::string & to, Sink & nextSink) - : from(from), to(to), nextSink(nextSink) + : from(from) + , to(to) + , nextSink(nextSink) { assert(from.size() == to.size()); } -void RewritingSink::operator () (std::string_view data) +void RewritingSink::operator()(std::string_view data) { std::string s(prev); s.append(data); @@ -132,12 +121,14 @@ void RewritingSink::operator () (std::string_view data) pos += consumed; - if (consumed) nextSink(s.substr(0, consumed)); + if (consumed) + nextSink(s.substr(0, consumed)); } void RewritingSink::flush() { - if (prev.empty()) return; + if (prev.empty()) + return; pos += prev.size(); nextSink(prev); prev.clear(); @@ -146,10 +137,9 @@ void RewritingSink::flush() HashModuloSink::HashModuloSink(HashType ht, const std::string & modulus) : hashSink(ht) , rewritingSink(modulus, std::string(modulus.size(), 0), hashSink) -{ -} +{} -void HashModuloSink::operator () (std::string_view data) +void HashModuloSink::operator()(std::string_view data) { rewritingSink(data); } diff --git a/src/libstore/references.hh b/src/libstore/references.hh index a6119c861904..371fe9200d76 100644 --- a/src/libstore/references.hh +++ b/src/libstore/references.hh @@ -18,13 +18,16 @@ class RefScanSink : public Sink public: - RefScanSink(StringSet && hashes) : hashes(hashes) - { } + RefScanSink(StringSet && hashes) + : hashes(hashes) + {} StringSet & getResult() - { return seen; } + { + return seen; + } - void operator () (std::string_view data) override; + void operator()(std::string_view data) override; }; struct RewritingSink : Sink @@ -37,7 +40,7 @@ struct RewritingSink : Sink RewritingSink(const std::string & from, const std::string & to, Sink & nextSink); - void operator () (std::string_view data) override; + void operator()(std::string_view data) override; void flush(); }; @@ -49,7 +52,7 @@ struct HashModuloSink : AbstractHashSink HashModuloSink(HashType ht, const std::string & modulus); - void operator () (std::string_view data) override; + void operator()(std::string_view data) override; HashResult finish() override; }; diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc index 0ce335646756..507291f1706d 100644 --- a/src/libstore/remote-fs-accessor.cc +++ b/src/libstore/remote-fs-accessor.cc @@ -60,7 +60,8 @@ std::pair, Path> RemoteFSAccessor::fetch(const Path & path_, boo throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath)); auto i = nars.find(std::string(storePath.hashPart())); - if (i != nars.end()) return {i->second, restPath}; + if (i != nars.end()) + return {i->second, restPath}; std::string listing; Path cacheFile; @@ -70,32 +71,32 @@ std::pair, Path> RemoteFSAccessor::fetch(const Path & path_, boo try { listing = nix::readFile(makeCacheFile(storePath.hashPart(), "ls")); - auto narAccessor = makeLazyNarAccessor(listing, - [cacheFile](uint64_t offset, uint64_t length) { + auto narAccessor = makeLazyNarAccessor(listing, [cacheFile](uint64_t offset, uint64_t length) { + AutoCloseFD fd = open(cacheFile.c_str(), O_RDONLY | O_CLOEXEC); + if (!fd) + throw SysError("opening NAR cache file '%s'", cacheFile); - AutoCloseFD fd = open(cacheFile.c_str(), O_RDONLY | O_CLOEXEC); - if (!fd) - throw SysError("opening NAR cache file '%s'", cacheFile); + if (lseek(fd.get(), offset, SEEK_SET) != (off_t) offset) + throw SysError("seeking in '%s'", cacheFile); - if (lseek(fd.get(), offset, SEEK_SET) != (off_t) offset) - throw SysError("seeking in '%s'", cacheFile); + std::string buf(length, 0); + readFull(fd.get(), buf.data(), length); - std::string buf(length, 0); - readFull(fd.get(), buf.data(), length); - - return buf; - }); + return buf; + }); nars.emplace(storePath.hashPart(), narAccessor); return {narAccessor, restPath}; - } catch (SysError &) { } + } catch (SysError &) { + } try { auto narAccessor = makeNarAccessor(nix::readFile(cacheFile)); nars.emplace(storePath.hashPart(), narAccessor); return {narAccessor, restPath}; - } catch (SysError &) { } + } catch (SysError &) { + } } StringSink sink; diff --git a/src/libstore/remote-fs-accessor.hh b/src/libstore/remote-fs-accessor.hh index 99f5544ef08a..162a457fe72b 100644 --- a/src/libstore/remote-fs-accessor.hh +++ b/src/libstore/remote-fs-accessor.hh @@ -24,8 +24,7 @@ class RemoteFSAccessor : public FSAccessor public: - RemoteFSAccessor(ref store, - const /* FIXME: use std::optional */ Path & cacheDir = ""); + RemoteFSAccessor(ref store, const /* FIXME: use std::optional */ Path & cacheDir = ""); Stat stat(const Path & path) override; diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc index bc36aef5d0fa..603f807df9a6 100644 --- a/src/libstore/remote-store.cc +++ b/src/libstore/remote-store.cc @@ -30,7 +30,6 @@ void write(const Store & store, Sink & out, const std::string & str) out << str; } - StorePath read(const Store & store, Source & from, Phantom _) { return store.parseStorePath(readString(from)); @@ -41,7 +40,6 @@ void write(const Store & store, Sink & out, const StorePath & storePath) out << store.printStorePath(storePath); } - ContentAddress read(const Store & store, Source & from, Phantom _) { return parseContentAddress(readString(from)); @@ -52,7 +50,6 @@ void write(const Store & store, Sink & out, const ContentAddress & ca) out << renderContentAddress(ca); } - DerivedPath read(const Store & store, Source & from, Phantom _) { auto s = readString(from); @@ -64,14 +61,10 @@ void write(const Store & store, Sink & out, const DerivedPath & req) out << req.to_string(store); } - Realisation read(const Store & store, Source & from, Phantom _) { std::string rawInput = readString(from); - return Realisation::fromJSON( - nlohmann::json::parse(rawInput), - "remote-protocol" - ); + return Realisation::fromJSON(nlohmann::json::parse(rawInput), "remote-protocol"); } void write(const Store & store, Sink & out, const Realisation & realisation) @@ -79,7 +72,6 @@ void write(const Store & store, Sink & out, const Realisation & realisation) out << realisation.toJSON().dump(); } - DrvOutput read(const Store & store, Source & from, Phantom _) { return DrvOutput::parse(readString(from)); @@ -90,40 +82,27 @@ void write(const Store & store, Sink & out, const DrvOutput & drvOutput) out << drvOutput.to_string(); } - BuildResult read(const Store & store, Source & from, Phantom _) { - auto path = worker_proto::read(store, from, Phantom {}); - BuildResult res { .path = path }; + auto path = worker_proto::read(store, from, Phantom{}); + BuildResult res{.path = path}; res.status = (BuildResult::Status) readInt(from); - from - >> res.errorMsg - >> res.timesBuilt - >> res.isNonDeterministic - >> res.startTime - >> res.stopTime; - res.builtOutputs = worker_proto::read(store, from, Phantom {}); + from >> res.errorMsg >> res.timesBuilt >> res.isNonDeterministic >> res.startTime >> res.stopTime; + res.builtOutputs = worker_proto::read(store, from, Phantom{}); return res; } void write(const Store & store, Sink & to, const BuildResult & res) { worker_proto::write(store, to, res.path); - to - << res.status - << res.errorMsg - << res.timesBuilt - << res.isNonDeterministic - << res.startTime - << res.stopTime; + to << res.status << res.errorMsg << res.timesBuilt << res.isNonDeterministic << res.startTime << res.stopTime; worker_proto::write(store, to, res.builtOutputs); } - std::optional read(const Store & store, Source & from, Phantom> _) { auto s = readString(from); - return s == "" ? std::optional {} : store.parseStorePath(s); + return s == "" ? std::optional{} : store.parseStorePath(s); } void write(const Store & store, Sink & out, const std::optional & storePathOpt) @@ -131,7 +110,6 @@ void write(const Store & store, Sink & out, const std::optional & sto out << (storePathOpt ? store.printStorePath(*storePathOpt) : ""); } - std::optional read(const Store & store, Source & from, Phantom> _) { return parseContentAddressOpt(readString(from)); @@ -144,34 +122,30 @@ void write(const Store & store, Sink & out, const std::optional } - /* TODO: Separate these store impls into different files, give them better names */ RemoteStore::RemoteStore(const Params & params) : RemoteStoreConfig(params) , Store(params) , connections(make_ref>( - std::max(1, (int) maxConnections), - [this]() { - auto conn = openConnectionWrapper(); - try { - initConnection(*conn); - } catch (...) { - failed = true; - throw; - } - return conn; - }, - [this](const ref & r) { - return - r->to.good() - && r->from.good() - && std::chrono::duration_cast( - std::chrono::steady_clock::now() - r->startTime).count() < maxConnectionAge; - } - )) -{ -} - + std::max(1, (int) maxConnections), + [this]() { + auto conn = openConnectionWrapper(); + try { + initConnection(*conn); + } catch (...) { + failed = true; + throw; + } + return conn; + }, + [this](const ref & r) { + return r->to.good() && r->from.good() + && std::chrono::duration_cast( + std::chrono::steady_clock::now() - r->startTime) + .count() + < maxConnectionAge; + })) +{} ref RemoteStore::openConnectionWrapper() { @@ -185,7 +159,6 @@ ref RemoteStore::openConnectionWrapper() } } - void RemoteStore::initConnection(Connection & conn) { /* Send the magic greeting, check for the reply. */ @@ -227,31 +200,22 @@ void RemoteStore::initConnection(Connection & conn) } auto ex = conn.processStderr(); - if (ex) std::rethrow_exception(ex); - } - catch (Error & e) { + if (ex) + std::rethrow_exception(ex); + } catch (Error & e) { throw Error("cannot open connection to remote store '%s': %s", getUri(), e.what()); } setOptions(conn); } - void RemoteStore::setOptions(Connection & conn) { - conn.to << wopSetOptions - << settings.keepFailed - << settings.keepGoing - << settings.tryFallback - << verbosity - << settings.maxBuildJobs - << settings.maxSilentTime - << true - << (settings.verboseBuild ? lvlError : lvlVomit) - << 0 // obsolete log type - << 0 /* obsolete print build trace */ - << settings.buildCores - << settings.useSubstitutes; + conn.to << wopSetOptions << settings.keepFailed << settings.keepGoing << settings.tryFallback << verbosity + << settings.maxBuildJobs << settings.maxSilentTime << true << (settings.verboseBuild ? lvlError : lvlVomit) + << 0 // obsolete log type + << 0 /* obsolete print build trace */ + << settings.buildCores << settings.useSubstitutes; if (GET_PROTOCOL_MINOR(conn.daemonVersion) >= 12) { std::map overrides; @@ -272,10 +236,10 @@ void RemoteStore::setOptions(Connection & conn) } auto ex = conn.processStderr(); - if (ex) std::rethrow_exception(ex); + if (ex) + std::rethrow_exception(ex); } - /* A wrapper around Pool::Handle that marks the connection as bad (causing it to be closed) if a non-daemon exception is thrown before the handle is closed. Such an exception @@ -288,11 +252,11 @@ struct ConnectionHandle ConnectionHandle(Pool::Handle && handle) : handle(std::move(handle)) - { } + {} ConnectionHandle(ConnectionHandle && h) : handle(std::move(h.handle)) - { } + {} ~ConnectionHandle() { @@ -302,7 +266,10 @@ struct ConnectionHandle } } - RemoteStore::Connection * operator -> () { return &*handle; } + RemoteStore::Connection * operator->() + { + return &*handle; + } void processStderr(Sink * sink = 0, Source * source = 0, bool flush = true) { @@ -316,7 +283,6 @@ struct ConnectionHandle void withFramedSink(std::function fun); }; - ConnectionHandle RemoteStore::getConnection() { return ConnectionHandle(connections->get()); @@ -335,14 +301,14 @@ bool RemoteStore::isValidPathUncached(const StorePath & path) return readInt(conn->from); } - StorePathSet RemoteStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute) { auto conn(getConnection()); if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 12) { StorePathSet res; for (auto & i : paths) - if (isValidPath(i)) res.insert(i); + if (isValidPath(i)) + res.insert(i); return res; } else { conn->to << wopQueryValidPaths; @@ -351,20 +317,18 @@ StorePathSet RemoteStore::queryValidPaths(const StorePathSet & paths, Substitute conn->to << (settings.buildersUseSubstitutes ? 1 : 0); } conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom {}); + return worker_proto::read(*this, conn->from, Phantom{}); } } - StorePathSet RemoteStore::queryAllValidPaths() { auto conn(getConnection()); conn->to << wopQueryAllValidPaths; conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom {}); + return worker_proto::read(*this, conn->from, Phantom{}); } - StorePathSet RemoteStore::querySubstitutablePaths(const StorePathSet & paths) { auto conn(getConnection()); @@ -373,21 +337,22 @@ StorePathSet RemoteStore::querySubstitutablePaths(const StorePathSet & paths) for (auto & i : paths) { conn->to << wopHasSubstitutes << printStorePath(i); conn.processStderr(); - if (readInt(conn->from)) res.insert(i); + if (readInt(conn->from)) + res.insert(i); } return res; } else { conn->to << wopQuerySubstitutablePaths; worker_proto::write(*this, conn->to, paths); conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom {}); + return worker_proto::read(*this, conn->from, Phantom{}); } } - void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, SubstitutablePathInfos & infos) { - if (pathsMap.empty()) return; + if (pathsMap.empty()) + return; auto conn(getConnection()); @@ -398,11 +363,12 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S conn->to << wopQuerySubstitutablePathInfo << printStorePath(i.first); conn.processStderr(); unsigned int reply = readInt(conn->from); - if (reply == 0) continue; + if (reply == 0) + continue; auto deriver = readString(conn->from); if (deriver != "") info.deriver = parseStorePath(deriver); - info.references = worker_proto::read(*this, conn->from, Phantom {}); + info.references = worker_proto::read(*this, conn->from, Phantom{}); info.downloadSize = readLongLong(conn->from); info.narSize = readLongLong(conn->from); infos.insert_or_assign(i.first, std::move(info)); @@ -425,17 +391,15 @@ void RemoteStore::querySubstitutablePathInfos(const StorePathCAMap & pathsMap, S auto deriver = readString(conn->from); if (deriver != "") info.deriver = parseStorePath(deriver); - info.references = worker_proto::read(*this, conn->from, Phantom {}); + info.references = worker_proto::read(*this, conn->from, Phantom{}); info.downloadSize = readLongLong(conn->from); info.narSize = readLongLong(conn->from); } - } } - -void RemoteStore::queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept +void RemoteStore::queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept { try { std::shared_ptr info; @@ -451,37 +415,37 @@ void RemoteStore::queryPathInfoUncached(const StorePath & path, throw; } if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 17) { - bool valid; conn->from >> valid; - if (!valid) throw InvalidPath("path '%s' is not valid", printStorePath(path)); + bool valid; + conn->from >> valid; + if (!valid) + throw InvalidPath("path '%s' is not valid", printStorePath(path)); } info = std::make_shared( ValidPathInfo::read(conn->from, *this, GET_PROTOCOL_MINOR(conn->daemonVersion), StorePath{path})); } callback(std::move(info)); - } catch (...) { callback.rethrow(); } + } catch (...) { + callback.rethrow(); + } } - -void RemoteStore::queryReferrers(const StorePath & path, - StorePathSet & referrers) +void RemoteStore::queryReferrers(const StorePath & path, StorePathSet & referrers) { auto conn(getConnection()); conn->to << wopQueryReferrers << printStorePath(path); conn.processStderr(); - for (auto & i : worker_proto::read(*this, conn->from, Phantom {})) + for (auto & i : worker_proto::read(*this, conn->from, Phantom{})) referrers.insert(i); } - StorePathSet RemoteStore::queryValidDerivers(const StorePath & path) { auto conn(getConnection()); conn->to << wopQueryValidDerivers << printStorePath(path); conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom {}); + return worker_proto::read(*this, conn->from, Phantom{}); } - StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path) { if (GET_PROTOCOL_MINOR(getProtocol()) >= 0x16) { @@ -490,17 +454,16 @@ StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path) auto conn(getConnection()); conn->to << wopQueryDerivationOutputs << printStorePath(path); conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom {}); + return worker_proto::read(*this, conn->from, Phantom{}); } - std::map> RemoteStore::queryPartialDerivationOutputMap(const StorePath & path) { if (GET_PROTOCOL_MINOR(getProtocol()) >= 0x16) { auto conn(getConnection()); conn->to << wopQueryDerivationOutputMap << printStorePath(path); conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom>> {}); + return worker_proto::read(*this, conn->from, Phantom>>{}); } else { // Fallback for old daemon versions. // For floating-CA derivations (and their co-dependencies) this is an @@ -524,11 +487,11 @@ std::optional RemoteStore::queryPathFromHashPart(const std::string & conn->to << wopQueryPathFromHashPart << hashPart; conn.processStderr(); Path path = readString(conn->from); - if (path.empty()) return {}; + if (path.empty()) + return {}; return parseStorePath(path); } - ref RemoteStore::addCAToStore( Source & dump, std::string_view name, @@ -541,10 +504,7 @@ ref RemoteStore::addCAToStore( if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 25) { - conn->to - << wopAddToStore - << name - << renderContentAddressMethod(caMethod); + conn->to << wopAddToStore << name << renderContentAddressMethod(caMethod); worker_proto::write(*this, conn->to, references); conn->to << repair; @@ -552,59 +512,58 @@ ref RemoteStore::addCAToStore( connections->incCapacity(); { Finally cleanup([&]() { connections->decCapacity(); }); - conn.withFramedSink([&](Sink & sink) { - dump.drainInto(sink); - }); + conn.withFramedSink([&](Sink & sink) { dump.drainInto(sink); }); } - return make_ref( - ValidPathInfo::read(conn->from, *this, GET_PROTOCOL_MINOR(conn->daemonVersion))); - } - else { - if (repair) throw Error("repairing is not supported when building through the Nix daemon protocol < 1.25"); - - std::visit(overloaded { - [&](const TextHashMethod & thm) -> void { - std::string s = dump.drain(); - conn->to << wopAddTextToStore << name << s; - worker_proto::write(*this, conn->to, references); - conn.processStderr(); - }, - [&](const FixedOutputHashMethod & fohm) -> void { - conn->to - << wopAddToStore - << name - << ((fohm.hashType == htSHA256 && fohm.fileIngestionMethod == FileIngestionMethod::Recursive) ? 0 : 1) /* backwards compatibility hack */ - << (fohm.fileIngestionMethod == FileIngestionMethod::Recursive ? 1 : 0) - << printHashType(fohm.hashType); - - try { - conn->to.written = 0; - conn->to.warn = true; - connections->incCapacity(); - { - Finally cleanup([&]() { connections->decCapacity(); }); - if (fohm.fileIngestionMethod == FileIngestionMethod::Recursive) { - dump.drainInto(conn->to); - } else { - std::string contents = dump.drain(); - dumpString(contents, conn->to); + return make_ref(ValidPathInfo::read(conn->from, *this, GET_PROTOCOL_MINOR(conn->daemonVersion))); + } else { + if (repair) + throw Error("repairing is not supported when building through the Nix daemon protocol < 1.25"); + + std::visit( + overloaded{ + [&](const TextHashMethod & thm) -> void { + std::string s = dump.drain(); + conn->to << wopAddTextToStore << name << s; + worker_proto::write(*this, conn->to, references); + conn.processStderr(); + }, + [&](const FixedOutputHashMethod & fohm) -> void { + conn->to << wopAddToStore << name + << ((fohm.hashType == htSHA256 + && fohm.fileIngestionMethod == FileIngestionMethod::Recursive) + ? 0 + : 1) /* backwards compatibility hack */ + << (fohm.fileIngestionMethod == FileIngestionMethod::Recursive ? 1 : 0) + << printHashType(fohm.hashType); + + try { + conn->to.written = 0; + conn->to.warn = true; + connections->incCapacity(); + { + Finally cleanup([&]() { connections->decCapacity(); }); + if (fohm.fileIngestionMethod == FileIngestionMethod::Recursive) { + dump.drainInto(conn->to); + } else { + std::string contents = dump.drain(); + dumpString(contents, conn->to); + } } + conn->to.warn = false; + conn.processStderr(); + } catch (SysError & e) { + /* Daemon closed while we were sending the path. Probably OOM + or I/O error. */ + if (e.errNo == EPIPE) + try { + conn.processStderr(); + } catch (EndOfFile & e) { + } + throw; } - conn->to.warn = false; - conn.processStderr(); - } catch (SysError & e) { - /* Daemon closed while we were sending the path. Probably OOM - or I/O error. */ - if (e.errNo == EPIPE) - try { - conn.processStderr(); - } catch (EndOfFile & e) { } - throw; - } - - } - }, caMethod); + }}, + caMethod); auto path = parseStorePath(readString(conn->from)); // Release our connection to prevent a deadlock in queryPathInfo(). conn_.reset(); @@ -612,16 +571,21 @@ ref RemoteStore::addCAToStore( } } - -StorePath RemoteStore::addToStoreFromDump(Source & dump, std::string_view name, - FileIngestionMethod method, HashType hashType, RepairFlag repair, const StorePathSet & references) +StorePath RemoteStore::addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method, + HashType hashType, + RepairFlag repair, + const StorePathSet & references) { - return addCAToStore(dump, name, FixedOutputHashMethod{ .fileIngestionMethod = method, .hashType = hashType }, references, repair)->path; + return addCAToStore( + dump, name, FixedOutputHashMethod{.fileIngestionMethod = method, .hashType = hashType}, references, + repair) + ->path; } - -void RemoteStore::addToStore(const ValidPathInfo & info, Source & source, - RepairFlag repair, CheckSigsFlag checkSigs) +void RemoteStore::addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs) { auto conn(getConnection()); @@ -632,37 +596,28 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source, sink << 1 // == path follows ; copyNAR(source, sink); - sink - << exportMagic - << printStorePath(info.path); + sink << exportMagic << printStorePath(info.path); worker_proto::write(*this, sink, info.references); - sink - << (info.deriver ? printStorePath(*info.deriver) : "") - << 0 // == no legacy signature - << 0 // == no path follows + sink << (info.deriver ? printStorePath(*info.deriver) : "") << 0 // == no legacy signature + << 0 // == no path follows ; }); conn.processStderr(0, source2.get()); - auto importedPaths = worker_proto::read(*this, conn->from, Phantom {}); + auto importedPaths = worker_proto::read(*this, conn->from, Phantom{}); assert(importedPaths.size() <= 1); } else { - conn->to << wopAddToStoreNar - << printStorePath(info.path) - << (info.deriver ? printStorePath(*info.deriver) : "") + conn->to << wopAddToStoreNar << printStorePath(info.path) << (info.deriver ? printStorePath(*info.deriver) : "") << info.narHash.to_string(Base16, false); worker_proto::write(*this, conn->to, info.references); - conn->to << info.registrationTime << info.narSize - << info.ultimate << info.sigs << renderContentAddress(info.ca) + conn->to << info.registrationTime << info.narSize << info.ultimate << info.sigs << renderContentAddress(info.ca) << repair << !checkSigs; if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 23) { - conn.withFramedSink([&](Sink & sink) { - copyNAR(source, sink); - }); + conn.withFramedSink([&](Sink & sink) { copyNAR(source, sink); }); } else if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 21) { conn.processStderr(0, &source); } else { @@ -672,31 +627,18 @@ void RemoteStore::addToStore(const ValidPathInfo & info, Source & source, } } - -void RemoteStore::addMultipleToStore( - Source & source, - RepairFlag repair, - CheckSigsFlag checkSigs) +void RemoteStore::addMultipleToStore(Source & source, RepairFlag repair, CheckSigsFlag checkSigs) { if (GET_PROTOCOL_MINOR(getConnection()->daemonVersion) >= 32) { auto conn(getConnection()); - conn->to - << wopAddMultipleToStore - << repair - << !checkSigs; - conn.withFramedSink([&](Sink & sink) { - source.drainInto(sink); - }); + conn->to << wopAddMultipleToStore << repair << !checkSigs; + conn.withFramedSink([&](Sink & sink) { source.drainInto(sink); }); } else Store::addMultipleToStore(source, repair, checkSigs); } - StorePath RemoteStore::addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) { StringSource source(s); return addCAToStore(source, name, TextHashMethod{}, references, repair)->path; @@ -715,8 +657,8 @@ void RemoteStore::registerDrvOutput(const Realisation & info) conn.processStderr(); } -void RemoteStore::queryRealisationUncached(const DrvOutput & id, - Callback> callback) noexcept +void RemoteStore::queryRealisationUncached( + const DrvOutput & id, Callback> callback) noexcept { try { auto conn(getConnection()); @@ -732,14 +674,12 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id, auto real = [&]() -> std::shared_ptr { if (GET_PROTOCOL_MINOR(conn->daemonVersion) < 31) { - auto outPaths = worker_proto::read( - *this, conn->from, Phantom> {}); + auto outPaths = worker_proto::read(*this, conn->from, Phantom>{}); if (outPaths.empty()) return nullptr; - return std::make_shared(Realisation { .id = id, .outPath = *outPaths.begin() }); + return std::make_shared(Realisation{.id = id, .outPath = *outPaths.begin()}); } else { - auto realisations = worker_proto::read( - *this, conn->from, Phantom> {}); + auto realisations = worker_proto::read(*this, conn->from, Phantom>{}); if (realisations.empty()) return nullptr; return std::make_shared(*realisations.begin()); @@ -747,7 +687,9 @@ void RemoteStore::queryRealisationUncached(const DrvOutput & id, }(); callback(std::shared_ptr(real)); - } catch (...) { return callback.rethrow(); } + } catch (...) { + return callback.rethrow(); + } } static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, const std::vector & reqs) @@ -758,25 +700,23 @@ static void writeDerivedPaths(RemoteStore & store, ConnectionHandle & conn, cons Strings ss; for (auto & p : reqs) { auto sOrDrvPath = StorePathWithOutputs::tryFromDerivedPath(p); - std::visit(overloaded { - [&](const StorePathWithOutputs & s) { - ss.push_back(s.to_string(store)); - }, - [&](const StorePath & drvPath) { - throw Error("trying to request '%s', but daemon protocol %d.%d is too old (< 1.29) to request a derivation file", - store.printStorePath(drvPath), - GET_PROTOCOL_MAJOR(conn->daemonVersion), - GET_PROTOCOL_MINOR(conn->daemonVersion)); + std::visit( + overloaded{ + [&](const StorePathWithOutputs & s) { ss.push_back(s.to_string(store)); }, + [&](const StorePath & drvPath) { + throw Error( + "trying to request '%s', but daemon protocol %d.%d is too old (< 1.29) to request a derivation file", + store.printStorePath(drvPath), GET_PROTOCOL_MAJOR(conn->daemonVersion), + GET_PROTOCOL_MINOR(conn->daemonVersion)); + }, }, - }, sOrDrvPath); + sOrDrvPath); } conn->to << ss; } } -void RemoteStore::copyDrvsFromEvalStore( - const std::vector & paths, - std::shared_ptr evalStore) +void RemoteStore::copyDrvsFromEvalStore(const std::vector & paths, std::shared_ptr evalStore) { if (evalStore && evalStore.get() != this) { /* The remote doesn't have a way to access evalStore, so copy @@ -789,7 +729,8 @@ void RemoteStore::copyDrvsFromEvalStore( } } -void RemoteStore::buildPaths(const std::vector & drvPaths, BuildMode buildMode, std::shared_ptr evalStore) +void RemoteStore::buildPaths( + const std::vector & drvPaths, BuildMode buildMode, std::shared_ptr evalStore) { copyDrvsFromEvalStore(drvPaths, evalStore); @@ -809,9 +750,7 @@ void RemoteStore::buildPaths(const std::vector & drvPaths, BuildMod } std::vector RemoteStore::buildPathsWithResults( - const std::vector & paths, - BuildMode buildMode, - std::shared_ptr evalStore) + const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) { copyDrvsFromEvalStore(paths, evalStore); @@ -823,7 +762,7 @@ std::vector RemoteStore::buildPathsWithResults( writeDerivedPaths(*this, conn, paths); conn->to << buildMode; conn.processStderr(); - return worker_proto::read(*this, conn->from, Phantom> {}); + return worker_proto::read(*this, conn->from, Phantom>{}); } else { // Avoid deadlock. conn_.reset(); @@ -836,15 +775,15 @@ std::vector RemoteStore::buildPathsWithResults( for (auto & path : paths) { std::visit( - overloaded { + overloaded{ [&](const DerivedPath::Opaque & bo) { - results.push_back(BuildResult { + results.push_back(BuildResult{ .status = BuildResult::Substituted, .path = bo, }); }, [&](const DerivedPath::Built & bfd) { - BuildResult res { + BuildResult res{ .status = BuildResult::Built, .path = bfd, }; @@ -859,10 +798,9 @@ std::vector RemoteStore::buildPathsWithResults( throw Error( "the derivation '%s' doesn't have an output named '%s'", printStorePath(bfd.drvPath), output); - auto outputId = DrvOutput{ *outputHash, output }; + auto outputId = DrvOutput{*outputHash, output}; if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { - auto realisation = - queryRealisation(outputId); + auto realisation = queryRealisation(outputId); if (!realisation) throw Error( "cannot operate on an output of unbuilt " @@ -876,17 +814,15 @@ std::vector RemoteStore::buildPathsWithResults( assert(drvOutput); assert(drvOutput->second); res.builtOutputs.emplace( - outputId, - Realisation { - .id = outputId, - .outPath = *drvOutput->second, - }); + outputId, Realisation{ + .id = outputId, + .outPath = *drvOutput->second, + }); } } results.push_back(res); - } - }, + }}, path.raw()); } @@ -894,29 +830,26 @@ std::vector RemoteStore::buildPathsWithResults( } } - -BuildResult RemoteStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, - BuildMode buildMode) +BuildResult RemoteStore::buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode) { auto conn(getConnection()); conn->to << wopBuildDerivation << printStorePath(drvPath); writeDerivation(conn->to, *this, drv); conn->to << buildMode; conn.processStderr(); - BuildResult res { .path = DerivedPath::Built { .drvPath = drvPath } }; + BuildResult res{.path = DerivedPath::Built{.drvPath = drvPath}}; res.status = (BuildResult::Status) readInt(conn->from); conn->from >> res.errorMsg; if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 29) { conn->from >> res.timesBuilt >> res.isNonDeterministic >> res.startTime >> res.stopTime; } if (GET_PROTOCOL_MINOR(conn->daemonVersion) >= 28) { - auto builtOutputs = worker_proto::read(*this, conn->from, Phantom {}); + auto builtOutputs = worker_proto::read(*this, conn->from, Phantom{}); res.builtOutputs = builtOutputs; } return res; } - void RemoteStore::ensurePath(const StorePath & path) { auto conn(getConnection()); @@ -925,7 +858,6 @@ void RemoteStore::ensurePath(const StorePath & path) readInt(conn->from); } - void RemoteStore::addTempRoot(const StorePath & path) { auto conn(getConnection()); @@ -934,7 +866,6 @@ void RemoteStore::addTempRoot(const StorePath & path) readInt(conn->from); } - void RemoteStore::addIndirectRoot(const Path & path) { auto conn(getConnection()); @@ -943,7 +874,6 @@ void RemoteStore::addIndirectRoot(const Path & path) readInt(conn->from); } - Roots RemoteStore::findRoots(bool censor) { auto conn(getConnection()); @@ -959,18 +889,16 @@ Roots RemoteStore::findRoots(bool censor) return result; } - void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results) { auto conn(getConnection()); - conn->to - << wopCollectGarbage << options.action; + conn->to << wopCollectGarbage << options.action; worker_proto::write(*this, conn->to, options.pathsToDelete); conn->to << options.ignoreLiveness - << options.maxFreed - /* removed options */ - << 0 << 0 << 0; + << options.maxFreed + /* removed options */ + << 0 << 0 << 0; conn.processStderr(); @@ -984,7 +912,6 @@ void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results) } } - void RemoteStore::optimiseStore() { auto conn(getConnection()); @@ -993,7 +920,6 @@ void RemoteStore::optimiseStore() readInt(conn->from); } - bool RemoteStore::verifyStore(bool checkContents, RepairFlag repair) { auto conn(getConnection()); @@ -1002,7 +928,6 @@ bool RemoteStore::verifyStore(bool checkContents, RepairFlag repair) return readInt(conn->from); } - void RemoteStore::addSignatures(const StorePath & storePath, const StringSet & sigs) { auto conn(getConnection()); @@ -1011,10 +936,13 @@ void RemoteStore::addSignatures(const StorePath & storePath, const StringSet & s readInt(conn->from); } - -void RemoteStore::queryMissing(const std::vector & targets, - StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown, - uint64_t & downloadSize, uint64_t & narSize) +void RemoteStore::queryMissing( + const std::vector & targets, + StorePathSet & willBuild, + StorePathSet & willSubstitute, + StorePathSet & unknown, + uint64_t & downloadSize, + uint64_t & narSize) { { auto conn(getConnection()); @@ -1025,57 +953,48 @@ void RemoteStore::queryMissing(const std::vector & targets, conn->to << wopQueryMissing; writeDerivedPaths(*this, conn, targets); conn.processStderr(); - willBuild = worker_proto::read(*this, conn->from, Phantom {}); - willSubstitute = worker_proto::read(*this, conn->from, Phantom {}); - unknown = worker_proto::read(*this, conn->from, Phantom {}); + willBuild = worker_proto::read(*this, conn->from, Phantom{}); + willSubstitute = worker_proto::read(*this, conn->from, Phantom{}); + unknown = worker_proto::read(*this, conn->from, Phantom{}); conn->from >> downloadSize >> narSize; return; } - fallback: - return Store::queryMissing(targets, willBuild, willSubstitute, - unknown, downloadSize, narSize); +fallback: + return Store::queryMissing(targets, willBuild, willSubstitute, unknown, downloadSize, narSize); } - void RemoteStore::addBuildLog(const StorePath & drvPath, std::string_view log) { auto conn(getConnection()); conn->to << wopAddBuildLog << drvPath.to_string(); StringSource source(log); - conn.withFramedSink([&](Sink & sink) { - source.drainInto(sink); - }); + conn.withFramedSink([&](Sink & sink) { source.drainInto(sink); }); readInt(conn->from); } - std::optional RemoteStore::getVersion() { auto conn(getConnection()); return conn->daemonNixVersion; } - void RemoteStore::connect() { auto conn(getConnection()); } - unsigned int RemoteStore::getProtocol() { auto conn(connections->get()); return conn->daemonVersion; } - void RemoteStore::flushBadConnections() { connections->flushBad(); } - RemoteStore::Connection::~Connection() { try { @@ -1114,7 +1033,6 @@ static Logger::Fields readFields(Source & from) return fields; } - std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source * source, bool flush) { if (flush) @@ -1126,12 +1044,14 @@ std::exception_ptr RemoteStore::Connection::processStderr(Sink * sink, Source * if (msg == STDERR_WRITE) { auto s = readString(from); - if (!sink) throw Error("no sink"); + if (!sink) + throw Error("no sink"); (*sink)(s); } else if (msg == STDERR_READ) { - if (!source) throw Error("no source"); + if (!source) + throw Error("no source"); size_t len = readNum(from); auto buf = std::make_unique(len); writeString({(const char *) buf.get(), source->read(buf.get(), len)}, to); @@ -1191,8 +1111,7 @@ void ConnectionHandle::withFramedSink(std::function fun) /* Handle log messages / exceptions from the remote on a separate thread. */ - std::thread stderrThread([&]() - { + std::thread stderrThread([&]() { try { processStderr(nullptr, nullptr, false); } catch (...) { @@ -1200,8 +1119,7 @@ void ConnectionHandle::withFramedSink(std::function fun) } }); - Finally joinStderrThread([&]() - { + Finally joinStderrThread([&]() { if (stderrThread.joinable()) { stderrThread.join(); if (ex) { diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh index 8493be6fc544..c5c579e60e9a 100644 --- a/src/libstore/remote-store.hh +++ b/src/libstore/remote-store.hh @@ -7,34 +7,34 @@ #include "gc-store.hh" #include "log-store.hh" - namespace nix { - class Pipe; class Pid; struct FdSink; struct FdSource; -template class Pool; +template +class Pool; struct ConnectionHandle; struct RemoteStoreConfig : virtual StoreConfig { using StoreConfig::StoreConfig; - const Setting maxConnections{(StoreConfig*) this, 1, - "max-connections", "maximum number of concurrent connections to the Nix daemon"}; + const Setting maxConnections{ + (StoreConfig *) this, 1, "max-connections", "maximum number of concurrent connections to the Nix daemon"}; - const Setting maxConnectionAge{(StoreConfig*) this, std::numeric_limits::max(), - "max-connection-age", "number of seconds to reuse a connection"}; + const Setting maxConnectionAge{ + (StoreConfig *) this, std::numeric_limits::max(), "max-connection-age", + "number of seconds to reuse a connection"}; }; /* FIXME: RemoteStore is a misnomer - should be something like DaemonStore. */ class RemoteStore : public virtual RemoteStoreConfig, - public virtual Store, - public virtual GcStore, - public virtual LogStore + public virtual Store, + public virtual GcStore, + public virtual LogStore { public: @@ -46,13 +46,12 @@ public: bool isValidPathUncached(const StorePath & path) override; - StorePathSet queryValidPaths(const StorePathSet & paths, - SubstituteFlag maybeSubstitute = NoSubstitute) override; + StorePathSet queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute = NoSubstitute) override; StorePathSet queryAllValidPaths() override; - void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept override; + void queryPathInfoUncached( + const StorePath & path, Callback> callback) noexcept override; void queryReferrers(const StorePath & path, StorePathSet & referrers) override; @@ -65,8 +64,7 @@ public: StorePathSet querySubstitutablePaths(const StorePathSet & paths) override; - void querySubstitutablePathInfos(const StorePathCAMap & paths, - SubstitutablePathInfos & infos) override; + void querySubstitutablePathInfos(const StorePathCAMap & paths, SubstitutablePathInfos & infos) override; /* Add a content-addressable store path. `dump` will be drained. */ ref addCAToStore( @@ -77,37 +75,33 @@ public: RepairFlag repair); /* Add a content-addressable store path. Does not support references. `dump` will be drained. */ - StorePath addToStoreFromDump(Source & dump, std::string_view name, - FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair, const StorePathSet & references = StorePathSet()) override; + StorePath addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method = FileIngestionMethod::Recursive, + HashType hashAlgo = htSHA256, + RepairFlag repair = NoRepair, + const StorePathSet & references = StorePathSet()) override; - void addToStore(const ValidPathInfo & info, Source & nar, - RepairFlag repair, CheckSigsFlag checkSigs) override; + void addToStore(const ValidPathInfo & info, Source & nar, RepairFlag repair, CheckSigsFlag checkSigs) override; - void addMultipleToStore( - Source & source, - RepairFlag repair, - CheckSigsFlag checkSigs) override; + void addMultipleToStore(Source & source, RepairFlag repair, CheckSigsFlag checkSigs) override; StorePath addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair) override; + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair) override; void registerDrvOutput(const Realisation & info) override; - void queryRealisationUncached(const DrvOutput &, - Callback> callback) noexcept override; + void queryRealisationUncached( + const DrvOutput &, Callback> callback) noexcept override; - void buildPaths(const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override; + void + buildPaths(const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override; std::vector buildPathsWithResults( - const std::vector & paths, - BuildMode buildMode, - std::shared_ptr evalStore) override; + const std::vector & paths, BuildMode buildMode, std::shared_ptr evalStore) override; - BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, - BuildMode buildMode) override; + BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode) override; void ensurePath(const StorePath & path) override; @@ -125,9 +119,13 @@ public: void addSignatures(const StorePath & storePath, const StringSet & sigs) override; - void queryMissing(const std::vector & targets, - StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown, - uint64_t & downloadSize, uint64_t & narSize) override; + void queryMissing( + const std::vector & targets, + StorePathSet & willBuild, + StorePathSet & willSubstitute, + StorePathSet & unknown, + uint64_t & downloadSize, + uint64_t & narSize) override; void addBuildLog(const StorePath & drvPath, std::string_view log) override; @@ -180,10 +178,7 @@ private: std::atomic_bool failed{false}; - void copyDrvsFromEvalStore( - const std::vector & paths, - std::shared_ptr evalStore); + void copyDrvsFromEvalStore(const std::vector & paths, std::shared_ptr evalStore); }; - } diff --git a/src/libstore/s3-binary-cache-store.cc b/src/libstore/s3-binary-cache-store.cc index 844553ad3094..d07e0d539d99 100644 --- a/src/libstore/s3-binary-cache-store.cc +++ b/src/libstore/s3-binary-cache-store.cc @@ -33,8 +33,9 @@ struct S3Error : public Error Aws::S3::S3Errors err; template - S3Error(Aws::S3::S3Errors err, const Args & ... args) - : Error(args...), err(err) { }; + S3Error(Aws::S3::S3Errors err, const Args &... args) + : Error(args...) + , err(err){}; }; /* Helper: given an Outcome, return R in case of success, or @@ -43,9 +44,7 @@ template R && checkAws(const FormatOrString & fs, Aws::Utils::Outcome && outcome) { if (!outcome.IsSuccess()) - throw S3Error( - outcome.GetError().GetErrorType(), - fs.s + ": " + outcome.GetError().GetMessage()); + throw S3Error(outcome.GetError().GetErrorType(), fs.s + ": " + outcome.GetError().GetMessage()); return outcome.GetResultWithOwnership(); } @@ -75,9 +74,7 @@ static void initAWS() if (verbosity >= lvlDebug) { options.loggingOptions.logLevel = - verbosity == lvlDebug - ? Aws::Utils::Logging::LogLevel::Debug - : Aws::Utils::Logging::LogLevel::Trace; + verbosity == lvlDebug ? Aws::Utils::Logging::LogLevel::Debug : Aws::Utils::Logging::LogLevel::Trace; options.loggingOptions.logger_create_fn = [options]() { return std::make_shared(options.loggingOptions.logLevel); }; @@ -88,47 +85,39 @@ static void initAWS() } S3Helper::S3Helper( - const std::string & profile, - const std::string & region, - const std::string & scheme, - const std::string & endpoint) + const std::string & profile, const std::string & region, const std::string & scheme, const std::string & endpoint) : config(makeConfig(region, scheme, endpoint)) , client(make_ref( - profile == "" - ? std::dynamic_pointer_cast( - std::make_shared()) - : std::dynamic_pointer_cast( - std::make_shared(profile.c_str())), - *config, - // FIXME: https://github.com/aws/aws-sdk-cpp/issues/759 + profile == "" ? std::dynamic_pointer_cast( + std::make_shared()) + : std::dynamic_pointer_cast( + std::make_shared(profile.c_str())), + *config, +// FIXME: https://github.com/aws/aws-sdk-cpp/issues/759 #if AWS_VERSION_MAJOR == 1 && AWS_VERSION_MINOR < 3 - false, + false, #else - Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, + Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, #endif - endpoint.empty())) -{ -} + endpoint.empty())) +{} /* Log AWS retries. */ class RetryStrategy : public Aws::Client::DefaultRetryStrategy { - bool ShouldRetry(const Aws::Client::AWSError& error, long attemptedRetries) const override + bool ShouldRetry(const Aws::Client::AWSError & error, long attemptedRetries) const override { auto retry = Aws::Client::DefaultRetryStrategy::ShouldRetry(error, attemptedRetries); if (retry) - printError("AWS error '%s' (%s), will retry in %d ms", - error.GetExceptionName(), - error.GetMessage(), + printError( + "AWS error '%s' (%s), will retry in %d ms", error.GetExceptionName(), error.GetMessage(), CalculateDelayBeforeNextRetry(error, attemptedRetries)); return retry; } }; -ref S3Helper::makeConfig( - const std::string & region, - const std::string & scheme, - const std::string & endpoint) +ref +S3Helper::makeConfig(const std::string & region, const std::string & scheme, const std::string & endpoint) { initAWS(); auto res = make_ref(); @@ -146,19 +135,13 @@ ref S3Helper::makeConfig( return res; } -S3Helper::FileTransferResult S3Helper::getObject( - const std::string & bucketName, const std::string & key) +S3Helper::FileTransferResult S3Helper::getObject(const std::string & bucketName, const std::string & key) { debug("fetching 's3://%s/%s'...", bucketName, key); - auto request = - Aws::S3::Model::GetObjectRequest() - .WithBucket(bucketName) - .WithKey(key); + auto request = Aws::S3::Model::GetObjectRequest().WithBucket(bucketName).WithKey(key); - request.SetResponseStreamFactory([&]() { - return Aws::New("STRINGSTREAM"); - }); + request.SetResponseStreamFactory([&]() { return Aws::New("STRINGSTREAM"); }); FileTransferResult res; @@ -166,15 +149,13 @@ S3Helper::FileTransferResult S3Helper::getObject( try { - auto result = checkAws(fmt("AWS error fetching '%s'", key), - client->GetObject(request)); + auto result = checkAws(fmt("AWS error fetching '%s'", key), client->GetObject(request)); - res.data = decompress(result.GetContentEncoding(), - dynamic_cast(result.GetBody()).str()); + res.data = decompress(result.GetContentEncoding(), dynamic_cast(result.GetBody()).str()); } catch (S3Error & e) { - if ((e.err != Aws::S3::S3Errors::NO_SUCH_KEY) && - (e.err != Aws::S3::S3Errors::ACCESS_DENIED)) throw; + if ((e.err != Aws::S3::S3Errors::NO_SUCH_KEY) && (e.err != Aws::S3::S3Errors::ACCESS_DENIED)) + throw; } auto now2 = std::chrono::steady_clock::now(); @@ -187,24 +168,33 @@ S3Helper::FileTransferResult S3Helper::getObject( S3BinaryCacheStore::S3BinaryCacheStore(const Params & params) : BinaryCacheStoreConfig(params) , BinaryCacheStore(params) -{ } +{} struct S3BinaryCacheStoreConfig : virtual BinaryCacheStoreConfig { using BinaryCacheStoreConfig::BinaryCacheStoreConfig; - const Setting profile{(StoreConfig*) this, "", "profile", "The name of the AWS configuration profile to use."}; - const Setting region{(StoreConfig*) this, Aws::Region::US_EAST_1, "region", {"aws-region"}}; - const Setting scheme{(StoreConfig*) this, "", "scheme", "The scheme to use for S3 requests, https by default."}; - const Setting endpoint{(StoreConfig*) this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."}; - const Setting narinfoCompression{(StoreConfig*) this, "", "narinfo-compression", "compression method for .narinfo files"}; - const Setting lsCompression{(StoreConfig*) this, "", "ls-compression", "compression method for .ls files"}; - const Setting logCompression{(StoreConfig*) this, "", "log-compression", "compression method for log/* files"}; + const Setting profile{ + (StoreConfig *) this, "", "profile", "The name of the AWS configuration profile to use."}; + const Setting region{(StoreConfig *) this, Aws::Region::US_EAST_1, "region", {"aws-region"}}; + const Setting scheme{ + (StoreConfig *) this, "", "scheme", "The scheme to use for S3 requests, https by default."}; + const Setting endpoint{ + (StoreConfig *) this, "", "endpoint", "An optional override of the endpoint to use when talking to S3."}; + const Setting narinfoCompression{ + (StoreConfig *) this, "", "narinfo-compression", "compression method for .narinfo files"}; + const Setting lsCompression{ + (StoreConfig *) this, "", "ls-compression", "compression method for .ls files"}; + const Setting logCompression{ + (StoreConfig *) this, "", "log-compression", "compression method for log/* files"}; const Setting multipartUpload{ - (StoreConfig*) this, false, "multipart-upload", "whether to use multi-part uploads"}; + (StoreConfig *) this, false, "multipart-upload", "whether to use multi-part uploads"}; const Setting bufferSize{ - (StoreConfig*) this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"}; + (StoreConfig *) this, 5 * 1024 * 1024, "buffer-size", "size (in bytes) of each part in multi-part uploads"}; - const std::string name() override { return "S3 Binary Cache Store"; } + const std::string name() override + { + return "S3 Binary Cache Store"; + } }; struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual S3BinaryCacheStore @@ -215,10 +205,7 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual S3Helper s3Helper; - S3BinaryCacheStoreImpl( - const std::string & uriScheme, - const std::string & bucketName, - const Params & params) + S3BinaryCacheStoreImpl(const std::string & uriScheme, const std::string & bucketName, const Params & params) : StoreConfig(params) , BinaryCacheStoreConfig(params) , S3BinaryCacheStoreConfig(params) @@ -270,10 +257,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual { stats.head++; - auto res = s3Helper.client->HeadObject( - Aws::S3::Model::HeadObjectRequest() - .WithBucket(bucketName) - .WithKey(path)); + auto res = + s3Helper.client->HeadObject(Aws::S3::Model::HeadObjectRequest().WithBucket(bucketName).WithKey(path)); if (!res.IsSuccess()) { auto & error = res.GetError(); @@ -291,7 +276,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual std::shared_ptr transferManager; std::once_flag transferManagerCreated; - void uploadFile(const std::string & path, + void uploadFile( + const std::string & path, std::shared_ptr> istream, const std::string & mimeType, const std::string & contentEncoding) @@ -302,11 +288,10 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual auto maxThreads = std::thread::hardware_concurrency(); - static std::shared_ptr - executor = std::make_shared(maxThreads); + static std::shared_ptr executor = + std::make_shared(maxThreads); - std::call_once(transferManagerCreated, [&]() - { + std::call_once(transferManagerCreated, [&]() { if (multipartUpload) { TransferManagerConfiguration transferConfig(executor.get()); @@ -314,16 +299,13 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual transferConfig.bufferSize = bufferSize; transferConfig.uploadProgressCallback = - [](const TransferManager *transferManager, - const std::shared_ptr - &transferHandle) - { - //FIXME: find a way to properly abort the multipart upload. - //checkInterrupt(); - debug("upload progress ('%s'): '%d' of '%d' bytes", - transferHandle->GetKey(), - transferHandle->GetBytesTransferred(), - transferHandle->GetBytesTotalSize()); + [](const TransferManager * transferManager, + const std::shared_ptr & transferHandle) { + // FIXME: find a way to properly abort the multipart upload. + // checkInterrupt(); + debug( + "upload progress ('%s'): '%d' of '%d' bytes", transferHandle->GetKey(), + transferHandle->GetBytesTransferred(), transferHandle->GetBytesTotalSize()); }; transferManager = TransferManager::Create(transferConfig); @@ -337,28 +319,23 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual if (contentEncoding != "") throw Error("setting a content encoding is not supported with S3 multi-part uploads"); - std::shared_ptr transferHandle = - transferManager->UploadFile( - istream, bucketName, path, mimeType, - Aws::Map(), - nullptr /*, contentEncoding */); + std::shared_ptr transferHandle = transferManager->UploadFile( + istream, bucketName, path, mimeType, Aws::Map(), + nullptr /*, contentEncoding */); transferHandle->WaitUntilFinished(); if (transferHandle->GetStatus() == TransferStatus::FAILED) - throw Error("AWS error: failed to upload 's3://%s/%s': %s", - bucketName, path, transferHandle->GetLastError().GetMessage()); + throw Error( + "AWS error: failed to upload 's3://%s/%s': %s", bucketName, path, + transferHandle->GetLastError().GetMessage()); if (transferHandle->GetStatus() != TransferStatus::COMPLETED) - throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state", - bucketName, path); + throw Error("AWS error: transfer status of 's3://%s/%s' in unexpected state", bucketName, path); } else { - auto request = - Aws::S3::Model::PutObjectRequest() - .WithBucket(bucketName) - .WithKey(path); + auto request = Aws::S3::Model::PutObjectRequest().WithBucket(bucketName).WithKey(path); request.SetContentType(mimeType); @@ -367,30 +344,26 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual request.SetBody(istream); - auto result = checkAws(fmt("AWS error uploading '%s'", path), - s3Helper.client->PutObject(request)); + auto result = checkAws(fmt("AWS error uploading '%s'", path), s3Helper.client->PutObject(request)); } auto now2 = std::chrono::steady_clock::now(); - auto duration = - std::chrono::duration_cast(now2 - now1) - .count(); + auto duration = std::chrono::duration_cast(now2 - now1).count(); - printInfo("uploaded 's3://%s/%s' (%d bytes) in %d ms", - bucketName, path, size, duration); + printInfo("uploaded 's3://%s/%s' (%d bytes) in %d ms", bucketName, path, size, duration); stats.putTimeMs += duration; stats.putBytes += std::max(size, (decltype(size)) 0); stats.put++; } - void upsertFile(const std::string & path, + void upsertFile( + const std::string & path, std::shared_ptr> istream, const std::string & mimeType) override { - auto compress = [&](std::string compression) - { + auto compress = [&](std::string compression) { auto compressed = nix::compress(compression, StreamToSourceAdapter(istream).drain()); return std::make_shared(std::move(compressed)); }; @@ -416,8 +389,8 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual stats.getTimeMs += res.durationMs; if (res.data) { - printTalkative("downloaded 's3://%s/%s' (%d bytes) in %d ms", - bucketName, path, res.data->size(), res.durationMs); + printTalkative( + "downloaded 's3://%s/%s' (%d bytes) in %d ms", bucketName, path, res.data->size(), res.durationMs); sink(*res.data); } else @@ -432,21 +405,19 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual do { debug(format("listing bucket 's3://%s' from key '%s'...") % bucketName % marker); - auto res = checkAws(format("AWS error listing bucket '%s'") % bucketName, + auto res = checkAws( + format("AWS error listing bucket '%s'") % bucketName, s3Helper.client->ListObjects( - Aws::S3::Model::ListObjectsRequest() - .WithBucket(bucketName) - .WithDelimiter("/") - .WithMarker(marker))); + Aws::S3::Model::ListObjectsRequest().WithBucket(bucketName).WithDelimiter("/").WithMarker(marker))); auto & contents = res.GetContents(); - debug(format("got %d keys, next marker '%s'") - % contents.size() % res.GetNextMarker()); + debug(format("got %d keys, next marker '%s'") % contents.size() % res.GetNextMarker()); for (auto object : contents) { auto & key = object.GetKey(); - if (key.size() != 40 || !hasSuffix(key, ".narinfo")) continue; + if (key.size() != 40 || !hasSuffix(key, ".narinfo")) + continue; paths.insert(parseStorePath(storeDir + "/" + key.substr(0, key.size() - 8) + "-" + MissingName)); } @@ -456,8 +427,10 @@ struct S3BinaryCacheStoreImpl : virtual S3BinaryCacheStoreConfig, public virtual return paths; } - static std::set uriSchemes() { return {"s3"}; } - + static std::set uriSchemes() + { + return {"s3"}; + } }; static RegisterStoreImplementation regS3BinaryCacheStore; diff --git a/src/libstore/s3.hh b/src/libstore/s3.hh index cdb3e59080e5..b9660be5c361 100644 --- a/src/libstore/s3.hh +++ b/src/libstore/s3.hh @@ -7,8 +7,16 @@ #include #include -namespace Aws { namespace Client { class ClientConfiguration; } } -namespace Aws { namespace S3 { class S3Client; } } +namespace Aws { +namespace Client { +class ClientConfiguration; +} +} +namespace Aws { +namespace S3 { +class S3Client; +} +} namespace nix { @@ -17,9 +25,14 @@ struct S3Helper ref config; ref client; - S3Helper(const std::string & profile, const std::string & region, const std::string & scheme, const std::string & endpoint); + S3Helper( + const std::string & profile, + const std::string & region, + const std::string & scheme, + const std::string & endpoint); - ref makeConfig(const std::string & region, const std::string & scheme, const std::string & endpoint); + ref + makeConfig(const std::string & region, const std::string & scheme, const std::string & endpoint); struct FileTransferResult { @@ -27,8 +40,7 @@ struct S3Helper unsigned int durationMs; }; - FileTransferResult getObject( - const std::string & bucketName, const std::string & key); + FileTransferResult getObject(const std::string & bucketName, const std::string & key); }; } diff --git a/src/libstore/serve-protocol.hh b/src/libstore/serve-protocol.hh index 3f76baa82ead..eece9283a3e6 100644 --- a/src/libstore/serve-protocol.hh +++ b/src/libstore/serve-protocol.hh @@ -6,8 +6,8 @@ namespace nix { #define SERVE_MAGIC_2 0x5452eecb #define SERVE_PROTOCOL_VERSION (2 << 8 | 7) -#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00) -#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff) +#define GET_PROTOCOL_MAJOR(x) ((x) &0xff00) +#define GET_PROTOCOL_MINOR(x) ((x) &0x00ff) typedef enum { cmdQueryValidPaths = 1, diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index 2090beabdfa5..356614ab8e98 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -8,13 +8,14 @@ namespace nix { -SQLiteError::SQLiteError(const char *path, int errNo, int extendedErrNo, hintformat && hf) - : Error(""), path(path), errNo(errNo), extendedErrNo(extendedErrNo) +SQLiteError::SQLiteError(const char * path, int errNo, int extendedErrNo, hintformat && hf) + : Error("") + , path(path) + , errNo(errNo) + , extendedErrNo(extendedErrNo) { - err.msg = hintfmt("%s: %s (in '%s')", - normaltxt(hf.str()), - sqlite3_errstr(extendedErrNo), - path ? path : "(in-memory)"); + err.msg = + hintfmt("%s: %s (in '%s')", normaltxt(hf.str()), sqlite3_errstr(extendedErrNo), path ? path : "(in-memory)"); } [[noreturn]] void SQLiteError::throw_(sqlite3 * db, hintformat && hf) @@ -27,9 +28,7 @@ SQLiteError::SQLiteError(const char *path, int errNo, int extendedErrNo, hintfor if (err == SQLITE_BUSY || err == SQLITE_PROTOCOL) { auto exp = SQLiteBusy(path, err, exterr, std::move(hf)); exp.err.msg = hintfmt( - err == SQLITE_PROTOCOL - ? "SQLite database '%s' is busy (SQLITE_PROTOCOL)" - : "SQLite database '%s' is busy", + err == SQLITE_PROTOCOL ? "SQLite database '%s' is busy (SQLITE_PROTOCOL)" : "SQLite database '%s' is busy", path ? path : "(in-memory)"); throw exp; } else @@ -41,9 +40,8 @@ SQLite::SQLite(const Path & path, bool create) // useSQLiteWAL also indicates what virtual file system we need. Using // `unix-dotfile` is needed on NFS file systems and on Windows' Subsystem // for Linux (WSL) where useSQLiteWAL should be false by default. - const char *vfs = settings.useSQLiteWAL ? 0 : "unix-dotfile"; - if (sqlite3_open_v2(path.c_str(), &db, - SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), vfs) != SQLITE_OK) + const char * vfs = settings.useSQLiteWAL ? 0 : "unix-dotfile"; + if (sqlite3_open_v2(path.c_str(), &db, SQLITE_OPEN_READWRITE | (create ? SQLITE_OPEN_CREATE : 0), vfs) != SQLITE_OK) throw Error("cannot open SQLite database '%s'", path); if (sqlite3_busy_timeout(db, 60 * 60 * 1000) != SQLITE_OK) @@ -115,7 +113,7 @@ SQLiteStmt::Use::~Use() sqlite3_reset(stmt); } -SQLiteStmt::Use & SQLiteStmt::Use::operator () (std::string_view value, bool notNull) +SQLiteStmt::Use & SQLiteStmt::Use::operator()(std::string_view value, bool notNull) { if (notNull) { if (sqlite3_bind_text(stmt, curArg++, value.data(), -1, SQLITE_TRANSIENT) != SQLITE_OK) @@ -125,7 +123,7 @@ SQLiteStmt::Use & SQLiteStmt::Use::operator () (std::string_view value, bool not return *this; } -SQLiteStmt::Use & SQLiteStmt::Use::operator () (const unsigned char * data, size_t len, bool notNull) +SQLiteStmt::Use & SQLiteStmt::Use::operator()(const unsigned char * data, size_t len, bool notNull) { if (notNull) { if (sqlite3_bind_blob(stmt, curArg++, data, len, SQLITE_TRANSIENT) != SQLITE_OK) @@ -135,7 +133,7 @@ SQLiteStmt::Use & SQLiteStmt::Use::operator () (const unsigned char * data, size return *this; } -SQLiteStmt::Use & SQLiteStmt::Use::operator () (int64_t value, bool notNull) +SQLiteStmt::Use & SQLiteStmt::Use::operator()(int64_t value, bool notNull) { if (notNull) { if (sqlite3_bind_int64(stmt, curArg++, value) != SQLITE_OK) @@ -224,9 +222,7 @@ void handleSQLiteBusy(const SQLiteBusy & e) if (now > lastWarned + 10) { lastWarned = now; - logWarning({ - .msg = hintfmt(e.what()) - }); + logWarning({.msg = hintfmt(e.what())}); } /* Sleep for a while since retrying the transaction right away diff --git a/src/libstore/sqlite.hh b/src/libstore/sqlite.hh index 1d1c553ea505..5315777741e6 100644 --- a/src/libstore/sqlite.hh +++ b/src/libstore/sqlite.hh @@ -14,13 +14,21 @@ namespace nix { struct SQLite { sqlite3 * db = 0; - SQLite() { } + SQLite() {} SQLite(const Path & path, bool create = true); SQLite(const SQLite & from) = delete; - SQLite& operator = (const SQLite & from) = delete; - SQLite& operator = (SQLite && from) { db = from.db; from.db = 0; return *this; } + SQLite & operator=(const SQLite & from) = delete; + SQLite & operator=(SQLite && from) + { + db = from.db; + from.db = 0; + return *this; + } ~SQLite(); - operator sqlite3 * () { return db; } + operator sqlite3 *() + { + return db; + } /* Disable synchronous mode, set truncate journal mode. */ void isCache(); @@ -36,11 +44,17 @@ struct SQLiteStmt sqlite3 * db = 0; sqlite3_stmt * stmt = 0; std::string sql; - SQLiteStmt() { } - SQLiteStmt(sqlite3 * db, const std::string & sql) { create(db, sql); } + SQLiteStmt() {} + SQLiteStmt(sqlite3 * db, const std::string & sql) + { + create(db, sql); + } void create(sqlite3 * db, const std::string & s); ~SQLiteStmt(); - operator sqlite3_stmt * () { return stmt; } + operator sqlite3_stmt *() + { + return stmt; + } /* Helper for binding / executing statements. */ class Use @@ -56,9 +70,9 @@ struct SQLiteStmt ~Use(); /* Bind the next parameter. */ - Use & operator () (std::string_view value, bool notNull = true); - Use & operator () (const unsigned char * data, size_t len, bool notNull = true); - Use & operator () (int64_t value, bool notNull = true); + Use & operator()(std::string_view value, bool notNull = true); + Use & operator()(const unsigned char * data, size_t len, bool notNull = true); + Use & operator()(int64_t value, bool notNull = true); Use & bind(); // null int step(); @@ -95,28 +109,27 @@ struct SQLiteTxn ~SQLiteTxn(); }; - struct SQLiteError : Error { - const char *path; + const char * path; int errNo, extendedErrNo; template - [[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args & ... args) { + [[noreturn]] static void throw_(sqlite3 * db, const std::string & fs, const Args &... args) + { throw_(db, hintfmt(fs, args...)); } - SQLiteError(const char *path, int errNo, int extendedErrNo, hintformat && hf); + SQLiteError(const char * path, int errNo, int extendedErrNo, hintformat && hf); protected: template - SQLiteError(const char *path, int errNo, int extendedErrNo, const std::string & fs, const Args & ... args) - : SQLiteError(path, errNo, extendedErrNo, hintfmt(fs, args...)) - { } + SQLiteError(const char * path, int errNo, int extendedErrNo, const std::string & fs, const Args &... args) + : SQLiteError(path, errNo, extendedErrNo, hintfmt(fs, args...)) + {} [[noreturn]] static void throw_(sqlite3 * db, hintformat && hf); - }; MakeError(SQLiteBusy, SQLiteError); diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc index 62daa838ce63..392860d7ef14 100644 --- a/src/libstore/ssh-store.cc +++ b/src/libstore/ssh-store.cc @@ -12,13 +12,19 @@ struct SSHStoreConfig : virtual RemoteStoreConfig { using RemoteStoreConfig::RemoteStoreConfig; - const Setting sshKey{(StoreConfig*) this, "", "ssh-key", "path to an SSH private key"}; - const Setting sshPublicHostKey{(StoreConfig*) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"}; - const Setting compress{(StoreConfig*) this, false, "compress", "whether to compress the connection"}; - const Setting remoteProgram{(StoreConfig*) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"}; - const Setting remoteStore{(StoreConfig*) this, "", "remote-store", "URI of the store on the remote system"}; - - const std::string name() override { return "SSH Store"; } + const Setting sshKey{(StoreConfig *) this, "", "ssh-key", "path to an SSH private key"}; + const Setting sshPublicHostKey{ + (StoreConfig *) this, "", "base64-ssh-public-host-key", "The public half of the host's SSH key"}; + const Setting compress{(StoreConfig *) this, false, "compress", "whether to compress the connection"}; + const Setting remoteProgram{ + (StoreConfig *) this, "nix-daemon", "remote-program", "path to the nix-daemon executable on the remote system"}; + const Setting remoteStore{ + (StoreConfig *) this, "", "remote-store", "URI of the store on the remote system"}; + + const std::string name() override + { + return "SSH Store"; + } }; class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore @@ -33,28 +39,34 @@ class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore , RemoteStore(params) , host(host) , master( - host, - sshKey, - sshPublicHostKey, - // Use SSH master only if using more than 1 connection. - connections->capacity() > 1, - compress) + host, + sshKey, + sshPublicHostKey, + // Use SSH master only if using more than 1 connection. + connections->capacity() > 1, + compress) + {} + + static std::set uriSchemes() { + return {"ssh-ng"}; } - static std::set uriSchemes() { return {"ssh-ng"}; } - std::string getUri() override { return *uriSchemes().begin() + "://" + host; } bool sameMachine() override - { return false; } + { + return false; + } // FIXME extend daemon protocol, move implementation to RemoteStore std::optional getBuildLog(const StorePath & path) override - { unsupported("getBuildLog"); } + { + unsupported("getBuildLog"); + } private: @@ -74,8 +86,7 @@ class SSHStore : public virtual SSHStoreConfig, public virtual RemoteStore SSHMaster master; - void setOptions(RemoteStore::Connection & conn) override - { + void setOptions(RemoteStore::Connection & conn) override{ /* TODO Add a way to explicitly ask for some options to be forwarded. One option: A way to query the daemon for its settings, and then a series of params to SSHStore like diff --git a/src/libstore/ssh.cc b/src/libstore/ssh.cc index 1bbad71f259c..d1a072ee813e 100644 --- a/src/libstore/ssh.cc +++ b/src/libstore/ssh.cc @@ -2,7 +2,13 @@ namespace nix { -SSHMaster::SSHMaster(const std::string & host, const std::string & keyFile, const std::string & sshPublicHostKey, bool useMaster, bool compress, int logFD) +SSHMaster::SSHMaster( + const std::string & host, + const std::string & keyFile, + const std::string & sshPublicHostKey, + bool useMaster, + bool compress, + int logFD) : host(host) , fakeSSH(host == "localhost") , keyFile(keyFile) @@ -49,39 +55,40 @@ std::unique_ptr SSHMaster::startCommand(const std::string ProcessOptions options; options.dieWithParent = false; - conn->sshPid = startProcess([&]() { - restoreProcessContext(); - - close(in.writeSide.get()); - close(out.readSide.get()); - - if (dup2(in.readSide.get(), STDIN_FILENO) == -1) - throw SysError("duping over stdin"); - if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) - throw SysError("duping over stdout"); - if (logFD != -1 && dup2(logFD, STDERR_FILENO) == -1) - throw SysError("duping over stderr"); - - Strings args; - - if (fakeSSH) { - args = { "bash", "-c" }; - } else { - args = { "ssh", host.c_str(), "-x", "-a" }; - addCommonSSHOpts(args); - if (socketPath != "") - args.insert(args.end(), {"-S", socketPath}); - if (verbosity >= lvlChatty) - args.push_back("-v"); - } - - args.push_back(command); - execvp(args.begin()->c_str(), stringsToCharPtrs(args).data()); - - // could not exec ssh/bash - throw SysError("unable to execute '%s'", args.front()); - }, options); - + conn->sshPid = startProcess( + [&]() { + restoreProcessContext(); + + close(in.writeSide.get()); + close(out.readSide.get()); + + if (dup2(in.readSide.get(), STDIN_FILENO) == -1) + throw SysError("duping over stdin"); + if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) + throw SysError("duping over stdout"); + if (logFD != -1 && dup2(logFD, STDERR_FILENO) == -1) + throw SysError("duping over stderr"); + + Strings args; + + if (fakeSSH) { + args = {"bash", "-c"}; + } else { + args = {"ssh", host.c_str(), "-x", "-a"}; + addCommonSSHOpts(args); + if (socketPath != "") + args.insert(args.end(), {"-S", socketPath}); + if (verbosity >= lvlChatty) + args.push_back("-v"); + } + + args.push_back(command); + execvp(args.begin()->c_str(), stringsToCharPtrs(args).data()); + + // could not exec ssh/bash + throw SysError("unable to execute '%s'", args.front()); + }, + options); in.readSide = -1; out.writeSide = -1; @@ -94,12 +101,13 @@ std::unique_ptr SSHMaster::startCommand(const std::string Path SSHMaster::startMaster() { - if (!useMaster) return ""; + if (!useMaster) + return ""; auto state(state_.lock()); - if (state->sshMaster != -1) return state->socketPath; - + if (state->sshMaster != -1) + return state->socketPath; state->socketPath = (Path) *state->tmpDir + "/ssh.sock"; @@ -109,33 +117,36 @@ Path SSHMaster::startMaster() ProcessOptions options; options.dieWithParent = false; - state->sshMaster = startProcess([&]() { - restoreProcessContext(); + state->sshMaster = startProcess( + [&]() { + restoreProcessContext(); - close(out.readSide.get()); + close(out.readSide.get()); - if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) - throw SysError("duping over stdout"); + if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) + throw SysError("duping over stdout"); - Strings args = - { "ssh", host.c_str(), "-M", "-N", "-S", state->socketPath - , "-o", "LocalCommand=echo started" - , "-o", "PermitLocalCommand=yes" - }; - if (verbosity >= lvlChatty) - args.push_back("-v"); - addCommonSSHOpts(args); - execvp(args.begin()->c_str(), stringsToCharPtrs(args).data()); + Strings args = {"ssh", host.c_str(), + "-M", "-N", + "-S", state->socketPath, + "-o", "LocalCommand=echo started", + "-o", "PermitLocalCommand=yes"}; + if (verbosity >= lvlChatty) + args.push_back("-v"); + addCommonSSHOpts(args); + execvp(args.begin()->c_str(), stringsToCharPtrs(args).data()); - throw SysError("unable to execute '%s'", args.front()); - }, options); + throw SysError("unable to execute '%s'", args.front()); + }, + options); out.writeSide = -1; std::string reply; try { reply = readLine(out.readSide.get()); - } catch (EndOfFile & e) { } + } catch (EndOfFile & e) { + } if (reply != "started") throw Error("failed to start SSH master connection to '%s'", host); diff --git a/src/libstore/ssh.hh b/src/libstore/ssh.hh index dabbcedda095..46546cfc584a 100644 --- a/src/libstore/ssh.hh +++ b/src/libstore/ssh.hh @@ -30,7 +30,13 @@ private: public: - SSHMaster(const std::string & host, const std::string & keyFile, const std::string & sshPublicHostKey, bool useMaster, bool compress, int logFD = -1); + SSHMaster( + const std::string & host, + const std::string & keyFile, + const std::string & sshPublicHostKey, + bool useMaster, + bool compress, + int logFD = -1); struct Connection { diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 53b1a8777f3e..05746a657495 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -16,13 +16,11 @@ namespace nix { - bool Store::isInStore(const Path & path) const { return isInDir(path, storeDir); } - std::pair Store::toStorePath(const Path & path) const { if (!isInStore(path)) @@ -34,12 +32,12 @@ std::pair Store::toStorePath(const Path & path) const return {parseStorePath(std::string_view(path).substr(0, slash)), path.substr(slash)}; } - Path Store::followLinksToStore(std::string_view _path) const { Path path = absPath(std::string(_path)); while (!isInStore(path)) { - if (!isLink(path)) break; + if (!isLink(path)) + break; auto target = readLink(path); path = absPath(target, dirOf(path)); } @@ -48,13 +46,11 @@ Path Store::followLinksToStore(std::string_view _path) const return path; } - StorePath Store::followLinksToStorePath(std::string_view path) const { return toStorePath(followLinksToStore(path)).first; } - /* Store paths have the following form: = /- @@ -134,47 +130,36 @@ StorePath Store::followLinksToStorePath(std::string_view path) const "source:". */ - -StorePath Store::makeStorePath(std::string_view type, - std::string_view hash, std::string_view name) const +StorePath Store::makeStorePath(std::string_view type, std::string_view hash, std::string_view name) const { /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */ - auto s = std::string(type) + ":" + std::string(hash) - + ":" + storeDir + ":" + std::string(name); + auto s = std::string(type) + ":" + std::string(hash) + ":" + storeDir + ":" + std::string(name); auto h = compressHash(hashString(htSHA256, s), 20); return StorePath(h, name); } - -StorePath Store::makeStorePath(std::string_view type, - const Hash & hash, std::string_view name) const +StorePath Store::makeStorePath(std::string_view type, const Hash & hash, std::string_view name) const { return makeStorePath(type, hash.to_string(Base16, true), name); } - -StorePath Store::makeOutputPath(std::string_view id, - const Hash & hash, std::string_view name) const +StorePath Store::makeOutputPath(std::string_view id, const Hash & hash, std::string_view name) const { - return makeStorePath("output:" + std::string { id }, hash, outputPathName(name, id)); + return makeStorePath("output:" + std::string{id}, hash, outputPathName(name, id)); } - -static std::string makeType( - const Store & store, - std::string && type, - const StorePathSet & references, - bool hasSelfReference = false) +static std::string +makeType(const Store & store, std::string && type, const StorePathSet & references, bool hasSelfReference = false) { for (auto & i : references) { type += ":"; type += store.printStorePath(i); } - if (hasSelfReference) type += ":self"; + if (hasSelfReference) + type += ":self"; return std::move(type); } - StorePath Store::makeFixedOutputPath( FileIngestionMethod method, const Hash & hash, @@ -186,31 +171,27 @@ StorePath Store::makeFixedOutputPath( return makeStorePath(makeType(*this, "source", references, hasSelfReference), hash, name); } else { assert(references.empty()); - return makeStorePath("output:out", - hashString(htSHA256, - "fixed:out:" - + makeFileIngestionPrefix(method) - + hash.to_string(Base16, true) + ":"), + return makeStorePath( + "output:out", + hashString(htSHA256, "fixed:out:" + makeFileIngestionPrefix(method) + hash.to_string(Base16, true) + ":"), name); } } -StorePath Store::makeFixedOutputPathFromCA(std::string_view name, ContentAddress ca, - const StorePathSet & references, bool hasSelfReference) const +StorePath Store::makeFixedOutputPathFromCA( + std::string_view name, ContentAddress ca, const StorePathSet & references, bool hasSelfReference) const { // New template - return std::visit(overloaded { - [&](const TextHash & th) { - return makeTextPath(name, th.hash, references); - }, - [&](const FixedOutputHash & fsh) { - return makeFixedOutputPath(fsh.method, fsh.hash, name, references, hasSelfReference); - } - }, ca); + return std::visit( + overloaded{ + [&](const TextHash & th) { return makeTextPath(name, th.hash, references); }, + [&](const FixedOutputHash & fsh) { + return makeFixedOutputPath(fsh.method, fsh.hash, name, references, hasSelfReference); + }}, + ca); } -StorePath Store::makeTextPath(std::string_view name, const Hash & hash, - const StorePathSet & references) const +StorePath Store::makeTextPath(std::string_view name, const Hash & hash, const StorePathSet & references) const { assert(hash.type == htSHA256); /* Stuff the references (if any) into the type. This is a bit @@ -219,26 +200,24 @@ StorePath Store::makeTextPath(std::string_view name, const Hash & hash, return makeStorePath(makeType(*this, "text", references), hash, name); } - -std::pair Store::computeStorePathForPath(std::string_view name, - const Path & srcPath, FileIngestionMethod method, HashType hashAlgo, PathFilter & filter) const +std::pair Store::computeStorePathForPath( + std::string_view name, + const Path & srcPath, + FileIngestionMethod method, + HashType hashAlgo, + PathFilter & filter) const { - Hash h = method == FileIngestionMethod::Recursive - ? hashPath(hashAlgo, srcPath, filter).first - : hashFile(hashAlgo, srcPath); + Hash h = method == FileIngestionMethod::Recursive ? hashPath(hashAlgo, srcPath, filter).first + : hashFile(hashAlgo, srcPath); return std::make_pair(makeFixedOutputPath(method, h, name), h); } - -StorePath Store::computeStorePathForText( - std::string_view name, - std::string_view s, - const StorePathSet & references) const +StorePath +Store::computeStorePathForText(std::string_view name, std::string_view s, const StorePathSet & references) const { return makeTextPath(name, hashString(htSHA256, s), references); } - StorePath Store::addToStore( std::string_view name, const Path & _srcPath, @@ -258,11 +237,7 @@ StorePath Store::addToStore( return addToStoreFromDump(*source, name, method, hashAlgo, repair, references); } - -void Store::addMultipleToStore( - Source & source, - RepairFlag repair, - CheckSigsFlag checkSigs) +void Store::addMultipleToStore(Source & source, RepairFlag repair, CheckSigsFlag checkSigs) { auto expected = readNum(source); for (uint64_t i = 0; i < expected; ++i) { @@ -272,7 +247,6 @@ void Store::addMultipleToStore( } } - /* The aim of this function is to compute in one pass the correct ValidPathInfo for the files that we are trying to add to the store. To accomplish that in one @@ -296,38 +270,37 @@ digraph graphname { fileSink -> caHashSink } */ -ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath, - FileIngestionMethod method, HashType hashAlgo, +ValidPathInfo Store::addToStoreSlow( + std::string_view name, + const Path & srcPath, + FileIngestionMethod method, + HashType hashAlgo, std::optional expectedCAHash) { - HashSink narHashSink { htSHA256 }; - HashSink caHashSink { hashAlgo }; + HashSink narHashSink{htSHA256}; + HashSink caHashSink{hashAlgo}; /* Note that fileSink and unusualHashTee must be mutually exclusive, since they both write to caHashSink. Note that that requisite is currently true because the former is only used in the flat case. */ - RetrieveRegularNARSink fileSink { caHashSink }; - TeeSink unusualHashTee { narHashSink, caHashSink }; + RetrieveRegularNARSink fileSink{caHashSink}; + TeeSink unusualHashTee{narHashSink, caHashSink}; auto & narSink = method == FileIngestionMethod::Recursive && hashAlgo != htSHA256 - ? static_cast(unusualHashTee) - : narHashSink; + ? static_cast(unusualHashTee) + : narHashSink; /* Functionally, this means that fileSource will yield the content of srcPath. The fact that we use scratchpadSink as a temporary buffer here is an implementation detail. */ - auto fileSource = sinkToSource([&](Sink & scratchpadSink) { - dumpPath(srcPath, scratchpadSink); - }); + auto fileSource = sinkToSource([&](Sink & scratchpadSink) { dumpPath(srcPath, scratchpadSink); }); /* tapped provides the same data as fileSource, but we also write all the information to narSink. */ - TeeSource tapped { *fileSource, narSink }; + TeeSource tapped{*fileSource, narSink}; ParseSink blank; - auto & parseSink = method == FileIngestionMethod::Flat - ? fileSink - : blank; + auto & parseSink = method == FileIngestionMethod::Flat ? fileSink : blank; /* The information that flows from tapped (besides being replicated in narSink), is now put in parseSink. */ @@ -337,24 +310,20 @@ ValidPathInfo Store::addToStoreSlow(std::string_view name, const Path & srcPath, finish. */ auto [narHash, narSize] = narHashSink.finish(); - auto hash = method == FileIngestionMethod::Recursive && hashAlgo == htSHA256 - ? narHash - : caHashSink.finish().first; + auto hash = method == FileIngestionMethod::Recursive && hashAlgo == htSHA256 ? narHash : caHashSink.finish().first; if (expectedCAHash && expectedCAHash != hash) throw Error("hash mismatch for '%s'", srcPath); - ValidPathInfo info { + ValidPathInfo info{ makeFixedOutputPath(method, hash, name), narHash, }; info.narSize = narSize; - info.ca = FixedOutputHash { .method = method, .hash = hash }; + info.ca = FixedOutputHash{.method = method, .hash = hash}; if (!isValidPath(info.path)) { - auto source = sinkToSource([&](Sink & scratchpadSink) { - dumpPath(srcPath, scratchpadSink); - }); + auto source = sinkToSource([&](Sink & scratchpadSink) { dumpPath(srcPath, scratchpadSink); }); addToStore(info, *source); } @@ -377,9 +346,7 @@ StringSet StoreConfig::getDefaultSystemFeatures() Store::Store(const Params & params) : StoreConfig(params) , state({(size_t) pathInfoCacheSize}) -{ -} - +{} std::string Store::getUri() { @@ -388,9 +355,8 @@ std::string Store::getUri() bool Store::PathInfoCacheValue::isKnownNow() { - std::chrono::duration ttl = didExist() - ? std::chrono::seconds(settings.ttlPositiveNarInfoCache) - : std::chrono::seconds(settings.ttlNegativeNarInfoCache); + std::chrono::duration ttl = didExist() ? std::chrono::seconds(settings.ttlPositiveNarInfoCache) + : std::chrono::seconds(settings.ttlNegativeNarInfoCache); return std::chrono::steady_clock::now() < time_point + ttl; } @@ -399,13 +365,14 @@ std::map> Store::queryPartialDerivationOut { std::map> outputs; auto drv = readInvalidDerivation(path); - for (auto& [outputName, output] : drv.outputsAndOptPaths(*this)) { + for (auto & [outputName, output] : drv.outputsAndOptPaths(*this)) { outputs.emplace(outputName, output.second); } return outputs; } -OutputPathMap Store::queryDerivationOutputMap(const StorePath & path) { +OutputPathMap Store::queryDerivationOutputMap(const StorePath & path) +{ auto resp = queryPartialDerivationOutputMap(path); OutputPathMap result; for (auto & [outName, optOutPath] : resp) { @@ -420,7 +387,7 @@ StorePathSet Store::queryDerivationOutputs(const StorePath & path) { auto outputMap = this->queryDerivationOutputMap(path); StorePathSet outputPaths; - for (auto & i: outputMap) { + for (auto & i : outputMap) { outputPaths.emplace(std::move(i.second)); } return outputPaths; @@ -442,8 +409,10 @@ bool Store::isValidPath(const StorePath & storePath) if (res.first != NarInfoDiskCache::oUnknown) { stats.narInfoReadAverted++; auto state_(state.lock()); - state_->pathInfoCache.upsert(std::string(storePath.to_string()), - res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{} : PathInfoCacheValue { .value = res.second }); + state_->pathInfoCache.upsert( + std::string(storePath.to_string()), res.first == NarInfoDiskCache::oInvalid + ? PathInfoCacheValue{} + : PathInfoCacheValue{.value = res.second}); return res.first == NarInfoDiskCache::oValid; } } @@ -457,7 +426,6 @@ bool Store::isValidPath(const StorePath & storePath) return valid; } - /* Default implementation for stores that only implement queryPathInfoUncached(). */ bool Store::isValidPathUncached(const StorePath & path) @@ -470,34 +438,28 @@ bool Store::isValidPathUncached(const StorePath & path) } } - ref Store::queryPathInfo(const StorePath & storePath) { std::promise> promise; - queryPathInfo(storePath, - {[&](std::future> result) { - try { - promise.set_value(result.get()); - } catch (...) { - promise.set_exception(std::current_exception()); - } - }}); + queryPathInfo(storePath, {[&](std::future> result) { + try { + promise.set_value(result.get()); + } catch (...) { + promise.set_exception(std::current_exception()); + } + }}); return promise.get_future().get(); } - static bool goodStorePath(const StorePath & expected, const StorePath & actual) { - return - expected.hashPart() == actual.hashPart() - && (expected.name() == Store::MissingName || expected.name() == actual.name()); + return expected.hashPart() == actual.hashPart() + && (expected.name() == Store::MissingName || expected.name() == actual.name()); } - -void Store::queryPathInfo(const StorePath & storePath, - Callback> callback) noexcept +void Store::queryPathInfo(const StorePath & storePath, Callback> callback) noexcept { auto hashPart = std::string(storePath.hashPart()); @@ -518,23 +480,25 @@ void Store::queryPathInfo(const StorePath & storePath, stats.narInfoReadAverted++; { auto state_(state.lock()); - state_->pathInfoCache.upsert(std::string(storePath.to_string()), - res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{} : PathInfoCacheValue{ .value = res.second }); - if (res.first == NarInfoDiskCache::oInvalid || - !goodStorePath(storePath, res.second->path)) + state_->pathInfoCache.upsert( + std::string(storePath.to_string()), res.first == NarInfoDiskCache::oInvalid + ? PathInfoCacheValue{} + : PathInfoCacheValue{.value = res.second}); + if (res.first == NarInfoDiskCache::oInvalid || !goodStorePath(storePath, res.second->path)) throw InvalidPath("path '%s' is not valid", printStorePath(storePath)); } return callback(ref(res.second)); } } - } catch (...) { return callback.rethrow(); } + } catch (...) { + return callback.rethrow(); + } auto callbackPtr = std::make_shared(std::move(callback)); - queryPathInfoUncached(storePath, - {[this, storePath, hashPart, callbackPtr](std::future> fut) { - + queryPathInfoUncached( + storePath, {[this, storePath, hashPart, callbackPtr](std::future> fut) { try { auto info = fut.get(); @@ -543,7 +507,7 @@ void Store::queryPathInfo(const StorePath & storePath, { auto state_(state.lock()); - state_->pathInfoCache.upsert(std::string(storePath.to_string()), PathInfoCacheValue { .value = info }); + state_->pathInfoCache.upsert(std::string(storePath.to_string()), PathInfoCacheValue{.value = info}); } if (!info || !goodStorePath(storePath, info->path)) { @@ -552,27 +516,25 @@ void Store::queryPathInfo(const StorePath & storePath, } (*callbackPtr)(ref(info)); - } catch (...) { callbackPtr->rethrow(); } + } catch (...) { + callbackPtr->rethrow(); + } }}); } -void Store::queryRealisation(const DrvOutput & id, - Callback> callback) noexcept +void Store::queryRealisation(const DrvOutput & id, Callback> callback) noexcept { try { if (diskCache) { - auto [cacheOutcome, maybeCachedRealisation] - = diskCache->lookupRealisation(getUri(), id); + auto [cacheOutcome, maybeCachedRealisation] = diskCache->lookupRealisation(getUri(), id); switch (cacheOutcome) { case NarInfoDiskCache::oValid: debug("Returning a cached realisation for %s", id.to_string()); callback(maybeCachedRealisation); return; case NarInfoDiskCache::oInvalid: - debug( - "Returning a cached missing realisation for %s", - id.to_string()); + debug("Returning a cached missing realisation for %s", id.to_string()); callback(nullptr); return; case NarInfoDiskCache::oUnknown: @@ -583,29 +545,25 @@ void Store::queryRealisation(const DrvOutput & id, return callback.rethrow(); } - auto callbackPtr - = std::make_shared(std::move(callback)); + auto callbackPtr = std::make_shared(std::move(callback)); - queryRealisationUncached( - id, - { [this, id, callbackPtr]( - std::future> fut) { - try { - auto info = fut.get(); + queryRealisationUncached(id, {[this, id, callbackPtr](std::future> fut) { + try { + auto info = fut.get(); - if (diskCache) { - if (info) - diskCache->upsertRealisation(getUri(), *info); - else - diskCache->upsertAbsentRealisation(getUri(), id); - } + if (diskCache) { + if (info) + diskCache->upsertRealisation(getUri(), *info); + else + diskCache->upsertAbsentRealisation(getUri(), id); + } - (*callbackPtr)(std::shared_ptr(info)); + (*callbackPtr)(std::shared_ptr(info)); - } catch (...) { - callbackPtr->rethrow(); - } - } }); + } catch (...) { + callbackPtr->rethrow(); + } + }}); } std::shared_ptr Store::queryRealisation(const DrvOutput & id) @@ -613,14 +571,13 @@ std::shared_ptr Store::queryRealisation(const DrvOutput & id) using RealPtr = std::shared_ptr; std::promise promise; - queryRealisation(id, - {[&](std::future result) { - try { - promise.set_value(result.get()); - } catch (...) { - promise.set_exception(std::current_exception()); - } - }}); + queryRealisation(id, {[&](std::future result) { + try { + promise.set_value(result.get()); + } catch (...) { + promise.set_exception(std::current_exception()); + } + }}); return promise.get_future().get(); } @@ -633,20 +590,19 @@ void Store::substitutePaths(const StorePathSet & paths) paths2.push_back(DerivedPath::Opaque{path}); uint64_t downloadSize, narSize; StorePathSet willBuild, willSubstitute, unknown; - queryMissing(paths2, - willBuild, willSubstitute, unknown, downloadSize, narSize); + queryMissing(paths2, willBuild, willSubstitute, unknown, downloadSize, narSize); if (!willSubstitute.empty()) try { std::vector subs; - for (auto & p : willSubstitute) subs.push_back(DerivedPath::Opaque{p}); + for (auto & p : willSubstitute) + subs.push_back(DerivedPath::Opaque{p}); buildPaths(subs); } catch (Error & e) { logWarning(e.info()); } } - StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute) { struct State @@ -664,18 +620,18 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m auto doQuery = [&](const Path & path) { checkInterrupt(); queryPathInfo(parseStorePath(path), {[path, this, &state_, &wakeup](std::future> fut) { - auto state(state_.lock()); - try { - auto info = fut.get(); - state->valid.insert(parseStorePath(path)); - } catch (InvalidPath &) { - } catch (...) { - state->exc = std::current_exception(); - } - assert(state->left); - if (!--state->left) - wakeup.notify_one(); - }}); + auto state(state_.lock()); + try { + auto info = fut.get(); + state->valid.insert(parseStorePath(path)); + } catch (InvalidPath &) { + } catch (...) { + state->exc = std::current_exception(); + } + assert(state->left); + if (!--state->left) + wakeup.notify_one(); + }}); }; for (auto & path : paths) @@ -686,19 +642,18 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m while (true) { auto state(state_.lock()); if (!state->left) { - if (state->exc) std::rethrow_exception(state->exc); + if (state->exc) + std::rethrow_exception(state->exc); return std::move(state->valid); } state.wait(wakeup); } } - /* Return a string accepted by decodeValidPathInfo() that registers the specified paths as valid. Note: it's the responsibility of the caller to provide a closure. */ -std::string Store::makeValidityRegistration(const StorePathSet & paths, - bool showDerivers, bool showHash) +std::string Store::makeValidityRegistration(const StorePathSet & paths, bool showDerivers, bool showHash) { std::string s = ""; @@ -724,14 +679,15 @@ std::string Store::makeValidityRegistration(const StorePathSet & paths, return s; } - StorePathSet Store::exportReferences(const StorePathSet & storePaths, const StorePathSet & inputPaths) { StorePathSet paths; for (auto & storePath : storePaths) { if (!inputPaths.count(storePath)) - throw BuildError("cannot export references of path '%s' because it is not in the input closure of the derivation", printStorePath(storePath)); + throw BuildError( + "cannot export references of path '%s' because it is not in the input closure of the derivation", + printStorePath(storePath)); computeFSClosure({storePath}, paths); } @@ -760,9 +716,11 @@ StorePathSet Store::exportReferences(const StorePathSet & storePaths, const Stor return paths; } - -void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths, - bool includeImpureInfo, bool showClosureSize, +void Store::pathInfoToJSON( + JSONPlaceholder & jsonOut, + const StorePathSet & storePaths, + bool includeImpureInfo, + bool showClosureSize, Base hashBase, AllowInvalidFlag allowInvalid) { @@ -775,9 +733,7 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store auto info = queryPathInfo(storePath); jsonPath.attr("path", printStorePath(info->path)); - jsonPath - .attr("narHash", info->narHash.to_string(hashBase, true)) - .attr("narSize", info->narSize); + jsonPath.attr("narHash", info->narHash.to_string(hashBase, true)).attr("narSize", info->narSize); { auto jsonRefs = jsonPath.list("references"); @@ -812,8 +768,7 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store jsonSigs.elem(sig); } - auto narInfo = std::dynamic_pointer_cast( - std::shared_ptr(info)); + auto narInfo = std::dynamic_pointer_cast(std::shared_ptr(info)); if (narInfo) { if (!narInfo->url.empty()) @@ -834,7 +789,6 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store } } - std::pair Store::getClosureSize(const StorePath & storePath) { uint64_t totalNarSize = 0, totalDownloadSize = 0; @@ -843,15 +797,13 @@ std::pair Store::getClosureSize(const StorePath & storePath) for (auto & p : closure) { auto info = queryPathInfo(p); totalNarSize += info->narSize; - auto narInfo = std::dynamic_pointer_cast( - std::shared_ptr(info)); + auto narInfo = std::dynamic_pointer_cast(std::shared_ptr(info)); if (narInfo) totalDownloadSize += narInfo->fileSize; } return {totalNarSize, totalDownloadSize}; } - const Store::Stats & Store::getStats() { { @@ -861,33 +813,22 @@ const Store::Stats & Store::getStats() return stats; } - -static std::string makeCopyPathMessage( - std::string_view srcUri, - std::string_view dstUri, - std::string_view storePath) +static std::string makeCopyPathMessage(std::string_view srcUri, std::string_view dstUri, std::string_view storePath) { - return srcUri == "local" || srcUri == "daemon" - ? fmt("copying path '%s' to '%s'", storePath, dstUri) - : dstUri == "local" || dstUri == "daemon" - ? fmt("copying path '%s' from '%s'", storePath, srcUri) - : fmt("copying path '%s' from '%s' to '%s'", storePath, srcUri, dstUri); + return srcUri == "local" || srcUri == "daemon" ? fmt("copying path '%s' to '%s'", storePath, dstUri) + : dstUri == "local" || dstUri == "daemon" + ? fmt("copying path '%s' from '%s'", storePath, srcUri) + : fmt("copying path '%s' from '%s' to '%s'", storePath, srcUri, dstUri); } - void copyStorePath( - Store & srcStore, - Store & dstStore, - const StorePath & storePath, - RepairFlag repair, - CheckSigsFlag checkSigs) + Store & srcStore, Store & dstStore, const StorePath & storePath, RepairFlag repair, CheckSigsFlag checkSigs) { auto srcUri = srcStore.getUri(); auto dstUri = dstStore.getUri(); auto storePathS = srcStore.printStorePath(storePath); - Activity act(*logger, lvlInfo, actCopyPath, - makeCopyPathMessage(srcUri, dstUri, storePathS), - {storePathS, srcUri, dstUri}); + Activity act( + *logger, lvlInfo, actCopyPath, makeCopyPathMessage(srcUri, dstUri, storePathS), {storePathS, srcUri, dstUri}); PushActivity pact(act.id); auto info = srcStore.queryPathInfo(storePath); @@ -909,21 +850,23 @@ void copyStorePath( info = info2; } - auto source = sinkToSource([&](Sink & sink) { - LambdaSink progressSink([&](std::string_view data) { - total += data.size(); - act.progress(total, info->narSize); + auto source = sinkToSource( + [&](Sink & sink) { + LambdaSink progressSink([&](std::string_view data) { + total += data.size(); + act.progress(total, info->narSize); + }); + TeeSink tee{sink, progressSink}; + srcStore.narFromPath(storePath, tee); + }, + [&]() { + throw EndOfFile( + "NAR for '%s' fetched from '%s' is incomplete", srcStore.printStorePath(storePath), srcStore.getUri()); }); - TeeSink tee { sink, progressSink }; - srcStore.narFromPath(storePath, tee); - }, [&]() { - throw EndOfFile("NAR for '%s' fetched from '%s' is incomplete", srcStore.printStorePath(storePath), srcStore.getUri()); - }); dstStore.addToStore(*info, *source, repair, checkSigs); } - std::map copyPaths( Store & srcStore, Store & dstStore, @@ -962,9 +905,7 @@ std::map copyPaths( } return children; }, - [&](const Realisation& current) -> void { - dstStore.registerDrvOutput(current, checkSigs); - }); + [&](const Realisation & current) -> void { dstStore.registerDrvOutput(current, checkSigs); }); } catch (MissingExperimentalFeature & e) { // Don't fail if the remote doesn't support CA derivations is it might // not be within our control to change that, and we might still want @@ -990,7 +931,8 @@ std::map copyPaths( StorePathSet missing; for (auto & path : storePaths) - if (!valid.count(path)) missing.insert(path); + if (!valid.count(path)) + missing.insert(path); std::map pathsMap; for (auto & path : storePaths) @@ -1007,8 +949,8 @@ std::map copyPaths( auto srcUri = srcStore.getUri(); auto dstUri = dstStore.getUri(); auto storePathS = srcStore.printStorePath(storePath); - Activity act(*logger, lvlInfo, actCopyPath, - makeCopyPathMessage(srcUri, dstUri, storePathS), + Activity act( + *logger, lvlInfo, actCopyPath, makeCopyPathMessage(srcUri, dstUri, storePathS), {storePathS, srcUri, dstUri}); PushActivity pact(act.id); @@ -1020,7 +962,7 @@ std::map copyPaths( dstStore.addMultipleToStore(*source, repair, checkSigs); - #if 0 +#if 0 std::atomic nrDone{0}; std::atomic nrFailed{0}; std::atomic bytesExpected{0}; @@ -1098,7 +1040,7 @@ std::map copyPaths( nrDone++; showProgress(); }); - #endif +#endif return pathsMap; } @@ -1111,7 +1053,8 @@ void copyClosure( CheckSigsFlag checkSigs, SubstituteFlag substitute) { - if (&srcStore == &dstStore) return; + if (&srcStore == &dstStore) + return; RealisedPath::Set closure; RealisedPath::closure(srcStore, paths, closure); @@ -1127,75 +1070,77 @@ void copyClosure( CheckSigsFlag checkSigs, SubstituteFlag substitute) { - if (&srcStore == &dstStore) return; + if (&srcStore == &dstStore) + return; StorePathSet closure; srcStore.computeFSClosure(storePaths, closure); copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute); } -std::optional decodeValidPathInfo(const Store & store, std::istream & str, std::optional hashGiven) +std::optional +decodeValidPathInfo(const Store & store, std::istream & str, std::optional hashGiven) { std::string path; getline(str, path); - if (str.eof()) { return {}; } + if (str.eof()) { + return {}; + } if (!hashGiven) { std::string s; getline(str, s); auto narHash = Hash::parseAny(s, htSHA256); getline(str, s); auto narSize = string2Int(s); - if (!narSize) throw Error("number expected"); - hashGiven = { narHash, *narSize }; + if (!narSize) + throw Error("number expected"); + hashGiven = {narHash, *narSize}; } ValidPathInfo info(store.parseStorePath(path), hashGiven->first); info.narSize = hashGiven->second; std::string deriver; getline(str, deriver); - if (deriver != "") info.deriver = store.parseStorePath(deriver); + if (deriver != "") + info.deriver = store.parseStorePath(deriver); std::string s; getline(str, s); auto n = string2Int(s); - if (!n) throw Error("number expected"); + if (!n) + throw Error("number expected"); while ((*n)--) { getline(str, s); info.references.insert(store.parseStorePath(s)); } - if (!str || str.eof()) throw Error("missing input"); + if (!str || str.eof()) + throw Error("missing input"); return std::optional(std::move(info)); } - std::string Store::showPaths(const StorePathSet & paths) { std::string s; for (auto & i : paths) { - if (s.size() != 0) s += ", "; + if (s.size() != 0) + s += ", "; s += "'" + printStorePath(i) + "'"; } return s; } - std::string showPaths(const PathSet & paths) { return concatStringsSep(", ", quoteStrings(paths)); } - std::string ValidPathInfo::fingerprint(const Store & store) const { if (narSize == 0) - throw Error("cannot calculate fingerprint of path '%s' because its size is not known", - store.printStorePath(path)); - return - "1;" + store.printStorePath(path) + ";" - + narHash.to_string(Base32, true) + ";" - + std::to_string(narSize) + ";" - + concatStringsSep(",", store.printStorePathSet(references)); + throw Error( + "cannot calculate fingerprint of path '%s' because its size is not known", store.printStorePath(path)); + return "1;" + store.printStorePath(path) + ";" + narHash.to_string(Base32, true) + ";" + std::to_string(narSize) + + ";" + concatStringsSep(",", store.printStorePathSet(references)); } - void ValidPathInfo::sign(const Store & store, const SecretKey & secretKey) { sigs.insert(secretKey.signDetached(fingerprint(store))); @@ -1203,22 +1148,22 @@ void ValidPathInfo::sign(const Store & store, const SecretKey & secretKey) bool ValidPathInfo::isContentAddressed(const Store & store) const { - if (! ca) return false; + if (!ca) + return false; - auto caPath = std::visit(overloaded { - [&](const TextHash & th) { - return store.makeTextPath(path.name(), th.hash, references); - }, - [&](const FixedOutputHash & fsh) { - auto refs = references; - bool hasSelfReference = false; - if (refs.count(path)) { - hasSelfReference = true; - refs.erase(path); - } - return store.makeFixedOutputPath(fsh.method, fsh.hash, path.name(), refs, hasSelfReference); - } - }, *ca); + auto caPath = std::visit( + overloaded{ + [&](const TextHash & th) { return store.makeTextPath(path.name(), th.hash, references); }, + [&](const FixedOutputHash & fsh) { + auto refs = references; + bool hasSelfReference = false; + if (refs.count(path)) { + hasSelfReference = true; + refs.erase(path); + } + return store.makeFixedOutputPath(fsh.method, fsh.hash, path.name(), refs, hasSelfReference); + }}, + *ca); bool res = caPath == path; @@ -1228,10 +1173,10 @@ bool ValidPathInfo::isContentAddressed(const Store & store) const return res; } - size_t ValidPathInfo::checkSignatures(const Store & store, const PublicKeys & publicKeys) const { - if (isContentAddressed(store)) return maxSigs; + if (isContentAddressed(store)) + return maxSigs; size_t good = 0; for (auto & sig : sigs) @@ -1240,13 +1185,11 @@ size_t ValidPathInfo::checkSignatures(const Store & store, const PublicKeys & pu return good; } - bool ValidPathInfo::checkSignature(const Store & store, const PublicKeys & publicKeys, const std::string & sig) const { return verifyDetached(fingerprint(store), sig, publicKeys); } - Strings ValidPathInfo::shortRefs() const { Strings refs; @@ -1255,19 +1198,18 @@ Strings ValidPathInfo::shortRefs() const return refs; } - Derivation Store::derivationFromPath(const StorePath & drvPath) { ensurePath(drvPath); return readDerivation(drvPath); } -Derivation readDerivationCommon(Store& store, const StorePath& drvPath, bool requireValidPath) +Derivation readDerivationCommon(Store & store, const StorePath & drvPath, bool requireValidPath) { auto accessor = store.getFSAccessor(); try { - return parseDerivation(store, - accessor->readFile(store.printStorePath(drvPath), requireValidPath), + return parseDerivation( + store, accessor->readFile(store.printStorePath(drvPath), requireValidPath), Derivation::nameFromPath(drvPath)); } catch (FormatError & e) { throw Error("error parsing derivation '%s': %s", store.printStorePath(drvPath), e.msg()); @@ -1275,18 +1217,20 @@ Derivation readDerivationCommon(Store& store, const StorePath& drvPath, bool req } Derivation Store::readDerivation(const StorePath & drvPath) -{ return readDerivationCommon(*this, drvPath, true); } +{ + return readDerivationCommon(*this, drvPath, true); +} Derivation Store::readInvalidDerivation(const StorePath & drvPath) -{ return readDerivationCommon(*this, drvPath, false); } - +{ + return readDerivationCommon(*this, drvPath, false); } +} #include "local-store.hh" #include "uds-remote-store.hh" - namespace nix { /* Split URI into protocol+hierarchy part and its parameter set. */ @@ -1320,7 +1264,7 @@ std::shared_ptr openFromNonUri(const std::string & uri, const Store::Para return std::make_shared(params); else if (pathExists(settings.nixDaemonSocketFile)) return std::make_shared(params); - #if __linux__ +#if __linux__ else if (!pathExists(stateDir) && params.empty() && getuid() != 0) { /* If /nix doesn't exist, there is no daemon socket, and we're not root, then automatically set up a chroot @@ -1334,7 +1278,7 @@ std::shared_ptr openFromNonUri(const std::string & uri, const Store::Para params2["root"] = chrootStore; return std::make_shared(params2); } - #endif +#endif else return std::make_shared(params); } else if (uri == "daemon") { @@ -1361,7 +1305,7 @@ std::shared_ptr openFromNonUri(const std::string & uri, const Store::Para // will be transformed into `root@::1` for SSH (same for `[::1]` -> `::1`). // * If the URL looks like `root@::1` it will be left as-is. // * In any other case, the string will be left as-is. -static std::string extractConnStr(const std::string &proto, const std::string &connStr) +static std::string extractConnStr(const std::string & proto, const std::string & connStr) { if (proto.rfind("ssh") != std::string::npos) { std::smatch result; @@ -1378,18 +1322,14 @@ static std::string extractConnStr(const std::string &proto, const std::string &c return connStr; } -ref openStore(const std::string & uri_, - const Store::Params & extraParams) +ref openStore(const std::string & uri_, const Store::Params & extraParams) { auto params = extraParams; try { auto parsedUri = parseURL(uri_); params.insert(parsedUri.query.begin(), parsedUri.query.end()); - auto baseURI = extractConnStr( - parsedUri.scheme, - parsedUri.authority.value_or("") + parsedUri.path - ); + auto baseURI = extractConnStr(parsedUri.scheme, parsedUri.authority.value_or("") + parsedUri.path); for (auto implem : *Implementations::registered) { if (implem.uriSchemes.count(parsedUri.scheme)) { @@ -1401,8 +1341,7 @@ ref openStore(const std::string & uri_, } } } - } - catch (BadURL &) { + } catch (BadURL &) { auto [uri, uriParams] = splitUriAndParams(uri_); params.insert(uriParams.begin(), uriParams.end()); @@ -1423,7 +1362,8 @@ std::list> getDefaultSubstituters() StringSet done; auto addStore = [&](const std::string & uri) { - if (!done.insert(uri).second) return; + if (!done.insert(uri).second) + return; try { stores.push_back(openStore(uri)); } catch (Error & e) { @@ -1434,12 +1374,10 @@ std::list> getDefaultSubstituters() for (auto uri : settings.substituters.get()) addStore(uri); - stores.sort([](ref & a, ref & b) { - return a->priority < b->priority; - }); + stores.sort([](ref & a, ref & b) { return a->priority < b->priority; }); return stores; - } ()); + }()); return stores; } diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 0c8a4db5667c..b17c7a325317 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -23,7 +23,6 @@ #include #include - namespace nix { /** @@ -69,7 +68,6 @@ class NarInfoDiskCache; class Store; class JSONPlaceholder; - enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true }; enum SubstituteFlag : bool { NoSubstitute = false, Substitute = true }; enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true }; @@ -77,12 +75,10 @@ enum AllowInvalidFlag : bool { DisallowInvalid = false, AllowInvalid = true }; /* Magic header of exportPath() output (obsolete). */ const uint32_t exportMagic = 0x4558494e; - enum BuildMode { bmNormal, bmRepair, bmCheck }; struct BuildResult; - struct StoreConfig : public Config { using Config::Config; @@ -91,26 +87,28 @@ struct StoreConfig : public Config StringSet getDefaultSystemFeatures(); - virtual ~StoreConfig() { } + virtual ~StoreConfig() {} virtual const std::string name() = 0; - const PathSetting storeDir_{this, false, settings.nixStore, - "store", "path to the Nix store"}; + const PathSetting storeDir_{this, false, settings.nixStore, "store", "path to the Nix store"}; const Path storeDir = storeDir_; - const Setting pathInfoCacheSize{this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"}; + const Setting pathInfoCacheSize{ + this, 65536, "path-info-cache-size", "size of the in-memory store path information cache"}; - const Setting isTrusted{this, false, "trusted", "whether paths from this store can be used as substitutes even when they lack trusted signatures"}; + const Setting isTrusted{ + this, false, "trusted", + "whether paths from this store can be used as substitutes even when they lack trusted signatures"}; Setting priority{this, 0, "priority", "priority of this substituter (lower value means higher priority)"}; - Setting wantMassQuery{this, false, "want-mass-query", "whether this substituter can be queried efficiently for path validity"}; + Setting wantMassQuery{ + this, false, "want-mass-query", "whether this substituter can be queried efficiently for path validity"}; - Setting systemFeatures{this, getDefaultSystemFeatures(), - "system-features", + Setting systemFeatures{ + this, getDefaultSystemFeatures(), "system-features", "Optional features that the system this store builds on implements (like \"kvm\")."}; - }; class Store : public std::enable_shared_from_this, public virtual StoreConfig @@ -121,7 +119,8 @@ public: protected: - struct PathInfoCacheValue { + struct PathInfoCacheValue + { // Time of cache entry creation or update std::chrono::time_point time_point = std::chrono::steady_clock::now(); @@ -134,8 +133,9 @@ protected: // Past tense, because a path can only be assumed to exists when // isKnownNow() && didExist() - inline bool didExist() { - return value != nullptr; + inline bool didExist() + { + return value != nullptr; } }; @@ -155,9 +155,9 @@ public: * Perform any necessary effectful operation to make the store up and * running */ - virtual void init() {}; + virtual void init(){}; - virtual ~Store() { } + virtual ~Store() {} virtual std::string getUri() = 0; @@ -196,32 +196,35 @@ public: StorePath followLinksToStorePath(std::string_view path) const; /* Constructs a unique store path name. */ - StorePath makeStorePath(std::string_view type, - std::string_view hash, std::string_view name) const; - StorePath makeStorePath(std::string_view type, - const Hash & hash, std::string_view name) const; + StorePath makeStorePath(std::string_view type, std::string_view hash, std::string_view name) const; + StorePath makeStorePath(std::string_view type, const Hash & hash, std::string_view name) const; - StorePath makeOutputPath(std::string_view id, - const Hash & hash, std::string_view name) const; + StorePath makeOutputPath(std::string_view id, const Hash & hash, std::string_view name) const; - StorePath makeFixedOutputPath(FileIngestionMethod method, - const Hash & hash, std::string_view name, + StorePath makeFixedOutputPath( + FileIngestionMethod method, + const Hash & hash, + std::string_view name, const StorePathSet & references = {}, bool hasSelfReference = false) const; - StorePath makeTextPath(std::string_view name, const Hash & hash, - const StorePathSet & references = {}) const; + StorePath makeTextPath(std::string_view name, const Hash & hash, const StorePathSet & references = {}) const; - StorePath makeFixedOutputPathFromCA(std::string_view name, ContentAddress ca, + StorePath makeFixedOutputPathFromCA( + std::string_view name, + ContentAddress ca, const StorePathSet & references = {}, bool hasSelfReference = false) const; /* This is the preparatory part of addToStore(); it computes the store path to which srcPath is to be copied. Returns the store path and the cryptographic hash of the contents of srcPath. */ - std::pair computeStorePathForPath(std::string_view name, - const Path & srcPath, FileIngestionMethod method = FileIngestionMethod::Recursive, - HashType hashAlgo = htSHA256, PathFilter & filter = defaultPathFilter) const; + std::pair computeStorePathForPath( + std::string_view name, + const Path & srcPath, + FileIngestionMethod method = FileIngestionMethod::Recursive, + HashType hashAlgo = htSHA256, + PathFilter & filter = defaultPathFilter) const; /* Preparatory part of addTextToStore(). @@ -237,10 +240,7 @@ public: simply yield a different store path, so other users wouldn't be affected), but it has some backwards compatibility issues (the hashing scheme changes), so I'm not doing that for now. */ - StorePath computeStorePathForText( - std::string_view name, - std::string_view s, - const StorePathSet & references) const; + StorePath computeStorePathForText(std::string_view name, std::string_view s, const StorePathSet & references) const; /* Check whether a path is valid. */ bool isValidPath(const StorePath & path); @@ -258,8 +258,7 @@ public: /* Query which of the given paths is valid. Optionally, try to substitute missing paths. */ - virtual StorePathSet queryValidPaths(const StorePathSet & paths, - SubstituteFlag maybeSubstitute = NoSubstitute); + virtual StorePathSet queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubstitute = NoSubstitute); /* Query the set of all valid paths. Note that for some store backends, the name part of store paths may be replaced by 'x' @@ -268,7 +267,9 @@ public: full store path. FIXME: should return a set of std::variant to get rid of this hack. */ virtual StorePathSet queryAllValidPaths() - { unsupported("queryAllValidPaths"); } + { + unsupported("queryAllValidPaths"); + } constexpr static const char * MissingName = "x"; @@ -277,16 +278,13 @@ public: ref queryPathInfo(const StorePath & path); /* Asynchronous version of queryPathInfo(). */ - void queryPathInfo(const StorePath & path, - Callback> callback) noexcept; + void queryPathInfo(const StorePath & path, Callback> callback) noexcept; /* Query the information about a realisation. */ std::shared_ptr queryRealisation(const DrvOutput &); /* Asynchronous version of queryRealisation(). */ - void queryRealisation(const DrvOutput &, - Callback> callback) noexcept; - + void queryRealisation(const DrvOutput &, Callback> callback) noexcept; /* Check whether the given valid path info is sufficiently attested, by either being signed by a trusted public key or content-addressed, in @@ -303,30 +301,35 @@ public: return true; } - virtual bool realisationIsUntrusted(const Realisation & ) + virtual bool realisationIsUntrusted(const Realisation &) { return true; } protected: - virtual void queryPathInfoUncached(const StorePath & path, - Callback> callback) noexcept = 0; - virtual void queryRealisationUncached(const DrvOutput &, - Callback> callback) noexcept = 0; + virtual void + queryPathInfoUncached(const StorePath & path, Callback> callback) noexcept = 0; + virtual void + queryRealisationUncached(const DrvOutput &, Callback> callback) noexcept = 0; public: /* Queries the set of incoming FS references for a store path. The result is not cleared. */ virtual void queryReferrers(const StorePath & path, StorePathSet & referrers) - { unsupported("queryReferrers"); } + { + unsupported("queryReferrers"); + } /* Return all currently valid derivations that have `path' as an output. (Note that the result of `queryDeriver()' is the derivation that was actually used to produce `path', which may not exist anymore.) */ - virtual StorePathSet queryValidDerivers(const StorePath & path) { return {}; }; + virtual StorePathSet queryValidDerivers(const StorePath & path) + { + return {}; + }; /* Query the outputs of the derivation denoted by `path'. */ virtual StorePathSet queryDerivationOutputs(const StorePath & path); @@ -345,25 +348,30 @@ public: virtual std::optional queryPathFromHashPart(const std::string & hashPart) = 0; /* Query which of the given paths have substitutes. */ - virtual StorePathSet querySubstitutablePaths(const StorePathSet & paths) { return {}; }; + virtual StorePathSet querySubstitutablePaths(const StorePathSet & paths) + { + return {}; + }; /* Query substitute info (i.e. references, derivers and download sizes) of a map of paths to their optional ca values. The info of the first succeeding substituter for each path will be returned. If a path does not have substitute info, it's omitted from the resulting ‘infos’ map. */ - virtual void querySubstitutablePathInfos(const StorePathCAMap & paths, - SubstitutablePathInfos & infos) { return; }; + virtual void querySubstitutablePathInfos(const StorePathCAMap & paths, SubstitutablePathInfos & infos) + { + return; + }; /* Import a path into the store. */ - virtual void addToStore(const ValidPathInfo & info, Source & narSource, - RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs) = 0; + virtual void addToStore( + const ValidPathInfo & info, + Source & narSource, + RepairFlag repair = NoRepair, + CheckSigsFlag checkSigs = CheckSigs) = 0; /* Import multiple paths into the store. */ - virtual void addMultipleToStore( - Source & source, - RepairFlag repair = NoRepair, - CheckSigsFlag checkSigs = CheckSigs); + virtual void addMultipleToStore(Source & source, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs); /* Copy the contents of a path to the store and register the validity the resulting path. The resulting path is returned. @@ -381,8 +389,11 @@ public: /* Copy the contents of a path to the store and register the validity the resulting path, using a constant amount of memory. */ - ValidPathInfo addToStoreSlow(std::string_view name, const Path & srcPath, - FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, + ValidPathInfo addToStoreSlow( + std::string_view name, + const Path & srcPath, + FileIngestionMethod method = FileIngestionMethod::Recursive, + HashType hashAlgo = htSHA256, std::optional expectedCAHash = {}); /* Like addToStore(), but the contents of the path are contained @@ -391,18 +402,21 @@ public: false). `dump` may be drained */ // FIXME: remove? - virtual StorePath addToStoreFromDump(Source & dump, std::string_view name, - FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair, + virtual StorePath addToStoreFromDump( + Source & dump, + std::string_view name, + FileIngestionMethod method = FileIngestionMethod::Recursive, + HashType hashAlgo = htSHA256, + RepairFlag repair = NoRepair, const StorePathSet & references = StorePathSet()) - { unsupported("addToStoreFromDump"); } + { + unsupported("addToStoreFromDump"); + } /* Like addToStore, but the contents written to the output path is a regular file containing the given string. */ virtual StorePath addTextToStore( - std::string_view name, - std::string_view s, - const StorePathSet & references, - RepairFlag repair = NoRepair) = 0; + std::string_view name, std::string_view s, const StorePathSet & references, RepairFlag repair = NoRepair) = 0; /** * Add a mapping indicating that `deriver!outputName` maps to the output path @@ -414,9 +428,13 @@ public: * retrieve this information otherwise. */ virtual void registerDrvOutput(const Realisation & output) - { unsupported("registerDrvOutput"); } + { + unsupported("registerDrvOutput"); + } virtual void registerDrvOutput(const Realisation & output, CheckSigsFlag checkSigs) - { return registerDrvOutput(output); } + { + return registerDrvOutput(output); + } /* Write a NAR dump of a store path. */ virtual void narFromPath(const StorePath & path, Sink & sink) = 0; @@ -477,8 +495,8 @@ public: up with multiple different versions of dependencies without explicitly choosing to allow it). */ - virtual BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, - BuildMode buildMode = bmNormal); + virtual BuildResult + buildDerivation(const StorePath & drvPath, const BasicDerivation & drv, BuildMode buildMode = bmNormal); /* Ensure that a path is valid. If it is not currently valid, it may be made valid by running a substitute (if defined for the @@ -488,21 +506,25 @@ public: /* Add a store path as a temporary root of the garbage collector. The root disappears as soon as we exit. */ virtual void addTempRoot(const StorePath & path) - { debug("not creating temporary root, store doesn't support GC"); } + { + debug("not creating temporary root, store doesn't support GC"); + } /* Return a string representing information about the path that can be loaded into the database using `nix-store --load-db' or `nix-store --register-validity'. */ - std::string makeValidityRegistration(const StorePathSet & paths, - bool showDerivers, bool showHash); + std::string makeValidityRegistration(const StorePathSet & paths, bool showDerivers, bool showHash); /* Write a JSON representation of store path metadata, such as the hash and the references. If ‘includeImpureInfo’ is true, variable elements such as the registration time are included. If ‘showClosureSize’ is true, the closure size of each path is included. */ - void pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths, - bool includeImpureInfo, bool showClosureSize, + void pathInfoToJSON( + JSONPlaceholder & jsonOut, + const StorePathSet & storePaths, + bool includeImpureInfo, + bool showClosureSize, Base hashBase = Base32, AllowInvalidFlag allowInvalid = DisallowInvalid); @@ -513,25 +535,34 @@ public: /* Optimise the disk space usage of the Nix store by hard-linking files with the same contents. */ - virtual void optimiseStore() { }; + virtual void optimiseStore(){}; /* Check the integrity of the Nix store. Returns true if errors remain. */ - virtual bool verifyStore(bool checkContents, RepairFlag repair = NoRepair) { return false; }; + virtual bool verifyStore(bool checkContents, RepairFlag repair = NoRepair) + { + return false; + }; /* Return an object to access files in the Nix store. */ virtual ref getFSAccessor() - { unsupported("getFSAccessor"); } + { + unsupported("getFSAccessor"); + } /* Repair the contents of the given path by redownloading it using a substituter (if available). */ virtual void repairPath(const StorePath & path) - { unsupported("repairPath"); } + { + unsupported("repairPath"); + } /* Add signatures to the specified store path. The signatures are not verified. */ virtual void addSignatures(const StorePath & storePath, const StringSet & sigs) - { unsupported("addSignatures"); } + { + unsupported("addSignatures"); + } /* Utility functions. */ @@ -552,20 +583,30 @@ public: `storePath' is returned; that is, the closures under the `referrers' relation instead of the `references' relation is returned. */ - virtual void computeFSClosure(const StorePathSet & paths, - StorePathSet & out, bool flipDirection = false, - bool includeOutputs = false, bool includeDerivers = false); - - void computeFSClosure(const StorePath & path, - StorePathSet & out, bool flipDirection = false, - bool includeOutputs = false, bool includeDerivers = false); + virtual void computeFSClosure( + const StorePathSet & paths, + StorePathSet & out, + bool flipDirection = false, + bool includeOutputs = false, + bool includeDerivers = false); + + void computeFSClosure( + const StorePath & path, + StorePathSet & out, + bool flipDirection = false, + bool includeOutputs = false, + bool includeDerivers = false); /* Given a set of paths that are to be built, return the set of derivations that will be built, and the set of output paths that will be substituted. */ - virtual void queryMissing(const std::vector & targets, - StorePathSet & willBuild, StorePathSet & willSubstitute, StorePathSet & unknown, - uint64_t & downloadSize, uint64_t & narSize); + virtual void queryMissing( + const std::vector & targets, + StorePathSet & willBuild, + StorePathSet & willSubstitute, + StorePathSet & unknown, + uint64_t & downloadSize, + uint64_t & narSize); /* Sort a set of paths topologically under the references relation. If p refers to q, then p precedes q in this list. */ @@ -616,7 +657,7 @@ public: /* Establish a connection to the store, for store types that have a notion of connection. Otherwise this is a no-op. */ - virtual void connect() { }; + virtual void connect(){}; /* Get the protocol version of this store or it's connection. */ virtual unsigned int getProtocol() @@ -634,16 +675,18 @@ public: return toRealPath(printStorePath(storePath)); } - virtual void createUser(const std::string & userName, uid_t userId) - { } + virtual void createUser(const std::string & userName, uid_t userId) {} /* * Synchronises the options of the client with those of the daemon * (a no-op when there’s no daemon) */ - virtual void setOptions() { } + virtual void setOptions() {} - virtual std::optional getVersion() { return {}; } + virtual std::optional getVersion() + { + return {}; + } protected: @@ -654,10 +697,8 @@ protected: { throw Unsupported("operation '%s' is not supported by store '%s'", op, getUri()); } - }; - /* Copy a path from one store to another. */ void copyStorePath( Store & srcStore, @@ -666,7 +707,6 @@ void copyStorePath( RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs); - /* Copy store paths from one store to another. The paths may be copied in parallel. They are copied in a topologically sorted order (i.e. if A is a reference of B, then A is copied before B), but the set @@ -674,14 +714,16 @@ void copyStorePath( that. Returns a map of what each path was copied to the dstStore as. */ std::map copyPaths( - Store & srcStore, Store & dstStore, + Store & srcStore, + Store & dstStore, const RealisedPath::Set &, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs, SubstituteFlag substitute = NoSubstitute); std::map copyPaths( - Store & srcStore, Store & dstStore, + Store & srcStore, + Store & dstStore, const StorePathSet & paths, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs, @@ -689,14 +731,16 @@ std::map copyPaths( /* Copy the closure of `paths` from `srcStore` to `dstStore`. */ void copyClosure( - Store & srcStore, Store & dstStore, + Store & srcStore, + Store & dstStore, const RealisedPath::Set & paths, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs, SubstituteFlag substitute = NoSubstitute); void copyClosure( - Store & srcStore, Store & dstStore, + Store & srcStore, + Store & dstStore, const StorePathSet & paths, RepairFlag repair = NoRepair, CheckSigsFlag checkSigs = CheckSigs, @@ -707,7 +751,6 @@ void copyClosure( as a (permanent) root. */ void removeTempRoots(); - /* Return a Store object to access the Nix store denoted by ‘uri’ (slight misnomer...). Supported values are: @@ -737,9 +780,8 @@ void removeTempRoots(); You can pass parameters to the store implementation by appending ‘?key=value&key=value&...’ to the URI. */ -ref openStore(const std::string & uri = settings.storeUri.get(), - const Store::Params & extraParams = Store::Params()); - +ref +openStore(const std::string & uri = settings.storeUri.get(), const Store::Params & extraParams = Store::Params()); /* Return the default substituter stores, defined by the ‘substituters’ option and various legacy options. */ @@ -748,8 +790,10 @@ std::list> getDefaultSubstituters(); struct StoreFactory { std::set uriSchemes; - std::function (const std::string & scheme, const std::string & uri, const Store::Params & params)> create; - std::function ()> getConfig; + std::function( + const std::string & scheme, const std::string & uri, const Store::Params & params)> + create; + std::function()> getConfig; }; struct Implementations @@ -759,18 +803,14 @@ struct Implementations template static void add() { - if (!registered) registered = new std::vector(); + if (!registered) + registered = new std::vector(); StoreFactory factory{ .uriSchemes = T::uriSchemes(), .create = ([](const std::string & scheme, const std::string & uri, const Store::Params & params) - -> std::shared_ptr - { return std::make_shared(scheme, uri, params); }), - .getConfig = - ([]() - -> std::shared_ptr - { return std::make_shared(StringMap({})); }) - }; + -> std::shared_ptr { return std::make_shared(scheme, uri, params); }), + .getConfig = ([]() -> std::shared_ptr { return std::make_shared(StringMap({})); })}; registered->push_back(factory); } }; @@ -784,25 +824,18 @@ struct RegisterStoreImplementation } }; - /* Display a set of paths in human-readable form (i.e., between quotes and separated by commas). */ std::string showPaths(const PathSet & paths); - -std::optional decodeValidPathInfo( - const Store & store, - std::istream & str, - std::optional hashGiven = std::nullopt); +std::optional +decodeValidPathInfo(const Store & store, std::istream & str, std::optional hashGiven = std::nullopt); /* Split URI into protocol+hierarchy part and its parameter set. */ std::pair splitUriAndParams(const std::string & uri); std::optional getDerivationCA(const BasicDerivation & drv); -std::map drvOutputReferences( - Store & store, - const Derivation & drv, - const StorePath & outputPath); +std::map drvOutputReferences(Store & store, const Derivation & drv, const StorePath & outputPath); } diff --git a/src/libstore/tests/machines.cc b/src/libstore/tests/machines.cc index f51052b14626..7d62ea8e9dbd 100644 --- a/src/libstore/tests/machines.cc +++ b/src/libstore/tests/machines.cc @@ -19,21 +19,26 @@ using nix::pathExists; using nix::Settings; using nix::settings; -class Environment : public ::testing::Environment { - public: - void SetUp() override { settings.thisSystem = "TEST_ARCH-TEST_OS"; } +class Environment : public ::testing::Environment +{ +public: + void SetUp() override + { + settings.thisSystem = "TEST_ARCH-TEST_OS"; + } }; -testing::Environment* const foo_env = - testing::AddGlobalTestEnvironment(new Environment); +testing::Environment * const foo_env = testing::AddGlobalTestEnvironment(new Environment); -TEST(machines, getMachinesWithEmptyBuilders) { +TEST(machines, getMachinesWithEmptyBuilders) +{ settings.builders = ""; Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(0)); } -TEST(machines, getMachinesUriOnly) { +TEST(machines, getMachinesUriOnly) +{ settings.builders = "nix@scratchy.labs.cs.uu.nl"; Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(1)); @@ -47,7 +52,8 @@ TEST(machines, getMachinesUriOnly) { EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, SizeIs(0))); } -TEST(machines, getMachinesDefaults) { +TEST(machines, getMachinesDefaults) +{ settings.builders = "nix@scratchy.labs.cs.uu.nl - - - - - - -"; Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(1)); @@ -61,7 +67,8 @@ TEST(machines, getMachinesDefaults) { EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, SizeIs(0))); } -TEST(machines, getMachinesWithNewLineSeparator) { +TEST(machines, getMachinesWithNewLineSeparator) +{ settings.builders = "nix@scratchy.labs.cs.uu.nl\nnix@itchy.labs.cs.uu.nl"; Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(2)); @@ -69,7 +76,8 @@ TEST(machines, getMachinesWithNewLineSeparator) { EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@itchy.labs.cs.uu.nl")))); } -TEST(machines, getMachinesWithSemicolonSeparator) { +TEST(machines, getMachinesWithSemicolonSeparator) +{ settings.builders = "nix@scratchy.labs.cs.uu.nl ; nix@itchy.labs.cs.uu.nl"; Machines actual = getMachines(); EXPECT_THAT(actual, SizeIs(2)); @@ -77,10 +85,12 @@ TEST(machines, getMachinesWithSemicolonSeparator) { EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@itchy.labs.cs.uu.nl")))); } -TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) { - settings.builders = "nix@scratchy.labs.cs.uu.nl i686-linux " - "/home/nix/.ssh/id_scratchy_auto 8 3 kvm " - "benchmark SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="; +TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) +{ + settings.builders = + "nix@scratchy.labs.cs.uu.nl i686-linux " + "/home/nix/.ssh/id_scratchy_auto 8 3 kvm " + "benchmark SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="; Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(1)); EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl"))); @@ -93,8 +103,8 @@ TEST(machines, getMachinesWithCorrectCompleteSingleBuilder) { EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, Eq("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); } -TEST(machines, - getMachinesWithCorrectCompleteSingleBuilderWithTabColumnDelimiter) { +TEST(machines, getMachinesWithCorrectCompleteSingleBuilderWithTabColumnDelimiter) +{ settings.builders = "nix@scratchy.labs.cs.uu.nl\ti686-linux\t/home/nix/.ssh/" "id_scratchy_auto\t8\t3\tkvm\tbenchmark\tSSH+HOST+PUBLIC+" @@ -111,10 +121,12 @@ TEST(machines, EXPECT_THAT(actual[0], Field(&Machine::sshPublicHostKey, Eq("SSH+HOST+PUBLIC+KEY+BASE64+ENCODED=="))); } -TEST(machines, getMachinesWithMultiOptions) { - settings.builders = "nix@scratchy.labs.cs.uu.nl Arch1,Arch2 - - - " - "SupportedFeature1,SupportedFeature2 " - "MandatoryFeature1,MandatoryFeature2"; +TEST(machines, getMachinesWithMultiOptions) +{ + settings.builders = + "nix@scratchy.labs.cs.uu.nl Arch1,Arch2 - - - " + "SupportedFeature1,SupportedFeature2 " + "MandatoryFeature1,MandatoryFeature2"; Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(1)); EXPECT_THAT(actual[0], Field(&Machine::storeUri, EndsWith("nix@scratchy.labs.cs.uu.nl"))); @@ -123,7 +135,8 @@ TEST(machines, getMachinesWithMultiOptions) { EXPECT_THAT(actual[0], Field(&Machine::mandatoryFeatures, ElementsAre("MandatoryFeature1", "MandatoryFeature2"))); } -TEST(machines, getMachinesWithIncorrectFormat) { +TEST(machines, getMachinesWithIncorrectFormat) +{ settings.builders = "nix@scratchy.labs.cs.uu.nl - - eight"; EXPECT_THROW(getMachines(), FormatError); settings.builders = "nix@scratchy.labs.cs.uu.nl - - -1"; @@ -136,7 +149,8 @@ TEST(machines, getMachinesWithIncorrectFormat) { EXPECT_THROW(getMachines(), FormatError); } -TEST(machines, getMachinesWithCorrectFileReference) { +TEST(machines, getMachinesWithCorrectFileReference) +{ auto path = absPath("src/libstore/tests/test-data/machines.valid"); ASSERT_TRUE(pathExists(path)); @@ -148,7 +162,8 @@ TEST(machines, getMachinesWithCorrectFileReference) { EXPECT_THAT(actual, Contains(Field(&Machine::storeUri, EndsWith("nix@poochie.labs.cs.uu.nl")))); } -TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) { +TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) +{ auto path = "/dev/null"; ASSERT_TRUE(pathExists(path)); @@ -157,13 +172,15 @@ TEST(machines, getMachinesWithCorrectFileReferenceToEmptyFile) { ASSERT_THAT(actual, SizeIs(0)); } -TEST(machines, getMachinesWithIncorrectFileReference) { +TEST(machines, getMachinesWithIncorrectFileReference) +{ settings.builders = std::string("@") + absPath("/not/a/file"); Machines actual = getMachines(); ASSERT_THAT(actual, SizeIs(0)); } -TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) { +TEST(machines, getMachinesWithCorrectFileReferenceToIncorrectFile) +{ settings.builders = std::string("@") + absPath("src/libstore/tests/test-data/machines.bad_format"); EXPECT_THROW(getMachines(), FormatError); } diff --git a/src/libstore/uds-remote-store.cc b/src/libstore/uds-remote-store.cc index 5c38323cd337..5eac0da2bac6 100644 --- a/src/libstore/uds-remote-store.cc +++ b/src/libstore/uds-remote-store.cc @@ -10,7 +10,6 @@ #include - namespace nix { UDSRemoteStore::UDSRemoteStore(const Params & params) @@ -21,20 +20,14 @@ UDSRemoteStore::UDSRemoteStore(const Params & params) , Store(params) , LocalFSStore(params) , RemoteStore(params) -{ -} - +{} -UDSRemoteStore::UDSRemoteStore( - const std::string scheme, - std::string socket_path, - const Params & params) +UDSRemoteStore::UDSRemoteStore(const std::string scheme, std::string socket_path, const Params & params) : UDSRemoteStore(params) { path.emplace(socket_path); } - std::string UDSRemoteStore::getUri() { if (path) { @@ -44,13 +37,11 @@ std::string UDSRemoteStore::getUri() } } - void UDSRemoteStore::Connection::closeWrite() { shutdown(fd.get(), SHUT_WR); } - ref UDSRemoteStore::openConnection() { auto conn = make_ref(); @@ -68,7 +59,6 @@ ref UDSRemoteStore::openConnection() return conn; } - static RegisterStoreImplementation regUDSRemoteStore; } diff --git a/src/libstore/uds-remote-store.hh b/src/libstore/uds-remote-store.hh index f8dfcca704a0..c1a06c3cc226 100644 --- a/src/libstore/uds-remote-store.hh +++ b/src/libstore/uds-remote-store.hh @@ -11,10 +11,12 @@ struct UDSRemoteStoreConfig : virtual LocalFSStoreConfig, virtual RemoteStoreCon : StoreConfig(params) , LocalFSStoreConfig(params) , RemoteStoreConfig(params) + {} + + const std::string name() override { + return "Local Daemon Store"; } - - const std::string name() override { return "Local Daemon Store"; } }; class UDSRemoteStore : public virtual UDSRemoteStoreConfig, public virtual LocalFSStore, public virtual RemoteStore @@ -27,16 +29,24 @@ public: std::string getUri() override; static std::set uriSchemes() - { return {"unix"}; } + { + return {"unix"}; + } bool sameMachine() override - { return true; } + { + return true; + } ref getFSAccessor() override - { return LocalFSStore::getFSAccessor(); } + { + return LocalFSStore::getFSAccessor(); + } void narFromPath(const StorePath & path, Sink & sink) override - { LocalFSStore::narFromPath(path, sink); } + { + LocalFSStore::narFromPath(path, sink); + } private: diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh index 87088a3ac105..34d845d5e54f 100644 --- a/src/libstore/worker-protocol.hh +++ b/src/libstore/worker-protocol.hh @@ -5,19 +5,17 @@ namespace nix { - #define WORKER_MAGIC_1 0x6e697863 #define WORKER_MAGIC_2 0x6478696f #define PROTOCOL_VERSION (1 << 8 | 34) -#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00) -#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff) - +#define GET_PROTOCOL_MAJOR(x) ((x) &0xff00) +#define GET_PROTOCOL_MINOR(x) ((x) &0x00ff) typedef enum { wopIsValidPath = 1, wopHasSubstitutes = 3, - wopQueryPathHash = 4, // obsolete + wopQueryPathHash = 4, // obsolete wopQueryReferences = 5, // obsolete wopQueryReferrers = 6, wopAddToStore = 7, @@ -28,7 +26,7 @@ typedef enum { wopAddIndirectRoot = 12, wopSyncWithGC = 13, wopFindRoots = 14, - wopExportPath = 16, // obsolete + wopExportPath = 16, // obsolete wopQueryDeriver = 18, // obsolete wopSetOptions = 19, wopCollectGarbage = 20, @@ -38,7 +36,7 @@ typedef enum { wopQueryFailedPaths = 24, wopClearFailedPaths = 25, wopQueryPathInfo = 26, - wopImportPaths = 27, // obsolete + wopImportPaths = 27, // obsolete wopQueryDerivationOutputNames = 28, // obsolete wopQueryPathFromHashPart = 29, wopQuerySubstitutablePathInfos = 30, @@ -60,30 +58,28 @@ typedef enum { wopBuildPathsWithResults = 46, } WorkerOp; - -#define STDERR_NEXT 0x6f6c6d67 -#define STDERR_READ 0x64617461 // data needed from source +#define STDERR_NEXT 0x6f6c6d67 +#define STDERR_READ 0x64617461 // data needed from source #define STDERR_WRITE 0x64617416 // data for sink -#define STDERR_LAST 0x616c7473 +#define STDERR_LAST 0x616c7473 #define STDERR_ERROR 0x63787470 #define STDERR_START_ACTIVITY 0x53545254 -#define STDERR_STOP_ACTIVITY 0x53544f50 -#define STDERR_RESULT 0x52534c54 - +#define STDERR_STOP_ACTIVITY 0x53544f50 +#define STDERR_RESULT 0x52534c54 class Store; struct Source; /* To guide overloading */ template -struct Phantom {}; - +struct Phantom +{}; namespace worker_proto { /* FIXME maybe move more stuff inside here */ #define MAKE_WORKER_PROTO(TEMPLATE, T) \ - TEMPLATE T read(const Store & store, Source & from, Phantom< T > _); \ + TEMPLATE T read(const Store & store, Source & from, Phantom _); \ TEMPLATE void write(const Store & store, Sink & out, const T & str) MAKE_WORKER_PROTO(, std::string); @@ -125,7 +121,7 @@ std::vector read(const Store & store, Source & from, Phantom> std::vector resSet; auto size = readNum(from); while (size--) { - resSet.push_back(read(store, from, Phantom {})); + resSet.push_back(read(store, from, Phantom{})); } return resSet; } @@ -145,7 +141,7 @@ std::set read(const Store & store, Source & from, Phantom> _) std::set resSet; auto size = readNum(from); while (size--) { - resSet.insert(read(store, from, Phantom {})); + resSet.insert(read(store, from, Phantom{})); } return resSet; } @@ -165,8 +161,8 @@ std::map read(const Store & store, Source & from, Phantom> std::map resMap; auto size = readNum(from); while (size--) { - auto k = read(store, from, Phantom {}); - auto v = read(store, from, Phantom {}); + auto k = read(store, from, Phantom{}); + auto v = read(store, from, Phantom{}); resMap.insert_or_assign(std::move(k), std::move(v)); } return resMap; diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc index 30b471af546c..6fc551154e34 100644 --- a/src/libutil/archive.cc +++ b/src/libutil/archive.cc @@ -19,16 +19,18 @@ namespace nix { struct ArchiveSettings : Config { - Setting useCaseHack{this, - #if __APPLE__ + Setting useCaseHack + { + this, +#if __APPLE__ true, - #else +#else false, - #endif - "use-case-hack", - "Whether to enable a Darwin-specific hack for dealing with file name collisions."}; - Setting preallocateContents{this, false, "preallocate-contents", - "Whether to preallocate files when writing objects with known size."}; +#endif + "use-case-hack", "Whether to enable a Darwin-specific hack for dealing with file name collisions." + }; + Setting preallocateContents{ + this, false, "preallocate-contents", "Whether to preallocate files when writing objects with known size."}; }; static ArchiveSettings archiveSettings; @@ -41,14 +43,13 @@ static std::string caseHackSuffix = "~nix~case~hack~"; PathFilter defaultPathFilter = [](const Path &) { return true; }; - -static void dumpContents(const Path & path, off_t size, - Sink & sink) +static void dumpContents(const Path & path, off_t size, Sink & sink) { sink << "contents" << size; AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); - if (!fd) throw SysError("opening file '%1%'", path); + if (!fd) + throw SysError("opening file '%1%'", path); std::vector buf(65536); size_t left = size; @@ -63,7 +64,6 @@ static void dumpContents(const Path & path, off_t size, writePadding(size, sink); } - static time_t dump(const Path & path, Sink & sink, PathFilter & filter) { checkInterrupt(); @@ -74,14 +74,17 @@ static time_t dump(const Path & path, Sink & sink, PathFilter & filter) sink << "("; if (S_ISREG(st.st_mode)) { - sink << "type" << "regular"; + sink << "type" + << "regular"; if (st.st_mode & S_IXUSR) - sink << "executable" << ""; + sink << "executable" + << ""; dumpContents(path, st.st_size, sink); } else if (S_ISDIR(st.st_mode)) { - sink << "type" << "directory"; + sink << "type" + << "directory"; /* If we're on a case-insensitive system like macOS, undo the case hack applied by restorePath(). */ @@ -95,15 +98,17 @@ static time_t dump(const Path & path, Sink & sink, PathFilter & filter) name.erase(pos); } if (!unhacked.emplace(name, i.name).second) - throw Error("file name collision in between '%1%' and '%2%'", - (path + "/" + unhacked[name]), - (path + "/" + i.name)); + throw Error( + "file name collision in between '%1%' and '%2%'", (path + "/" + unhacked[name]), + (path + "/" + i.name)); } else unhacked.emplace(i.name, i.name); for (auto & i : unhacked) if (filter(path + "/" + i.first)) { - sink << "entry" << "(" << "name" << i.first << "node"; + sink << "entry" + << "(" + << "name" << i.first << "node"; auto tmp_mtime = dump(path + "/" + i.second, sink, filter); if (tmp_mtime > result) { result = tmp_mtime; @@ -113,16 +118,18 @@ static time_t dump(const Path & path, Sink & sink, PathFilter & filter) } else if (S_ISLNK(st.st_mode)) - sink << "type" << "symlink" << "target" << readLink(path); + sink << "type" + << "symlink" + << "target" << readLink(path); - else throw Error("file '%1%' has an unsupported type", path); + else + throw Error("file '%1%' has an unsupported type", path); sink << ")"; return result; } - time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter) { sink << narVersionMagic1; @@ -134,19 +141,19 @@ void dumpPath(const Path & path, Sink & sink, PathFilter & filter) dumpPathAndGetMtime(path, sink, filter); } - void dumpString(std::string_view s, Sink & sink) { - sink << narVersionMagic1 << "(" << "type" << "regular" << "contents" << s << ")"; + sink << narVersionMagic1 << "(" + << "type" + << "regular" + << "contents" << s << ")"; } - static SerialisationError badArchive(const std::string & s) { return SerialisationError("bad archive: " + s); } - #if 0 static void skipGeneric(Source & source) { @@ -157,7 +164,6 @@ static void skipGeneric(Source & source) } #endif - static void parseContents(ParseSink & sink, Source & source, const Path & path) { uint64_t size = readLongLong(source); @@ -170,7 +176,8 @@ static void parseContents(ParseSink & sink, Source & source, const Path & path) while (left) { checkInterrupt(); auto n = buf.size(); - if ((uint64_t)n > left) n = left; + if ((uint64_t) n > left) + n = left; source(buf.data(), n); sink.receiveContents({buf.data(), n}); left -= n; @@ -179,22 +186,21 @@ static void parseContents(ParseSink & sink, Source & source, const Path & path) readPadding(size, source); } - struct CaseInsensitiveCompare { - bool operator() (const std::string & a, const std::string & b) const + bool operator()(const std::string & a, const std::string & b) const { return strcasecmp(a.c_str(), b.c_str()) < 0; } }; - static void parse(ParseSink & sink, Source & source, const Path & path) { std::string s; s = readString(source); - if (s != "(") throw badArchive("expected open tag"); + if (s != "(") + throw badArchive("expected open tag"); enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown; @@ -228,7 +234,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path) type = tpSymlink; } - else throw badArchive("unknown file type " + t); + else + throw badArchive("unknown file type " + t); } @@ -238,7 +245,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path) else if (s == "executable" && type == tpRegular) { auto s = readString(source); - if (s != "") throw badArchive("executable marker has non-empty value"); + if (s != "") + throw badArchive("executable marker has non-empty value"); sink.isExecutable(); } @@ -246,7 +254,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path) std::string name, prevName; s = readString(source); - if (s != "(") throw badArchive("expected open tag"); + if (s != "(") + throw badArchive("expected open tag"); while (1) { checkInterrupt(); @@ -257,7 +266,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path) break; } else if (s == "name") { name = readString(source); - if (name.empty() || name == "." || name == ".." || name.find('/') != std::string::npos || name.find((char) 0) != std::string::npos) + if (name.empty() || name == "." || name == ".." || name.find('/') != std::string::npos + || name.find((char) 0) != std::string::npos) throw Error("NAR contains invalid file name '%1%'", name); if (name <= prevName) throw Error("NAR directory is not sorted"); @@ -272,7 +282,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path) names[name] = 0; } } else if (s == "node") { - if (name.empty()) throw badArchive("entry name missing"); + if (name.empty()) + throw badArchive("entry name missing"); parse(sink, source, path + "/" + name); } else throw badArchive("unknown field " + s); @@ -289,7 +300,6 @@ static void parse(ParseSink & sink, Source & source, const Path & path) } } - void parseDump(ParseSink & sink, Source & source) { std::string version; @@ -304,7 +314,6 @@ void parseDump(ParseSink & sink, Source & source) parse(sink, source, ""); } - struct RestoreSink : ParseSink { Path dstPath; @@ -321,7 +330,8 @@ struct RestoreSink : ParseSink { Path p = dstPath + path; fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666); - if (!fd) throw SysError("creating file '%1%'", p); + if (!fd) + throw SysError("creating file '%1%'", p); } void isExecutable() override @@ -363,7 +373,6 @@ struct RestoreSink : ParseSink } }; - void restorePath(const Path & path, Source & source) { RestoreSink sink; @@ -371,7 +380,6 @@ void restorePath(const Path & path, Source & source) parseDump(sink, source); } - void copyNAR(Source & source, Sink & sink) { // FIXME: if 'source' is the output of dumpPath() followed by EOF, @@ -379,19 +387,15 @@ void copyNAR(Source & source, Sink & sink) ParseSink parseSink; /* null sink; just parse the NAR */ - TeeSource wrapper { source, sink }; + TeeSource wrapper{source, sink}; parseDump(parseSink, wrapper); } - void copyPath(const Path & from, const Path & to) { - auto source = sinkToSource([&](Sink & sink) { - dumpPath(from, sink); - }); + auto source = sinkToSource([&](Sink & sink) { dumpPath(from, sink); }); restorePath(to, *source); } - } diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh index 79ce08df0c4f..6123b9b55616 100644 --- a/src/libutil/archive.hh +++ b/src/libutil/archive.hh @@ -3,10 +3,8 @@ #include "types.hh" #include "serialise.hh" - namespace nix { - /* dumpPath creates a Nix archive of the specified path. The format is as follows: @@ -44,27 +42,24 @@ namespace nix { `+' denotes string concatenation. */ - -void dumpPath(const Path & path, Sink & sink, - PathFilter & filter = defaultPathFilter); +void dumpPath(const Path & path, Sink & sink, PathFilter & filter = defaultPathFilter); /* Same as `void dumpPath()`, but returns the last modified date of the path */ -time_t dumpPathAndGetMtime(const Path & path, Sink & sink, - PathFilter & filter = defaultPathFilter); +time_t dumpPathAndGetMtime(const Path & path, Sink & sink, PathFilter & filter = defaultPathFilter); void dumpString(std::string_view s, Sink & sink); /* FIXME: fix this API, it sucks. */ struct ParseSink { - virtual void createDirectory(const Path & path) { }; + virtual void createDirectory(const Path & path){}; - virtual void createRegularFile(const Path & path) { }; - virtual void isExecutable() { }; - virtual void preallocateContents(uint64_t size) { }; - virtual void receiveContents(std::string_view data) { }; + virtual void createRegularFile(const Path & path){}; + virtual void isExecutable(){}; + virtual void preallocateContents(uint64_t size){}; + virtual void receiveContents(std::string_view data){}; - virtual void createSymlink(const Path & path, const std::string & target) { }; + virtual void createSymlink(const Path & path, const std::string & target){}; }; /* If the NAR archive contains a single file at top-level, then save @@ -74,7 +69,9 @@ struct RetrieveRegularNARSink : ParseSink bool regular = true; Sink & sink; - RetrieveRegularNARSink(Sink & sink) : sink(sink) { } + RetrieveRegularNARSink(Sink & sink) + : sink(sink) + {} void createDirectory(const Path & path) override { @@ -101,8 +98,6 @@ void copyNAR(Source & source, Sink & sink); void copyPath(const Path & from, const Path & to); - extern const std::string narVersionMagic1; - } diff --git a/src/libutil/args.cc b/src/libutil/args.cc index 4b8c55686f51..6718d4eb50b1 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -16,28 +16,29 @@ void Args::addFlag(Flag && flag_) longFlags[flag->longName] = flag; for (auto & alias : flag->aliases) longFlags[alias] = flag; - if (flag->shortName) shortFlags[flag->shortName] = flag; + if (flag->shortName) + shortFlags[flag->shortName] = flag; } void Args::removeFlag(const std::string & longName) { auto flag = longFlags.find(longName); assert(flag != longFlags.end()); - if (flag->second->shortName) shortFlags.erase(flag->second->shortName); + if (flag->second->shortName) + shortFlags.erase(flag->second->shortName); longFlags.erase(flag); } void Completions::add(std::string completion, std::string description) { assert(description.find('\n') == std::string::npos); - insert(Completion { - .completion = completion, - .description = description - }); + insert(Completion{.completion = completion, .description = description}); } bool Completion::operator<(const Completion & other) const -{ return completion < other.completion || (completion == other.completion && description < other.description); } +{ + return completion < other.completion || (completion == other.completion && description < other.description); +} CompletionType completionType = ctNormal; std::shared_ptr completions; @@ -46,7 +47,8 @@ std::string completionMarker = "___COMPLETE___"; std::optional needsCompletion(std::string_view s) { - if (!completions) return {}; + if (!completions) + return {}; auto i = s.find(completionMarker); if (i != std::string::npos) return std::string(s.begin(), i); @@ -69,7 +71,7 @@ void Args::parseCmdline(const Strings & _cmdline) } bool argsSeen = false; - for (auto pos = cmdline.begin(); pos != cmdline.end(); ) { + for (auto pos = cmdline.begin(); pos != cmdline.end();) { auto arg = *pos; @@ -77,7 +79,8 @@ void Args::parseCmdline(const Strings & _cmdline) `-j3` -> `-j 3`). */ if (!dashDash && arg.length() > 2 && arg[0] == '-' && arg[1] != '-' && isalpha(arg[1])) { *pos = (std::string) "-" + arg[1]; - auto next = pos; ++next; + auto next = pos; + ++next; for (unsigned int j = 2; j < arg.length(); j++) if (isalpha(arg[j])) cmdline.insert(next, (std::string) "-" + arg[j]); @@ -91,12 +94,10 @@ void Args::parseCmdline(const Strings & _cmdline) if (!dashDash && arg == "--") { dashDash = true; ++pos; - } - else if (!dashDash && std::string(arg, 0, 1) == "-") { + } else if (!dashDash && std::string(arg, 0, 1) == "-") { if (!processFlag(pos, cmdline.end())) throw UsageError("unrecognised flag '%1%'", arg); - } - else { + } else { if (!argsSeen) { argsSeen = true; initialFlagsProcessed(); @@ -122,9 +123,10 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end) ++pos; std::vector args; bool anyCompleted = false; - for (size_t n = 0 ; n < flag.handler.arity; ++n) { + for (size_t n = 0; n < flag.handler.arity; ++n) { if (pos == end) { - if (flag.handler.arity == ArityAny) break; + if (flag.handler.arity == ArityAny) + break; throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity); } if (auto prefix = needsCompletion(*pos)) { @@ -142,21 +144,22 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end) if (std::string(*pos, 0, 2) == "--") { if (auto prefix = needsCompletion(*pos)) { for (auto & [name, flag] : longFlags) { - if (!hiddenCategories.count(flag->category) - && hasPrefix(name, std::string(*prefix, 2))) + if (!hiddenCategories.count(flag->category) && hasPrefix(name, std::string(*prefix, 2))) completions->add("--" + name, flag->description); } return false; } auto i = longFlags.find(std::string(*pos, 2)); - if (i == longFlags.end()) return false; + if (i == longFlags.end()) + return false; return process("--" + i->first, *i->second); } if (std::string(*pos, 0, 1) == "-" && pos->size() == 2) { auto c = (*pos)[1]; auto i = shortFlags.find(c); - if (i == shortFlags.end()) return false; + if (i == shortFlags.end()) + return false; return process(std::string("-") + c, *i->second); } @@ -183,11 +186,10 @@ bool Args::processArgs(const Strings & args, bool finish) bool res = false; - if ((exp.handler.arity == ArityAny && finish) || - (exp.handler.arity != ArityAny && args.size() == exp.handler.arity)) - { + if ((exp.handler.arity == ArityAny && finish) + || (exp.handler.arity != ArityAny && args.size() == exp.handler.arity)) { std::vector ss; - for (const auto &[n, s] : enumerate(args)) { + for (const auto & [n, s] : enumerate(args)) { if (auto prefix = needsCompletion(s)) { ss.push_back(*prefix); if (exp.completer) @@ -212,7 +214,8 @@ nlohmann::json Args::toJSON() for (auto & [name, flag] : longFlags) { auto j = nlohmann::json::object(); - if (flag->aliases.count(name)) continue; + if (flag->aliases.count(name)) + continue; if (flag->shortName) j["shortName"] = std::string(1, flag->shortName); if (flag->description != "") @@ -241,7 +244,8 @@ nlohmann::json Args::toJSON() res["flags"] = std::move(flags); res["args"] = std::move(args); auto s = doc(); - if (s != "") res.emplace("doc", stripIndentation(s)); + if (s != "") + res.emplace("doc", stripIndentation(s)); return res; } @@ -254,28 +258,23 @@ static void hashTypeCompleter(size_t index, std::string_view prefix) Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht) { - return Flag { + return Flag{ .longName = std::move(longName), .description = "hash algorithm ('md5', 'sha1', 'sha256', or 'sha512')", .labels = {"hash-algo"}, - .handler = {[ht](std::string s) { - *ht = parseHashType(s); - }}, - .completer = hashTypeCompleter - }; + .handler = {[ht](std::string s) { *ht = parseHashType(s); }}, + .completer = hashTypeCompleter}; } Args::Flag Args::Flag::mkHashTypeOptFlag(std::string && longName, std::optional * oht) { - return Flag { + return Flag{ .longName = std::move(longName), - .description = "hash algorithm ('md5', 'sha1', 'sha256', or 'sha512'). Optional as can also be gotten from SRI hash itself.", + .description = + "hash algorithm ('md5', 'sha1', 'sha256', or 'sha512'). Optional as can also be gotten from SRI hash itself.", .labels = {"hash-algo"}, - .handler = {[oht](std::string s) { - *oht = std::optional { parseHashType(s) }; - }}, - .completer = hashTypeCompleter - }; + .handler = {[oht](std::string s) { *oht = std::optional{parseHashType(s)}; }}, + .completer = hashTypeCompleter}; } static void _completePath(std::string_view prefix, bool onlyDirs) @@ -283,16 +282,17 @@ static void _completePath(std::string_view prefix, bool onlyDirs) completionType = ctFilenames; glob_t globbuf; int flags = GLOB_NOESCAPE; - #ifdef GLOB_ONLYDIR +#ifdef GLOB_ONLYDIR if (onlyDirs) flags |= GLOB_ONLYDIR; - #endif +#endif // using expandTilde here instead of GLOB_TILDE(_CHECK) so that ~ expands to /home/user/ if (glob((expandTilde(prefix) + "*").c_str(), flags, nullptr, &globbuf) == 0) { for (size_t i = 0; i < globbuf.gl_pathc; ++i) { if (onlyDirs) { auto st = stat(globbuf.gl_pathv[i]); - if (!S_ISDIR(st.st_mode)) continue; + if (!S_ISDIR(st.st_mode)) + continue; } completions->add(globbuf.gl_pathv[i]); } @@ -310,47 +310,50 @@ void completeDir(size_t, std::string_view prefix) _completePath(prefix, true); } -Strings argvToStrings(int argc, char * * argv) +Strings argvToStrings(int argc, char ** argv) { Strings args; - argc--; argv++; - while (argc--) args.push_back(*argv++); + argc--; + argv++; + while (argc--) + args.push_back(*argv++); return args; } MultiCommand::MultiCommand(const Commands & commands_) : commands(commands_) { - expectArgs({ - .label = "subcommand", - .optional = true, - .handler = {[=](std::string s) { - assert(!command); - auto i = commands.find(s); - if (i == commands.end()) { - std::set commandNames; - for (auto & [name, _] : commands) - commandNames.insert(name); - auto suggestions = Suggestions::bestMatches(commandNames, s); - throw UsageError(suggestions, "'%s' is not a recognised command", s); - } - command = {s, i->second()}; - command->second->parent = this; - }}, - .completer = {[&](size_t, std::string_view prefix) { - for (auto & [name, command] : commands) - if (hasPrefix(name, prefix)) - completions->add(name); - }} - }); + expectArgs( + {.label = "subcommand", + .optional = true, + .handler = {[=](std::string s) { + assert(!command); + auto i = commands.find(s); + if (i == commands.end()) { + std::set commandNames; + for (auto & [name, _] : commands) + commandNames.insert(name); + auto suggestions = Suggestions::bestMatches(commandNames, s); + throw UsageError(suggestions, "'%s' is not a recognised command", s); + } + command = {s, i->second()}; + command->second->parent = this; + }}, + .completer = {[&](size_t, std::string_view prefix) { + for (auto & [name, command] : commands) + if (hasPrefix(name, prefix)) + completions->add(name); + }}}); categories[Command::catDefault] = "Available commands"; } bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end) { - if (Args::processFlag(pos, end)) return true; - if (command && command->second->processFlag(pos, end)) return true; + if (Args::processFlag(pos, end)) + return true; + if (command && command->second->processFlag(pos, end)) + return true; return false; } diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 07c017719e95..aec018c75740 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -23,12 +23,21 @@ public: void parseCmdline(const Strings & cmdline); /* Return a short one-line description of the command. */ - virtual std::string description() { return ""; } + virtual std::string description() + { + return ""; + } - virtual bool forceImpureByDefault() { return false; } + virtual bool forceImpureByDefault() + { + return false; + } /* Return documentation about this command, in Markdown format. */ - virtual std::string doc() { return ""; } + virtual std::string doc() + { + return ""; + } protected: @@ -44,63 +53,57 @@ protected: Handler(std::function)> && fun) : fun(std::move(fun)) , arity(ArityAny) - { } + {} Handler(std::function && handler) : fun([handler{std::move(handler)}](std::vector) { handler(); }) , arity(0) - { } + {} Handler(std::function && handler) - : fun([handler{std::move(handler)}](std::vector ss) { - handler(std::move(ss[0])); - }) + : fun([handler{std::move(handler)}](std::vector ss) { handler(std::move(ss[0])); }) , arity(1) - { } + {} Handler(std::function && handler) : fun([handler{std::move(handler)}](std::vector ss) { handler(std::move(ss[0]), std::move(ss[1])); - }) + }) , arity(2) - { } + {} Handler(std::vector * dest) : fun([=](std::vector ss) { *dest = ss; }) , arity(ArityAny) - { } + {} Handler(std::string * dest) : fun([=](std::vector ss) { *dest = ss[0]; }) , arity(1) - { } + {} Handler(std::optional * dest) : fun([=](std::vector ss) { *dest = ss[0]; }) , arity(1) - { } + {} template Handler(T * dest, const T & val) : fun([=](std::vector ss) { *dest = val; }) , arity(0) - { } + {} template Handler(I * dest) - : fun([=](std::vector ss) { - *dest = string2IntWithUnitPrefix(ss[0]); - }) + : fun([=](std::vector ss) { *dest = string2IntWithUnitPrefix(ss[0]); }) , arity(1) - { } + {} template Handler(std::optional * dest) - : fun([=](std::vector ss) { - *dest = string2IntWithUnitPrefix(ss[0]); - }) + : fun([=](std::vector ss) { *dest = string2IntWithUnitPrefix(ss[0]); }) , arity(1) - { } + {} }; /* Options. */ @@ -140,7 +143,9 @@ protected: virtual bool processArgs(const Strings & args, bool finish); virtual Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) - { return pos; } + { + return pos; + } std::set hiddenCategories; @@ -162,20 +167,13 @@ public: /* Expect a string argument. */ void expectArg(const std::string & label, std::string * dest, bool optional = false) { - expectArgs({ - .label = label, - .optional = optional, - .handler = {dest} - }); + expectArgs({.label = label, .optional = optional, .handler = {dest}}); } /* Expect 0 or more arguments. */ void expectArgs(const std::string & label, std::vector * dest) { - expectArgs({ - .label = label, - .handler = {dest} - }); + expectArgs({.label = label, .handler = {dest}}); } virtual nlohmann::json toJSON(); @@ -191,16 +189,19 @@ struct Command : virtual public Args { friend class MultiCommand; - virtual ~Command() { } + virtual ~Command() {} - virtual void prepare() { }; + virtual void prepare(){}; virtual void run() = 0; typedef int Category; static constexpr Category catDefault = 0; - virtual Category category() { return catDefault; } + virtual Category category() + { + return catDefault; + } }; typedef std::map()>> Commands; @@ -226,25 +227,23 @@ public: nlohmann::json toJSON() override; }; -Strings argvToStrings(int argc, char * * argv); +Strings argvToStrings(int argc, char ** argv); -struct Completion { +struct Completion +{ std::string completion; std::string description; bool operator<(const Completion & other) const; }; -class Completions : public std::set { +class Completions : public std::set +{ public: void add(std::string completion, std::string description = ""); }; extern std::shared_ptr completions; -enum CompletionType { - ctNormal, - ctFilenames, - ctAttrs -}; +enum CompletionType { ctNormal, ctFilenames, ctAttrs }; extern CompletionType completionType; std::optional needsCompletion(std::string_view s); diff --git a/src/libutil/callback.hh b/src/libutil/callback.hh index ef31794bee30..1e1d8a6dad2f 100644 --- a/src/libutil/callback.hh +++ b/src/libutil/callback.hh @@ -16,12 +16,16 @@ class Callback public: - Callback(std::function)> fun) : fun(fun) { } + Callback(std::function)> fun) + : fun(fun) + {} - Callback(Callback && callback) : fun(std::move(callback.fun)) + Callback(Callback && callback) + : fun(std::move(callback.fun)) { auto prev = callback.done.test_and_set(); - if (prev) done.test_and_set(); + if (prev) + done.test_and_set(); } void operator()(T && t) noexcept diff --git a/src/libutil/chunked-vector.hh b/src/libutil/chunked-vector.hh index 0a4f0b400d14..da75f85fe3aa 100644 --- a/src/libutil/chunked-vector.hh +++ b/src/libutil/chunked-vector.hh @@ -15,14 +15,14 @@ namespace nix { eliminates copies within the vector during resizing, and provides stable references to its elements. */ template -class ChunkedVector { +class ChunkedVector +{ private: uint32_t size_ = 0; std::vector> chunks; /* keep this out of the ::add hot path */ - [[gnu::noinline]] - auto & addChunk() + [[gnu::noinline]] auto & addChunk() { if (size_ >= std::numeric_limits::max() - ChunkSize) abort(); @@ -38,16 +38,21 @@ public: addChunk(); } - uint32_t size() const { return size_; } + uint32_t size() const + { + return size_; + } std::pair add(T value) { const auto idx = size_++; - auto & chunk = [&] () -> auto & { + auto & chunk = [&]() -> auto & + { if (auto & back = chunks.back(); back.size() < ChunkSize) return back; return addChunk(); - }(); + } + (); auto & result = chunk.emplace_back(std::move(value)); return {result, idx}; } diff --git a/src/libutil/closure.hh b/src/libutil/closure.hh index 779b9b2d54a3..ee23a2a54ec2 100644 --- a/src/libutil/closure.hh +++ b/src/libutil/closure.hh @@ -10,11 +10,7 @@ template using GetEdgesAsync = std::function> &)>)>; template -void computeClosure( - const set startElts, - set & res, - GetEdgesAsync getEdgesAsync -) +void computeClosure(const set startElts, set & res, GetEdgesAsync getEdgesAsync) { struct State { @@ -32,8 +28,10 @@ void computeClosure( enqueue = [&](const T & current) -> void { { auto state(state_.lock()); - if (state->exc) return; - if (!state->res.insert(current).second) return; + if (state->exc) + return; + if (!state->res.insert(current).second) + return; state->pending++; } @@ -45,13 +43,16 @@ void computeClosure( { auto state(state_.lock()); assert(state->pending); - if (!--state->pending) done.notify_one(); + if (!--state->pending) + done.notify_one(); } } catch (...) { auto state(state_.lock()); - if (!state->exc) state->exc = std::current_exception(); + if (!state->exc) + state->exc = std::current_exception(); assert(state->pending); - if (!--state->pending) done.notify_one(); + if (!--state->pending) + done.notify_one(); }; }); }; @@ -61,8 +62,10 @@ void computeClosure( { auto state(state_.lock()); - while (state->pending) state.wait(done); - if (state->exc) std::rethrow_exception(state->exc); + while (state->pending) + state.wait(done); + if (state->exc) + std::rethrow_exception(state->exc); } } diff --git a/src/libutil/comparator.hh b/src/libutil/comparator.hh index eecd5b819c63..fdc8a5608ded 100644 --- a/src/libutil/comparator.hh +++ b/src/libutil/comparator.hh @@ -16,12 +16,13 @@ * ``` */ #define GENERATE_ONE_CMP(COMPARATOR, MY_TYPE, FIELDS...) \ - bool operator COMPARATOR(const MY_TYPE& other) const { \ - const MY_TYPE* me = this; \ - auto fields1 = std::make_tuple( FIELDS ); \ - me = &other; \ - auto fields2 = std::make_tuple( FIELDS ); \ - return fields1 COMPARATOR fields2; \ + bool operator COMPARATOR(const MY_TYPE & other) const \ + { \ + const MY_TYPE * me = this; \ + auto fields1 = std::make_tuple(FIELDS); \ + me = &other; \ + auto fields2 = std::make_tuple(FIELDS); \ + return fields1 COMPARATOR fields2; \ } #define GENERATE_EQUAL(args...) GENERATE_ONE_CMP(==, args) #define GENERATE_LEQ(args...) GENERATE_ONE_CMP(<, args) diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc index 89180e7a756f..f97de69c6333 100644 --- a/src/libutil/compression.cc +++ b/src/libutil/compression.cc @@ -40,20 +40,23 @@ struct ArchiveDecompressionSource : Source { std::unique_ptr archive = 0; Source & src; - ArchiveDecompressionSource(Source & src) : src(src) {} + ArchiveDecompressionSource(Source & src) + : src(src) + {} ~ArchiveDecompressionSource() override {} - size_t read(char * data, size_t len) override { + size_t read(char * data, size_t len) override + { struct archive_entry * ae; if (!archive) { archive = std::make_unique(src, true); - this->archive->check(archive_read_next_header(this->archive->archive, &ae), - "failed to read header (%s)"); + this->archive->check(archive_read_next_header(this->archive->archive, &ae), "failed to read header (%s)"); if (archive_filter_count(this->archive->archive) < 2) { throw CompressionError("input compression not recognized"); } } ssize_t result = archive_read_data(this->archive->archive, data, len); - if (result > 0) return result; + if (result > 0) + return result; if (result == 0) { throw EndOfFile("reached end of compressed file"); } @@ -67,16 +70,19 @@ struct ArchiveCompressionSink : CompressionSink Sink & nextSink; struct archive * archive; - ArchiveCompressionSink(Sink & nextSink, std::string format, bool parallel, int level = COMPRESSION_LEVEL_DEFAULT) : nextSink(nextSink) + ArchiveCompressionSink(Sink & nextSink, std::string format, bool parallel, int level = COMPRESSION_LEVEL_DEFAULT) + : nextSink(nextSink) { archive = archive_write_new(); - if (!archive) throw Error("failed to initialize libarchive"); + if (!archive) + throw Error("failed to initialize libarchive"); check(archive_write_add_filter_by_name(archive, format.c_str()), "couldn't initialize compression (%s)"); check(archive_write_set_format_raw(archive)); if (parallel) check(archive_write_set_filter_option(archive, format.c_str(), "threads", "0")); if (level != COMPRESSION_LEVEL_DEFAULT) - check(archive_write_set_filter_option(archive, format.c_str(), "compression-level", std::to_string(level).c_str())); + check(archive_write_set_filter_option( + archive, format.c_str(), "compression-level", std::to_string(level).c_str())); // disable internal buffering check(archive_write_set_bytes_per_block(archive, 0)); // disable output padding @@ -86,7 +92,8 @@ struct ArchiveCompressionSink : CompressionSink ~ArchiveCompressionSink() override { - if (archive) archive_write_free(archive); + if (archive) + archive_write_free(archive); } void finish() override @@ -106,7 +113,8 @@ struct ArchiveCompressionSink : CompressionSink void write(std::string_view data) override { ssize_t result = archive_write_data(archive, data.data(), data.length()); - if (result <= 0) check(result); + if (result <= 0) + check(result); } private: @@ -130,13 +138,20 @@ struct ArchiveCompressionSink : CompressionSink struct NoneSink : CompressionSink { Sink & nextSink; - NoneSink(Sink & nextSink, int level = COMPRESSION_LEVEL_DEFAULT) : nextSink(nextSink) + NoneSink(Sink & nextSink, int level = COMPRESSION_LEVEL_DEFAULT) + : nextSink(nextSink) { if (level != COMPRESSION_LEVEL_DEFAULT) warn("requested compression level '%d' not supported by compression method 'none'", level); } - void finish() override { flush(); } - void write(std::string_view data) override { nextSink(data); } + void finish() override + { + flush(); + } + void write(std::string_view data) override + { + nextSink(data); + } }; struct BrotliDecompressionSink : ChunkedCompressionSink @@ -145,7 +160,8 @@ struct BrotliDecompressionSink : ChunkedCompressionSink BrotliDecoderState * state; bool finished = false; - BrotliDecompressionSink(Sink & nextSink) : nextSink(nextSink) + BrotliDecompressionSink(Sink & nextSink) + : nextSink(nextSink) { state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr); if (!state) @@ -173,10 +189,7 @@ struct BrotliDecompressionSink : ChunkedCompressionSink while (!finished && (!data.data() || avail_in)) { checkInterrupt(); - if (!BrotliDecoderDecompressStream(state, - &avail_in, &next_in, - &avail_out, &next_out, - nullptr)) + if (!BrotliDecoderDecompressStream(state, &avail_in, &next_in, &avail_out, &next_out, nullptr)) throw CompressionError("error while decompressing brotli file"); if (avail_out < sizeof(outbuf) || avail_in == 0) { @@ -219,7 +232,8 @@ struct BrotliCompressionSink : ChunkedCompressionSink BrotliEncoderState * state; bool finished = false; - BrotliCompressionSink(Sink & nextSink) : nextSink(nextSink) + BrotliCompressionSink(Sink & nextSink) + : nextSink(nextSink) { state = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr); if (!state) @@ -247,11 +261,9 @@ struct BrotliCompressionSink : ChunkedCompressionSink while (!finished && (!data.data() || avail_in)) { checkInterrupt(); - if (!BrotliEncoderCompressStream(state, - data.data() ? BROTLI_OPERATION_PROCESS : BROTLI_OPERATION_FINISH, - &avail_in, &next_in, - &avail_out, &next_out, - nullptr)) + if (!BrotliEncoderCompressStream( + state, data.data() ? BROTLI_OPERATION_PROCESS : BROTLI_OPERATION_FINISH, &avail_in, &next_in, + &avail_out, &next_out, nullptr)) throw CompressionError("error while compressing brotli compression"); if (avail_out < sizeof(outbuf) || avail_in == 0) { @@ -267,9 +279,8 @@ struct BrotliCompressionSink : ChunkedCompressionSink ref makeCompressionSink(const std::string & method, Sink & nextSink, const bool parallel, int level) { - std::vector la_supports = { - "bzip2", "compress", "grzip", "gzip", "lrzip", "lz4", "lzip", "lzma", "lzop", "xz", "zstd" - }; + std::vector la_supports = {"bzip2", "compress", "grzip", "gzip", "lrzip", "lz4", + "lzip", "lzma", "lzop", "xz", "zstd"}; if (std::find(la_supports.begin(), la_supports.end(), method) != la_supports.end()) { return make_ref(nextSink, method, parallel, level); } diff --git a/src/libutil/compression.hh b/src/libutil/compression.hh index c470b82a5093..07e09099d42c 100644 --- a/src/libutil/compression.hh +++ b/src/libutil/compression.hh @@ -10,7 +10,7 @@ namespace nix { struct CompressionSink : BufferedSink, FinishSink { - using BufferedSink::operator (); + using BufferedSink::operator(); using BufferedSink::write; using FinishSink::finish; }; @@ -21,7 +21,8 @@ std::unique_ptr makeDecompressionSink(const std::string & method, Si std::string compress(const std::string & method, std::string_view in, const bool parallel = false, int level = -1); -ref makeCompressionSink(const std::string & method, Sink & nextSink, const bool parallel = false, int level = -1); +ref +makeCompressionSink(const std::string & method, Sink & nextSink, const bool parallel = false, int level = -1); MakeError(UnknownCompressionMethod, Error); diff --git a/src/libutil/compute-levels.cc b/src/libutil/compute-levels.cc index 19eaedfa8d1c..c8a8b19313a0 100644 --- a/src/libutil/compute-levels.cc +++ b/src/libutil/compute-levels.cc @@ -8,7 +8,8 @@ namespace nix { #if HAVE_LIBCPUID -StringSet computeLevels() { +StringSet computeLevels() +{ StringSet levels; if (!cpuid_present()) @@ -23,45 +24,31 @@ StringSet computeLevels() { if (cpu_identify(&raw, &data) < 0) return levels; - if (!(data.flags[CPU_FEATURE_CMOV] && - data.flags[CPU_FEATURE_CX8] && - data.flags[CPU_FEATURE_FPU] && - data.flags[CPU_FEATURE_FXSR] && - data.flags[CPU_FEATURE_MMX] && - data.flags[CPU_FEATURE_SSE] && - data.flags[CPU_FEATURE_SSE2])) + if (!(data.flags[CPU_FEATURE_CMOV] && data.flags[CPU_FEATURE_CX8] && data.flags[CPU_FEATURE_FPU] + && data.flags[CPU_FEATURE_FXSR] && data.flags[CPU_FEATURE_MMX] && data.flags[CPU_FEATURE_SSE] + && data.flags[CPU_FEATURE_SSE2])) return levels; levels.insert("x86_64-v1"); - if (!(data.flags[CPU_FEATURE_CX16] && - data.flags[CPU_FEATURE_LAHF_LM] && - data.flags[CPU_FEATURE_POPCNT] && - // SSE3 - data.flags[CPU_FEATURE_PNI] && - data.flags[CPU_FEATURE_SSSE3] && - data.flags[CPU_FEATURE_SSE4_1] && - data.flags[CPU_FEATURE_SSE4_2])) + if (!(data.flags[CPU_FEATURE_CX16] && data.flags[CPU_FEATURE_LAHF_LM] && data.flags[CPU_FEATURE_POPCNT] && + // SSE3 + data.flags[CPU_FEATURE_PNI] && data.flags[CPU_FEATURE_SSSE3] && data.flags[CPU_FEATURE_SSE4_1] + && data.flags[CPU_FEATURE_SSE4_2])) return levels; levels.insert("x86_64-v2"); - if (!(data.flags[CPU_FEATURE_AVX] && - data.flags[CPU_FEATURE_AVX2] && - data.flags[CPU_FEATURE_F16C] && - data.flags[CPU_FEATURE_FMA3] && - // LZCNT - data.flags[CPU_FEATURE_ABM] && - data.flags[CPU_FEATURE_MOVBE])) + if (!(data.flags[CPU_FEATURE_AVX] && data.flags[CPU_FEATURE_AVX2] && data.flags[CPU_FEATURE_F16C] + && data.flags[CPU_FEATURE_FMA3] && + // LZCNT + data.flags[CPU_FEATURE_ABM] && data.flags[CPU_FEATURE_MOVBE])) return levels; levels.insert("x86_64-v3"); - if (!(data.flags[CPU_FEATURE_AVX512F] && - data.flags[CPU_FEATURE_AVX512BW] && - data.flags[CPU_FEATURE_AVX512CD] && - data.flags[CPU_FEATURE_AVX512DQ] && - data.flags[CPU_FEATURE_AVX512VL])) + if (!(data.flags[CPU_FEATURE_AVX512F] && data.flags[CPU_FEATURE_AVX512BW] && data.flags[CPU_FEATURE_AVX512CD] + && data.flags[CPU_FEATURE_AVX512DQ] && data.flags[CPU_FEATURE_AVX512VL])) return levels; levels.insert("x86_64-v4"); @@ -71,7 +58,8 @@ StringSet computeLevels() { #else -StringSet computeLevels() { +StringSet computeLevels() +{ return StringSet{}; } diff --git a/src/libutil/config.cc b/src/libutil/config.cc index 9bb412b4f5ea..654af6e764fe 100644 --- a/src/libutil/config.cc +++ b/src/libutil/config.cc @@ -45,8 +45,7 @@ void Config::addSetting(AbstractSetting * setting) auto i = unknownSettings.find(alias); if (i != unknownSettings.end()) { if (set) - warn("setting '%s' is set, but it's an alias of '%s' which is also set", - alias, setting->name); + warn("setting '%s' is set, but it's an alias of '%s' which is also set", alias, setting->name); else { setting->set(i->second); setting->overridden = true; @@ -77,7 +76,8 @@ void Config::getSettings(std::map & res, bool overridd res.emplace(opt.first, SettingInfo{opt.second.setting->to_string(), opt.second.setting->description}); } -void AbstractConfig::applyConfig(const std::string & contents, const std::string & path) { +void AbstractConfig::applyConfig(const std::string & contents, const std::string & path) +{ unsigned int pos = 0; while (pos < contents.size()) { @@ -91,7 +91,8 @@ void AbstractConfig::applyConfig(const std::string & contents, const std::string line = std::string(line, 0, hash); auto tokens = tokenizeString>(line); - if (tokens.empty()) continue; + if (tokens.empty()) + continue; if (tokens.size() < 2) throw UsageError("illegal configuration line '%1%' in '%2%'", line, path); @@ -134,7 +135,8 @@ void AbstractConfig::applyConfigFile(const Path & path) try { std::string contents = readFile(path); applyConfig(contents, path); - } catch (SysError &) { } + } catch (SysError &) { + } } void Config::resetOverridden() @@ -171,12 +173,11 @@ void Config::convertToArgs(Args & args, const std::string & category) } AbstractSetting::AbstractSetting( - const std::string & name, - const std::string & description, - const std::set & aliases) - : name(name), description(stripIndentation(description)), aliases(aliases) -{ -} + const std::string & name, const std::string & description, const std::set & aliases) + : name(name) + , description(stripIndentation(description)) + , aliases(aliases) +{} nlohmann::json AbstractSetting::toJSON() { @@ -191,9 +192,7 @@ std::map AbstractSetting::toJSONObject() return obj; } -void AbstractSetting::convertToArg(Args & args, const std::string & category) -{ -} +void AbstractSetting::convertToArg(Args & args, const std::string & category) {} template bool BaseSetting::isAppendable() @@ -209,7 +208,10 @@ void BaseSetting::convertToArg(Args & args, const std::string & category) .description = fmt("Set the `%s` setting.", name), .category = category, .labels = {"value"}, - .handler = {[=](std::string s) { overridden = true; set(s); }}, + .handler = {[=](std::string s) { + overridden = true; + set(s); + }}, }); if (isAppendable()) @@ -218,16 +220,21 @@ void BaseSetting::convertToArg(Args & args, const std::string & category) .description = fmt("Append to the `%s` setting.", name), .category = category, .labels = {"value"}, - .handler = {[=](std::string s) { overridden = true; set(s, true); }}, + .handler = {[=](std::string s) { + overridden = true; + set(s, true); + }}, }); } -template<> void BaseSetting::set(const std::string & str, bool append) +template<> +void BaseSetting::set(const std::string & str, bool append) { value = str; } -template<> std::string BaseSetting::to_string() const +template<> +std::string BaseSetting::to_string() const { return value; } @@ -249,7 +256,8 @@ std::string BaseSetting::to_string() const return std::to_string(value); } -template<> void BaseSetting::set(const std::string & str, bool append) +template<> +void BaseSetting::set(const std::string & str, bool append) { if (str == "true" || str == "yes" || str == "1") value = true; @@ -259,64 +267,75 @@ template<> void BaseSetting::set(const std::string & str, bool append) throw UsageError("Boolean setting '%s' has invalid value '%s'", name, str); } -template<> std::string BaseSetting::to_string() const +template<> +std::string BaseSetting::to_string() const { return value ? "true" : "false"; } -template<> void BaseSetting::convertToArg(Args & args, const std::string & category) +template<> +void BaseSetting::convertToArg(Args & args, const std::string & category) { - args.addFlag({ - .longName = name, - .description = fmt("Enable the `%s` setting.", name), - .category = category, - .handler = {[=]() { override(true); }} - }); - args.addFlag({ - .longName = "no-" + name, - .description = fmt("Disable the `%s` setting.", name), - .category = category, - .handler = {[=]() { override(false); }} - }); + args.addFlag( + {.longName = name, + .description = fmt("Enable the `%s` setting.", name), + .category = category, + .handler = {[=]() { override(true); }}}); + args.addFlag( + {.longName = "no-" + name, + .description = fmt("Disable the `%s` setting.", name), + .category = category, + .handler = {[=]() { override(false); }}}); } -template<> void BaseSetting::set(const std::string & str, bool append) +template<> +void BaseSetting::set(const std::string & str, bool append) { auto ss = tokenizeString(str); - if (!append) value.clear(); - for (auto & s : ss) value.push_back(std::move(s)); + if (!append) + value.clear(); + for (auto & s : ss) + value.push_back(std::move(s)); } -template<> bool BaseSetting::isAppendable() +template<> +bool BaseSetting::isAppendable() { return true; } -template<> std::string BaseSetting::to_string() const +template<> +std::string BaseSetting::to_string() const { return concatStringsSep(" ", value); } -template<> void BaseSetting::set(const std::string & str, bool append) +template<> +void BaseSetting::set(const std::string & str, bool append) { - if (!append) value.clear(); + if (!append) + value.clear(); for (auto & s : tokenizeString(str)) value.insert(s); } -template<> bool BaseSetting::isAppendable() +template<> +bool BaseSetting::isAppendable() { return true; } -template<> std::string BaseSetting::to_string() const +template<> +std::string BaseSetting::to_string() const { return concatStringsSep(" ", value); } -template<> void BaseSetting>::set(const std::string & str, bool append) +template<> +void BaseSetting>::set(const std::string & str, bool append) { - if (!append) value.clear(); + if (!append) + value.clear(); for (auto & s : tokenizeString(str)) { auto thisXpFeature = parseExperimentalFeature(s); if (thisXpFeature) @@ -326,12 +345,14 @@ template<> void BaseSetting>::set(const std::strin } } -template<> bool BaseSetting>::isAppendable() +template<> +bool BaseSetting>::isAppendable() { return true; } -template<> std::string BaseSetting>::to_string() const +template<> +std::string BaseSetting>::to_string() const { StringSet stringifiedXpFeatures; for (auto & feature : value) @@ -339,9 +360,11 @@ template<> std::string BaseSetting>::to_string() c return concatStringsSep(" ", stringifiedXpFeatures); } -template<> void BaseSetting::set(const std::string & str, bool append) +template<> +void BaseSetting::set(const std::string & str, bool append) { - if (!append) value.clear(); + if (!append) + value.clear(); for (auto & s : tokenizeString(str)) { auto eq = s.find_first_of('='); if (std::string::npos != eq) @@ -350,16 +373,19 @@ template<> void BaseSetting::set(const std::string & str, bool append } } -template<> bool BaseSetting::isAppendable() +template<> +bool BaseSetting::isAppendable() { return true; } -template<> std::string BaseSetting::to_string() const +template<> +std::string BaseSetting::to_string() const { Strings kvstrs; - std::transform(value.begin(), value.end(), back_inserter(kvstrs), - [&](auto kvpair){ return kvpair.first + "=" + kvpair.second; }); + std::transform(value.begin(), value.end(), back_inserter(kvstrs), [&](auto kvpair) { + return kvpair.first + "=" + kvpair.second; + }); return concatStringsSep(" ", kvstrs); } @@ -390,7 +416,8 @@ void PathSetting::set(const std::string & str, bool append) bool GlobalConfig::set(const std::string & name, const std::string & value) { for (auto & config : *configRegistrations) - if (config->set(name, value)) return true; + if (config->set(name, value)) + return true; unknownSettings.emplace(name, value); diff --git a/src/libutil/config.hh b/src/libutil/config.hh index 79ec0f9cf363..7e8f77d07849 100644 --- a/src/libutil/config.hh +++ b/src/libutil/config.hh @@ -52,7 +52,7 @@ protected: AbstractConfig(const StringMap & initials = {}) : unknownSettings(initials) - { } + {} public: @@ -149,8 +149,9 @@ public: bool isAlias; AbstractSetting * setting; SettingData(bool isAlias, AbstractSetting * setting) - : isAlias(isAlias), setting(setting) - { } + : isAlias(isAlias) + , setting(setting) + {} }; typedef std::map Settings; @@ -163,7 +164,7 @@ public: Config(const StringMap & initials = {}) : AbstractConfig(initials) - { } + {} bool set(const std::string & name, const std::string & value) override; @@ -196,10 +197,7 @@ public: protected: - AbstractSetting( - const std::string & name, - const std::string & description, - const std::set & aliases); + AbstractSetting(const std::string & name, const std::string & description, const std::set & aliases); virtual ~AbstractSetting() { @@ -211,7 +209,9 @@ protected: virtual void set(const std::string & value, bool append = false) = 0; virtual bool isAppendable() - { return false; } + { + return false; + } virtual std::string to_string() const = 0; @@ -221,7 +221,10 @@ protected: virtual void convertToArg(Args & args, const std::string & category); - bool isOverridden() const { return overridden; } + bool isOverridden() const + { + return overridden; + } }; /* A setting of type T. */ @@ -236,7 +239,8 @@ protected: public: - BaseSetting(const T & def, + BaseSetting( + const T & def, const bool documentDefault, const std::string & name, const std::string & description, @@ -245,16 +249,41 @@ public: , value(def) , defaultValue(def) , documentDefault(documentDefault) - { } + {} - operator const T &() const { return value; } - operator T &() { return value; } - const T & get() const { return value; } - bool operator ==(const T & v2) const { return value == v2; } - bool operator !=(const T & v2) const { return value != v2; } - void operator =(const T & v) { assign(v); } - virtual void assign(const T & v) { value = v; } - void setDefault(const T & v) { if (!overridden) value = v; } + operator const T &() const + { + return value; + } + operator T &() + { + return value; + } + const T & get() const + { + return value; + } + bool operator==(const T & v2) const + { + return value == v2; + } + bool operator!=(const T & v2) const + { + return value != v2; + } + void operator=(const T & v) + { + assign(v); + } + virtual void assign(const T & v) + { + value = v; + } + void setDefault(const T & v) + { + if (!overridden) + value = v; + } void set(const std::string & str, bool append = false) override; @@ -274,20 +303,24 @@ public: }; template -std::ostream & operator <<(std::ostream & str, const BaseSetting & opt) +std::ostream & operator<<(std::ostream & str, const BaseSetting & opt) { str << (const T &) opt; return str; } template -bool operator ==(const T & v1, const BaseSetting & v2) { return v1 == (const T &) v2; } +bool operator==(const T & v1, const BaseSetting & v2) +{ + return v1 == (const T &) v2; +} template class Setting : public BaseSetting { public: - Setting(Config * options, + Setting( + Config * options, const T & def, const std::string & name, const std::string & description, @@ -298,7 +331,10 @@ public: options->addSetting(this); } - void operator =(const T & v) { this->assign(v); } + void operator=(const T & v) + { + this->assign(v); + } }; /* A special setting for Paths. These are automatically canonicalised @@ -309,7 +345,8 @@ class PathSetting : public BaseSetting public: - PathSetting(Config * options, + PathSetting( + Config * options, bool allowEmpty, const Path & def, const std::string & name, @@ -323,14 +360,20 @@ public: void set(const std::string & str, bool append = false) override; - Path operator +(const char * p) const { return value + p; } + Path operator+(const char * p) const + { + return value + p; + } - void operator =(const Path & v) { this->assign(v); } + void operator=(const Path & v) + { + this->assign(v); + } }; struct GlobalConfig : public AbstractConfig { - typedef std::vector ConfigRegistrations; + typedef std::vector ConfigRegistrations; static ConfigRegistrations * configRegistrations; bool set(const std::string & name, const std::string & value) override; diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 9172f67a65de..f130adebf052 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -11,7 +11,7 @@ const std::string nativeSystem = SYSTEM; void BaseError::addTrace(std::optional e, hintformat hint) { - err.traces.push_front(Trace { .pos = e, .hint = hint }); + err.traces.push_front(Trace{.pos = e, .hint = hint}); } // c++ std::exception descendants must have a 'const char* what()' function. @@ -43,8 +43,7 @@ std::string showErrPos(const ErrPos & errPos) } else { return fmt("%d", errPos.line); } - } - else { + } else { return ""; } } @@ -60,14 +59,14 @@ std::optional getCodeLines(const ErrPos & errPos) // 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 {}; + if (!fd) + return {}; // count the newlines. int count = 0; std::string line; int pl = errPos.line - 1; - do - { + do { line = readLine(fd.get()); ++count; if (count < pl) @@ -82,14 +81,12 @@ std::optional getCodeLines(const ErrPos & errPos) } } while (true); return loc; - } - catch (EndOfFile & eof) { + } catch (EndOfFile & eof) { if (loc.errLineOfCode.has_value()) return loc; else return std::nullopt; - } - catch (std::exception & e) { + } catch (std::exception & e) { return std::nullopt; } } else { @@ -101,15 +98,12 @@ std::optional getCodeLines(const ErrPos & errPos) LinesOfCode loc; - do - { + do { std::getline(iss, line); ++count; - if (count < pl) - { + if (count < pl) { ; - } - else if (count == pl) { + } else if (count == pl) { loc.prevLineOfCode = line; } else if (count == pl + 1) { loc.errLineOfCode = line; @@ -127,27 +121,16 @@ std::optional getCodeLines(const ErrPos & errPos) } // print lines of code to the ostream, indicating the error column. -void printCodeLines(std::ostream & out, - const std::string & prefix, - const ErrPos & errPos, - const LinesOfCode & loc) +void printCodeLines(std::ostream & out, const std::string & prefix, const ErrPos & errPos, const LinesOfCode & loc) { // previous line of code. if (loc.prevLineOfCode.has_value()) { - out << std::endl - << fmt("%1% %|2$5d|| %3%", - prefix, - (errPos.line - 1), - *loc.prevLineOfCode); + out << std::endl << fmt("%1% %|2$5d|| %3%", prefix, (errPos.line - 1), *loc.prevLineOfCode); } if (loc.errLineOfCode.has_value()) { // line of code containing the error. - out << std::endl - << fmt("%1% %|2$5d|| %3%", - prefix, - (errPos.line), - *loc.errLineOfCode); + out << std::endl << fmt("%1% %|2$5d|| %3%", prefix, (errPos.line), *loc.errLineOfCode); // error arrows for the column range. if (errPos.column > 0) { int start = errPos.column; @@ -158,21 +141,13 @@ void printCodeLines(std::ostream & out, std::string arrows("^"); - out << std::endl - << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, - prefix, - spaces, - arrows); + out << std::endl << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, prefix, spaces, arrows); } } // next line of code. if (loc.nextLineOfCode.has_value()) { - out << std::endl - << fmt("%1% %|2$5d|| %3%", - prefix, - (errPos.line + 1), - *loc.nextLineOfCode); + out << std::endl << fmt("%1% %|2$5d|| %3%", prefix, (errPos.line + 1), *loc.nextLineOfCode); } } @@ -180,20 +155,20 @@ void printAtPos(const ErrPos & pos, std::ostream & out) { if (pos) { switch (pos.origin) { - case foFile: { - out << fmt(ANSI_BLUE "at " ANSI_WARNING "%s:%s" ANSI_NORMAL ":", pos.file, showErrPos(pos)); - break; - } - case foString: { - out << fmt(ANSI_BLUE "at " ANSI_WARNING "«string»:%s" ANSI_NORMAL ":", showErrPos(pos)); - break; - } - case foStdin: { - out << fmt(ANSI_BLUE "at " ANSI_WARNING "«stdin»:%s" ANSI_NORMAL ":", showErrPos(pos)); - break; - } - default: - throw Error("invalid FileOrigin in errPos"); + case foFile: { + out << fmt(ANSI_BLUE "at " ANSI_WARNING "%s:%s" ANSI_NORMAL ":", pos.file, showErrPos(pos)); + break; + } + case foString: { + out << fmt(ANSI_BLUE "at " ANSI_WARNING "«string»:%s" ANSI_NORMAL ":", showErrPos(pos)); + break; + } + case foStdin: { + out << fmt(ANSI_BLUE "at " ANSI_WARNING "«stdin»:%s" ANSI_NORMAL ":", showErrPos(pos)); + break; + } + default: + throw Error("invalid FileOrigin in errPos"); } } } @@ -205,10 +180,12 @@ static std::string indent(std::string_view indentFirst, std::string_view indentR while (!s.empty()) { auto end = s.find('\n'); - if (!first) res += "\n"; + if (!first) + res += "\n"; res += chomp(std::string(first ? indentFirst : indentRest) + std::string(s.substr(0, end))); first = false; - if (end == s.npos) break; + if (end == s.npos) + break; s = s.substr(end + 1); } @@ -219,40 +196,40 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s { std::string prefix; switch (einfo.level) { - case Verbosity::lvlError: { - prefix = ANSI_RED "error"; - break; - } - case Verbosity::lvlNotice: { - prefix = ANSI_RED "note"; - break; - } - case Verbosity::lvlWarn: { - prefix = ANSI_WARNING "warning"; - break; - } - case Verbosity::lvlInfo: { - prefix = ANSI_GREEN "info"; - break; - } - case Verbosity::lvlTalkative: { - prefix = ANSI_GREEN "talk"; - break; - } - case Verbosity::lvlChatty: { - prefix = ANSI_GREEN "chat"; - break; - } - case Verbosity::lvlVomit: { - prefix = ANSI_GREEN "vomit"; - break; - } - case Verbosity::lvlDebug: { - prefix = ANSI_WARNING "debug"; - break; - } - default: - assert(false); + case Verbosity::lvlError: { + prefix = ANSI_RED "error"; + break; + } + case Verbosity::lvlNotice: { + prefix = ANSI_RED "note"; + break; + } + case Verbosity::lvlWarn: { + prefix = ANSI_WARNING "warning"; + break; + } + case Verbosity::lvlInfo: { + prefix = ANSI_GREEN "info"; + break; + } + case Verbosity::lvlTalkative: { + prefix = ANSI_GREEN "talk"; + break; + } + case Verbosity::lvlChatty: { + prefix = ANSI_GREEN "chat"; + break; + } + case Verbosity::lvlVomit: { + prefix = ANSI_GREEN "vomit"; + break; + } + case Verbosity::lvlDebug: { + prefix = ANSI_WARNING "debug"; + break; + } + default: + assert(false); } // FIXME: show the program name as part of the trace? @@ -279,16 +256,15 @@ std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool s } auto suggestions = einfo.suggestions.trim(); - if (! suggestions.suggestions.empty()){ - oss << "Did you mean " << - suggestions.trim() << - "?" << std::endl; + if (!suggestions.suggestions.empty()) { + oss << "Did you mean " << suggestions.trim() << "?" << std::endl; } // traces if (showTrace && !einfo.traces.empty()) { for (auto iter = einfo.traces.rbegin(); iter != einfo.traces.rend(); ++iter) { - oss << "\n" << "… " << iter->hint.str() << "\n"; + oss << "\n" + << "… " << iter->hint.str() << "\n"; if (iter->pos.has_value() && (*iter->pos)) { auto pos = iter->pos.value(); diff --git a/src/libutil/error.hh b/src/libutil/error.hh index a53e9802e01b..3d052609bf0d 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -43,33 +43,22 @@ namespace nix { */ -typedef enum { - lvlError = 0, - lvlWarn, - lvlNotice, - lvlInfo, - lvlTalkative, - lvlChatty, - lvlDebug, - lvlVomit -} Verbosity; +typedef enum { lvlError = 0, lvlWarn, lvlNotice, lvlInfo, lvlTalkative, lvlChatty, lvlDebug, lvlVomit } Verbosity; /* adjust Pos::origin bit width when adding stuff here */ -typedef enum { - foFile, - foStdin, - foString -} FileOrigin; +typedef enum { foFile, foStdin, foString } FileOrigin; // the lines of code surrounding an error. -struct LinesOfCode { +struct LinesOfCode +{ std::optional prevLineOfCode; std::optional errLineOfCode; std::optional nextLineOfCode; }; // ErrPos indicates the location of an error in a nix file. -struct ErrPos { +struct ErrPos +{ int line = 0; int column = 0; std::string file; @@ -81,7 +70,7 @@ struct ErrPos { } // convert from the Pos struct, found in libexpr. - template + template ErrPos & operator=(const P & pos) { origin = pos.origin; @@ -91,7 +80,7 @@ struct ErrPos { return *this; } - template + template ErrPos(const P & p) { *this = p; @@ -100,19 +89,18 @@ struct ErrPos { std::optional getCodeLines(const ErrPos & errPos); -void printCodeLines(std::ostream & out, - const std::string & prefix, - const ErrPos & errPos, - const LinesOfCode & loc); +void printCodeLines(std::ostream & out, const std::string & prefix, const ErrPos & errPos, const LinesOfCode & loc); void printAtPos(const ErrPos & pos, std::ostream & out); -struct Trace { +struct Trace +{ std::optional pos; hintformat hint; }; -struct ErrorInfo { +struct ErrorInfo +{ Verbosity level; hintformat msg; std::optional errPos; @@ -139,59 +127,75 @@ public: unsigned int status = 1; // exit status template - BaseError(unsigned int status, const Args & ... args) - : err { .level = lvlError, .msg = hintfmt(args...) } + BaseError(unsigned int status, const Args &... args) + : err{.level = lvlError, .msg = hintfmt(args...)} , status(status) - { } + {} template - explicit BaseError(const std::string & fs, const Args & ... args) - : err { .level = lvlError, .msg = hintfmt(fs, args...) } - { } + explicit BaseError(const std::string & fs, const Args &... args) + : err{.level = lvlError, .msg = hintfmt(fs, args...)} + {} template - BaseError(const Suggestions & sug, const Args & ... args) - : err { .level = lvlError, .msg = hintfmt(args...), .suggestions = sug } - { } + BaseError(const Suggestions & sug, const Args &... args) + : err{.level = lvlError, .msg = hintfmt(args...), .suggestions = sug} + {} BaseError(hintformat hint) - : err { .level = lvlError, .msg = hint } - { } + : err{.level = lvlError, .msg = hint} + {} BaseError(ErrorInfo && e) : err(std::move(e)) - { } + {} BaseError(const ErrorInfo & e) : err(e) - { } + {} #ifdef EXCEPTION_NEEDS_THROW_SPEC - ~BaseError() throw () { }; - const char * what() const throw () { return calcWhat().c_str(); } + ~BaseError() throw(){}; + const char * what() const throw() + { + return calcWhat().c_str(); + } #else - const char * what() const noexcept override { return calcWhat().c_str(); } + const char * what() const noexcept override + { + return calcWhat().c_str(); + } #endif - const std::string & msg() const { return calcWhat(); } - const ErrorInfo & info() const { calcWhat(); return err; } + const std::string & msg() const + { + return calcWhat(); + } + const ErrorInfo & info() const + { + calcWhat(); + return err; + } template - void addTrace(std::optional e, const std::string & fs, const Args & ... args) + void addTrace(std::optional e, const std::string & fs, const Args &... args) { addTrace(e, hintfmt(fs, args...)); } void addTrace(std::optional e, hintformat hint); - bool hasTrace() const { return !err.traces.empty(); } + bool hasTrace() const + { + return !err.traces.empty(); + } }; #define MakeError(newClass, superClass) \ - class newClass : public superClass \ - { \ - public: \ - using superClass::superClass; \ + class newClass : public superClass \ + { \ + public: \ + using superClass::superClass; \ } MakeError(Error, BaseError); @@ -204,7 +208,7 @@ public: int errNo; template - SysError(const Args & ... args) + SysError(const Args &... args) : Error("") { errNo = errno; diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 315de64a4014..a67f23a00b10 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -6,21 +6,20 @@ namespace nix { std::map stringifiedXpFeatures = { - { Xp::CaDerivations, "ca-derivations" }, - { Xp::ImpureDerivations, "impure-derivations" }, - { Xp::Flakes, "flakes" }, - { Xp::NixCommand, "nix-command" }, - { Xp::RecursiveNix, "recursive-nix" }, - { Xp::NoUrlLiterals, "no-url-literals" }, - { Xp::FetchClosure, "fetch-closure" }, + {Xp::CaDerivations, "ca-derivations"}, + {Xp::ImpureDerivations, "impure-derivations"}, + {Xp::Flakes, "flakes"}, + {Xp::NixCommand, "nix-command"}, + {Xp::RecursiveNix, "recursive-nix"}, + {Xp::NoUrlLiterals, "no-url-literals"}, + {Xp::FetchClosure, "fetch-closure"}, }; const std::optional parseExperimentalFeature(const std::string_view & name) { using ReverseXpMap = std::map; - static auto reverseXpMap = []() - { + static auto reverseXpMap = []() { auto reverseXpMap = std::make_unique(); for (auto & [feature, name] : stringifiedXpFeatures) (*reverseXpMap)[name] = feature; @@ -51,11 +50,13 @@ std::set parseFeatures(const std::set & rawFea } MissingExperimentalFeature::MissingExperimentalFeature(ExperimentalFeature feature) - : Error("experimental Nix feature '%1%' is disabled; use '--extra-experimental-features %1%' to override", showExperimentalFeature(feature)) + : Error( + "experimental Nix feature '%1%' is disabled; use '--extra-experimental-features %1%' to override", + showExperimentalFeature(feature)) , missingFeature(feature) {} -std::ostream & operator <<(std::ostream & str, const ExperimentalFeature & feature) +std::ostream & operator<<(std::ostream & str, const ExperimentalFeature & feature) { return str << showExperimentalFeature(feature); } diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 57512830c707..889985fc227c 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -13,8 +13,7 @@ namespace nix { * If you update this, don’t forget to also change the map defining their * string representation in the corresponding `.cc` file. **/ -enum struct ExperimentalFeature -{ +enum struct ExperimentalFeature { CaDerivations, ImpureDerivations, Flakes, @@ -29,13 +28,10 @@ enum struct ExperimentalFeature */ using Xp = ExperimentalFeature; -const std::optional parseExperimentalFeature( - const std::string_view & name); +const std::optional parseExperimentalFeature(const std::string_view & name); std::string_view showExperimentalFeature(const ExperimentalFeature); -std::ostream & operator<<( - std::ostream & str, - const ExperimentalFeature & feature); +std::ostream & operator<<(std::ostream & str, const ExperimentalFeature & feature); /** * Parse a set of strings to the corresponding set of experimental features, diff --git a/src/libutil/finally.hh b/src/libutil/finally.hh index dee2e8d2ff27..b45e9a19cfe6 100644 --- a/src/libutil/finally.hh +++ b/src/libutil/finally.hh @@ -8,6 +8,11 @@ private: Fn fun; public: - Finally(Fn fun) : fun(std::move(fun)) { } - ~Finally() { fun(); } + Finally(Fn fun) + : fun(std::move(fun)) + {} + ~Finally() + { + fun(); + } }; diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh index 7664e5c0419a..47b123009f11 100644 --- a/src/libutil/fmt.hh +++ b/src/libutil/fmt.hh @@ -4,29 +4,32 @@ #include #include "ansicolor.hh" - namespace nix { - /* Inherit some names from other namespaces for convenience. */ using boost::format; - /* A variadic template that does nothing. Useful to call a function for all variadic arguments but ignoring the result. */ -struct nop { template nop(T...) {} }; - +struct nop +{ + template + nop(T...) + {} +}; struct FormatOrString { std::string s; - FormatOrString(std::string s) : s(std::move(s)) { }; + FormatOrString(std::string s) + : s(std::move(s)){}; template - FormatOrString(const F & f) : s(f.str()) { }; - FormatOrString(const char * s) : s(s) { }; + 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 @@ -34,11 +37,10 @@ struct FormatOrString template inline void formatHelper(F & f) -{ -} +{} template -inline void formatHelper(F & f, const T & x, const Args & ... args) +inline void formatHelper(F & f, const T & x, const Args &... args) { formatHelper(f % x, args...); } @@ -59,7 +61,7 @@ inline std::string fmt(const FormatOrString & fs) } template -inline std::string fmt(const std::string & fs, const Args & ... args) +inline std::string fmt(const std::string & fs, const Args &... args) { boost::format f(fs); f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); @@ -71,27 +73,31 @@ inline std::string fmt(const std::string & fs, const Args & ... args) // format function for hints in errors. same as fmt, except templated values // are always in yellow. -template +template struct yellowtxt { - yellowtxt(const T &s) : value(s) {} + yellowtxt(const T & s) + : value(s) + {} const T & value; }; -template +template std::ostream & operator<<(std::ostream & out, const yellowtxt & y) { return out << ANSI_WARNING << y.value << ANSI_NORMAL; } -template +template struct normaltxt { - normaltxt(const T & s) : value(s) {} + normaltxt(const T & s) + : value(s) + {} const T & value; }; -template +template std::ostream & operator<<(std::ostream & out, const normaltxt & y) { return out << ANSI_NORMAL << y.value; @@ -100,20 +106,19 @@ std::ostream & operator<<(std::ostream & out, const normaltxt & y) class hintformat { public: - hintformat(const std::string & format) : fmt(format) + hintformat(const std::string & format) + : fmt(format) { - fmt.exceptions(boost::io::all_error_bits ^ - boost::io::too_many_args_bit ^ - boost::io::too_few_args_bit); + fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit ^ boost::io::too_few_args_bit); } hintformat(const hintformat & hf) : fmt(hf.fmt) - { } + {} hintformat(format && fmt) : fmt(std::move(fmt)) - { } + {} template hintformat & operator%(const T & value) @@ -141,7 +146,7 @@ private: std::ostream & operator<<(std::ostream & os, const hintformat & hf); template -inline hintformat hintfmt(const std::string & fs, const Args & ... args) +inline hintformat hintfmt(const std::string & fs, const Args &... args) { hintformat f(fs); formatHelper(f, args...); diff --git a/src/libutil/git.cc b/src/libutil/git.cc index f35c2fdb75cf..d0b4e04bbb42 100644 --- a/src/libutil/git.cc +++ b/src/libutil/git.cc @@ -12,13 +12,10 @@ std::optional parseLsRemoteLine(std::string_view line) if (!std::regex_match(line.cbegin(), line.cend(), match, line_regex)) return std::nullopt; - return LsRemoteRefLine { - .kind = match[1].length() == 0 - ? LsRemoteRefLine::Kind::Object - : LsRemoteRefLine::Kind::Symbolic, + return LsRemoteRefLine{ + .kind = match[1].length() == 0 ? LsRemoteRefLine::Kind::Object : LsRemoteRefLine::Kind::Symbolic, .target = match[2], - .reference = match[3].length() == 0 ? std::nullopt : std::optional{ match[3] } - }; + .reference = match[3].length() == 0 ? std::nullopt : std::optional{match[3]}}; } } diff --git a/src/libutil/git.hh b/src/libutil/git.hh index cb13ef0e5bb1..e6f7a905eb90 100644 --- a/src/libutil/git.hh +++ b/src/libutil/git.hh @@ -23,11 +23,9 @@ namespace git { // {target} {reference} // // where {target} is a commit id and {reference} is mandatory -struct LsRemoteRefLine { - enum struct Kind { - Symbolic, - Object - }; +struct LsRemoteRefLine +{ + enum struct Kind { Symbolic, Object }; Kind kind; std::string target; std::optional reference; diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index d2fd0c15a1e5..72de3d9e2415 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -16,59 +16,63 @@ namespace nix { - -static size_t regularHashSize(HashType type) { +static size_t regularHashSize(HashType type) +{ switch (type) { - case htMD5: return md5HashSize; - case htSHA1: return sha1HashSize; - case htSHA256: return sha256HashSize; - case htSHA512: return sha512HashSize; + case htMD5: + return md5HashSize; + case htSHA1: + return sha1HashSize; + case htSHA256: + return sha256HashSize; + case htSHA512: + return sha512HashSize; } abort(); } +std::set hashTypes = {"md5", "sha1", "sha256", "sha512"}; -std::set hashTypes = { "md5", "sha1", "sha256", "sha512" }; - - -Hash::Hash(HashType type) : type(type) +Hash::Hash(HashType type) + : type(type) { hashSize = regularHashSize(type); assert(hashSize <= maxHashSize); memset(hash, 0, maxHashSize); } - -bool Hash::operator == (const Hash & h2) const +bool Hash::operator==(const Hash & h2) const { - if (hashSize != h2.hashSize) return false; + if (hashSize != h2.hashSize) + return false; for (unsigned int i = 0; i < hashSize; i++) - if (hash[i] != h2.hash[i]) return false; + if (hash[i] != h2.hash[i]) + return false; return true; } - -bool Hash::operator != (const Hash & h2) const +bool Hash::operator!=(const Hash & h2) const { return !(*this == h2); } - -bool Hash::operator < (const Hash & h) const +bool Hash::operator<(const Hash & h) const { - if (hashSize < h.hashSize) return true; - if (hashSize > h.hashSize) return false; + if (hashSize < h.hashSize) + return true; + if (hashSize > h.hashSize) + return false; for (unsigned int i = 0; i < hashSize; i++) { - if (hash[i] < h.hash[i]) return true; - if (hash[i] > h.hash[i]) return false; + if (hash[i] < h.hash[i]) + return true; + if (hash[i] > h.hash[i]) + return false; } return false; } - const std::string base16Chars = "0123456789abcdef"; - static std::string printHash16(const Hash & hash) { char buf[hash.hashSize * 2]; @@ -79,11 +83,9 @@ static std::string printHash16(const Hash & hash) return std::string(buf, hash.hashSize * 2); } - // omitted: E O U T const std::string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz"; - static std::string printHash32(const Hash & hash) { assert(hash.hashSize); @@ -97,23 +99,19 @@ static std::string printHash32(const Hash & hash) unsigned int b = n * 5; unsigned int i = b / 8; unsigned int j = b % 8; - unsigned char c = - (hash.hash[i] >> j) - | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j)); + unsigned char c = (hash.hash[i] >> j) | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j)); s.push_back(base32Chars[c & 0x1f]); } return s; } - std::string printHash16or32(const Hash & hash) { assert(hash.type); return hash.to_string(hash.type == htMD5 ? Base16 : Base32, false); } - std::string Hash::to_string(Base base, bool includeType) const { std::string s; @@ -138,7 +136,8 @@ std::string Hash::to_string(Base base, bool includeType) const Hash Hash::dummy(htSHA256); -Hash Hash::parseSRI(std::string_view original) { +Hash Hash::parseSRI(std::string_view original) +{ auto rest = original; // Parse the has type before the separater, if there was one. @@ -212,16 +211,17 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI) if (!isSRI && rest.size() == base16Len()) { auto parseHexDigit = [&](char c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; throw BadHash("invalid base-16 hash '%s'", rest); }; for (unsigned int i = 0; i < hashSize; i++) { - hash[i] = - parseHexDigit(rest[i * 2]) << 4 - | parseHexDigit(rest[i * 2 + 1]); + hash[i] = parseHexDigit(rest[i * 2]) << 4 | parseHexDigit(rest[i * 2 + 1]); } } @@ -231,7 +231,8 @@ Hash::Hash(std::string_view rest, HashType type, bool isSRI) char c = rest[rest.size() - n - 1]; unsigned char digit; for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */ - if (base32Chars[digit] == c) break; + if (base32Chars[digit] == c) + break; if (digit >= 32) throw BadHash("invalid base-32 hash '%s'", rest); unsigned int b = n * 5; @@ -272,7 +273,6 @@ Hash newHashAllowEmpty(std::string_view hashStr, std::optional ht) return Hash::parseAny(hashStr, ht); } - union Ctx { MD5_CTX md5; @@ -281,35 +281,42 @@ union Ctx SHA512_CTX sha512; }; - static void start(HashType ht, Ctx & ctx) { - if (ht == htMD5) MD5_Init(&ctx.md5); - else if (ht == htSHA1) SHA1_Init(&ctx.sha1); - else if (ht == htSHA256) SHA256_Init(&ctx.sha256); - else if (ht == htSHA512) SHA512_Init(&ctx.sha512); + if (ht == htMD5) + MD5_Init(&ctx.md5); + else if (ht == htSHA1) + SHA1_Init(&ctx.sha1); + else if (ht == htSHA256) + SHA256_Init(&ctx.sha256); + else if (ht == htSHA512) + SHA512_Init(&ctx.sha512); } - -static void update(HashType ht, Ctx & ctx, - std::string_view data) +static void update(HashType ht, Ctx & ctx, std::string_view data) { - if (ht == htMD5) MD5_Update(&ctx.md5, data.data(), data.size()); - else if (ht == htSHA1) SHA1_Update(&ctx.sha1, data.data(), data.size()); - else if (ht == htSHA256) SHA256_Update(&ctx.sha256, data.data(), data.size()); - else if (ht == htSHA512) SHA512_Update(&ctx.sha512, data.data(), data.size()); + if (ht == htMD5) + MD5_Update(&ctx.md5, data.data(), data.size()); + else if (ht == htSHA1) + SHA1_Update(&ctx.sha1, data.data(), data.size()); + else if (ht == htSHA256) + SHA256_Update(&ctx.sha256, data.data(), data.size()); + else if (ht == htSHA512) + SHA512_Update(&ctx.sha512, data.data(), data.size()); } - static void finish(HashType ht, Ctx & ctx, unsigned char * hash) { - if (ht == htMD5) MD5_Final(hash, &ctx.md5); - else if (ht == htSHA1) SHA1_Final(hash, &ctx.sha1); - else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256); - else if (ht == htSHA512) SHA512_Final(hash, &ctx.sha512); + if (ht == htMD5) + MD5_Final(hash, &ctx.md5); + else if (ht == htSHA1) + SHA1_Final(hash, &ctx.sha1); + else if (ht == htSHA256) + SHA256_Final(hash, &ctx.sha256); + else if (ht == htSHA512) + SHA512_Final(hash, &ctx.sha512); } - Hash hashString(HashType ht, std::string_view s) { Ctx ctx; @@ -320,7 +327,6 @@ Hash hashString(HashType ht, std::string_view s) return hash; } - Hash hashFile(HashType ht, const Path & path) { HashSink sink(ht); @@ -328,8 +334,8 @@ Hash hashFile(HashType ht, const Path & path) return sink.finish().first; } - -HashSink::HashSink(HashType ht) : ht(ht) +HashSink::HashSink(HashType ht) + : ht(ht) { ctx = new Ctx; bytes = 0; @@ -365,16 +371,13 @@ HashResult HashSink::currentHash() return HashResult(hash, bytes); } - -HashResult hashPath( - HashType ht, const Path & path, PathFilter & filter) +HashResult hashPath(HashType ht, const Path & path, PathFilter & filter) { HashSink sink(ht); dumpPath(path, sink, filter); return sink.finish(); } - Hash compressHash(const Hash & hash, unsigned int newSize) { Hash h(hash.type); @@ -384,14 +387,18 @@ Hash compressHash(const Hash & hash, unsigned int newSize) return h; } - std::optional parseHashTypeOpt(std::string_view s) { - if (s == "md5") return htMD5; - else if (s == "sha1") return htSHA1; - else if (s == "sha256") return htSHA256; - else if (s == "sha512") return htSHA512; - else return std::optional {}; + if (s == "md5") + return htMD5; + else if (s == "sha1") + return htSHA1; + else if (s == "sha256") + return htSHA256; + else if (s == "sha512") + return htSHA512; + else + return std::optional{}; } HashType parseHashType(std::string_view s) @@ -406,10 +413,14 @@ HashType parseHashType(std::string_view s) std::string printHashType(HashType ht) { switch (ht) { - case htMD5: return "md5"; - case htSHA1: return "sha1"; - case htSHA256: return "sha256"; - case htSHA512: return "sha512"; + case htMD5: + return "md5"; + case htSHA1: + return "sha1"; + case htSHA256: + return "sha256"; + case htSHA512: + return "sha512"; default: // illegal hash type enum value internally, as opposed to external input // which should be validated with nice error message. diff --git a/src/libutil/hash.hh b/src/libutil/hash.hh index 00f70a572957..23f577cbd778 100644 --- a/src/libutil/hash.hh +++ b/src/libutil/hash.hh @@ -3,16 +3,12 @@ #include "types.hh" #include "serialise.hh" - namespace nix { - MakeError(BadHash, Error); - enum HashType : char { htMD5 = 42, htSHA1, htSHA256, htSHA512 }; - const int md5HashSize = 16; const int sha1HashSize = 20; const int sha256HashSize = 32; @@ -24,7 +20,6 @@ extern const std::string base32Chars; enum Base : int { Base64, Base32, Base16, SRI }; - struct Hash { constexpr static size_t maxHashSize = 64; @@ -60,13 +55,13 @@ private: public: /* Check whether two hash are equal. */ - bool operator == (const Hash & h2) const; + bool operator==(const Hash & h2) const; /* Check whether two hash are not equal. */ - bool operator != (const Hash & h2) const; + bool operator!=(const Hash & h2) const; /* For sorting. */ - bool operator < (const Hash & h) const; + bool operator<(const Hash & h) const; /* Returns the length of a base-16 representation of this hash. */ size_t base16Len() const @@ -119,8 +114,7 @@ Hash hashFile(HashType ht, const Path & path); /* Compute the hash of the given path. The hash is defined as (essentially) hashString(ht, dumpPath(path)). */ typedef std::pair HashResult; -HashResult hashPath(HashType ht, const Path & path, - PathFilter & filter = defaultPathFilter); +HashResult hashPath(HashType ht, const Path & path, PathFilter & filter = defaultPathFilter); /* Compress a hash to the specified number of bytes by cyclically XORing bytes together. */ @@ -135,7 +129,6 @@ std::optional parseHashTypeOpt(std::string_view s); /* And the reverse. */ std::string printHashType(HashType ht); - union Ctx; struct AbstractHashSink : virtual Sink @@ -159,5 +152,4 @@ public: HashResult currentHash(); }; - } diff --git a/src/libutil/hilite.cc b/src/libutil/hilite.cc index e5088230d7c3..01f2b878719a 100644 --- a/src/libutil/hilite.cc +++ b/src/libutil/hilite.cc @@ -2,19 +2,15 @@ namespace nix { -std::string hiliteMatches( - std::string_view s, - std::vector matches, - std::string_view prefix, - std::string_view postfix) +std::string +hiliteMatches(std::string_view s, std::vector matches, std::string_view prefix, std::string_view postfix) { // Avoid extra work on zero matches if (matches.size() == 0) return std::string(s); - std::sort(matches.begin(), matches.end(), [](const auto & a, const auto & b) { - return a.position() < b.position(); - }); + std::sort( + matches.begin(), matches.end(), [](const auto & a, const auto & b) { return a.position() < b.position(); }); std::string out; ssize_t last_end = 0; diff --git a/src/libutil/hilite.hh b/src/libutil/hilite.hh index f8bdbfc5515c..23ce2ff825de 100644 --- a/src/libutil/hilite.hh +++ b/src/libutil/hilite.hh @@ -11,10 +11,7 @@ namespace nix { If some matches overlap, then their union will be wrapped rather than the individual matches. */ -std::string hiliteMatches( - std::string_view s, - std::vector matches, - std::string_view prefix, - std::string_view postfix); +std::string +hiliteMatches(std::string_view s, std::vector matches, std::string_view prefix, std::string_view postfix); } diff --git a/src/libutil/json-utils.hh b/src/libutil/json-utils.hh index b8a03122743a..470587b50c7d 100644 --- a/src/libutil/json-utils.hh +++ b/src/libutil/json-utils.hh @@ -7,14 +7,16 @@ namespace nix { const nlohmann::json * get(const nlohmann::json & map, const std::string & key) { auto i = map.find(key); - if (i == map.end()) return nullptr; + if (i == map.end()) + return nullptr; return &*i; } nlohmann::json * get(nlohmann::json & map, const std::string & key) { auto i = map.find(key); - if (i == map.end()) return nullptr; + if (i == map.end()) + return nullptr; return &*i; } diff --git a/src/libutil/json.cc b/src/libutil/json.cc index b0a5d7e75821..59147add3404 100644 --- a/src/libutil/json.cc +++ b/src/libutil/json.cc @@ -16,27 +16,34 @@ void toJSON(std::ostream & str, const char * start, const char * end) str.write(buf, bufPos); bufPos = 0; }; - const auto put = [&] (char c) { - buf[bufPos++] = c; - }; + const auto put = [&](char c) { buf[bufPos++] = c; }; put('"'); for (auto i = start; i != end; i++) { - if (bufPos >= BUF_SIZE) flush(); - if (*i == '\"' || *i == '\\') { put('\\'); put(*i); } - else if (*i == '\n') { put('\\'); put('n'); } - else if (*i == '\r') { put('\\'); put('r'); } - else if (*i == '\t') { put('\\'); put('t'); } - else if (*i >= 0 && *i < 32) { + if (bufPos >= BUF_SIZE) + flush(); + if (*i == '\"' || *i == '\\') { + put('\\'); + put(*i); + } else if (*i == '\n') { + put('\\'); + put('n'); + } else if (*i == '\r') { + put('\\'); + put('r'); + } else if (*i == '\t') { + put('\\'); + put('t'); + } else if (*i >= 0 && *i < 32) { const char hex[17] = "0123456789abcdef"; put('\\'); put('u'); put(hex[(uint16_t(*i) >> 12) & 0xf]); - put(hex[(uint16_t(*i) >> 8) & 0xf]); - put(hex[(uint16_t(*i) >> 4) & 0xf]); - put(hex[(uint16_t(*i) >> 0) & 0xf]); - } - else put(*i); + put(hex[(uint16_t(*i) >> 8) & 0xf]); + put(hex[(uint16_t(*i) >> 4) & 0xf]); + put(hex[(uint16_t(*i) >> 0) & 0xf]); + } else + put(*i); } put('"'); flush(); @@ -44,29 +51,67 @@ void toJSON(std::ostream & str, const char * start, const char * end) void toJSON(std::ostream & str, const char * s) { - if (!s) str << "null"; else toJSON(str, s, s + strlen(s)); + if (!s) + str << "null"; + else + toJSON(str, s, s + strlen(s)); } -template<> void toJSON(std::ostream & str, const int & n) { str << n; } -template<> void toJSON(std::ostream & str, const unsigned int & n) { str << n; } -template<> void toJSON(std::ostream & str, const long & n) { str << n; } -template<> void toJSON(std::ostream & str, const unsigned long & n) { str << n; } -template<> void toJSON(std::ostream & str, const long long & n) { str << n; } -template<> void toJSON(std::ostream & str, const unsigned long long & n) { str << n; } -template<> void toJSON(std::ostream & str, const float & n) { str << n; } -template<> void toJSON(std::ostream & str, const double & n) { str << n; } +template<> +void toJSON(std::ostream & str, const int & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const unsigned int & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const long & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const unsigned long & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const long long & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const unsigned long long & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const float & n) +{ + str << n; +} +template<> +void toJSON(std::ostream & str, const double & n) +{ + str << n; +} -template<> void toJSON(std::ostream & str, const std::string & s) +template<> +void toJSON(std::ostream & str, const std::string & s) { toJSON(str, s.c_str(), s.c_str() + s.size()); } -template<> void toJSON(std::ostream & str, const bool & b) +template<> +void toJSON(std::ostream & str, const bool & b) { str << (b ? "true" : "false"); } -template<> void toJSON(std::ostream & str, const std::nullptr_t & b) +template<> +void toJSON(std::ostream & str, const std::nullptr_t & b) { str << "null"; } @@ -88,7 +133,8 @@ JSONWriter::~JSONWriter() if (state) { assertActive(); state->stack--; - if (state->stack == 0) delete state; + if (state->stack == 0) + delete state; } } @@ -100,7 +146,8 @@ void JSONWriter::comma() } else { state->str << ','; } - if (state->indent) indent(); + if (state->indent) + indent(); } void JSONWriter::indent() @@ -117,7 +164,8 @@ void JSONList::open() JSONList::~JSONList() { state->depth--; - if (state->indent && !first) indent(); + if (state->indent && !first) + indent(); state->str << "]"; } @@ -149,7 +197,8 @@ JSONObject::~JSONObject() { if (state) { state->depth--; - if (state->indent && !first) indent(); + if (state->indent && !first) + indent(); state->str << "}"; } } @@ -159,7 +208,8 @@ void JSONObject::attr(const std::string & s) comma(); toJSON(state->str, s); state->str << ':'; - if (state->indent) state->str << ' '; + if (state->indent) + state->str << ' '; } JSONList JSONObject::list(const std::string & name) diff --git a/src/libutil/json.hh b/src/libutil/json.hh index 83213ca6664c..ded36124c959 100644 --- a/src/libutil/json.hh +++ b/src/libutil/json.hh @@ -22,7 +22,10 @@ protected: bool indent; size_t depth = 0; size_t stack = 0; - JSONState(std::ostream & str, bool indent) : str(str), indent(indent) { } + JSONState(std::ostream & str, bool indent) + : str(str) + , indent(indent) + {} ~JSONState() { assert(stack == 0); @@ -152,8 +155,7 @@ private: JSONPlaceholder(JSONState * state) : JSONWriter(state) - { - } + {} void assertValid() { @@ -165,8 +167,7 @@ public: JSONPlaceholder(std::ostream & str, bool indent = false) : JSONWriter(str, indent) - { - } + {} ~JSONPlaceholder(); diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc index cb2b15b41aad..6acaff18117f 100644 --- a/src/libutil/logging.cc +++ b/src/libutil/logging.cc @@ -49,24 +49,36 @@ class SimpleLogger : public Logger tty = shouldANSI(); } - bool isVerbose() override { + bool isVerbose() override + { return printBuildLogs; } void log(Verbosity lvl, const FormatOrString & fs) override { - if (lvl > verbosity) return; + if (lvl > verbosity) + return; std::string prefix; if (systemd) { char c; switch (lvl) { - case lvlError: c = '3'; break; - case lvlWarn: c = '4'; break; - case lvlInfo: c = '5'; break; - case lvlTalkative: case lvlChatty: c = '6'; break; - default: c = '7'; + case lvlError: + c = '3'; + break; + case lvlWarn: + c = '4'; + break; + case lvlInfo: + c = '5'; + break; + case lvlTalkative: + case lvlChatty: + c = '6'; + break; + default: + c = '7'; } prefix = std::string("<") + c + ">"; } @@ -82,9 +94,13 @@ class SimpleLogger : public Logger log(ei.level, oss.str()); } - void startActivity(ActivityId act, Verbosity lvl, ActivityType type, - const std::string & s, const Fields & fields, ActivityId parent) - override + void startActivity( + ActivityId act, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Fields & fields, + ActivityId parent) override { if (lvl <= verbosity && !s.empty()) log(lvl, s + "..."); @@ -95,8 +111,7 @@ class SimpleLogger : public Logger if (type == resBuildLogLine && printBuildLogs) { auto lastLine = fields[0].s; printError(lastLine); - } - else if (type == resPostBuildLogLine && printBuildLogs) { + } else if (type == resPostBuildLogLine && printBuildLogs) { auto lastLine = fields[0].s; printError("post-build-hook: " + lastLine); } @@ -132,25 +147,36 @@ Logger * makeSimpleLogger(bool printBuildLogs) std::atomic nextId{(uint64_t) getpid() << 32}; -Activity::Activity(Logger & logger, Verbosity lvl, ActivityType type, - const std::string & s, const Logger::Fields & fields, ActivityId parent) - : logger(logger), id(nextId++) +Activity::Activity( + Logger & logger, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Logger::Fields & fields, + ActivityId parent) + : logger(logger) + , id(nextId++) { logger.startActivity(id, lvl, type, s, fields, parent); } -struct JSONLogger : Logger { +struct JSONLogger : Logger +{ Logger & prevLogger; - JSONLogger(Logger & prevLogger) : prevLogger(prevLogger) { } + JSONLogger(Logger & prevLogger) + : prevLogger(prevLogger) + {} - bool isVerbose() override { + bool isVerbose() override + { return true; } void addFields(nlohmann::json & json, const Fields & fields) { - if (fields.empty()) return; + if (fields.empty()) + return; auto & arr = json["fields"] = nlohmann::json::array(); for (auto & f : fields) if (f.type == Logger::Field::tInt) @@ -215,8 +241,13 @@ struct JSONLogger : Logger { write(json); } - void startActivity(ActivityId act, Verbosity lvl, ActivityType type, - const std::string & s, const Fields & fields, ActivityId parent) override + void startActivity( + ActivityId act, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Fields & fields, + ActivityId parent) override { nlohmann::json json; json["action"] = "start"; @@ -261,14 +292,16 @@ static Logger::Fields getFields(nlohmann::json & json) fields.emplace_back(Logger::Field(f.get())); else if (f.type() == nlohmann::json::value_t::string) fields.emplace_back(Logger::Field(f.get())); - else throw Error("unsupported JSON type %d", (int) f.type()); + else + throw Error("unsupported JSON type %d", (int) f.type()); } return fields; } std::optional parseJSONMessage(const std::string & msg) { - if (!hasPrefix(msg, "@nix ")) return std::nullopt; + if (!hasPrefix(msg, "@nix ")) + return std::nullopt; try { return nlohmann::json::parse(std::string(msg, 5)); } catch (std::exception & e) { @@ -277,19 +310,18 @@ std::optional parseJSONMessage(const std::string & msg) return std::nullopt; } -bool handleJSONLogMessage(nlohmann::json & json, - const Activity & act, std::map & activities, - bool trusted) +bool handleJSONLogMessage( + nlohmann::json & json, const Activity & act, std::map & activities, bool trusted) { std::string action = json["action"]; if (action == "start") { auto type = (ActivityType) json["type"]; if (trusted || type == actFileTransfer) - activities.emplace(std::piecewise_construct, - std::forward_as_tuple(json["id"]), - std::forward_as_tuple(*logger, (Verbosity) json["level"], type, - json["text"], getFields(json["fields"]), act.id)); + activities.emplace( + std::piecewise_construct, std::forward_as_tuple(json["id"]), + std::forward_as_tuple( + *logger, (Verbosity) json["level"], type, json["text"], getFields(json["fields"]), act.id)); } else if (action == "stop") @@ -314,11 +346,12 @@ bool handleJSONLogMessage(nlohmann::json & json, return true; } -bool handleJSONLogMessage(const std::string & msg, - const Activity & act, std::map & activities, bool trusted) +bool handleJSONLogMessage( + const std::string & msg, const Activity & act, std::map & activities, bool trusted) { auto json = parseJSONMessage(msg); - if (!json) return false; + if (!json) + return false; return handleJSONLogMessage(*json, act, activities, trusted); } diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index 6f81b92de07d..82ef3c6bfc5a 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -61,19 +61,31 @@ public: enum { tInt = 0, tString = 1 } type; uint64_t i = 0; std::string s; - Field(const std::string & s) : type(tString), s(s) { } - Field(const char * s) : type(tString), s(s) { } - Field(const uint64_t & i) : type(tInt), i(i) { } + Field(const std::string & s) + : type(tString) + , s(s) + {} + Field(const char * s) + : type(tString) + , s(s) + {} + Field(const uint64_t & i) + : type(tInt) + , i(i) + {} }; typedef std::vector Fields; - virtual ~Logger() { } + virtual ~Logger() {} - virtual void stop() { }; + virtual void stop(){}; // Whether the logger prints the whole build log - virtual bool isVerbose() { return false; } + virtual bool isVerbose() + { + return false; + } virtual void log(Verbosity lvl, const FormatOrString & fs) = 0; @@ -82,7 +94,7 @@ public: log(lvlInfo, fs); } - virtual void logEI(const ErrorInfo &ei) = 0; + virtual void logEI(const ErrorInfo & ei) = 0; void logEI(Verbosity lvl, ErrorInfo ei) { @@ -92,17 +104,22 @@ public: virtual void warn(const std::string & msg); - virtual void startActivity(ActivityId act, Verbosity lvl, ActivityType type, - const std::string & s, const Fields & fields, ActivityId parent) { }; + virtual void startActivity( + ActivityId act, + Verbosity lvl, + ActivityType type, + const std::string & s, + const Fields & fields, + ActivityId parent){}; - virtual void stopActivity(ActivityId act) { }; + virtual void stopActivity(ActivityId act){}; - virtual void result(ActivityId act, ResultType type, const Fields & fields) { }; + virtual void result(ActivityId act, ResultType type, const Fields & fields){}; virtual void writeToStdout(std::string_view s); template - inline void cout(const std::string & fs, const Args & ... args) + inline void cout(const std::string & fs, const Args &... args) { boost::format f(fs); formatHelper(f, args...); @@ -110,7 +127,9 @@ public: } virtual std::optional ask(std::string_view s) - { return {}; } + { + return {}; + } }; ActivityId getCurActivity(); @@ -122,25 +141,34 @@ struct Activity const ActivityId id; - Activity(Logger & logger, Verbosity lvl, ActivityType type, const std::string & s = "", - const Logger::Fields & fields = {}, ActivityId parent = getCurActivity()); + Activity( + Logger & logger, + Verbosity lvl, + ActivityType type, + const std::string & s = "", + const Logger::Fields & fields = {}, + ActivityId parent = getCurActivity()); - Activity(Logger & logger, ActivityType type, - const Logger::Fields & fields = {}, ActivityId parent = getCurActivity()) - : Activity(logger, lvlError, type, "", fields, parent) { }; + Activity( + Logger & logger, ActivityType type, const Logger::Fields & fields = {}, ActivityId parent = getCurActivity()) + : Activity(logger, lvlError, type, "", fields, parent){}; Activity(const Activity & act) = delete; ~Activity(); void progress(uint64_t done = 0, uint64_t expected = 0, uint64_t running = 0, uint64_t failed = 0) const - { result(resProgress, done, expected, running, failed); } + { + result(resProgress, done, expected, running, failed); + } void setExpected(ActivityType type2, uint64_t expected) const - { result(resSetExpected, type2, expected); } + { + result(resSetExpected, type2, expected); + } template - void result(ResultType type, const Args & ... args) const + void result(ResultType type, const Args &... args) const { Logger::Fields fields; nop{(fields.emplace_back(Logger::Field(args)), 1)...}; @@ -158,8 +186,15 @@ struct Activity struct PushActivity { const ActivityId prevAct; - PushActivity(ActivityId act) : prevAct(getCurActivity()) { setCurActivity(act); } - ~PushActivity() { setCurActivity(prevAct); } + PushActivity(ActivityId act) + : prevAct(getCurActivity()) + { + setCurActivity(act); + } + ~PushActivity() + { + setCurActivity(prevAct); + } }; extern Logger * logger; @@ -170,13 +205,11 @@ Logger * makeJSONLogger(Logger & prevLogger); std::optional parseJSONMessage(const std::string & msg); -bool handleJSONLogMessage(nlohmann::json & json, - const Activity & act, std::map & activities, - bool trusted); +bool handleJSONLogMessage( + nlohmann::json & json, const Activity & act, std::map & activities, bool trusted); -bool handleJSONLogMessage(const std::string & msg, - const Activity & act, std::map & activities, - bool trusted); +bool handleJSONLogMessage( + const std::string & msg, const Activity & act, std::map & activities, bool trusted); extern Verbosity verbosity; /* suppress msgs > this */ @@ -186,8 +219,8 @@ extern Verbosity verbosity; /* suppress msgs > this */ lightweight status messages. */ #define logErrorInfo(level, errorInfo...) \ do { \ - if ((level) <= nix::verbosity) { \ - logger->logEI((level), errorInfo); \ + if ((level) <= nix::verbosity) { \ + logger->logEI((level), errorInfo); \ } \ } while (0) @@ -215,7 +248,7 @@ extern Verbosity verbosity; /* suppress msgs > this */ /* if verbosity >= lvlWarn, print a message with a yellow 'warning:' prefix. */ template -inline void warn(const std::string & fs, const Args & ... args) +inline void warn(const std::string & fs, const Args &... args) { boost::format f(fs); formatHelper(f, args...); diff --git a/src/libutil/lru-cache.hh b/src/libutil/lru-cache.hh index 6ef4a3e067d6..78c22375b9f4 100644 --- a/src/libutil/lru-cache.hh +++ b/src/libutil/lru-cache.hh @@ -22,19 +22,25 @@ private: using Data = std::map>; using LRU = std::list; - struct LRUIterator { typename LRU::iterator it; }; + struct LRUIterator + { + typename LRU::iterator it; + }; Data data; LRU lru; public: - LRUCache(size_t capacity) : capacity(capacity) { } + LRUCache(size_t capacity) + : capacity(capacity) + {} /* Insert or upsert an item in the cache. */ void upsert(const Key & key, const Value & value) { - if (capacity == 0) return; + if (capacity == 0) + return; erase(key); @@ -57,7 +63,8 @@ public: bool erase(const Key & key) { auto i = data.find(key); - if (i == data.end()) return false; + if (i == data.end()) + return false; lru.erase(i->second.first.it); data.erase(i); return true; @@ -68,7 +75,8 @@ public: std::optional get(const Key & key) { auto i = data.find(key); - if (i == data.end()) return {}; + if (i == data.end()) + return {}; /* Move this item to the back of the LRU list. */ lru.erase(i->second.first.it); diff --git a/src/libutil/monitor-fd.hh b/src/libutil/monitor-fd.hh index 5ee0b88ef50f..c251bc8cb989 100644 --- a/src/libutil/monitor-fd.hh +++ b/src/libutil/monitor-fd.hh @@ -11,7 +11,6 @@ namespace nix { - class MonitorFdHup { private: @@ -22,27 +21,29 @@ public: { thread = std::thread([fd]() { while (true) { - /* Wait indefinitely until a POLLHUP occurs. */ - struct pollfd fds[1]; - fds[0].fd = fd; - /* This shouldn't be necessary, but macOS doesn't seem to - like a zeroed out events field. - See rdar://37537852. - */ - fds[0].events = POLLHUP; - auto count = poll(fds, 1, -1); - if (count == -1) abort(); // can't happen - /* This shouldn't happen, but can on macOS due to a bug. - See rdar://37550628. - - This may eventually need a delay or further - coordination with the main thread if spinning proves - too harmful. - */ - if (count == 0) continue; - assert(fds[0].revents & POLLHUP); - triggerInterrupt(); - break; + /* Wait indefinitely until a POLLHUP occurs. */ + struct pollfd fds[1]; + fds[0].fd = fd; + /* This shouldn't be necessary, but macOS doesn't seem to + like a zeroed out events field. + See rdar://37537852. + */ + fds[0].events = POLLHUP; + auto count = poll(fds, 1, -1); + if (count == -1) + abort(); // can't happen + /* This shouldn't happen, but can on macOS due to a bug. + See rdar://37550628. + + This may eventually need a delay or further + coordination with the main thread if spinning proves + too harmful. + */ + if (count == 0) + continue; + assert(fds[0].revents & POLLHUP); + triggerInterrupt(); + break; } }); }; @@ -54,5 +55,4 @@ public: } }; - } diff --git a/src/libutil/pool.hh b/src/libutil/pool.hh index d49067bb95dc..6df3669e4c75 100644 --- a/src/libutil/pool.hh +++ b/src/libutil/pool.hh @@ -28,7 +28,7 @@ namespace nix { returned to the pool when ‘conn’ goes out of scope. */ -template +template class Pool { public: @@ -58,7 +58,8 @@ private: public: - Pool(size_t max = std::numeric_limits::max(), + Pool( + size_t max = std::numeric_limits::max(), const Factory & factory = []() { return make_ref(); }, const Validator & validator = [](ref r) { return true; }) : factory(factory) @@ -101,16 +102,25 @@ public: friend Pool; - Handle(Pool & pool, std::shared_ptr r) : pool(pool), r(r) { } + Handle(Pool & pool, std::shared_ptr r) + : pool(pool) + , r(r) + {} public: - Handle(Handle && h) : pool(h.pool), r(h.r) { h.r.reset(); } + Handle(Handle && h) + : pool(h.pool) + , r(h.r) + { + h.r.reset(); + } Handle(const Handle & l) = delete; ~Handle() { - if (!r) return; + if (!r) + return; { auto state_(pool.state.lock()); if (!bad) @@ -121,10 +131,19 @@ public: pool.wakeup.notify_one(); } - R * operator -> () { return &*r; } - R & operator * () { return *r; } + R * operator->() + { + return &*r; + } + R & operator*() + { + return *r; + } - void markBad() { bad = true; } + void markBad() + { + bad = true; + } }; Handle get() diff --git a/src/libutil/ref.hh b/src/libutil/ref.hh index bf26321db4ca..2315d74d658e 100644 --- a/src/libutil/ref.hh +++ b/src/libutil/ref.hh @@ -19,7 +19,7 @@ public: ref(const ref & r) : p(r.p) - { } + {} explicit ref(const std::shared_ptr & p) : p(p) @@ -35,17 +35,17 @@ public: throw std::invalid_argument("null pointer cast to ref"); } - T* operator ->() const + T * operator->() const { return &*p; } - T& operator *() const + T & operator*() const { return *p; } - operator std::shared_ptr () const + operator std::shared_ptr() const { return p; } @@ -68,17 +68,17 @@ public: } template - operator ref () const + operator ref() const { return ref((std::shared_ptr) p); } - bool operator == (const ref & other) const + bool operator==(const ref & other) const { return p == other.p; } - bool operator != (const ref & other) const + bool operator!=(const ref & other) const { return p != other.p; } @@ -86,14 +86,11 @@ public: private: template - friend ref - make_ref(Args&&... args); - + friend ref make_ref(Args &&... args); }; template -inline ref -make_ref(Args&&... args) +inline ref make_ref(Args &&... args) { auto p = std::make_shared(std::forward(args)...); return ref(p); diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc index 8ff90458304d..c7ede33ad9b4 100644 --- a/src/libutil/serialise.cc +++ b/src/libutil/serialise.cc @@ -7,13 +7,12 @@ #include - namespace nix { - -void BufferedSink::operator () (std::string_view data) +void BufferedSink::operator()(std::string_view data) { - if (!buffer) buffer = decltype(buffer)(new char[bufSize]); + if (!buffer) + buffer = decltype(buffer)(new char[bufSize]); while (!data.empty()) { /* Optimisation: bypass the buffer if the data exceeds the @@ -27,27 +26,31 @@ void BufferedSink::operator () (std::string_view data) when it's full. */ size_t n = bufPos + data.size() > bufSize ? bufSize - bufPos : data.size(); memcpy(buffer.get() + bufPos, data.data(), n); - data.remove_prefix(n); bufPos += n; - if (bufPos == bufSize) flush(); + data.remove_prefix(n); + bufPos += n; + if (bufPos == bufSize) + flush(); } } - void BufferedSink::flush() { - if (bufPos == 0) return; + if (bufPos == 0) + return; size_t n = bufPos; bufPos = 0; // don't trigger the assert() in ~BufferedSink() write({buffer.get(), n}); } - FdSink::~FdSink() { - try { flush(); } catch (...) { ignoreException(); } + try { + flush(); + } catch (...) { + ignoreException(); + } } - size_t threshold = 256 * 1024 * 1024; static void warnLargeDump() @@ -55,7 +58,6 @@ static void warnLargeDump() warn("dumping very large path (> 256 MiB); this may run out of memory"); } - void FdSink::write(std::string_view data) { written += data.size(); @@ -74,22 +76,20 @@ void FdSink::write(std::string_view data) } } - bool FdSink::good() { return _good; } - -void Source::operator () (char * data, size_t len) +void Source::operator()(char * data, size_t len) { while (len) { size_t n = read(data, len); - data += n; len -= n; + data += n; + len -= n; } } - void Source::drainInto(Sink & sink) { std::string s; @@ -105,7 +105,6 @@ void Source::drainInto(Sink & sink) } } - std::string Source::drain() { StringSink s; @@ -113,28 +112,28 @@ std::string Source::drain() return std::move(s.s); } - size_t BufferedSource::read(char * data, size_t len) { - if (!buffer) buffer = decltype(buffer)(new char[bufSize]); + if (!buffer) + buffer = decltype(buffer)(new char[bufSize]); - if (!bufPosIn) bufPosIn = readUnbuffered(buffer.get(), bufSize); + if (!bufPosIn) + bufPosIn = readUnbuffered(buffer.get(), bufSize); /* Copy out the data in the buffer. */ size_t n = len > bufPosIn - bufPosOut ? bufPosIn - bufPosOut : len; memcpy(data, buffer.get() + bufPosOut, n); bufPosOut += n; - if (bufPosIn == bufPosOut) bufPosIn = bufPosOut = 0; + if (bufPosIn == bufPosOut) + bufPosIn = bufPosOut = 0; return n; } - bool BufferedSource::hasData() { return bufPosOut < bufPosIn; } - size_t FdSource::readUnbuffered(char * data, size_t len) { ssize_t n; @@ -142,64 +141,72 @@ size_t FdSource::readUnbuffered(char * data, size_t len) checkInterrupt(); n = ::read(fd, data, len); } while (n == -1 && errno == EINTR); - if (n == -1) { _good = false; throw SysError("reading from file"); } - if (n == 0) { _good = false; throw EndOfFile("unexpected end-of-file"); } + if (n == -1) { + _good = false; + throw SysError("reading from file"); + } + if (n == 0) { + _good = false; + throw EndOfFile("unexpected end-of-file"); + } read += n; return n; } - bool FdSource::good() { return _good; } - size_t StringSource::read(char * data, size_t len) { - if (pos == s.size()) throw EndOfFile("end of string reached"); + if (pos == s.size()) + throw EndOfFile("end of string reached"); size_t n = s.copy(data, len, pos); pos += n; return n; } - #if BOOST_VERSION >= 106300 && BOOST_VERSION < 106600 #error Coroutines are broken in this version of Boost! #endif /* A concrete datatype allow virtual dispatch of stack allocation methods. */ -struct VirtualStackAllocator { - StackAllocator *allocator = StackAllocator::defaultAllocator; +struct VirtualStackAllocator +{ + StackAllocator * allocator = StackAllocator::defaultAllocator; - boost::context::stack_context allocate() { + boost::context::stack_context allocate() + { return allocator->allocate(); } - void deallocate(boost::context::stack_context sctx) { + void deallocate(boost::context::stack_context sctx) + { allocator->deallocate(sctx); } }; - /* This class reifies the default boost coroutine stack allocation strategy with a virtual interface. */ -class DefaultStackAllocator : public StackAllocator { +class DefaultStackAllocator : public StackAllocator +{ boost::coroutines2::default_stack stack; - boost::context::stack_context allocate() { + boost::context::stack_context allocate() + { return stack.allocate(); } - void deallocate(boost::context::stack_context sctx) { + void deallocate(boost::context::stack_context sctx) + { stack.deallocate(sctx); } }; static DefaultStackAllocator defaultAllocatorSingleton; -StackAllocator *StackAllocator::defaultAllocator = &defaultAllocatorSingleton; - +StackAllocator * StackAllocator::defaultAllocator = &defaultAllocatorSingleton; std::unique_ptr sourceToSink(std::function fun) { @@ -210,24 +217,25 @@ std::unique_ptr sourceToSink(std::function fun) std::function fun; std::optional coro; - SourceToSink(std::function fun) : fun(fun) - { - } + SourceToSink(std::function fun) + : fun(fun) + {} std::string_view cur; - void operator () (std::string_view in) override + void operator()(std::string_view in) override { - if (in.empty()) return; + if (in.empty()) + return; cur = in; if (!coro) coro = coro_t::push_type(VirtualStackAllocator{}, [&](coro_t::pull_type & yield) { - LambdaSource source([&](char *out, size_t out_len) { + LambdaSource source([&](char * out, size_t out_len) { if (cur.empty()) { yield(); if (yield.get()) { - return (size_t)0; + return (size_t) 0; } } @@ -239,27 +247,30 @@ std::unique_ptr sourceToSink(std::function fun) fun(source); }); - if (!*coro) { abort(); } + if (!*coro) { + abort(); + } - if (!cur.empty()) (*coro)(false); + if (!cur.empty()) + (*coro)(false); } void finish() override { - if (!coro) return; - if (!*coro) abort(); + if (!coro) + return; + if (!*coro) + abort(); (*coro)(true); - if (*coro) abort(); + if (*coro) + abort(); } }; return std::make_unique(fun); } - -std::unique_ptr sinkToSource( - std::function fun, - std::function eof) +std::unique_ptr sinkToSource(std::function fun, std::function eof) { struct SinkToSource : Source { @@ -270,9 +281,9 @@ std::unique_ptr sinkToSource( std::optional coro; SinkToSource(std::function fun, std::function eof) - : fun(fun), eof(eof) - { - } + : fun(fun) + , eof(eof) + {} std::string cur; size_t pos = 0; @@ -282,15 +293,20 @@ std::unique_ptr sinkToSource( if (!coro) coro = coro_t::pull_type(VirtualStackAllocator{}, [&](coro_t::push_type & yield) { LambdaSink sink([&](std::string_view data) { - if (!data.empty()) yield(std::string(data)); + if (!data.empty()) + yield(std::string(data)); }); fun(sink); }); - if (!*coro) { eof(); abort(); } + if (!*coro) { + eof(); + abort(); + } if (pos == cur.size()) { - if (!cur.empty()) (*coro)(); + if (!cur.empty()) + (*coro)(); cur = coro->get(); pos = 0; } @@ -306,7 +322,6 @@ std::unique_ptr sinkToSource( return std::make_unique(fun, eof); } - void writePadding(size_t len, Sink & sink) { if (len % 8) { @@ -316,7 +331,6 @@ void writePadding(size_t len, Sink & sink) } } - void writeString(std::string_view data, Sink & sink) { sink << data.size(); @@ -324,43 +338,38 @@ void writeString(std::string_view data, Sink & sink) writePadding(data.size(), sink); } - -Sink & operator << (Sink & sink, std::string_view s) +Sink & operator<<(Sink & sink, std::string_view s) { writeString(s, sink); return sink; } - -template void writeStrings(const T & ss, Sink & sink) +template +void writeStrings(const T & ss, Sink & sink) { sink << ss.size(); for (auto & i : ss) sink << i; } -Sink & operator << (Sink & sink, const Strings & s) +Sink & operator<<(Sink & sink, const Strings & s) { writeStrings(s, sink); return sink; } -Sink & operator << (Sink & sink, const StringSet & s) +Sink & operator<<(Sink & sink, const StringSet & s) { writeStrings(s, sink); return sink; } -Sink & operator << (Sink & sink, const Error & ex) +Sink & operator<<(Sink & sink, const Error & ex) { auto info = ex.info(); - sink - << "Error" - << info.level - << "Error" // removed - << info.msg.str() - << 0 // FIXME: info.errPos - << info.traces.size(); + sink << "Error" << info.level << "Error" // removed + << info.msg.str() << 0 // FIXME: info.errPos + << info.traces.size(); for (auto & trace : info.traces) { sink << 0; // FIXME: trace.pos sink << trace.hint.str(); @@ -368,7 +377,6 @@ Sink & operator << (Sink & sink, const Error & ex) return sink; } - void readPadding(size_t len, Source & source) { if (len % 8) { @@ -376,39 +384,40 @@ void readPadding(size_t len, Source & source) size_t n = 8 - (len % 8); source(zero, n); for (unsigned int i = 0; i < n; i++) - if (zero[i]) throw SerialisationError("non-zero padding"); + if (zero[i]) + throw SerialisationError("non-zero padding"); } } - size_t readString(char * buf, size_t max, Source & source) { auto len = readNum(source); - if (len > max) throw SerialisationError("string is too long"); + if (len > max) + throw SerialisationError("string is too long"); source(buf, len); readPadding(len, source); return len; } - std::string readString(Source & source, size_t max) { auto len = readNum(source); - if (len > max) throw SerialisationError("string is too long"); + if (len > max) + throw SerialisationError("string is too long"); std::string res(len, 0); source(res.data(), len); readPadding(len, source); return res; } -Source & operator >> (Source & in, std::string & s) +Source & operator>>(Source & in, std::string & s) { s = readString(in); return in; } - -template T readStrings(Source & source) +template +T readStrings(Source & source) { auto count = readNum(source); T ss; @@ -420,7 +429,6 @@ template T readStrings(Source & source) template Paths readStrings(Source & source); template PathSet readStrings(Source & source); - Error readError(Source & source) { auto type = readString(source); @@ -428,7 +436,7 @@ Error readError(Source & source) auto level = (Verbosity) readInt(source); auto name = readString(source); // removed auto msg = readString(source); - ErrorInfo info { + ErrorInfo info{ .level = level, .msg = hintformat(std::move(format("%s") % msg)), }; @@ -438,15 +446,12 @@ Error readError(Source & source) for (size_t i = 0; i < nrTraces; ++i) { havePos = readNum(source); assert(havePos == 0); - info.traces.push_back(Trace { - .hint = hintformat(std::move(format("%s") % readString(source))) - }); + info.traces.push_back(Trace{.hint = hintformat(std::move(format("%s") % readString(source)))}); } return Error(std::move(info)); } - -void StringSink::operator () (std::string_view data) +void StringSink::operator()(std::string_view data) { static bool warned = false; if (!warned && s.size() > threshold) { diff --git a/src/libutil/serialise.hh b/src/libutil/serialise.hh index 13da26c6acbc..222ab308c83b 100644 --- a/src/libutil/serialise.hh +++ b/src/libutil/serialise.hh @@ -5,33 +5,34 @@ #include "types.hh" #include "util.hh" -namespace boost::context { struct stack_context; } +namespace boost::context { +struct stack_context; +} namespace nix { - /* Abstract destination of binary data. */ struct Sink { - virtual ~Sink() { } - virtual void operator () (std::string_view data) = 0; - virtual bool good() { return true; } + virtual ~Sink() {} + virtual void operator()(std::string_view data) = 0; + virtual bool good() + { + return true; + } }; /* Just throws away data. */ struct NullSink : Sink { - void operator () (std::string_view data) override - { } + void operator()(std::string_view data) override {} }; - struct FinishSink : virtual Sink { virtual void finish() = 0; }; - /* A buffered abstract sink. Warning: a BufferedSink should not be used from multiple threads concurrently. */ struct BufferedSink : virtual Sink @@ -40,39 +41,43 @@ struct BufferedSink : virtual Sink std::unique_ptr buffer; BufferedSink(size_t bufSize = 32 * 1024) - : bufSize(bufSize), bufPos(0), buffer(nullptr) { } + : bufSize(bufSize) + , bufPos(0) + , buffer(nullptr) + {} - void operator () (std::string_view data) override; + void operator()(std::string_view data) override; void flush(); virtual void write(std::string_view data) = 0; }; - /* Abstract source of binary data. */ struct Source { - virtual ~Source() { } + virtual ~Source() {} /* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’. It blocks until all the requested data is available, or throws an error if it is not going to be available. */ - void operator () (char * data, size_t len); + void operator()(char * data, size_t len); /* Store up to ‘len’ in the buffer pointed to by ‘data’, and return the number of bytes stored. It blocks until at least one byte is available. */ virtual size_t read(char * data, size_t len) = 0; - virtual bool good() { return true; } + virtual bool good() + { + return true; + } void drainInto(Sink & sink); std::string drain(); }; - /* A buffered abstract source. Warning: a BufferedSource should not be used from multiple threads concurrently. */ struct BufferedSource : Source @@ -81,7 +86,11 @@ struct BufferedSource : Source std::unique_ptr buffer; BufferedSource(size_t bufSize = 32 * 1024) - : bufSize(bufSize), bufPosIn(0), bufPosOut(0), buffer(nullptr) { } + : bufSize(bufSize) + , bufPosIn(0) + , bufPosOut(0) + , buffer(nullptr) + {} size_t read(char * data, size_t len) override; @@ -92,7 +101,6 @@ protected: virtual size_t readUnbuffered(char * data, size_t len) = 0; }; - /* A sink that writes data to a file descriptor. */ struct FdSink : BufferedSink { @@ -100,11 +108,15 @@ struct FdSink : BufferedSink bool warn = false; size_t written = 0; - FdSink() : fd(-1) { } - FdSink(int fd) : fd(fd) { } - FdSink(FdSink&&) = default; + FdSink() + : fd(-1) + {} + FdSink(int fd) + : fd(fd) + {} + FdSink(FdSink &&) = default; - FdSink& operator=(FdSink && s) + FdSink & operator=(FdSink && s) { flush(); fd = s.fd; @@ -124,18 +136,21 @@ private: bool _good = true; }; - /* A source that reads data from a file descriptor. */ struct FdSource : BufferedSource { int fd; size_t read = 0; - FdSource() : fd(-1) { } - FdSource(int fd) : fd(fd) { } - FdSource(FdSource&&) = default; + FdSource() + : fd(-1) + {} + FdSource(int fd) + : fd(fd) + {} + FdSource(FdSource &&) = default; - FdSource& operator=(FdSource && s) + FdSource & operator=(FdSource && s) { fd = s.fd; s.fd = -1; @@ -150,51 +165,56 @@ private: bool _good = true; }; - /* A sink that writes data to a string. */ struct StringSink : Sink { std::string s; - StringSink() { } + StringSink() {} explicit StringSink(const size_t reservedSize) { - s.reserve(reservedSize); + s.reserve(reservedSize); }; - StringSink(std::string && s) : s(std::move(s)) { }; - void operator () (std::string_view data) override; + StringSink(std::string && s) + : s(std::move(s)){}; + void operator()(std::string_view data) override; }; - /* A source that reads data from a string. */ struct StringSource : Source { std::string_view s; size_t pos; - StringSource(std::string_view s) : s(s), pos(0) { } + StringSource(std::string_view s) + : s(s) + , pos(0) + {} size_t read(char * data, size_t len) override; }; - /* A sink that writes all incoming data to two other sinks. */ struct TeeSink : Sink { - Sink & sink1, & sink2; - TeeSink(Sink & sink1, Sink & sink2) : sink1(sink1), sink2(sink2) { } - virtual void operator () (std::string_view data) + Sink &sink1, &sink2; + TeeSink(Sink & sink1, Sink & sink2) + : sink1(sink1) + , sink2(sink2) + {} + virtual void operator()(std::string_view data) { sink1(data); sink2(data); } }; - /* Adapter class of a Source that saves all data read to a sink. */ struct TeeSource : Source { Source & orig; Sink & sink; TeeSource(Source & orig, Sink & sink) - : orig(orig), sink(sink) { } + : orig(orig) + , sink(sink) + {} size_t read(char * data, size_t len) { size_t n = orig.read(data, len); @@ -209,7 +229,9 @@ struct SizedSource : Source Source & orig; size_t remain; SizedSource(Source & orig, size_t size) - : orig(orig), remain(size) { } + : orig(orig) + , remain(size) + {} size_t read(char * data, size_t len) { if (this->remain <= 0) { @@ -239,7 +261,7 @@ struct LengthSink : Sink { uint64_t length = 0; - void operator () (std::string_view data) override + void operator()(std::string_view data) override { length += data.size(); } @@ -252,15 +274,16 @@ struct LambdaSink : Sink lambda_t lambda; - LambdaSink(const lambda_t & lambda) : lambda(lambda) { } + LambdaSink(const lambda_t & lambda) + : lambda(lambda) + {} - void operator () (std::string_view data) override + void operator()(std::string_view data) override { lambda(data); } }; - /* Convert a function into a source. */ struct LambdaSource : Source { @@ -268,7 +291,9 @@ struct LambdaSource : Source lambda_t lambda; - LambdaSource(const lambda_t & lambda) : lambda(lambda) { } + LambdaSource(const lambda_t & lambda) + : lambda(lambda) + {} size_t read(char * data, size_t len) override { @@ -280,11 +305,12 @@ struct LambdaSource : Source used */ struct ChainSource : Source { - Source & source1, & source2; + Source &source1, &source2; bool useSecond = false; ChainSource(Source & s1, Source & s2) - : source1(s1), source2(s2) - { } + : source1(s1) + , source2(s2) + {} size_t read(char * data, size_t len) override; }; @@ -294,16 +320,12 @@ std::unique_ptr sourceToSink(std::function fun); /* Convert a function that feeds data into a Sink into a Source. The Source executes the function as a coroutine. */ std::unique_ptr sinkToSource( - std::function fun, - std::function eof = []() { - throw EndOfFile("coroutine has finished"); - }); - + std::function fun, std::function eof = []() { throw EndOfFile("coroutine has finished"); }); void writePadding(size_t len, Sink & sink); void writeString(std::string_view s, Sink & sink); -inline Sink & operator << (Sink & sink, uint64_t n) +inline Sink & operator<<(Sink & sink, uint64_t n) { unsigned char buf[8]; buf[0] = n & 0xff; @@ -318,66 +340,56 @@ inline Sink & operator << (Sink & sink, uint64_t n) return sink; } -Sink & operator << (Sink & in, const Error & ex); -Sink & operator << (Sink & sink, std::string_view s); -Sink & operator << (Sink & sink, const Strings & s); -Sink & operator << (Sink & sink, const StringSet & s); - +Sink & operator<<(Sink & in, const Error & ex); +Sink & operator<<(Sink & sink, std::string_view s); +Sink & operator<<(Sink & sink, const Strings & s); +Sink & operator<<(Sink & sink, const StringSet & s); MakeError(SerialisationError, Error); - template T readNum(Source & source) { unsigned char buf[8]; source((char *) buf, sizeof(buf)); - uint64_t n = - ((uint64_t) buf[0]) | - ((uint64_t) buf[1] << 8) | - ((uint64_t) buf[2] << 16) | - ((uint64_t) buf[3] << 24) | - ((uint64_t) buf[4] << 32) | - ((uint64_t) buf[5] << 40) | - ((uint64_t) buf[6] << 48) | - ((uint64_t) buf[7] << 56); - - if (n > (uint64_t)std::numeric_limits::max()) + uint64_t n = ((uint64_t) buf[0]) | ((uint64_t) buf[1] << 8) | ((uint64_t) buf[2] << 16) | ((uint64_t) buf[3] << 24) + | ((uint64_t) buf[4] << 32) | ((uint64_t) buf[5] << 40) | ((uint64_t) buf[6] << 48) + | ((uint64_t) buf[7] << 56); + + if (n > (uint64_t) std::numeric_limits::max()) throw SerialisationError("serialised integer %d is too large for type '%s'", n, typeid(T).name()); return (T) n; } - inline unsigned int readInt(Source & source) { return readNum(source); } - inline uint64_t readLongLong(Source & source) { return readNum(source); } - void readPadding(size_t len, Source & source); size_t readString(char * buf, size_t max, Source & source); std::string readString(Source & source, size_t max = std::numeric_limits::max()); -template T readStrings(Source & source); +template +T readStrings(Source & source); -Source & operator >> (Source & in, std::string & s); +Source & operator>>(Source & in, std::string & s); template -Source & operator >> (Source & in, T & n) +Source & operator>>(Source & in, T & n) { n = readNum(in); return in; } template -Source & operator >> (Source & in, bool & b) +Source & operator>>(Source & in, bool & b) { b = readNum(in); return in; @@ -385,7 +397,6 @@ Source & operator >> (Source & in, bool & b) Error readError(Source & source); - /* An adapter that converts a std::basic_istream into a source. */ struct StreamToSourceAdapter : Source { @@ -393,7 +404,7 @@ struct StreamToSourceAdapter : Source StreamToSourceAdapter(std::shared_ptr> istream) : istream(istream) - { } + {} size_t read(char * data, size_t len) override { @@ -408,7 +419,6 @@ struct StreamToSourceAdapter : Source } }; - /* A source that reads a distinct format of concatenated chunks back into its logical form, in order to guarantee a known state to the original stream, even in the event of errors. @@ -423,15 +433,17 @@ struct FramedSource : Source std::vector pending; size_t pos = 0; - FramedSource(Source & from) : from(from) - { } + FramedSource(Source & from) + : from(from) + {} ~FramedSource() { if (!eof) { while (true) { auto n = readInt(from); - if (!n) break; + if (!n) + break; std::vector data(n); from(data.data(), n); } @@ -440,7 +452,8 @@ struct FramedSource : Source size_t read(char * data, size_t len) override { - if (eof) throw EndOfFile("reached end of FramedSource"); + if (eof) + throw EndOfFile("reached end of FramedSource"); if (pos >= pending.size()) { size_t len = readInt(from); @@ -470,8 +483,10 @@ struct FramedSink : nix::BufferedSink BufferedSink & to; std::exception_ptr & ex; - FramedSink(BufferedSink & to, std::exception_ptr & ex) : to(to), ex(ex) - { } + FramedSink(BufferedSink & to, std::exception_ptr & ex) + : to(to) + , ex(ex) + {} ~FramedSink() { @@ -502,13 +517,14 @@ struct FramedSink : nix::BufferedSink boost::context doesn't provide a virtual class, so we define our own. */ -struct StackAllocator { +struct StackAllocator +{ virtual boost::context::stack_context allocate() = 0; virtual void deallocate(boost::context::stack_context sctx) = 0; /* The stack allocator to use in sinkToSource and potentially elsewhere. It is reassigned by the initGC() method in libexpr. */ - static StackAllocator *defaultAllocator; + static StackAllocator * defaultAllocator; }; } diff --git a/src/libutil/split.hh b/src/libutil/split.hh index 87a23b13e3fa..a62898142ea9 100644 --- a/src/libutil/split.hh +++ b/src/libutil/split.hh @@ -11,19 +11,21 @@ namespace nix { // separator, and modify the string argument to contain only the part after the // separator. Otherwise, we return `std::nullopt`, and we leave the argument // string alone. -static inline std::optional splitPrefixTo(std::string_view & string, char separator) { +static inline std::optional splitPrefixTo(std::string_view & string, char separator) +{ auto sepInstance = string.find(separator); if (sepInstance != std::string_view::npos) { auto prefix = string.substr(0, sepInstance); - string.remove_prefix(sepInstance+1); + string.remove_prefix(sepInstance + 1); return prefix; } return std::nullopt; } -static inline bool splitPrefix(std::string_view & string, std::string_view prefix) { +static inline bool splitPrefix(std::string_view & string, std::string_view prefix) +{ bool res = hasPrefix(string, prefix); if (res) string.remove_prefix(prefix.length()); diff --git a/src/libutil/suggestions.cc b/src/libutil/suggestions.cc index 9510a5f0c415..b482bab8036a 100644 --- a/src/libutil/suggestions.cc +++ b/src/libutil/suggestions.cc @@ -13,20 +13,20 @@ int levenshteinDistance(std::string_view first, std::string_view second) int m = first.size(); int n = second.size(); - auto v0 = std::vector(n+1); - auto v1 = std::vector(n+1); + auto v0 = std::vector(n + 1); + auto v1 = std::vector(n + 1); for (auto i = 0; i <= n; i++) v0[i] = i; for (auto i = 0; i < m; i++) { - v1[0] = i+1; + v1[0] = i + 1; for (auto j = 0; j < n; j++) { - auto deletionCost = v0[j+1] + 1; + auto deletionCost = v0[j + 1] + 1; auto insertionCost = v1[j] + 1; auto substitutionCost = first[i] == second[j] ? v0[j] : v0[j] + 1; - v1[j+1] = std::min({deletionCost, insertionCost, substitutionCost}); + v1[j + 1] = std::min({deletionCost, insertionCost, substitutionCost}); } std::swap(v0, v1); @@ -35,18 +35,16 @@ int levenshteinDistance(std::string_view first, std::string_view second) return v0[n]; } -Suggestions Suggestions::bestMatches ( - std::set allMatches, - std::string query) +Suggestions Suggestions::bestMatches(std::set allMatches, std::string query) { std::set res; for (const auto & possibleMatch : allMatches) { - res.insert(Suggestion { + res.insert(Suggestion{ .distance = levenshteinDistance(query, possibleMatch), .suggestion = possibleMatch, }); } - return Suggestions { res }; + return Suggestions{res}; } Suggestions Suggestions::trim(int limit, int maxDistance) const @@ -73,31 +71,29 @@ std::string Suggestion::to_string() const std::string Suggestions::to_string() const { switch (suggestions.size()) { - case 0: - return ""; - case 1: - return suggestions.begin()->to_string(); - default: { - std::string res = "one of "; - auto iter = suggestions.begin(); - res += iter->to_string(); // Iter can’t be end() because the container isn’t null - iter++; - auto last = suggestions.end(); last--; - for ( ; iter != suggestions.end() ; iter++) { - res += (iter == last) ? " or " : ", "; - res += iter->to_string(); - } - return res; + case 0: + return ""; + case 1: + return suggestions.begin()->to_string(); + default: { + std::string res = "one of "; + auto iter = suggestions.begin(); + res += iter->to_string(); // Iter can’t be end() because the container isn’t null + iter++; + auto last = suggestions.end(); + last--; + for (; iter != suggestions.end(); iter++) { + res += (iter == last) ? " or " : ", "; + res += iter->to_string(); } + return res; + } } } Suggestions & Suggestions::operator+=(const Suggestions & other) { - suggestions.insert( - other.suggestions.begin(), - other.suggestions.end() - ); + suggestions.insert(other.suggestions.begin(), other.suggestions.end()); return *this; } diff --git a/src/libutil/suggestions.hh b/src/libutil/suggestions.hh index d54dd8e31eae..8f447861fc4f 100644 --- a/src/libutil/suggestions.hh +++ b/src/libutil/suggestions.hh @@ -11,7 +11,8 @@ int levenshteinDistance(std::string_view first, std::string_view second); /** * A potential suggestion for the cli interface. */ -class Suggestion { +class Suggestion +{ public: int distance; // The smaller the better std::string suggestion; @@ -21,23 +22,18 @@ public: GENERATE_CMP(Suggestion, me->distance, me->suggestion) }; -class Suggestions { +class Suggestions +{ public: std::set suggestions; std::string to_string() const; - Suggestions trim( - int limit = 5, - int maxDistance = 2 - ) const; + Suggestions trim(int limit = 5, int maxDistance = 2) const; - static Suggestions bestMatches ( - std::set allMatches, - std::string query - ); + static Suggestions bestMatches(std::set allMatches, std::string query); - Suggestions& operator+=(const Suggestions & other); + Suggestions & operator+=(const Suggestions & other); }; std::ostream & operator<<(std::ostream & str, const Suggestion &); @@ -45,18 +41,19 @@ std::ostream & operator<<(std::ostream & str, const Suggestions &); // Either a value of type `T`, or some suggestions template -class OrSuggestions { +class OrSuggestions +{ public: using Raw = std::variant; Raw raw; - T* operator ->() + T * operator->() { return &**this; } - T& operator *() + T & operator*() { return std::get(raw); } @@ -68,13 +65,11 @@ public: OrSuggestions(T t) : raw(t) - { - } + {} OrSuggestions() : raw(Suggestions{}) - { - } + {} static OrSuggestions failed(const Suggestions & s) { @@ -96,7 +91,6 @@ public: else return noSuggestions; } - }; } diff --git a/src/libutil/sync.hh b/src/libutil/sync.hh index e1d591d77a84..1518abf09b27 100644 --- a/src/libutil/sync.hh +++ b/src/libutil/sync.hh @@ -32,9 +32,13 @@ private: public: - Sync() { } - Sync(const T & data) : data(data) { } - Sync(T && data) noexcept : data(std::move(data)) { } + Sync() {} + Sync(const T & data) + : data(data) + {} + Sync(T && data) noexcept + : data(std::move(data)) + {} class Lock { @@ -42,13 +46,26 @@ public: Sync * s; std::unique_lock lk; friend Sync; - Lock(Sync * s) : s(s), lk(s->mutex) { } + Lock(Sync * s) + : s(s) + , lk(s->mutex) + {} public: - Lock(Lock && l) : s(l.s) { abort(); } + Lock(Lock && l) + : s(l.s) + { + abort(); + } Lock(const Lock & l) = delete; - ~Lock() { } - T * operator -> () { return &s->data; } - T & operator * () { return s->data; } + ~Lock() {} + T * operator->() + { + return &s->data; + } + T & operator*() + { + return s->data; + } void wait(std::condition_variable & cv) { @@ -57,32 +74,32 @@ public: } template - std::cv_status wait_for(std::condition_variable & cv, - const std::chrono::duration & duration) + std::cv_status wait_for(std::condition_variable & cv, const std::chrono::duration & duration) { assert(s); return cv.wait_for(lk, duration); } template - bool wait_for(std::condition_variable & cv, - const std::chrono::duration & duration, - Predicate pred) + bool wait_for(std::condition_variable & cv, const std::chrono::duration & duration, Predicate pred) { assert(s); return cv.wait_for(lk, duration, pred); } template - std::cv_status wait_until(std::condition_variable & cv, - const std::chrono::time_point & duration) + std::cv_status + wait_until(std::condition_variable & cv, const std::chrono::time_point & duration) { assert(s); return cv.wait_until(lk, duration); } }; - Lock lock() { return Lock(this); } + Lock lock() + { + return Lock(this); + } }; } diff --git a/src/libutil/tarfile.cc b/src/libutil/tarfile.cc index a7db58559cb6..f6eacfe37a9a 100644 --- a/src/libutil/tarfile.cc +++ b/src/libutil/tarfile.cc @@ -11,7 +11,7 @@ static int callback_open(struct archive *, void * self) return ARCHIVE_OK; } -static ssize_t callback_read(struct archive * archive, void * _self, const void * * buffer) +static ssize_t callback_read(struct archive * archive, void * _self, const void ** buffer) { auto self = (TarArchive *) _self; *buffer = self->buffer.data(); @@ -39,7 +39,8 @@ void TarArchive::check(int err, const std::string & reason) throw Error(reason, archive_error_string(this->archive)); } -TarArchive::TarArchive(Source & source, bool raw) : buffer(4096) +TarArchive::TarArchive(Source & source, bool raw) + : buffer(4096) { this->archive = archive_read_new(); this->source = &source; @@ -52,10 +53,11 @@ TarArchive::TarArchive(Source & source, bool raw) : buffer(4096) archive_read_support_format_raw(archive); archive_read_support_format_empty(archive); } - check(archive_read_open(archive, (void *)this, callback_open, callback_read, callback_close), "Failed to open archive (%s)"); + check( + archive_read_open(archive, (void *) this, callback_open, callback_read, callback_close), + "Failed to open archive (%s)"); } - TarArchive::TarArchive(const Path & path) { this->archive = archive_read_new(); @@ -72,21 +74,20 @@ void TarArchive::close() TarArchive::~TarArchive() { - if (this->archive) archive_read_free(this->archive); + if (this->archive) + archive_read_free(this->archive); } static void extract_archive(TarArchive & archive, const Path & destDir) { - int flags = ARCHIVE_EXTRACT_FFLAGS - | ARCHIVE_EXTRACT_PERM - | ARCHIVE_EXTRACT_TIME - | ARCHIVE_EXTRACT_SECURE_SYMLINKS - | ARCHIVE_EXTRACT_SECURE_NODOTDOT; + int flags = ARCHIVE_EXTRACT_FFLAGS | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_SECURE_SYMLINKS + | ARCHIVE_EXTRACT_SECURE_NODOTDOT; for (;;) { struct archive_entry * entry; int r = archive_read_next_header(archive.archive, &entry); - if (r == ARCHIVE_EOF) break; + if (r == ARCHIVE_EOF) + break; auto name = archive_entry_pathname(entry); if (!name) throw Error("cannot get archive member name: %s", archive_error_string(archive.archive)); @@ -95,14 +96,12 @@ static void extract_archive(TarArchive & archive, const Path & destDir) else archive.check(r); - archive_entry_copy_pathname(entry, - (destDir + "/" + name).c_str()); + archive_entry_copy_pathname(entry, (destDir + "/" + name).c_str()); // Patch hardlink path - const char *original_hardlink = archive_entry_hardlink(entry); + const char * original_hardlink = archive_entry_hardlink(entry); if (original_hardlink) { - archive_entry_copy_hardlink(entry, - (destDir + "/" + original_hardlink).c_str()); + archive_entry_copy_hardlink(entry, (destDir + "/" + original_hardlink).c_str()); } archive.check(archive_read_extract(archive.archive, entry, flags)); diff --git a/src/libutil/tarfile.hh b/src/libutil/tarfile.hh index 4d9141fd458a..995082d6fe19 100644 --- a/src/libutil/tarfile.hh +++ b/src/libutil/tarfile.hh @@ -3,7 +3,8 @@ namespace nix { -struct TarArchive { +struct TarArchive +{ struct archive * archive; Source * source; std::vector buffer; diff --git a/src/libutil/tests/chunked-vector.cc b/src/libutil/tests/chunked-vector.cc index 868d11f6f370..5b471ca6f309 100644 --- a/src/libutil/tests/chunked-vector.cc +++ b/src/libutil/tests/chunked-vector.cc @@ -3,52 +3,54 @@ #include namespace nix { - TEST(ChunkedVector, InitEmpty) { - auto v = ChunkedVector(100); - ASSERT_EQ(v.size(), 0); - } +TEST(ChunkedVector, InitEmpty) +{ + auto v = ChunkedVector(100); + ASSERT_EQ(v.size(), 0); +} - TEST(ChunkedVector, GrowsCorrectly) { - auto v = ChunkedVector(100); - for (auto i = 1; i < 20; i++) { - v.add(i); - ASSERT_EQ(v.size(), i); - } +TEST(ChunkedVector, GrowsCorrectly) +{ + auto v = ChunkedVector(100); + for (auto i = 1; i < 20; i++) { + v.add(i); + ASSERT_EQ(v.size(), i); } +} - TEST(ChunkedVector, AddAndGet) { - auto v = ChunkedVector(100); - for (auto i = 1; i < 20; i++) { - auto [i2, idx] = v.add(i); - auto & i3 = v[idx]; - ASSERT_EQ(i, i2); - ASSERT_EQ(&i2, &i3); - } +TEST(ChunkedVector, AddAndGet) +{ + auto v = ChunkedVector(100); + for (auto i = 1; i < 20; i++) { + auto [i2, idx] = v.add(i); + auto & i3 = v[idx]; + ASSERT_EQ(i, i2); + ASSERT_EQ(&i2, &i3); } +} - TEST(ChunkedVector, ForEach) { - auto v = ChunkedVector(100); - for (auto i = 1; i < 20; i++) { - v.add(i); - } - int count = 0; - v.forEach([&count](int elt) { - count++; - }); - ASSERT_EQ(count, v.size()); +TEST(ChunkedVector, ForEach) +{ + auto v = ChunkedVector(100); + for (auto i = 1; i < 20; i++) { + v.add(i); } + int count = 0; + v.forEach([&count](int elt) { count++; }); + ASSERT_EQ(count, v.size()); +} - TEST(ChunkedVector, OverflowOK) { - // Similar to the AddAndGet, but intentionnally use a small - // initial ChunkedVector to force it to overflow - auto v = ChunkedVector(2); - for (auto i = 1; i < 20; i++) { - auto [i2, idx] = v.add(i); - auto & i3 = v[idx]; - ASSERT_EQ(i, i2); - ASSERT_EQ(&i2, &i3); - } +TEST(ChunkedVector, OverflowOK) +{ + // Similar to the AddAndGet, but intentionnally use a small + // initial ChunkedVector to force it to overflow + auto v = ChunkedVector(2); + for (auto i = 1; i < 20; i++) { + auto [i2, idx] = v.add(i); + auto & i3 = v[idx]; + ASSERT_EQ(i, i2); + ASSERT_EQ(&i2, &i3); } - } +} diff --git a/src/libutil/tests/closure.cc b/src/libutil/tests/closure.cc index 7597e78073b4..eff99dff453d 100644 --- a/src/libutil/tests/closure.cc +++ b/src/libutil/tests/closure.cc @@ -6,53 +6,49 @@ namespace nix { using namespace std; map> testGraph = { - { "A", { "B", "C", "G" } }, - { "B", { "A" } }, // Loops back to A - { "C", { "F" } }, // Indirect reference - { "D", { "A" } }, // Not reachable, but has backreferences - { "E", {} }, // Just not reachable - { "F", {} }, - { "G", { "G" } }, // Self reference + {"A", {"B", "C", "G"}}, + {"B", {"A"}}, // Loops back to A + {"C", {"F"}}, // Indirect reference + {"D", {"A"}}, // Not reachable, but has backreferences + {"E", {}}, // Just not reachable + {"F", {}}, + {"G", {"G"}}, // Self reference }; -TEST(closure, correctClosure) { +TEST(closure, correctClosure) +{ set aClosure; set expectedClosure = {"A", "B", "C", "F", "G"}; computeClosure( - {"A"}, - aClosure, - [&](const string currentNode, function> &)> processEdges) { + {"A"}, aClosure, [&](const string currentNode, function> &)> processEdges) { promise> promisedNodes; promisedNodes.set_value(testGraph[currentNode]); processEdges(promisedNodes); - } - ); + }); ASSERT_EQ(aClosure, expectedClosure); } -TEST(closure, properlyHandlesDirectExceptions) { - struct TestExn {}; +TEST(closure, properlyHandlesDirectExceptions) +{ + struct TestExn + {}; set aClosure; EXPECT_THROW( computeClosure( - {"A"}, - aClosure, - [&](const string currentNode, function> &)> processEdges) { - throw TestExn(); - } - ), - TestExn - ); + {"A"}, aClosure, + [&](const string currentNode, function> &)> processEdges) { throw TestExn(); }), + TestExn); } -TEST(closure, properlyHandlesExceptionsInPromise) { - struct TestExn {}; +TEST(closure, properlyHandlesExceptionsInPromise) +{ + struct TestExn + {}; set aClosure; EXPECT_THROW( computeClosure( - {"A"}, - aClosure, + {"A"}, aClosure, [&](const string currentNode, function> &)> processEdges) { promise> promise; try { @@ -61,10 +57,8 @@ TEST(closure, properlyHandlesExceptionsInPromise) { promise.set_exception(std::current_exception()); } processEdges(promise); - } - ), - TestExn - ); + }), + TestExn); } } diff --git a/src/libutil/tests/compression.cc b/src/libutil/tests/compression.cc index bbbf3500fbfe..a5556d3c8416 100644 --- a/src/libutil/tests/compression.cc +++ b/src/libutil/tests/compression.cc @@ -3,94 +3,104 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * compress / decompress - * --------------------------------------------------------------------------*/ - - TEST(compress, compressWithUnknownMethod) { - ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); - } - - TEST(compress, noneMethodDoesNothingToTheInput) { - auto o = compress("none", "this-is-a-test"); - - ASSERT_EQ(o, "this-is-a-test"); - } - - TEST(decompress, decompressNoneCompressed) { - auto method = "none"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, str); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressEmptyCompressed) { - // Empty-method decompression used e.g. by S3 store - // (Content-Encoding == ""). - auto method = ""; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, str); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressXzCompressed) { - auto method = "xz"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressBzip2Compressed) { - auto method = "bzip2"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressBrCompressed) { - auto method = "br"; - auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto o = decompress(method, compress(method, str)); - - ASSERT_EQ(o, str); - } - - TEST(decompress, decompressInvalidInputThrowsCompressionError) { - auto method = "bzip2"; - auto str = "this is a string that does not qualify as valid bzip2 data"; - - ASSERT_THROW(decompress(method, str), CompressionError); - } - - /* ---------------------------------------------------------------------------- - * compression sinks - * --------------------------------------------------------------------------*/ - - TEST(makeCompressionSink, noneSinkDoesNothingToInput) { - StringSink strSink; - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto sink = makeCompressionSink("none", strSink); - (*sink)(inputString); - sink->finish(); - - ASSERT_STREQ(strSink.s.c_str(), inputString); - } - - TEST(makeCompressionSink, compressAndDecompress) { - StringSink strSink; - auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; - auto decompressionSink = makeDecompressionSink("bzip2", strSink); - auto sink = makeCompressionSink("bzip2", *decompressionSink); - - (*sink)(inputString); - sink->finish(); - decompressionSink->finish(); - - ASSERT_STREQ(strSink.s.c_str(), inputString); - } +/* ---------------------------------------------------------------------------- + * compress / decompress + * --------------------------------------------------------------------------*/ + +TEST(compress, compressWithUnknownMethod) +{ + ASSERT_THROW(compress("invalid-method", "something-to-compress"), UnknownCompressionMethod); +} + +TEST(compress, noneMethodDoesNothingToTheInput) +{ + auto o = compress("none", "this-is-a-test"); + + ASSERT_EQ(o, "this-is-a-test"); +} + +TEST(decompress, decompressNoneCompressed) +{ + auto method = "none"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto o = decompress(method, str); + + ASSERT_EQ(o, str); +} + +TEST(decompress, decompressEmptyCompressed) +{ + // Empty-method decompression used e.g. by S3 store + // (Content-Encoding == ""). + auto method = ""; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto o = decompress(method, str); + + ASSERT_EQ(o, str); +} + +TEST(decompress, decompressXzCompressed) +{ + auto method = "xz"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto o = decompress(method, compress(method, str)); + + ASSERT_EQ(o, str); +} + +TEST(decompress, decompressBzip2Compressed) +{ + auto method = "bzip2"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto o = decompress(method, compress(method, str)); + + ASSERT_EQ(o, str); +} + +TEST(decompress, decompressBrCompressed) +{ + auto method = "br"; + auto str = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto o = decompress(method, compress(method, str)); + + ASSERT_EQ(o, str); +} + +TEST(decompress, decompressInvalidInputThrowsCompressionError) +{ + auto method = "bzip2"; + auto str = "this is a string that does not qualify as valid bzip2 data"; + + ASSERT_THROW(decompress(method, str), CompressionError); +} + +/* ---------------------------------------------------------------------------- + * compression sinks + * --------------------------------------------------------------------------*/ + +TEST(makeCompressionSink, noneSinkDoesNothingToInput) +{ + StringSink strSink; + auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto sink = makeCompressionSink("none", strSink); + (*sink)(inputString); + sink->finish(); + + ASSERT_STREQ(strSink.s.c_str(), inputString); +} + +TEST(makeCompressionSink, compressAndDecompress) +{ + StringSink strSink; + auto inputString = "slfja;sljfklsa;jfklsjfkl;sdjfkl;sadjfkl;sdjf;lsdfjsadlf"; + auto decompressionSink = makeDecompressionSink("bzip2", strSink); + auto sink = makeCompressionSink("bzip2", *decompressionSink); + + (*sink)(inputString); + sink->finish(); + decompressionSink->finish(); + + ASSERT_STREQ(strSink.s.c_str(), inputString); +} } diff --git a/src/libutil/tests/config.cc b/src/libutil/tests/config.cc index 8be6730dd8df..98b387d16049 100644 --- a/src/libutil/tests/config.cc +++ b/src/libutil/tests/config.cc @@ -7,245 +7,271 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * Config - * --------------------------------------------------------------------------*/ - - TEST(Config, setUndefinedSetting) { - Config config; - ASSERT_EQ(config.set("undefined-key", "value"), false); - } - - TEST(Config, setDefinedSetting) { - Config config; - std::string value; - Setting foo{&config, value, "name-of-the-setting", "description"}; - ASSERT_EQ(config.set("name-of-the-setting", "value"), true); - } - - TEST(Config, getDefinedSetting) { - Config config; - std::string value; - std::map settings; - Setting foo{&config, value, "name-of-the-setting", "description"}; - - config.getSettings(settings, /* overriddenOnly = */ false); - const auto iter = settings.find("name-of-the-setting"); - ASSERT_NE(iter, settings.end()); - ASSERT_EQ(iter->second.value, ""); - ASSERT_EQ(iter->second.description, "description\n"); - } - - TEST(Config, getDefinedOverriddenSettingNotSet) { - Config config; - std::string value; - std::map settings; - Setting foo{&config, value, "name-of-the-setting", "description"}; - - config.getSettings(settings, /* overriddenOnly = */ true); - const auto e = settings.find("name-of-the-setting"); - ASSERT_EQ(e, settings.end()); - } - - TEST(Config, getDefinedSettingSet1) { - Config config; - std::string value; - std::map settings; - Setting setting{&config, value, "name-of-the-setting", "description"}; - - setting.assign("value"); - - config.getSettings(settings, /* overriddenOnly = */ false); - const auto iter = settings.find("name-of-the-setting"); - ASSERT_NE(iter, settings.end()); - ASSERT_EQ(iter->second.value, "value"); - ASSERT_EQ(iter->second.description, "description\n"); - } - - TEST(Config, getDefinedSettingSet2) { - Config config; - std::map settings; - Setting setting{&config, "", "name-of-the-setting", "description"}; - - ASSERT_TRUE(config.set("name-of-the-setting", "value")); +/* ---------------------------------------------------------------------------- + * Config + * --------------------------------------------------------------------------*/ + +TEST(Config, setUndefinedSetting) +{ + Config config; + ASSERT_EQ(config.set("undefined-key", "value"), false); +} - config.getSettings(settings, /* overriddenOnly = */ false); - const auto e = settings.find("name-of-the-setting"); - ASSERT_NE(e, settings.end()); - ASSERT_EQ(e->second.value, "value"); - ASSERT_EQ(e->second.description, "description\n"); - } +TEST(Config, setDefinedSetting) +{ + Config config; + std::string value; + Setting foo{&config, value, "name-of-the-setting", "description"}; + ASSERT_EQ(config.set("name-of-the-setting", "value"), true); +} - TEST(Config, addSetting) { - class TestSetting : public AbstractSetting { - public: - TestSetting() : AbstractSetting("test", "test", {}) {} - void set(const std::string & value, bool append) override {} - std::string to_string() const override { return {}; } - }; +TEST(Config, getDefinedSetting) +{ + Config config; + std::string value; + std::map settings; + Setting foo{&config, value, "name-of-the-setting", "description"}; + + config.getSettings(settings, /* overriddenOnly = */ false); + const auto iter = settings.find("name-of-the-setting"); + ASSERT_NE(iter, settings.end()); + ASSERT_EQ(iter->second.value, ""); + ASSERT_EQ(iter->second.description, "description\n"); +} - Config config; - TestSetting setting; +TEST(Config, getDefinedOverriddenSettingNotSet) +{ + Config config; + std::string value; + std::map settings; + Setting foo{&config, value, "name-of-the-setting", "description"}; - ASSERT_FALSE(config.set("test", "value")); - config.addSetting(&setting); - ASSERT_TRUE(config.set("test", "value")); - } + config.getSettings(settings, /* overriddenOnly = */ true); + const auto e = settings.find("name-of-the-setting"); + ASSERT_EQ(e, settings.end()); +} - TEST(Config, withInitialValue) { - const StringMap initials = { - { "key", "value" }, - }; - Config config(initials); +TEST(Config, getDefinedSettingSet1) +{ + Config config; + std::string value; + std::map settings; + Setting setting{&config, value, "name-of-the-setting", "description"}; - { - std::map settings; - config.getSettings(settings, /* overriddenOnly = */ false); - ASSERT_EQ(settings.find("key"), settings.end()); - } + setting.assign("value"); - Setting setting{&config, "default-value", "key", "description"}; + config.getSettings(settings, /* overriddenOnly = */ false); + const auto iter = settings.find("name-of-the-setting"); + ASSERT_NE(iter, settings.end()); + ASSERT_EQ(iter->second.value, "value"); + ASSERT_EQ(iter->second.description, "description\n"); +} - { - std::map settings; - config.getSettings(settings, /* overriddenOnly = */ false); - ASSERT_EQ(settings["key"].value, "value"); - } - } +TEST(Config, getDefinedSettingSet2) +{ + Config config; + std::map settings; + Setting setting{&config, "", "name-of-the-setting", "description"}; - TEST(Config, resetOverridden) { - Config config; - config.resetOverridden(); - } + ASSERT_TRUE(config.set("name-of-the-setting", "value")); - TEST(Config, resetOverriddenWithSetting) { - Config config; - Setting setting{&config, "", "name-of-the-setting", "description"}; + config.getSettings(settings, /* overriddenOnly = */ false); + const auto e = settings.find("name-of-the-setting"); + ASSERT_NE(e, settings.end()); + ASSERT_EQ(e->second.value, "value"); + ASSERT_EQ(e->second.description, "description\n"); +} +TEST(Config, addSetting) +{ + class TestSetting : public AbstractSetting + { + public: + TestSetting() + : AbstractSetting("test", "test", {}) + {} + void set(const std::string & value, bool append) override {} + std::string to_string() const override { - std::map settings; - - setting.set("foo"); - ASSERT_EQ(setting.get(), "foo"); - config.getSettings(settings, /* overriddenOnly = */ true); - ASSERT_TRUE(settings.empty()); + return {}; } + }; - { - std::map settings; + Config config; + TestSetting setting; - setting.override("bar"); - ASSERT_TRUE(setting.overridden); - ASSERT_EQ(setting.get(), "bar"); - config.getSettings(settings, /* overriddenOnly = */ true); - ASSERT_FALSE(settings.empty()); - } + ASSERT_FALSE(config.set("test", "value")); + config.addSetting(&setting); + ASSERT_TRUE(config.set("test", "value")); +} - { - std::map settings; +TEST(Config, withInitialValue) +{ + const StringMap initials = { + {"key", "value"}, + }; + Config config(initials); - config.resetOverridden(); - ASSERT_FALSE(setting.overridden); - config.getSettings(settings, /* overriddenOnly = */ true); - ASSERT_TRUE(settings.empty()); - } + { + std::map settings; + config.getSettings(settings, /* overriddenOnly = */ false); + ASSERT_EQ(settings.find("key"), settings.end()); } - TEST(Config, toJSONOnEmptyConfig) { - ASSERT_EQ(Config().toJSON().dump(), "{}"); - } + Setting setting{&config, "default-value", "key", "description"}; - TEST(Config, toJSONOnNonEmptyConfig) { - Config config; + { std::map settings; - Setting setting{&config, "", "name-of-the-setting", "description"}; - setting.assign("value"); - - ASSERT_EQ(config.toJSON().dump(), R"#({"name-of-the-setting":{"aliases":[],"defaultValue":"","description":"description\n","documentDefault":true,"value":"value"}})#"); + config.getSettings(settings, /* overriddenOnly = */ false); + ASSERT_EQ(settings["key"].value, "value"); } +} - TEST(Config, setSettingAlias) { - Config config; - Setting setting{&config, "", "some-int", "best number", { "another-int" }}; - ASSERT_TRUE(config.set("some-int", "1")); - ASSERT_EQ(setting.get(), "1"); - ASSERT_TRUE(config.set("another-int", "2")); - ASSERT_EQ(setting.get(), "2"); - ASSERT_TRUE(config.set("some-int", "3")); - ASSERT_EQ(setting.get(), "3"); - } +TEST(Config, resetOverridden) +{ + Config config; + config.resetOverridden(); +} - /* FIXME: The reapplyUnknownSettings method doesn't seem to do anything - * useful (these days). Whenever we add a new setting to Config the - * unknown settings are always considered. In which case is this function - * actually useful? Is there some way to register a Setting without calling - * addSetting? */ - TEST(Config, DISABLED_reapplyUnknownSettings) { - Config config; - ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue")); - Setting setting{&config, "default", "name-of-the-setting", "description"}; - ASSERT_EQ(setting.get(), "default"); - config.reapplyUnknownSettings(); - ASSERT_EQ(setting.get(), "unknownvalue"); - } +TEST(Config, resetOverriddenWithSetting) +{ + Config config; + Setting setting{&config, "", "name-of-the-setting", "description"}; - TEST(Config, applyConfigEmpty) { - Config config; + { std::map settings; - config.applyConfig(""); - config.getSettings(settings); - ASSERT_TRUE(settings.empty()); - } - TEST(Config, applyConfigEmptyWithComment) { - Config config; - std::map settings; - config.applyConfig("# just a comment"); - config.getSettings(settings); + setting.set("foo"); + ASSERT_EQ(setting.get(), "foo"); + config.getSettings(settings, /* overriddenOnly = */ true); ASSERT_TRUE(settings.empty()); } - TEST(Config, applyConfigAssignment) { - Config config; + { std::map settings; - Setting setting{&config, "", "name-of-the-setting", "description"}; - config.applyConfig( - "name-of-the-setting = value-from-file #useful comment\n" - "# name-of-the-setting = foo\n" - ); - config.getSettings(settings); - ASSERT_FALSE(settings.empty()); - ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file"); - } - TEST(Config, applyConfigWithReassignedSetting) { - Config config; - std::map settings; - Setting setting{&config, "", "name-of-the-setting", "description"}; - config.applyConfig( - "name-of-the-setting = first-value\n" - "name-of-the-setting = second-value\n" - ); - config.getSettings(settings); + setting.override("bar"); + ASSERT_TRUE(setting.overridden); + ASSERT_EQ(setting.get(), "bar"); + config.getSettings(settings, /* overriddenOnly = */ true); ASSERT_FALSE(settings.empty()); - ASSERT_EQ(settings["name-of-the-setting"].value, "second-value"); } - TEST(Config, applyConfigFailsOnMissingIncludes) { - Config config; + { std::map settings; - Setting setting{&config, "", "name-of-the-setting", "description"}; - ASSERT_THROW(config.applyConfig( - "name-of-the-setting = value-from-file\n" - "# name-of-the-setting = foo\n" - "include /nix/store/does/not/exist.nix" - ), Error); + config.resetOverridden(); + ASSERT_FALSE(setting.overridden); + config.getSettings(settings, /* overriddenOnly = */ true); + ASSERT_TRUE(settings.empty()); } +} - TEST(Config, applyConfigInvalidThrows) { - Config config; - ASSERT_THROW(config.applyConfig("value == key"), UsageError); - ASSERT_THROW(config.applyConfig("value "), UsageError); - } +TEST(Config, toJSONOnEmptyConfig) +{ + ASSERT_EQ(Config().toJSON().dump(), "{}"); +} + +TEST(Config, toJSONOnNonEmptyConfig) +{ + Config config; + std::map settings; + Setting setting{&config, "", "name-of-the-setting", "description"}; + setting.assign("value"); + + ASSERT_EQ( + config.toJSON().dump(), + R"#({"name-of-the-setting":{"aliases":[],"defaultValue":"","description":"description\n","documentDefault":true,"value":"value"}})#"); +} + +TEST(Config, setSettingAlias) +{ + Config config; + Setting setting{&config, "", "some-int", "best number", {"another-int"}}; + ASSERT_TRUE(config.set("some-int", "1")); + ASSERT_EQ(setting.get(), "1"); + ASSERT_TRUE(config.set("another-int", "2")); + ASSERT_EQ(setting.get(), "2"); + ASSERT_TRUE(config.set("some-int", "3")); + ASSERT_EQ(setting.get(), "3"); +} + +/* FIXME: The reapplyUnknownSettings method doesn't seem to do anything + * useful (these days). Whenever we add a new setting to Config the + * unknown settings are always considered. In which case is this function + * actually useful? Is there some way to register a Setting without calling + * addSetting? */ +TEST(Config, DISABLED_reapplyUnknownSettings) +{ + Config config; + ASSERT_FALSE(config.set("name-of-the-setting", "unknownvalue")); + Setting setting{&config, "default", "name-of-the-setting", "description"}; + ASSERT_EQ(setting.get(), "default"); + config.reapplyUnknownSettings(); + ASSERT_EQ(setting.get(), "unknownvalue"); +} + +TEST(Config, applyConfigEmpty) +{ + Config config; + std::map settings; + config.applyConfig(""); + config.getSettings(settings); + ASSERT_TRUE(settings.empty()); +} + +TEST(Config, applyConfigEmptyWithComment) +{ + Config config; + std::map settings; + config.applyConfig("# just a comment"); + config.getSettings(settings); + ASSERT_TRUE(settings.empty()); +} + +TEST(Config, applyConfigAssignment) +{ + Config config; + std::map settings; + Setting setting{&config, "", "name-of-the-setting", "description"}; + config.applyConfig( + "name-of-the-setting = value-from-file #useful comment\n" + "# name-of-the-setting = foo\n"); + config.getSettings(settings); + ASSERT_FALSE(settings.empty()); + ASSERT_EQ(settings["name-of-the-setting"].value, "value-from-file"); +} + +TEST(Config, applyConfigWithReassignedSetting) +{ + Config config; + std::map settings; + Setting setting{&config, "", "name-of-the-setting", "description"}; + config.applyConfig( + "name-of-the-setting = first-value\n" + "name-of-the-setting = second-value\n"); + config.getSettings(settings); + ASSERT_FALSE(settings.empty()); + ASSERT_EQ(settings["name-of-the-setting"].value, "second-value"); +} + +TEST(Config, applyConfigFailsOnMissingIncludes) +{ + Config config; + std::map settings; + Setting setting{&config, "", "name-of-the-setting", "description"}; + + ASSERT_THROW( + config.applyConfig("name-of-the-setting = value-from-file\n" + "# name-of-the-setting = foo\n" + "include /nix/store/does/not/exist.nix"), + Error); +} + +TEST(Config, applyConfigInvalidThrows) +{ + Config config; + ASSERT_THROW(config.applyConfig("value == key"), UsageError); + ASSERT_THROW(config.applyConfig("value "), UsageError); +} } diff --git a/src/libutil/tests/git.cc b/src/libutil/tests/git.cc index 5b5715fc26bb..f335d1abe207 100644 --- a/src/libutil/tests/git.cc +++ b/src/libutil/tests/git.cc @@ -3,31 +3,33 @@ namespace nix { - TEST(GitLsRemote, parseSymrefLineWithReference) { - auto line = "ref: refs/head/main HEAD"; - auto res = git::parseLsRemoteLine(line); - ASSERT_TRUE(res.has_value()); - ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic); - ASSERT_EQ(res->target, "refs/head/main"); - ASSERT_EQ(res->reference, "HEAD"); - } - - TEST(GitLsRemote, parseSymrefLineWithNoReference) { - auto line = "ref: refs/head/main"; - auto res = git::parseLsRemoteLine(line); - ASSERT_TRUE(res.has_value()); - ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic); - ASSERT_EQ(res->target, "refs/head/main"); - ASSERT_EQ(res->reference, std::nullopt); - } +TEST(GitLsRemote, parseSymrefLineWithReference) +{ + auto line = "ref: refs/head/main HEAD"; + auto res = git::parseLsRemoteLine(line); + ASSERT_TRUE(res.has_value()); + ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic); + ASSERT_EQ(res->target, "refs/head/main"); + ASSERT_EQ(res->reference, "HEAD"); +} - TEST(GitLsRemote, parseObjectRefLine) { - auto line = "abc123 refs/head/main"; - auto res = git::parseLsRemoteLine(line); - ASSERT_TRUE(res.has_value()); - ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Object); - ASSERT_EQ(res->target, "abc123"); - ASSERT_EQ(res->reference, "refs/head/main"); - } +TEST(GitLsRemote, parseSymrefLineWithNoReference) +{ + auto line = "ref: refs/head/main"; + auto res = git::parseLsRemoteLine(line); + ASSERT_TRUE(res.has_value()); + ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Symbolic); + ASSERT_EQ(res->target, "refs/head/main"); + ASSERT_EQ(res->reference, std::nullopt); } +TEST(GitLsRemote, parseObjectRefLine) +{ + auto line = "abc123 refs/head/main"; + auto res = git::parseLsRemoteLine(line); + ASSERT_TRUE(res.has_value()); + ASSERT_EQ(res->kind, git::LsRemoteRefLine::Kind::Object); + ASSERT_EQ(res->target, "abc123"); + ASSERT_EQ(res->reference, "refs/head/main"); +} +} diff --git a/src/libutil/tests/hash.cc b/src/libutil/tests/hash.cc index 412c03030347..20a1a7e119fa 100644 --- a/src/libutil/tests/hash.cc +++ b/src/libutil/tests/hash.cc @@ -3,73 +3,84 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * hashString - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * hashString + * --------------------------------------------------------------------------*/ - TEST(hashString, testKnownMD5Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc1321 - auto s1 = ""; - auto hash = hashString(HashType::htMD5, s1); - ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e"); - } +TEST(hashString, testKnownMD5Hashes1) +{ + // values taken from: https://tools.ietf.org/html/rfc1321 + auto s1 = ""; + auto hash = hashString(HashType::htMD5, s1); + ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:d41d8cd98f00b204e9800998ecf8427e"); +} - TEST(hashString, testKnownMD5Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc1321 - auto s2 = "abc"; - auto hash = hashString(HashType::htMD5, s2); - ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72"); - } +TEST(hashString, testKnownMD5Hashes2) +{ + // values taken from: https://tools.ietf.org/html/rfc1321 + auto s2 = "abc"; + auto hash = hashString(HashType::htMD5, s2); + ASSERT_EQ(hash.to_string(Base::Base16, true), "md5:900150983cd24fb0d6963f7d28e17f72"); +} - TEST(hashString, testKnownSHA1Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc3174 - auto s = "abc"; - auto hash = hashString(HashType::htSHA1, s); - ASSERT_EQ(hash.to_string(Base::Base16, true),"sha1:a9993e364706816aba3e25717850c26c9cd0d89d"); - } +TEST(hashString, testKnownSHA1Hashes1) +{ + // values taken from: https://tools.ietf.org/html/rfc3174 + auto s = "abc"; + auto hash = hashString(HashType::htSHA1, s); + ASSERT_EQ(hash.to_string(Base::Base16, true), "sha1:a9993e364706816aba3e25717850c26c9cd0d89d"); +} - TEST(hashString, testKnownSHA1Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc3174 - auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - auto hash = hashString(HashType::htSHA1, s); - ASSERT_EQ(hash.to_string(Base::Base16, true),"sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1"); - } +TEST(hashString, testKnownSHA1Hashes2) +{ + // values taken from: https://tools.ietf.org/html/rfc3174 + auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + auto hash = hashString(HashType::htSHA1, s); + ASSERT_EQ(hash.to_string(Base::Base16, true), "sha1:84983e441c3bd26ebaae4aa1f95129e5e54670f1"); +} - TEST(hashString, testKnownSHA256Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abc"; +TEST(hashString, testKnownSHA256Hashes1) +{ + // values taken from: https://tools.ietf.org/html/rfc4634 + auto s = "abc"; - auto hash = hashString(HashType::htSHA256, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); - } + auto hash = hashString(HashType::htSHA256, s); + ASSERT_EQ( + hash.to_string(Base::Base16, true), "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); +} - TEST(hashString, testKnownSHA256Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; - auto hash = hashString(HashType::htSHA256, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); - } +TEST(hashString, testKnownSHA256Hashes2) +{ + // values taken from: https://tools.ietf.org/html/rfc4634 + auto s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + auto hash = hashString(HashType::htSHA256, s); + ASSERT_EQ( + hash.to_string(Base::Base16, true), "sha256:248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"); +} - TEST(hashString, testKnownSHA512Hashes1) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abc"; - auto hash = hashString(HashType::htSHA512, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9" - "7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd" - "454d4423643ce80e2a9ac94fa54ca49f"); - } +TEST(hashString, testKnownSHA512Hashes1) +{ + // values taken from: https://tools.ietf.org/html/rfc4634 + auto s = "abc"; + auto hash = hashString(HashType::htSHA512, s); + ASSERT_EQ( + hash.to_string(Base::Base16, true), + "sha512:ddaf35a193617abacc417349ae20413112e6fa4e89a9" + "7ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd" + "454d4423643ce80e2a9ac94fa54ca49f"); +} - TEST(hashString, testKnownSHA512Hashes2) { - // values taken from: https://tools.ietf.org/html/rfc4634 - auto s = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; +TEST(hashString, testKnownSHA512Hashes2) +{ + // values taken from: https://tools.ietf.org/html/rfc4634 + auto s = + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; - auto hash = hashString(HashType::htSHA512, s); - ASSERT_EQ(hash.to_string(Base::Base16, true), - "sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1" - "7299aeadb6889018501d289e4900f7e4331b99dec4b5433a" - "c7d329eeb6dd26545e96e55b874be909"); - } + auto hash = hashString(HashType::htSHA512, s); + ASSERT_EQ( + hash.to_string(Base::Base16, true), + "sha512:8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa1" + "7299aeadb6889018501d289e4900f7e4331b99dec4b5433a" + "c7d329eeb6dd26545e96e55b874be909"); +} } diff --git a/src/libutil/tests/hilite.cc b/src/libutil/tests/hilite.cc index 1ff5980d5831..be5142634050 100644 --- a/src/libutil/tests/hilite.cc +++ b/src/libutil/tests/hilite.cc @@ -5,62 +5,57 @@ namespace nix { /* ----------- tests for fmt.hh -------------------------------------------------*/ - TEST(hiliteMatches, noHighlight) { - ASSERT_STREQ(hiliteMatches("Hello, world!", std::vector(), "(", ")").c_str(), "Hello, world!"); - } +TEST(hiliteMatches, noHighlight) +{ + ASSERT_STREQ(hiliteMatches("Hello, world!", std::vector(), "(", ")").c_str(), "Hello, world!"); +} - TEST(hiliteMatches, simpleHighlight) { - std::string str = "Hello, world!"; - std::regex re = std::regex("world"); - auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); - ASSERT_STREQ( - hiliteMatches(str, matches, "(", ")").c_str(), - "Hello, (world)!" - ); - } +TEST(hiliteMatches, simpleHighlight) +{ + std::string str = "Hello, world!"; + std::regex re = std::regex("world"); + auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); + ASSERT_STREQ(hiliteMatches(str, matches, "(", ")").c_str(), "Hello, (world)!"); +} - TEST(hiliteMatches, multipleMatches) { - std::string str = "Hello, world, world, world, world, world, world, Hello!"; - std::regex re = std::regex("world"); - auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); - ASSERT_STREQ( - hiliteMatches(str, matches, "(", ")").c_str(), - "Hello, (world), (world), (world), (world), (world), (world), Hello!" - ); - } +TEST(hiliteMatches, multipleMatches) +{ + std::string str = "Hello, world, world, world, world, world, world, Hello!"; + std::regex re = std::regex("world"); + auto matches = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); + ASSERT_STREQ( + hiliteMatches(str, matches, "(", ")").c_str(), + "Hello, (world), (world), (world), (world), (world), (world), Hello!"); +} - TEST(hiliteMatches, overlappingMatches) { - std::string str = "world, Hello, world, Hello, world, Hello, world, Hello, world!"; - std::regex re = std::regex("Hello, world"); - std::regex re2 = std::regex("world, Hello"); - auto v = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); - for(auto it = std::sregex_iterator(str.begin(), str.end(), re2); it != std::sregex_iterator(); ++it) { - v.push_back(*it); - } - ASSERT_STREQ( - hiliteMatches(str, v, "(", ")").c_str(), - "(world, Hello, world, Hello, world, Hello, world, Hello, world)!" - ); +TEST(hiliteMatches, overlappingMatches) +{ + std::string str = "world, Hello, world, Hello, world, Hello, world, Hello, world!"; + std::regex re = std::regex("Hello, world"); + std::regex re2 = std::regex("world, Hello"); + auto v = std::vector(std::sregex_iterator(str.begin(), str.end(), re), std::sregex_iterator()); + for (auto it = std::sregex_iterator(str.begin(), str.end(), re2); it != std::sregex_iterator(); ++it) { + v.push_back(*it); } + ASSERT_STREQ( + hiliteMatches(str, v, "(", ")").c_str(), "(world, Hello, world, Hello, world, Hello, world, Hello, world)!"); +} - TEST(hiliteMatches, complexOverlappingMatches) { - std::string str = "legacyPackages.x86_64-linux.git-crypt"; - std::vector regexes = { - std::regex("t-cry"), - std::regex("ux\\.git-cry"), - std::regex("git-c"), - std::regex("pt"), - }; - std::vector matches; - for(auto regex : regexes) - { - for(auto it = std::sregex_iterator(str.begin(), str.end(), regex); it != std::sregex_iterator(); ++it) { - matches.push_back(*it); - } +TEST(hiliteMatches, complexOverlappingMatches) +{ + std::string str = "legacyPackages.x86_64-linux.git-crypt"; + std::vector regexes = { + std::regex("t-cry"), + std::regex("ux\\.git-cry"), + std::regex("git-c"), + std::regex("pt"), + }; + std::vector matches; + for (auto regex : regexes) { + for (auto it = std::sregex_iterator(str.begin(), str.end(), regex); it != std::sregex_iterator(); ++it) { + matches.push_back(*it); } - ASSERT_STREQ( - hiliteMatches(str, matches, "(", ")").c_str(), - "legacyPackages.x86_64-lin(ux.git-crypt)" - ); } + ASSERT_STREQ(hiliteMatches(str, matches, "(", ")").c_str(), "legacyPackages.x86_64-lin(ux.git-crypt)"); +} } diff --git a/src/libutil/tests/json.cc b/src/libutil/tests/json.cc index dea73f53a91b..4b299feb71ac 100644 --- a/src/libutil/tests/json.cc +++ b/src/libutil/tests/json.cc @@ -4,190 +4,209 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * toJSON - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * toJSON + * --------------------------------------------------------------------------*/ - TEST(toJSON, quotesCharPtr) { - const char* input = "test"; - std::stringstream out; - toJSON(out, input); +TEST(toJSON, quotesCharPtr) +{ + const char * input = "test"; + std::stringstream out; + toJSON(out, input); - ASSERT_EQ(out.str(), "\"test\""); - } + ASSERT_EQ(out.str(), "\"test\""); +} - TEST(toJSON, quotesStdString) { - std::string input = "test"; - std::stringstream out; - toJSON(out, input); +TEST(toJSON, quotesStdString) +{ + std::string input = "test"; + std::stringstream out; + toJSON(out, input); - ASSERT_EQ(out.str(), "\"test\""); - } - - TEST(toJSON, convertsNullptrtoNull) { - auto input = nullptr; - std::stringstream out; - toJSON(out, input); + ASSERT_EQ(out.str(), "\"test\""); +} - ASSERT_EQ(out.str(), "null"); - } +TEST(toJSON, convertsNullptrtoNull) +{ + auto input = nullptr; + std::stringstream out; + toJSON(out, input); - TEST(toJSON, convertsNullToNull) { - const char* input = 0; - std::stringstream out; - toJSON(out, input); + ASSERT_EQ(out.str(), "null"); +} - ASSERT_EQ(out.str(), "null"); - } +TEST(toJSON, convertsNullToNull) +{ + const char * input = 0; + std::stringstream out; + toJSON(out, input); + ASSERT_EQ(out.str(), "null"); +} - TEST(toJSON, convertsFloat) { - auto input = 1.024f; - std::stringstream out; - toJSON(out, input); +TEST(toJSON, convertsFloat) +{ + auto input = 1.024f; + std::stringstream out; + toJSON(out, input); - ASSERT_EQ(out.str(), "1.024"); - } + ASSERT_EQ(out.str(), "1.024"); +} - TEST(toJSON, convertsDouble) { - const double input = 1.024; - std::stringstream out; - toJSON(out, input); +TEST(toJSON, convertsDouble) +{ + const double input = 1.024; + std::stringstream out; + toJSON(out, input); - ASSERT_EQ(out.str(), "1.024"); - } + ASSERT_EQ(out.str(), "1.024"); +} - TEST(toJSON, convertsBool) { - auto input = false; - std::stringstream out; - toJSON(out, input); +TEST(toJSON, convertsBool) +{ + auto input = false; + std::stringstream out; + toJSON(out, input); - ASSERT_EQ(out.str(), "false"); - } + ASSERT_EQ(out.str(), "false"); +} - TEST(toJSON, quotesTab) { - std::stringstream out; - toJSON(out, "\t"); +TEST(toJSON, quotesTab) +{ + std::stringstream out; + toJSON(out, "\t"); - ASSERT_EQ(out.str(), "\"\\t\""); - } + ASSERT_EQ(out.str(), "\"\\t\""); +} - TEST(toJSON, quotesNewline) { - std::stringstream out; - toJSON(out, "\n"); +TEST(toJSON, quotesNewline) +{ + std::stringstream out; + toJSON(out, "\n"); - ASSERT_EQ(out.str(), "\"\\n\""); - } + ASSERT_EQ(out.str(), "\"\\n\""); +} - TEST(toJSON, quotesCreturn) { - std::stringstream out; - toJSON(out, "\r"); +TEST(toJSON, quotesCreturn) +{ + std::stringstream out; + toJSON(out, "\r"); - ASSERT_EQ(out.str(), "\"\\r\""); - } + ASSERT_EQ(out.str(), "\"\\r\""); +} - TEST(toJSON, quotesCreturnNewLine) { - std::stringstream out; - toJSON(out, "\r\n"); +TEST(toJSON, quotesCreturnNewLine) +{ + std::stringstream out; + toJSON(out, "\r\n"); - ASSERT_EQ(out.str(), "\"\\r\\n\""); - } + ASSERT_EQ(out.str(), "\"\\r\\n\""); +} - TEST(toJSON, quotesDoublequotes) { - std::stringstream out; - toJSON(out, "\""); +TEST(toJSON, quotesDoublequotes) +{ + std::stringstream out; + toJSON(out, "\""); - ASSERT_EQ(out.str(), "\"\\\"\""); - } + ASSERT_EQ(out.str(), "\"\\\"\""); +} - TEST(toJSON, substringEscape) { - std::stringstream out; - const char *s = "foo\t"; - toJSON(out, s+3, s + strlen(s)); +TEST(toJSON, substringEscape) +{ + std::stringstream out; + const char * s = "foo\t"; + toJSON(out, s + 3, s + strlen(s)); - ASSERT_EQ(out.str(), "\"\\t\""); - } + ASSERT_EQ(out.str(), "\"\\t\""); +} - /* ---------------------------------------------------------------------------- - * JSONObject - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * JSONObject + * --------------------------------------------------------------------------*/ - TEST(JSONObject, emptyObject) { - std::stringstream out; - { - JSONObject t(out); - } - ASSERT_EQ(out.str(), "{}"); +TEST(JSONObject, emptyObject) +{ + std::stringstream out; + { + JSONObject t(out); } + ASSERT_EQ(out.str(), "{}"); +} - TEST(JSONObject, objectWithList) { - std::stringstream out; - { - JSONObject t(out); - auto l = t.list("list"); - l.elem("element"); - } - ASSERT_EQ(out.str(), R"#({"list":["element"]})#"); +TEST(JSONObject, objectWithList) +{ + std::stringstream out; + { + JSONObject t(out); + auto l = t.list("list"); + l.elem("element"); } + ASSERT_EQ(out.str(), R"#({"list":["element"]})#"); +} - TEST(JSONObject, objectWithListIndent) { - std::stringstream out; - { - JSONObject t(out, true); - auto l = t.list("list"); - l.elem("element"); - } - ASSERT_EQ(out.str(), -R"#({ +TEST(JSONObject, objectWithListIndent) +{ + std::stringstream out; + { + JSONObject t(out, true); + auto l = t.list("list"); + l.elem("element"); + } + ASSERT_EQ( + out.str(), + R"#({ "list": [ "element" ] })#"); - } - - TEST(JSONObject, objectWithPlaceholderAndList) { - std::stringstream out; - { - JSONObject t(out); - auto l = t.placeholder("list"); - l.list().elem("element"); - } +} - ASSERT_EQ(out.str(), R"#({"list":["element"]})#"); +TEST(JSONObject, objectWithPlaceholderAndList) +{ + std::stringstream out; + { + JSONObject t(out); + auto l = t.placeholder("list"); + l.list().elem("element"); } - TEST(JSONObject, objectWithPlaceholderAndObject) { - std::stringstream out; - { - JSONObject t(out); - auto l = t.placeholder("object"); - l.object().attr("key", "value"); - } + ASSERT_EQ(out.str(), R"#({"list":["element"]})#"); +} - ASSERT_EQ(out.str(), R"#({"object":{"key":"value"}})#"); +TEST(JSONObject, objectWithPlaceholderAndObject) +{ + std::stringstream out; + { + JSONObject t(out); + auto l = t.placeholder("object"); + l.object().attr("key", "value"); } - /* ---------------------------------------------------------------------------- - * JSONList - * --------------------------------------------------------------------------*/ + ASSERT_EQ(out.str(), R"#({"object":{"key":"value"}})#"); +} - TEST(JSONList, empty) { - std::stringstream out; - { - JSONList l(out); - } - ASSERT_EQ(out.str(), R"#([])#"); - } +/* ---------------------------------------------------------------------------- + * JSONList + * --------------------------------------------------------------------------*/ - TEST(JSONList, withElements) { - std::stringstream out; - { - JSONList l(out); - l.elem("one"); - l.object(); - l.placeholder().write("three"); - } - ASSERT_EQ(out.str(), R"#(["one",{},"three"])#"); +TEST(JSONList, empty) +{ + std::stringstream out; + { + JSONList l(out); } + ASSERT_EQ(out.str(), R"#([])#"); } +TEST(JSONList, withElements) +{ + std::stringstream out; + { + JSONList l(out); + l.elem("one"); + l.object(); + l.placeholder().write("three"); + } + ASSERT_EQ(out.str(), R"#(["one",{},"three"])#"); +} +} diff --git a/src/libutil/tests/lru-cache.cc b/src/libutil/tests/lru-cache.cc index 091d3d5ede19..d3c461dbf06f 100644 --- a/src/libutil/tests/lru-cache.cc +++ b/src/libutil/tests/lru-cache.cc @@ -3,128 +3,141 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * size - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, sizeOfEmptyCacheIsZero) { - LRUCache c(10); - ASSERT_EQ(c.size(), 0); - } - - TEST(LRUCache, sizeOfSingleElementCacheIsOne) { - LRUCache c(10); - c.upsert("foo", "bar"); - ASSERT_EQ(c.size(), 1); - } - - /* ---------------------------------------------------------------------------- - * upsert / get - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, getFromEmptyCache) { - LRUCache c(10); - auto val = c.get("x"); - ASSERT_EQ(val.has_value(), false); - } - - TEST(LRUCache, getExistingValue) { - LRUCache c(10); - c.upsert("foo", "bar"); - auto val = c.get("foo"); - ASSERT_EQ(val, "bar"); - } - - TEST(LRUCache, getNonExistingValueFromNonEmptyCache) { - LRUCache c(10); - c.upsert("foo", "bar"); - auto val = c.get("another"); - ASSERT_EQ(val.has_value(), false); - } - - TEST(LRUCache, upsertOnZeroCapacityCache) { - LRUCache c(0); - c.upsert("foo", "bar"); - auto val = c.get("foo"); - ASSERT_EQ(val.has_value(), false); - } - - TEST(LRUCache, updateExistingValue) { - LRUCache c(1); - c.upsert("foo", "bar"); - - auto val = c.get("foo"); - ASSERT_EQ(val.value_or("error"), "bar"); - ASSERT_EQ(c.size(), 1); - - c.upsert("foo", "changed"); - val = c.get("foo"); - ASSERT_EQ(val.value_or("error"), "changed"); - ASSERT_EQ(c.size(), 1); - } - - TEST(LRUCache, overwriteOldestWhenCapacityIsReached) { - LRUCache c(3); - c.upsert("one", "eins"); - c.upsert("two", "zwei"); - c.upsert("three", "drei"); - - ASSERT_EQ(c.size(), 3); - ASSERT_EQ(c.get("one").value_or("error"), "eins"); - - // exceed capacity - c.upsert("another", "whatever"); - - ASSERT_EQ(c.size(), 3); - // Retrieving "one" makes it the most recent element thus - // two will be the oldest one and thus replaced. - ASSERT_EQ(c.get("two").has_value(), false); - ASSERT_EQ(c.get("another").value(), "whatever"); - } - - /* ---------------------------------------------------------------------------- - * clear - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, clearEmptyCache) { - LRUCache c(10); - c.clear(); - ASSERT_EQ(c.size(), 0); - } - - TEST(LRUCache, clearNonEmptyCache) { - LRUCache c(10); - c.upsert("one", "eins"); - c.upsert("two", "zwei"); - c.upsert("three", "drei"); - ASSERT_EQ(c.size(), 3); - c.clear(); - ASSERT_EQ(c.size(), 0); - } - - /* ---------------------------------------------------------------------------- - * erase - * --------------------------------------------------------------------------*/ - - TEST(LRUCache, eraseFromEmptyCache) { - LRUCache c(10); - ASSERT_EQ(c.erase("foo"), false); - ASSERT_EQ(c.size(), 0); - } - - TEST(LRUCache, eraseMissingFromNonEmptyCache) { - LRUCache c(10); - c.upsert("one", "eins"); - ASSERT_EQ(c.erase("foo"), false); - ASSERT_EQ(c.size(), 1); - ASSERT_EQ(c.get("one").value_or("error"), "eins"); - } - - TEST(LRUCache, eraseFromNonEmptyCache) { - LRUCache c(10); - c.upsert("one", "eins"); - ASSERT_EQ(c.erase("one"), true); - ASSERT_EQ(c.size(), 0); - ASSERT_EQ(c.get("one").value_or("empty"), "empty"); - } +/* ---------------------------------------------------------------------------- + * size + * --------------------------------------------------------------------------*/ + +TEST(LRUCache, sizeOfEmptyCacheIsZero) +{ + LRUCache c(10); + ASSERT_EQ(c.size(), 0); +} + +TEST(LRUCache, sizeOfSingleElementCacheIsOne) +{ + LRUCache c(10); + c.upsert("foo", "bar"); + ASSERT_EQ(c.size(), 1); +} + +/* ---------------------------------------------------------------------------- + * upsert / get + * --------------------------------------------------------------------------*/ + +TEST(LRUCache, getFromEmptyCache) +{ + LRUCache c(10); + auto val = c.get("x"); + ASSERT_EQ(val.has_value(), false); +} + +TEST(LRUCache, getExistingValue) +{ + LRUCache c(10); + c.upsert("foo", "bar"); + auto val = c.get("foo"); + ASSERT_EQ(val, "bar"); +} + +TEST(LRUCache, getNonExistingValueFromNonEmptyCache) +{ + LRUCache c(10); + c.upsert("foo", "bar"); + auto val = c.get("another"); + ASSERT_EQ(val.has_value(), false); +} + +TEST(LRUCache, upsertOnZeroCapacityCache) +{ + LRUCache c(0); + c.upsert("foo", "bar"); + auto val = c.get("foo"); + ASSERT_EQ(val.has_value(), false); +} + +TEST(LRUCache, updateExistingValue) +{ + LRUCache c(1); + c.upsert("foo", "bar"); + + auto val = c.get("foo"); + ASSERT_EQ(val.value_or("error"), "bar"); + ASSERT_EQ(c.size(), 1); + + c.upsert("foo", "changed"); + val = c.get("foo"); + ASSERT_EQ(val.value_or("error"), "changed"); + ASSERT_EQ(c.size(), 1); +} + +TEST(LRUCache, overwriteOldestWhenCapacityIsReached) +{ + LRUCache c(3); + c.upsert("one", "eins"); + c.upsert("two", "zwei"); + c.upsert("three", "drei"); + + ASSERT_EQ(c.size(), 3); + ASSERT_EQ(c.get("one").value_or("error"), "eins"); + + // exceed capacity + c.upsert("another", "whatever"); + + ASSERT_EQ(c.size(), 3); + // Retrieving "one" makes it the most recent element thus + // two will be the oldest one and thus replaced. + ASSERT_EQ(c.get("two").has_value(), false); + ASSERT_EQ(c.get("another").value(), "whatever"); +} + +/* ---------------------------------------------------------------------------- + * clear + * --------------------------------------------------------------------------*/ + +TEST(LRUCache, clearEmptyCache) +{ + LRUCache c(10); + c.clear(); + ASSERT_EQ(c.size(), 0); +} + +TEST(LRUCache, clearNonEmptyCache) +{ + LRUCache c(10); + c.upsert("one", "eins"); + c.upsert("two", "zwei"); + c.upsert("three", "drei"); + ASSERT_EQ(c.size(), 3); + c.clear(); + ASSERT_EQ(c.size(), 0); +} + +/* ---------------------------------------------------------------------------- + * erase + * --------------------------------------------------------------------------*/ + +TEST(LRUCache, eraseFromEmptyCache) +{ + LRUCache c(10); + ASSERT_EQ(c.erase("foo"), false); + ASSERT_EQ(c.size(), 0); +} + +TEST(LRUCache, eraseMissingFromNonEmptyCache) +{ + LRUCache c(10); + c.upsert("one", "eins"); + ASSERT_EQ(c.erase("foo"), false); + ASSERT_EQ(c.size(), 1); + ASSERT_EQ(c.get("one").value_or("error"), "eins"); +} + +TEST(LRUCache, eraseFromNonEmptyCache) +{ + LRUCache c(10); + c.upsert("one", "eins"); + ASSERT_EQ(c.erase("one"), true); + ASSERT_EQ(c.size(), 0); + ASSERT_EQ(c.get("one").value_or("empty"), "empty"); +} } diff --git a/src/libutil/tests/pool.cc b/src/libutil/tests/pool.cc index 127e42dda2b1..e3633e6ed866 100644 --- a/src/libutil/tests/pool.cc +++ b/src/libutil/tests/pool.cc @@ -3,125 +3,133 @@ namespace nix { - struct TestResource +struct TestResource +{ + + TestResource() { + static int counter = 0; + num = counter++; + } - TestResource() { - static int counter = 0; - num = counter++; - } + int dummyValue = 1; + bool good = true; + int num; +}; - int dummyValue = 1; - bool good = true; - int num; - }; +/* ---------------------------------------------------------------------------- + * Pool + * --------------------------------------------------------------------------*/ - /* ---------------------------------------------------------------------------- - * Pool - * --------------------------------------------------------------------------*/ +TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity) +{ + auto isGood = [](const ref & r) { return r->good; }; + auto createResource = []() { return make_ref(); }; - TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity) { - auto isGood = [](const ref & r) { return r->good; }; - auto createResource = []() { return make_ref(); }; + Pool pool = Pool((size_t) 1, createResource, isGood); - Pool pool = Pool((size_t)1, createResource, isGood); + ASSERT_EQ(pool.count(), 0); + ASSERT_EQ(pool.capacity(), 1); +} - ASSERT_EQ(pool.count(), 0); - ASSERT_EQ(pool.capacity(), 1); - } +TEST(Pool, freshPoolCanGetAResource) +{ + auto isGood = [](const ref & r) { return r->good; }; + auto createResource = []() { return make_ref(); }; - TEST(Pool, freshPoolCanGetAResource) { - auto isGood = [](const ref & r) { return r->good; }; - auto createResource = []() { return make_ref(); }; + Pool pool = Pool((size_t) 1, createResource, isGood); + ASSERT_EQ(pool.count(), 0); - Pool pool = Pool((size_t)1, createResource, isGood); - ASSERT_EQ(pool.count(), 0); + TestResource r = *(pool.get()); - TestResource r = *(pool.get()); + ASSERT_EQ(pool.count(), 1); + ASSERT_EQ(pool.capacity(), 1); + ASSERT_EQ(r.dummyValue, 1); + ASSERT_EQ(r.good, true); +} - ASSERT_EQ(pool.count(), 1); - ASSERT_EQ(pool.capacity(), 1); - ASSERT_EQ(r.dummyValue, 1); - ASSERT_EQ(r.good, true); - } +TEST(Pool, capacityCanBeIncremented) +{ + auto isGood = [](const ref & r) { return r->good; }; + auto createResource = []() { return make_ref(); }; - TEST(Pool, capacityCanBeIncremented) { - auto isGood = [](const ref & r) { return r->good; }; - auto createResource = []() { return make_ref(); }; + Pool pool = Pool((size_t) 1, createResource, isGood); + ASSERT_EQ(pool.capacity(), 1); + pool.incCapacity(); + ASSERT_EQ(pool.capacity(), 2); +} - Pool pool = Pool((size_t)1, createResource, isGood); - ASSERT_EQ(pool.capacity(), 1); - pool.incCapacity(); - ASSERT_EQ(pool.capacity(), 2); - } +TEST(Pool, capacityCanBeDecremented) +{ + auto isGood = [](const ref & r) { return r->good; }; + auto createResource = []() { return make_ref(); }; + + Pool pool = Pool((size_t) 1, createResource, isGood); + ASSERT_EQ(pool.capacity(), 1); + pool.decCapacity(); + ASSERT_EQ(pool.capacity(), 0); +} + +TEST(Pool, flushBadDropsOutOfScopeResources) +{ + auto isGood = [](const ref & r) { return false; }; + auto createResource = []() { return make_ref(); }; - TEST(Pool, capacityCanBeDecremented) { - auto isGood = [](const ref & r) { return r->good; }; - auto createResource = []() { return make_ref(); }; + Pool pool = Pool((size_t) 1, createResource, isGood); - Pool pool = Pool((size_t)1, createResource, isGood); - ASSERT_EQ(pool.capacity(), 1); - pool.decCapacity(); - ASSERT_EQ(pool.capacity(), 0); + { + auto _r = pool.get(); + ASSERT_EQ(pool.count(), 1); } - TEST(Pool, flushBadDropsOutOfScopeResources) { - auto isGood = [](const ref & r) { return false; }; - auto createResource = []() { return make_ref(); }; + pool.flushBad(); + ASSERT_EQ(pool.count(), 0); +} - Pool pool = Pool((size_t)1, createResource, isGood); +// Test that the resources we allocate are being reused when they are still good. +TEST(Pool, reuseResource) +{ + auto isGood = [](const ref & r) { return true; }; + auto createResource = []() { return make_ref(); }; - { - auto _r = pool.get(); - ASSERT_EQ(pool.count(), 1); - } + Pool pool = Pool((size_t) 1, createResource, isGood); - pool.flushBad(); - ASSERT_EQ(pool.count(), 0); - } + // Compare the instance counter between the two handles. We expect them to be equal + // as the pool should hand out the same (still) good one again. + int counter = -1; + { + Pool::Handle h = pool.get(); + counter = h->num; + } // the first handle goes out of scope - // Test that the resources we allocate are being reused when they are still good. - TEST(Pool, reuseResource) { - auto isGood = [](const ref & r) { return true; }; - auto createResource = []() { return make_ref(); }; - - Pool pool = Pool((size_t)1, createResource, isGood); - - // Compare the instance counter between the two handles. We expect them to be equal - // as the pool should hand out the same (still) good one again. - int counter = -1; - { - Pool::Handle h = pool.get(); - counter = h->num; - } // the first handle goes out of scope - - { // the second handle should contain the same resource (with the same counter value) - Pool::Handle h = pool.get(); - ASSERT_EQ(h->num, counter); - } + { // the second handle should contain the same resource (with the same counter value) + Pool::Handle h = pool.get(); + ASSERT_EQ(h->num, counter); } +} - // Test that the resources we allocate are being thrown away when they are no longer good. - TEST(Pool, badResourceIsNotReused) { - auto isGood = [](const ref & r) { return false; }; - auto createResource = []() { return make_ref(); }; - - Pool pool = Pool((size_t)1, createResource, isGood); - - // Compare the instance counter between the two handles. We expect them - // to *not* be equal as the pool should hand out a new instance after - // the first one was returned. - int counter = -1; - { - Pool::Handle h = pool.get(); - counter = h->num; - } // the first handle goes out of scope - - { - // the second handle should contain a different resource (with a - //different counter value) - Pool::Handle h = pool.get(); - ASSERT_NE(h->num, counter); - } +// Test that the resources we allocate are being thrown away when they are no longer good. +TEST(Pool, badResourceIsNotReused) +{ + auto isGood = [](const ref & r) { return false; }; + auto createResource = []() { return make_ref(); }; + + Pool pool = Pool((size_t) 1, createResource, isGood); + + // Compare the instance counter between the two handles. We expect them + // to *not* be equal as the pool should hand out a new instance after + // the first one was returned. + int counter = -1; + { + Pool::Handle h = pool.get(); + counter = h->num; + } // the first handle goes out of scope + + { + // the second handle should contain a different resource (with a + // different counter value) + Pool::Handle h = pool.get(); + ASSERT_NE(h->num, counter); } } +} diff --git a/src/libutil/tests/suggestions.cc b/src/libutil/tests/suggestions.cc index 279994abc67e..a537579cdde9 100644 --- a/src/libutil/tests/suggestions.cc +++ b/src/libutil/tests/suggestions.cc @@ -3,41 +3,43 @@ namespace nix { - struct LevenshteinDistanceParam { - std::string s1, s2; - int distance; - }; - - class LevenshteinDistanceTest : - public testing::TestWithParam { - }; - - TEST_P(LevenshteinDistanceTest, CorrectlyComputed) { - auto params = GetParam(); - - ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance); - ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance); - } - - INSTANTIATE_TEST_SUITE_P(LevenshteinDistance, LevenshteinDistanceTest, - testing::Values( - LevenshteinDistanceParam{"foo", "foo", 0}, - LevenshteinDistanceParam{"foo", "", 3}, - LevenshteinDistanceParam{"", "", 0}, - LevenshteinDistanceParam{"foo", "fo", 1}, - LevenshteinDistanceParam{"foo", "oo", 1}, - LevenshteinDistanceParam{"foo", "fao", 1}, - LevenshteinDistanceParam{"foo", "abc", 3} - ) - ); - - TEST(Suggestions, Trim) { - auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo"); - auto onlyOne = suggestions.trim(1); - ASSERT_EQ(onlyOne.suggestions.size(), 1); - ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo"); - - auto closest = suggestions.trim(999, 2); - ASSERT_EQ(closest.suggestions.size(), 3); - } +struct LevenshteinDistanceParam +{ + std::string s1, s2; + int distance; +}; + +class LevenshteinDistanceTest : public testing::TestWithParam +{}; + +TEST_P(LevenshteinDistanceTest, CorrectlyComputed) +{ + auto params = GetParam(); + + ASSERT_EQ(levenshteinDistance(params.s1, params.s2), params.distance); + ASSERT_EQ(levenshteinDistance(params.s2, params.s1), params.distance); +} + +INSTANTIATE_TEST_SUITE_P( + LevenshteinDistance, + LevenshteinDistanceTest, + testing::Values( + LevenshteinDistanceParam{"foo", "foo", 0}, + LevenshteinDistanceParam{"foo", "", 3}, + LevenshteinDistanceParam{"", "", 0}, + LevenshteinDistanceParam{"foo", "fo", 1}, + LevenshteinDistanceParam{"foo", "oo", 1}, + LevenshteinDistanceParam{"foo", "fao", 1}, + LevenshteinDistanceParam{"foo", "abc", 3})); + +TEST(Suggestions, Trim) +{ + auto suggestions = Suggestions::bestMatches({"foooo", "bar", "fo", "gao"}, "foo"); + auto onlyOne = suggestions.trim(1); + ASSERT_EQ(onlyOne.suggestions.size(), 1); + ASSERT_TRUE(onlyOne.suggestions.begin()->suggestion == "fo"); + + auto closest = suggestions.trim(999, 2); + ASSERT_EQ(closest.suggestions.size(), 3); +} } diff --git a/src/libutil/tests/tests.cc b/src/libutil/tests/tests.cc index 6e325db9835b..a00423b7ad5b 100644 --- a/src/libutil/tests/tests.cc +++ b/src/libutil/tests/tests.cc @@ -10,614 +10,688 @@ namespace nix { /* ----------- tests for util.hh ------------------------------------------------*/ - /* ---------------------------------------------------------------------------- - * absPath - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * absPath + * --------------------------------------------------------------------------*/ - TEST(absPath, doesntChangeRoot) { - auto p = absPath("/"); +TEST(absPath, doesntChangeRoot) +{ + auto p = absPath("/"); - ASSERT_EQ(p, "/"); - } + ASSERT_EQ(p, "/"); +} +TEST(absPath, turnsEmptyPathIntoCWD) +{ + char cwd[PATH_MAX + 1]; + auto p = absPath(""); + ASSERT_EQ(p, getcwd((char *) &cwd, PATH_MAX)); +} +TEST(absPath, usesOptionalBasePathWhenGiven) +{ + char _cwd[PATH_MAX + 1]; + char * cwd = getcwd((char *) &_cwd, PATH_MAX); - TEST(absPath, turnsEmptyPathIntoCWD) { - char cwd[PATH_MAX+1]; - auto p = absPath(""); + auto p = absPath("", cwd); - ASSERT_EQ(p, getcwd((char*)&cwd, PATH_MAX)); - } + ASSERT_EQ(p, cwd); +} - TEST(absPath, usesOptionalBasePathWhenGiven) { - char _cwd[PATH_MAX+1]; - char* cwd = getcwd((char*)&_cwd, PATH_MAX); +TEST(absPath, isIdempotent) +{ + char _cwd[PATH_MAX + 1]; + char * cwd = getcwd((char *) &_cwd, PATH_MAX); + auto p1 = absPath(cwd); + auto p2 = absPath(p1); - auto p = absPath("", cwd); + ASSERT_EQ(p1, p2); +} - ASSERT_EQ(p, cwd); - } +TEST(absPath, pathIsCanonicalised) +{ + auto path = "/some/path/with/trailing/dot/."; + auto p1 = absPath(path); + auto p2 = absPath(p1); - TEST(absPath, isIdempotent) { - char _cwd[PATH_MAX+1]; - char* cwd = getcwd((char*)&_cwd, PATH_MAX); - auto p1 = absPath(cwd); - auto p2 = absPath(p1); + ASSERT_EQ(p1, "/some/path/with/trailing/dot"); + ASSERT_EQ(p1, p2); +} - ASSERT_EQ(p1, p2); - } +/* ---------------------------------------------------------------------------- + * canonPath + * --------------------------------------------------------------------------*/ +TEST(canonPath, removesTrailingSlashes) +{ + auto path = "/this/is/a/path//"; + auto p = canonPath(path); - TEST(absPath, pathIsCanonicalised) { - auto path = "/some/path/with/trailing/dot/."; - auto p1 = absPath(path); - auto p2 = absPath(p1); + ASSERT_EQ(p, "/this/is/a/path"); +} - ASSERT_EQ(p1, "/some/path/with/trailing/dot"); - ASSERT_EQ(p1, p2); - } +TEST(canonPath, removesDots) +{ + auto path = "/this/./is/a/path/./"; + auto p = canonPath(path); - /* ---------------------------------------------------------------------------- - * canonPath - * --------------------------------------------------------------------------*/ + ASSERT_EQ(p, "/this/is/a/path"); +} - TEST(canonPath, removesTrailingSlashes) { - auto path = "/this/is/a/path//"; - auto p = canonPath(path); +TEST(canonPath, removesDots2) +{ + auto path = "/this/a/../is/a////path/foo/.."; + auto p = canonPath(path); - ASSERT_EQ(p, "/this/is/a/path"); - } + ASSERT_EQ(p, "/this/is/a/path"); +} - TEST(canonPath, removesDots) { - auto path = "/this/./is/a/path/./"; - auto p = canonPath(path); +TEST(canonPath, requiresAbsolutePath) +{ + ASSERT_ANY_THROW(canonPath(".")); + ASSERT_ANY_THROW(canonPath("..")); + ASSERT_ANY_THROW(canonPath("../")); + ASSERT_DEATH({ canonPath(""); }, "path != \"\""); +} - ASSERT_EQ(p, "/this/is/a/path"); - } +/* ---------------------------------------------------------------------------- + * dirOf + * --------------------------------------------------------------------------*/ - TEST(canonPath, removesDots2) { - auto path = "/this/a/../is/a////path/foo/.."; - auto p = canonPath(path); +TEST(dirOf, returnsEmptyStringForRoot) +{ + auto p = dirOf("/"); - ASSERT_EQ(p, "/this/is/a/path"); - } + ASSERT_EQ(p, "/"); +} - TEST(canonPath, requiresAbsolutePath) { - ASSERT_ANY_THROW(canonPath(".")); - ASSERT_ANY_THROW(canonPath("..")); - ASSERT_ANY_THROW(canonPath("../")); - ASSERT_DEATH({ canonPath(""); }, "path != \"\""); - } +TEST(dirOf, returnsFirstPathComponent) +{ + auto p1 = dirOf("/dir/"); + ASSERT_EQ(p1, "/dir"); + auto p2 = dirOf("/dir"); + ASSERT_EQ(p2, "/"); + auto p3 = dirOf("/dir/.."); + ASSERT_EQ(p3, "/dir"); + auto p4 = dirOf("/dir/../"); + ASSERT_EQ(p4, "/dir/.."); +} - /* ---------------------------------------------------------------------------- - * dirOf - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * baseNameOf + * --------------------------------------------------------------------------*/ - TEST(dirOf, returnsEmptyStringForRoot) { - auto p = dirOf("/"); +TEST(baseNameOf, emptyPath) +{ + auto p1 = baseNameOf(""); + ASSERT_EQ(p1, ""); +} - ASSERT_EQ(p, "/"); - } +TEST(baseNameOf, pathOnRoot) +{ + auto p1 = baseNameOf("/dir"); + ASSERT_EQ(p1, "dir"); +} - TEST(dirOf, returnsFirstPathComponent) { - auto p1 = dirOf("/dir/"); - ASSERT_EQ(p1, "/dir"); - auto p2 = dirOf("/dir"); - ASSERT_EQ(p2, "/"); - auto p3 = dirOf("/dir/.."); - ASSERT_EQ(p3, "/dir"); - auto p4 = dirOf("/dir/../"); - ASSERT_EQ(p4, "/dir/.."); - } +TEST(baseNameOf, relativePath) +{ + auto p1 = baseNameOf("dir/foo"); + ASSERT_EQ(p1, "foo"); +} - /* ---------------------------------------------------------------------------- - * baseNameOf - * --------------------------------------------------------------------------*/ +TEST(baseNameOf, pathWithTrailingSlashRoot) +{ + auto p1 = baseNameOf("/"); + ASSERT_EQ(p1, ""); +} - TEST(baseNameOf, emptyPath) { - auto p1 = baseNameOf(""); - ASSERT_EQ(p1, ""); - } +TEST(baseNameOf, trailingSlash) +{ + auto p1 = baseNameOf("/dir/"); + ASSERT_EQ(p1, "dir"); +} - TEST(baseNameOf, pathOnRoot) { - auto p1 = baseNameOf("/dir"); - ASSERT_EQ(p1, "dir"); - } - - TEST(baseNameOf, relativePath) { - auto p1 = baseNameOf("dir/foo"); - ASSERT_EQ(p1, "foo"); - } - - TEST(baseNameOf, pathWithTrailingSlashRoot) { - auto p1 = baseNameOf("/"); - ASSERT_EQ(p1, ""); - } - - TEST(baseNameOf, trailingSlash) { - auto p1 = baseNameOf("/dir/"); - ASSERT_EQ(p1, "dir"); - } - - /* ---------------------------------------------------------------------------- - * isInDir - * --------------------------------------------------------------------------*/ - - TEST(isInDir, trivialCase) { - auto p1 = isInDir("/foo/bar", "/foo"); - ASSERT_EQ(p1, true); - } - - TEST(isInDir, notInDir) { - auto p1 = isInDir("/zes/foo/bar", "/foo"); - ASSERT_EQ(p1, false); - } - - // XXX: hm, bug or feature? :) Looking at the implementation - // this might be problematic. - TEST(isInDir, emptyDir) { - auto p1 = isInDir("/zes/foo/bar", ""); - ASSERT_EQ(p1, true); - } - - /* ---------------------------------------------------------------------------- - * isDirOrInDir - * --------------------------------------------------------------------------*/ - - TEST(isDirOrInDir, trueForSameDirectory) { - ASSERT_EQ(isDirOrInDir("/nix", "/nix"), true); - ASSERT_EQ(isDirOrInDir("/", "/"), true); - } - - TEST(isDirOrInDir, trueForEmptyPaths) { - ASSERT_EQ(isDirOrInDir("", ""), true); - } - - TEST(isDirOrInDir, falseForDisjunctPaths) { - ASSERT_EQ(isDirOrInDir("/foo", "/bar"), false); - } - - TEST(isDirOrInDir, relativePaths) { - ASSERT_EQ(isDirOrInDir("/foo/..", "/foo"), true); - } - - // XXX: while it is possible to use "." or ".." in the - // first argument this doesn't seem to work in the second. - TEST(isDirOrInDir, DISABLED_shouldWork) { - ASSERT_EQ(isDirOrInDir("/foo/..", "/foo/."), true); - - } - - /* ---------------------------------------------------------------------------- - * pathExists - * --------------------------------------------------------------------------*/ - - TEST(pathExists, rootExists) { - ASSERT_TRUE(pathExists("/")); - } - - TEST(pathExists, cwdExists) { - ASSERT_TRUE(pathExists(".")); - } - - TEST(pathExists, bogusPathDoesNotExist) { - ASSERT_FALSE(pathExists("/home/schnitzel/darmstadt/pommes")); - } - - /* ---------------------------------------------------------------------------- - * concatStringsSep - * --------------------------------------------------------------------------*/ - - TEST(concatStringsSep, buildCommaSeparatedString) { - Strings strings; - strings.push_back("this"); - strings.push_back("is"); - strings.push_back("great"); - - ASSERT_EQ(concatStringsSep(",", strings), "this,is,great"); - } - - TEST(concatStringsSep, buildStringWithEmptySeparator) { - Strings strings; - strings.push_back("this"); - strings.push_back("is"); - strings.push_back("great"); - - ASSERT_EQ(concatStringsSep("", strings), "thisisgreat"); - } - - TEST(concatStringsSep, buildSingleString) { - Strings strings; - strings.push_back("this"); - - ASSERT_EQ(concatStringsSep(",", strings), "this"); - } - - /* ---------------------------------------------------------------------------- - * hasPrefix - * --------------------------------------------------------------------------*/ - - TEST(hasPrefix, emptyStringHasNoPrefix) { - ASSERT_FALSE(hasPrefix("", "foo")); - } - - TEST(hasPrefix, emptyStringIsAlwaysPrefix) { - ASSERT_TRUE(hasPrefix("foo", "")); - ASSERT_TRUE(hasPrefix("jshjkfhsadf", "")); - } - - TEST(hasPrefix, trivialCase) { - ASSERT_TRUE(hasPrefix("foobar", "foo")); - } - - /* ---------------------------------------------------------------------------- - * hasSuffix - * --------------------------------------------------------------------------*/ - - TEST(hasSuffix, emptyStringHasNoSuffix) { - ASSERT_FALSE(hasSuffix("", "foo")); - } +/* ---------------------------------------------------------------------------- + * isInDir + * --------------------------------------------------------------------------*/ - TEST(hasSuffix, trivialCase) { - ASSERT_TRUE(hasSuffix("foo", "foo")); - ASSERT_TRUE(hasSuffix("foobar", "bar")); - } +TEST(isInDir, trivialCase) +{ + auto p1 = isInDir("/foo/bar", "/foo"); + ASSERT_EQ(p1, true); +} - /* ---------------------------------------------------------------------------- - * base64Encode - * --------------------------------------------------------------------------*/ +TEST(isInDir, notInDir) +{ + auto p1 = isInDir("/zes/foo/bar", "/foo"); + ASSERT_EQ(p1, false); +} - TEST(base64Encode, emptyString) { - ASSERT_EQ(base64Encode(""), ""); - } +// XXX: hm, bug or feature? :) Looking at the implementation +// this might be problematic. +TEST(isInDir, emptyDir) +{ + auto p1 = isInDir("/zes/foo/bar", ""); + ASSERT_EQ(p1, true); +} - TEST(base64Encode, encodesAString) { - ASSERT_EQ(base64Encode("quod erat demonstrandum"), "cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="); - } +/* ---------------------------------------------------------------------------- + * isDirOrInDir + * --------------------------------------------------------------------------*/ - TEST(base64Encode, encodeAndDecode) { - auto s = "quod erat demonstrandum"; - auto encoded = base64Encode(s); - auto decoded = base64Decode(encoded); +TEST(isDirOrInDir, trueForSameDirectory) +{ + ASSERT_EQ(isDirOrInDir("/nix", "/nix"), true); + ASSERT_EQ(isDirOrInDir("/", "/"), true); +} - ASSERT_EQ(decoded, s); - } +TEST(isDirOrInDir, trueForEmptyPaths) +{ + ASSERT_EQ(isDirOrInDir("", ""), true); +} - TEST(base64Encode, encodeAndDecodeNonPrintable) { - char s[256]; - std::iota(std::rbegin(s), std::rend(s), 0); +TEST(isDirOrInDir, falseForDisjunctPaths) +{ + ASSERT_EQ(isDirOrInDir("/foo", "/bar"), false); +} - auto encoded = base64Encode(s); - auto decoded = base64Decode(encoded); +TEST(isDirOrInDir, relativePaths) +{ + ASSERT_EQ(isDirOrInDir("/foo/..", "/foo"), true); +} - EXPECT_EQ(decoded.length(), 255); - ASSERT_EQ(decoded, s); - } +// XXX: while it is possible to use "." or ".." in the +// first argument this doesn't seem to work in the second. +TEST(isDirOrInDir, DISABLED_shouldWork) +{ + ASSERT_EQ(isDirOrInDir("/foo/..", "/foo/."), true); +} - /* ---------------------------------------------------------------------------- - * base64Decode - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * pathExists + * --------------------------------------------------------------------------*/ - TEST(base64Decode, emptyString) { - ASSERT_EQ(base64Decode(""), ""); - } +TEST(pathExists, rootExists) +{ + ASSERT_TRUE(pathExists("/")); +} - TEST(base64Decode, decodeAString) { - ASSERT_EQ(base64Decode("cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="), "quod erat demonstrandum"); - } +TEST(pathExists, cwdExists) +{ + ASSERT_TRUE(pathExists(".")); +} - TEST(base64Decode, decodeThrowsOnInvalidChar) { - ASSERT_THROW(base64Decode("cXVvZCBlcm_0IGRlbW9uc3RyYW5kdW0="), Error); - } +TEST(pathExists, bogusPathDoesNotExist) +{ + ASSERT_FALSE(pathExists("/home/schnitzel/darmstadt/pommes")); +} - /* ---------------------------------------------------------------------------- - * toLower - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * concatStringsSep + * --------------------------------------------------------------------------*/ - TEST(toLower, emptyString) { - ASSERT_EQ(toLower(""), ""); - } +TEST(concatStringsSep, buildCommaSeparatedString) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("is"); + strings.push_back("great"); - TEST(toLower, nonLetters) { - auto s = "!@(*$#)(@#=\\234_"; - ASSERT_EQ(toLower(s), s); - } + ASSERT_EQ(concatStringsSep(",", strings), "this,is,great"); +} - // std::tolower() doesn't handle unicode characters. In the context of - // store paths this isn't relevant but doesn't hurt to record this behavior - // here. - TEST(toLower, umlauts) { - auto s = "ÄÖÜ"; - ASSERT_EQ(toLower(s), "ÄÖÜ"); - } +TEST(concatStringsSep, buildStringWithEmptySeparator) +{ + Strings strings; + strings.push_back("this"); + strings.push_back("is"); + strings.push_back("great"); - /* ---------------------------------------------------------------------------- - * string2Float - * --------------------------------------------------------------------------*/ + ASSERT_EQ(concatStringsSep("", strings), "thisisgreat"); +} - TEST(string2Float, emptyString) { - ASSERT_EQ(string2Float(""), std::nullopt); - } +TEST(concatStringsSep, buildSingleString) +{ + Strings strings; + strings.push_back("this"); - TEST(string2Float, trivialConversions) { - ASSERT_EQ(string2Float("1.0"), 1.0); + ASSERT_EQ(concatStringsSep(",", strings), "this"); +} - ASSERT_EQ(string2Float("0.0"), 0.0); +/* ---------------------------------------------------------------------------- + * hasPrefix + * --------------------------------------------------------------------------*/ - ASSERT_EQ(string2Float("-100.25"), -100.25); - } +TEST(hasPrefix, emptyStringHasNoPrefix) +{ + ASSERT_FALSE(hasPrefix("", "foo")); +} - /* ---------------------------------------------------------------------------- - * string2Int - * --------------------------------------------------------------------------*/ +TEST(hasPrefix, emptyStringIsAlwaysPrefix) +{ + ASSERT_TRUE(hasPrefix("foo", "")); + ASSERT_TRUE(hasPrefix("jshjkfhsadf", "")); +} - TEST(string2Int, emptyString) { - ASSERT_EQ(string2Int(""), std::nullopt); - } +TEST(hasPrefix, trivialCase) +{ + ASSERT_TRUE(hasPrefix("foobar", "foo")); +} - TEST(string2Int, trivialConversions) { - ASSERT_EQ(string2Int("1"), 1); +/* ---------------------------------------------------------------------------- + * hasSuffix + * --------------------------------------------------------------------------*/ - ASSERT_EQ(string2Int("0"), 0); +TEST(hasSuffix, emptyStringHasNoSuffix) +{ + ASSERT_FALSE(hasSuffix("", "foo")); +} - ASSERT_EQ(string2Int("-100"), -100); - } +TEST(hasSuffix, trivialCase) +{ + ASSERT_TRUE(hasSuffix("foo", "foo")); + ASSERT_TRUE(hasSuffix("foobar", "bar")); +} - /* ---------------------------------------------------------------------------- - * statusOk - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * base64Encode + * --------------------------------------------------------------------------*/ - TEST(statusOk, zeroIsOk) { - ASSERT_EQ(statusOk(0), true); - ASSERT_EQ(statusOk(1), false); - } +TEST(base64Encode, emptyString) +{ + ASSERT_EQ(base64Encode(""), ""); +} +TEST(base64Encode, encodesAString) +{ + ASSERT_EQ(base64Encode("quod erat demonstrandum"), "cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="); +} - /* ---------------------------------------------------------------------------- - * rewriteStrings - * --------------------------------------------------------------------------*/ +TEST(base64Encode, encodeAndDecode) +{ + auto s = "quod erat demonstrandum"; + auto encoded = base64Encode(s); + auto decoded = base64Decode(encoded); - TEST(rewriteStrings, emptyString) { - StringMap rewrites; - rewrites["this"] = "that"; + ASSERT_EQ(decoded, s); +} - ASSERT_EQ(rewriteStrings("", rewrites), ""); - } +TEST(base64Encode, encodeAndDecodeNonPrintable) +{ + char s[256]; + std::iota(std::rbegin(s), std::rend(s), 0); - TEST(rewriteStrings, emptyRewrites) { - StringMap rewrites; + auto encoded = base64Encode(s); + auto decoded = base64Decode(encoded); - ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that"); - } + EXPECT_EQ(decoded.length(), 255); + ASSERT_EQ(decoded, s); +} - TEST(rewriteStrings, successfulRewrite) { - StringMap rewrites; - rewrites["this"] = "that"; +/* ---------------------------------------------------------------------------- + * base64Decode + * --------------------------------------------------------------------------*/ - ASSERT_EQ(rewriteStrings("this and that", rewrites), "that and that"); - } +TEST(base64Decode, emptyString) +{ + ASSERT_EQ(base64Decode(""), ""); +} - TEST(rewriteStrings, doesntOccur) { - StringMap rewrites; - rewrites["foo"] = "bar"; +TEST(base64Decode, decodeAString) +{ + ASSERT_EQ(base64Decode("cXVvZCBlcmF0IGRlbW9uc3RyYW5kdW0="), "quod erat demonstrandum"); +} - ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that"); - } +TEST(base64Decode, decodeThrowsOnInvalidChar) +{ + ASSERT_THROW(base64Decode("cXVvZCBlcm_0IGRlbW9uc3RyYW5kdW0="), Error); +} - /* ---------------------------------------------------------------------------- - * replaceStrings - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * toLower + * --------------------------------------------------------------------------*/ - TEST(replaceStrings, emptyString) { - ASSERT_EQ(replaceStrings("", "this", "that"), ""); - ASSERT_EQ(replaceStrings("this and that", "", ""), "this and that"); - } +TEST(toLower, emptyString) +{ + ASSERT_EQ(toLower(""), ""); +} - TEST(replaceStrings, successfulReplace) { - ASSERT_EQ(replaceStrings("this and that", "this", "that"), "that and that"); - } +TEST(toLower, nonLetters) +{ + auto s = "!@(*$#)(@#=\\234_"; + ASSERT_EQ(toLower(s), s); +} - TEST(replaceStrings, doesntOccur) { - ASSERT_EQ(replaceStrings("this and that", "foo", "bar"), "this and that"); - } +// std::tolower() doesn't handle unicode characters. In the context of +// store paths this isn't relevant but doesn't hurt to record this behavior +// here. +TEST(toLower, umlauts) +{ + auto s = "ÄÖÜ"; + ASSERT_EQ(toLower(s), "ÄÖÜ"); +} - /* ---------------------------------------------------------------------------- - * trim - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * string2Float + * --------------------------------------------------------------------------*/ - TEST(trim, emptyString) { - ASSERT_EQ(trim(""), ""); - } +TEST(string2Float, emptyString) +{ + ASSERT_EQ(string2Float(""), std::nullopt); +} - TEST(trim, removesWhitespace) { - ASSERT_EQ(trim("foo"), "foo"); - ASSERT_EQ(trim(" foo "), "foo"); - ASSERT_EQ(trim(" foo bar baz"), "foo bar baz"); - ASSERT_EQ(trim(" \t foo bar baz\n"), "foo bar baz"); - } +TEST(string2Float, trivialConversions) +{ + ASSERT_EQ(string2Float("1.0"), 1.0); - /* ---------------------------------------------------------------------------- - * chomp - * --------------------------------------------------------------------------*/ + ASSERT_EQ(string2Float("0.0"), 0.0); - TEST(chomp, emptyString) { - ASSERT_EQ(chomp(""), ""); - } + ASSERT_EQ(string2Float("-100.25"), -100.25); +} - TEST(chomp, removesWhitespace) { - ASSERT_EQ(chomp("foo"), "foo"); - ASSERT_EQ(chomp("foo "), "foo"); - ASSERT_EQ(chomp(" foo "), " foo"); - ASSERT_EQ(chomp(" foo bar baz "), " foo bar baz"); - ASSERT_EQ(chomp("\t foo bar baz\n"), "\t foo bar baz"); - } +/* ---------------------------------------------------------------------------- + * string2Int + * --------------------------------------------------------------------------*/ - /* ---------------------------------------------------------------------------- - * quoteStrings - * --------------------------------------------------------------------------*/ +TEST(string2Int, emptyString) +{ + ASSERT_EQ(string2Int(""), std::nullopt); +} - TEST(quoteStrings, empty) { - Strings s = { }; - Strings expected = { }; +TEST(string2Int, trivialConversions) +{ + ASSERT_EQ(string2Int("1"), 1); - ASSERT_EQ(quoteStrings(s), expected); - } + ASSERT_EQ(string2Int("0"), 0); - TEST(quoteStrings, emptyStrings) { - Strings s = { "", "", "" }; - Strings expected = { "''", "''", "''" }; - ASSERT_EQ(quoteStrings(s), expected); + ASSERT_EQ(string2Int("-100"), -100); +} - } +/* ---------------------------------------------------------------------------- + * statusOk + * --------------------------------------------------------------------------*/ - TEST(quoteStrings, trivialQuote) { - Strings s = { "foo", "bar", "baz" }; - Strings expected = { "'foo'", "'bar'", "'baz'" }; +TEST(statusOk, zeroIsOk) +{ + ASSERT_EQ(statusOk(0), true); + ASSERT_EQ(statusOk(1), false); +} - ASSERT_EQ(quoteStrings(s), expected); - } +/* ---------------------------------------------------------------------------- + * rewriteStrings + * --------------------------------------------------------------------------*/ - TEST(quoteStrings, quotedStrings) { - Strings s = { "'foo'", "'bar'", "'baz'" }; - Strings expected = { "''foo''", "''bar''", "''baz''" }; +TEST(rewriteStrings, emptyString) +{ + StringMap rewrites; + rewrites["this"] = "that"; - ASSERT_EQ(quoteStrings(s), expected); - } + ASSERT_EQ(rewriteStrings("", rewrites), ""); +} - /* ---------------------------------------------------------------------------- - * tokenizeString - * --------------------------------------------------------------------------*/ +TEST(rewriteStrings, emptyRewrites) +{ + StringMap rewrites; - TEST(tokenizeString, empty) { - Strings expected = { }; + ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that"); +} - ASSERT_EQ(tokenizeString(""), expected); - } +TEST(rewriteStrings, successfulRewrite) +{ + StringMap rewrites; + rewrites["this"] = "that"; - TEST(tokenizeString, tokenizeSpacesWithDefaults) { - auto s = "foo bar baz"; - Strings expected = { "foo", "bar", "baz" }; + ASSERT_EQ(rewriteStrings("this and that", rewrites), "that and that"); +} - ASSERT_EQ(tokenizeString(s), expected); - } +TEST(rewriteStrings, doesntOccur) +{ + StringMap rewrites; + rewrites["foo"] = "bar"; - TEST(tokenizeString, tokenizeTabsWithDefaults) { - auto s = "foo\tbar\tbaz"; - Strings expected = { "foo", "bar", "baz" }; + ASSERT_EQ(rewriteStrings("this and that", rewrites), "this and that"); +} + +/* ---------------------------------------------------------------------------- + * replaceStrings + * --------------------------------------------------------------------------*/ + +TEST(replaceStrings, emptyString) +{ + ASSERT_EQ(replaceStrings("", "this", "that"), ""); + ASSERT_EQ(replaceStrings("this and that", "", ""), "this and that"); +} + +TEST(replaceStrings, successfulReplace) +{ + ASSERT_EQ(replaceStrings("this and that", "this", "that"), "that and that"); +} + +TEST(replaceStrings, doesntOccur) +{ + ASSERT_EQ(replaceStrings("this and that", "foo", "bar"), "this and that"); +} + +/* ---------------------------------------------------------------------------- + * trim + * --------------------------------------------------------------------------*/ + +TEST(trim, emptyString) +{ + ASSERT_EQ(trim(""), ""); +} + +TEST(trim, removesWhitespace) +{ + ASSERT_EQ(trim("foo"), "foo"); + ASSERT_EQ(trim(" foo "), "foo"); + ASSERT_EQ(trim(" foo bar baz"), "foo bar baz"); + ASSERT_EQ(trim(" \t foo bar baz\n"), "foo bar baz"); +} + +/* ---------------------------------------------------------------------------- + * chomp + * --------------------------------------------------------------------------*/ + +TEST(chomp, emptyString) +{ + ASSERT_EQ(chomp(""), ""); +} + +TEST(chomp, removesWhitespace) +{ + ASSERT_EQ(chomp("foo"), "foo"); + ASSERT_EQ(chomp("foo "), "foo"); + ASSERT_EQ(chomp(" foo "), " foo"); + ASSERT_EQ(chomp(" foo bar baz "), " foo bar baz"); + ASSERT_EQ(chomp("\t foo bar baz\n"), "\t foo bar baz"); +} + +/* ---------------------------------------------------------------------------- + * quoteStrings + * --------------------------------------------------------------------------*/ + +TEST(quoteStrings, empty) +{ + Strings s = {}; + Strings expected = {}; + + ASSERT_EQ(quoteStrings(s), expected); +} + +TEST(quoteStrings, emptyStrings) +{ + Strings s = {"", "", ""}; + Strings expected = {"''", "''", "''"}; + ASSERT_EQ(quoteStrings(s), expected); +} + +TEST(quoteStrings, trivialQuote) +{ + Strings s = {"foo", "bar", "baz"}; + Strings expected = {"'foo'", "'bar'", "'baz'"}; + + ASSERT_EQ(quoteStrings(s), expected); +} + +TEST(quoteStrings, quotedStrings) +{ + Strings s = {"'foo'", "'bar'", "'baz'"}; + Strings expected = {"''foo''", "''bar''", "''baz''"}; + + ASSERT_EQ(quoteStrings(s), expected); +} - ASSERT_EQ(tokenizeString(s), expected); - } +/* ---------------------------------------------------------------------------- + * tokenizeString + * --------------------------------------------------------------------------*/ + +TEST(tokenizeString, empty) +{ + Strings expected = {}; + + ASSERT_EQ(tokenizeString(""), expected); +} + +TEST(tokenizeString, tokenizeSpacesWithDefaults) +{ + auto s = "foo bar baz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); +} + +TEST(tokenizeString, tokenizeTabsWithDefaults) +{ + auto s = "foo\tbar\tbaz"; + Strings expected = {"foo", "bar", "baz"}; + + ASSERT_EQ(tokenizeString(s), expected); +} - TEST(tokenizeString, tokenizeTabsSpacesWithDefaults) { - auto s = "foo\t bar\t baz"; - Strings expected = { "foo", "bar", "baz" }; +TEST(tokenizeString, tokenizeTabsSpacesWithDefaults) +{ + auto s = "foo\t bar\t baz"; + Strings expected = {"foo", "bar", "baz"}; - ASSERT_EQ(tokenizeString(s), expected); - } + ASSERT_EQ(tokenizeString(s), expected); +} - TEST(tokenizeString, tokenizeTabsSpacesNewlineWithDefaults) { - auto s = "foo\t\n bar\t\n baz"; - Strings expected = { "foo", "bar", "baz" }; +TEST(tokenizeString, tokenizeTabsSpacesNewlineWithDefaults) +{ + auto s = "foo\t\n bar\t\n baz"; + Strings expected = {"foo", "bar", "baz"}; - ASSERT_EQ(tokenizeString(s), expected); - } + ASSERT_EQ(tokenizeString(s), expected); +} - TEST(tokenizeString, tokenizeTabsSpacesNewlineRetWithDefaults) { - auto s = "foo\t\n\r bar\t\n\r baz"; - Strings expected = { "foo", "bar", "baz" }; +TEST(tokenizeString, tokenizeTabsSpacesNewlineRetWithDefaults) +{ + auto s = "foo\t\n\r bar\t\n\r baz"; + Strings expected = {"foo", "bar", "baz"}; - ASSERT_EQ(tokenizeString(s), expected); + ASSERT_EQ(tokenizeString(s), expected); - auto s2 = "foo \t\n\r bar \t\n\r baz"; - Strings expected2 = { "foo", "bar", "baz" }; + auto s2 = "foo \t\n\r bar \t\n\r baz"; + Strings expected2 = {"foo", "bar", "baz"}; - ASSERT_EQ(tokenizeString(s2), expected2); - } + ASSERT_EQ(tokenizeString(s2), expected2); +} - TEST(tokenizeString, tokenizeWithCustomSep) { - auto s = "foo\n,bar\n,baz\n"; - Strings expected = { "foo\n", "bar\n", "baz\n" }; +TEST(tokenizeString, tokenizeWithCustomSep) +{ + auto s = "foo\n,bar\n,baz\n"; + Strings expected = {"foo\n", "bar\n", "baz\n"}; - ASSERT_EQ(tokenizeString(s, ","), expected); - } + ASSERT_EQ(tokenizeString(s, ","), expected); +} - /* ---------------------------------------------------------------------------- - * get - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * get + * --------------------------------------------------------------------------*/ - TEST(get, emptyContainer) { - StringMap s = { }; - auto expected = nullptr; +TEST(get, emptyContainer) +{ + StringMap s = {}; + auto expected = nullptr; - ASSERT_EQ(get(s, "one"), expected); - } + ASSERT_EQ(get(s, "one"), expected); +} - TEST(get, getFromContainer) { - StringMap s; - s["one"] = "yi"; - s["two"] = "er"; - auto expected = "yi"; +TEST(get, getFromContainer) +{ + StringMap s; + s["one"] = "yi"; + s["two"] = "er"; + auto expected = "yi"; - ASSERT_EQ(*get(s, "one"), expected); - } + ASSERT_EQ(*get(s, "one"), expected); +} - TEST(getOr, emptyContainer) { - StringMap s = { }; - auto expected = "yi"; +TEST(getOr, emptyContainer) +{ + StringMap s = {}; + auto expected = "yi"; - ASSERT_EQ(getOr(s, "one", "yi"), expected); - } + ASSERT_EQ(getOr(s, "one", "yi"), expected); +} - TEST(getOr, getFromContainer) { - StringMap s; - s["one"] = "yi"; - s["two"] = "er"; - auto expected = "yi"; +TEST(getOr, getFromContainer) +{ + StringMap s; + s["one"] = "yi"; + s["two"] = "er"; + auto expected = "yi"; - ASSERT_EQ(getOr(s, "one", "nope"), expected); - } + ASSERT_EQ(getOr(s, "one", "nope"), expected); +} - /* ---------------------------------------------------------------------------- - * filterANSIEscapes - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * filterANSIEscapes + * --------------------------------------------------------------------------*/ - TEST(filterANSIEscapes, emptyString) { - auto s = ""; - auto expected = ""; +TEST(filterANSIEscapes, emptyString) +{ + auto s = ""; + auto expected = ""; - ASSERT_EQ(filterANSIEscapes(s), expected); - } + ASSERT_EQ(filterANSIEscapes(s), expected); +} - TEST(filterANSIEscapes, doesntChangePrintableChars) { - auto s = "09 2q304ruyhr slk2-19024 kjsadh sar f"; +TEST(filterANSIEscapes, doesntChangePrintableChars) +{ + auto s = "09 2q304ruyhr slk2-19024 kjsadh sar f"; - ASSERT_EQ(filterANSIEscapes(s), s); - } + ASSERT_EQ(filterANSIEscapes(s), s); +} - TEST(filterANSIEscapes, filtersColorCodes) { - auto s = "\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m"; +TEST(filterANSIEscapes, filtersColorCodes) +{ + auto s = "\u001b[30m A \u001b[31m B \u001b[32m C \u001b[33m D \u001b[0m"; - ASSERT_EQ(filterANSIEscapes(s, true, 2), " A" ); - ASSERT_EQ(filterANSIEscapes(s, true, 3), " A " ); - ASSERT_EQ(filterANSIEscapes(s, true, 4), " A " ); - ASSERT_EQ(filterANSIEscapes(s, true, 5), " A B" ); - ASSERT_EQ(filterANSIEscapes(s, true, 8), " A B C" ); - } + ASSERT_EQ(filterANSIEscapes(s, true, 2), " A"); + ASSERT_EQ(filterANSIEscapes(s, true, 3), " A "); + ASSERT_EQ(filterANSIEscapes(s, true, 4), " A "); + ASSERT_EQ(filterANSIEscapes(s, true, 5), " A B"); + ASSERT_EQ(filterANSIEscapes(s, true, 8), " A B C"); +} - TEST(filterANSIEscapes, expandsTabs) { - auto s = "foo\tbar\tbaz"; +TEST(filterANSIEscapes, expandsTabs) +{ + auto s = "foo\tbar\tbaz"; - ASSERT_EQ(filterANSIEscapes(s, true), "foo bar baz" ); - } + ASSERT_EQ(filterANSIEscapes(s, true), "foo bar baz"); +} - TEST(filterANSIEscapes, utf8) { - ASSERT_EQ(filterANSIEscapes("foobar", true, 5), "fooba"); - ASSERT_EQ(filterANSIEscapes("fóóbär", true, 6), "fóóbär"); - ASSERT_EQ(filterANSIEscapes("fóóbär", true, 5), "fóóbä"); - ASSERT_EQ(filterANSIEscapes("fóóbär", true, 3), "fóó"); - ASSERT_EQ(filterANSIEscapes("f€€bär", true, 4), "f€€b"); - ASSERT_EQ(filterANSIEscapes("f𐍈𐍈bär", true, 4), "f𐍈𐍈b"); - } +TEST(filterANSIEscapes, utf8) +{ + ASSERT_EQ(filterANSIEscapes("foobar", true, 5), "fooba"); + ASSERT_EQ(filterANSIEscapes("fóóbär", true, 6), "fóóbär"); + ASSERT_EQ(filterANSIEscapes("fóóbär", true, 5), "fóóbä"); + ASSERT_EQ(filterANSIEscapes("fóóbär", true, 3), "fóó"); + ASSERT_EQ(filterANSIEscapes("f€€bär", true, 4), "f€€b"); + ASSERT_EQ(filterANSIEscapes("f𐍈𐍈bär", true, 4), "f𐍈𐍈b"); +} } diff --git a/src/libutil/tests/url.cc b/src/libutil/tests/url.cc index c3b233797c39..2eb8460a425a 100644 --- a/src/libutil/tests/url.cc +++ b/src/libutil/tests/url.cc @@ -5,280 +5,298 @@ namespace nix { /* ----------- tests for url.hh --------------------------------------------------*/ - std::string print_map(std::map m) { - std::map::iterator it; - std::string s = "{ "; - for (it = m.begin(); it != m.end(); ++it) { - s += "{ "; - s += it->first; - s += " = "; - s += it->second; - s += " } "; - } - s += "}"; - return s; +std::string print_map(std::map m) +{ + std::map::iterator it; + std::string s = "{ "; + for (it = m.begin(); it != m.end(); ++it) { + s += "{ "; + s += it->first; + s += " = "; + s += it->second; + s += " } "; } + s += "}"; + return s; +} +std::ostream & operator<<(std::ostream & os, const ParsedURL & p) +{ + return os << "\n" + << "url: " << p.url << "\n" + << "base: " << p.base << "\n" + << "scheme: " << p.scheme << "\n" + << "authority: " << p.authority.value() << "\n" + << "path: " << p.path << "\n" + << "query: " << print_map(p.query) << "\n" + << "fragment: " << p.fragment << "\n"; +} - std::ostream& operator<<(std::ostream& os, const ParsedURL& p) { - return os << "\n" - << "url: " << p.url << "\n" - << "base: " << p.base << "\n" - << "scheme: " << p.scheme << "\n" - << "authority: " << p.authority.value() << "\n" - << "path: " << p.path << "\n" - << "query: " << print_map(p.query) << "\n" - << "fragment: " << p.fragment << "\n"; - } - - TEST(parseURL, parsesSimpleHttpUrl) { - auto s = "http://www.example.org/file.tar.gz"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://www.example.org/file.tar.gz", - .base = "http://www.example.org/file.tar.gz", - .scheme = "http", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesSimpleHttpsUrl) { - auto s = "https://www.example.org/file.tar.gz"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "https://www.example.org/file.tar.gz", - .base = "https://www.example.org/file.tar.gz", - .scheme = "https", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesSimpleHttpUrlWithQueryAndFragment) { - auto s = "https://www.example.org/file.tar.gz?download=fast&when=now#hello"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "https://www.example.org/file.tar.gz", - .base = "https://www.example.org/file.tar.gz", - .scheme = "https", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { { "download", "fast" }, { "when", "now" } }, - .fragment = "hello", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parsesSimpleHttpUrlWithComplexFragment) { - auto s = "http://www.example.org/file.tar.gz?field=value#?foo=bar%23"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://www.example.org/file.tar.gz", - .base = "http://www.example.org/file.tar.gz", - .scheme = "http", - .authority = "www.example.org", - .path = "/file.tar.gz", - .query = (StringMap) { { "field", "value" } }, - .fragment = "?foo=bar#", - }; - - ASSERT_EQ(parsed, expected); - } - - - TEST(parseURL, parseIPv4Address) { - auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://127.0.0.1:8080/file.tar.gz", - .base = "https://127.0.0.1:8080/file.tar.gz", - .scheme = "http", - .authority = "127.0.0.1:8080", - .path = "/file.tar.gz", - .query = (StringMap) { { "download", "fast" }, { "when", "now" } }, - .fragment = "hello", - }; - - ASSERT_EQ(parsed, expected); - } - - TEST(parseURL, parseScopedRFC4007IPv6Address) { - auto s = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080", - .base = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080", - .scheme = "http", - .authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080", - .path = "", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - - } - - TEST(parseURL, parseIPv6Address) { - auto s = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", - .base = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", - .scheme = "http", - .authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", - .path = "", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - - } +TEST(parseURL, parsesSimpleHttpUrl) +{ + auto s = "http://www.example.org/file.tar.gz"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "http://www.example.org/file.tar.gz", + .base = "http://www.example.org/file.tar.gz", + .scheme = "http", + .authority = "www.example.org", + .path = "/file.tar.gz", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - TEST(parseURL, parseEmptyQueryParams) { - auto s = "http://127.0.0.1:8080/file.tar.gz?&&&&&"; - auto parsed = parseURL(s); - ASSERT_EQ(parsed.query, (StringMap) { }); - } +TEST(parseURL, parsesSimpleHttpsUrl) +{ + auto s = "https://www.example.org/file.tar.gz"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "https://www.example.org/file.tar.gz", + .base = "https://www.example.org/file.tar.gz", + .scheme = "https", + .authority = "www.example.org", + .path = "/file.tar.gz", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - TEST(parseURL, parseUserPassword) { - auto s = "http://user:pass@www.example.org:8080/file.tar.gz"; - auto parsed = parseURL(s); +TEST(parseURL, parsesSimpleHttpUrlWithQueryAndFragment) +{ + auto s = "https://www.example.org/file.tar.gz?download=fast&when=now#hello"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "https://www.example.org/file.tar.gz", + .base = "https://www.example.org/file.tar.gz", + .scheme = "https", + .authority = "www.example.org", + .path = "/file.tar.gz", + .query = (StringMap){{"download", "fast"}, {"when", "now"}}, + .fragment = "hello", + }; + + ASSERT_EQ(parsed, expected); +} - ParsedURL expected { - .url = "http://user:pass@www.example.org/file.tar.gz", - .base = "http://user:pass@www.example.org/file.tar.gz", - .scheme = "http", - .authority = "user:pass@www.example.org:8080", - .path = "/file.tar.gz", - .query = (StringMap) { }, - .fragment = "", - }; +TEST(parseURL, parsesSimpleHttpUrlWithComplexFragment) +{ + auto s = "http://www.example.org/file.tar.gz?field=value#?foo=bar%23"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "http://www.example.org/file.tar.gz", + .base = "http://www.example.org/file.tar.gz", + .scheme = "http", + .authority = "www.example.org", + .path = "/file.tar.gz", + .query = (StringMap){{"field", "value"}}, + .fragment = "?foo=bar#", + }; + + ASSERT_EQ(parsed, expected); +} +TEST(parseURL, parseIPv4Address) +{ + auto s = "http://127.0.0.1:8080/file.tar.gz?download=fast&when=now#hello"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "http://127.0.0.1:8080/file.tar.gz", + .base = "https://127.0.0.1:8080/file.tar.gz", + .scheme = "http", + .authority = "127.0.0.1:8080", + .path = "/file.tar.gz", + .query = (StringMap){{"download", "fast"}, {"when", "now"}}, + .fragment = "hello", + }; + + ASSERT_EQ(parsed, expected); +} - ASSERT_EQ(parsed, expected); - } +TEST(parseURL, parseScopedRFC4007IPv6Address) +{ + auto s = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080", + .base = "http://[fe80::818c:da4d:8975:415c\%enp0s25]:8080", + .scheme = "http", + .authority = "[fe80::818c:da4d:8975:415c\%enp0s25]:8080", + .path = "", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - TEST(parseURL, parseFileURLWithQueryAndFragment) { - auto s = "file:///none/of//your/business"; - auto parsed = parseURL(s); +TEST(parseURL, parseIPv6Address) +{ + auto s = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", + .base = "http://[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", + .scheme = "http", + .authority = "[2a02:8071:8192:c100:311d:192d:81ac:11ea]:8080", + .path = "", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - ParsedURL expected { - .url = "", - .base = "", - .scheme = "file", - .authority = "", - .path = "/none/of//your/business", - .query = (StringMap) { }, - .fragment = "", - }; +TEST(parseURL, parseEmptyQueryParams) +{ + auto s = "http://127.0.0.1:8080/file.tar.gz?&&&&&"; + auto parsed = parseURL(s); + ASSERT_EQ(parsed.query, (StringMap){}); +} - ASSERT_EQ(parsed, expected); +TEST(parseURL, parseUserPassword) +{ + auto s = "http://user:pass@www.example.org:8080/file.tar.gz"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "http://user:pass@www.example.org/file.tar.gz", + .base = "http://user:pass@www.example.org/file.tar.gz", + .scheme = "http", + .authority = "user:pass@www.example.org:8080", + .path = "/file.tar.gz", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - } +TEST(parseURL, parseFileURLWithQueryAndFragment) +{ + auto s = "file:///none/of//your/business"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "", + .base = "", + .scheme = "file", + .authority = "", + .path = "/none/of//your/business", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - TEST(parseURL, parsedUrlsIsEqualToItself) { - auto s = "http://www.example.org/file.tar.gz"; - auto url = parseURL(s); +TEST(parseURL, parsedUrlsIsEqualToItself) +{ + auto s = "http://www.example.org/file.tar.gz"; + auto url = parseURL(s); - ASSERT_TRUE(url == url); - } + ASSERT_TRUE(url == url); +} - TEST(parseURL, parseFTPUrl) { - auto s = "ftp://ftp.nixos.org/downloads/nixos.iso"; - auto parsed = parseURL(s); - - ParsedURL expected { - .url = "ftp://ftp.nixos.org/downloads/nixos.iso", - .base = "ftp://ftp.nixos.org/downloads/nixos.iso", - .scheme = "ftp", - .authority = "ftp.nixos.org", - .path = "/downloads/nixos.iso", - .query = (StringMap) { }, - .fragment = "", - }; - - ASSERT_EQ(parsed, expected); - } +TEST(parseURL, parseFTPUrl) +{ + auto s = "ftp://ftp.nixos.org/downloads/nixos.iso"; + auto parsed = parseURL(s); + + ParsedURL expected{ + .url = "ftp://ftp.nixos.org/downloads/nixos.iso", + .base = "ftp://ftp.nixos.org/downloads/nixos.iso", + .scheme = "ftp", + .authority = "ftp.nixos.org", + .path = "/downloads/nixos.iso", + .query = (StringMap){}, + .fragment = "", + }; + + ASSERT_EQ(parsed, expected); +} - TEST(parseURL, parsesAnythingInUriFormat) { - auto s = "whatever://github.com/NixOS/nixpkgs.git"; - auto parsed = parseURL(s); - } +TEST(parseURL, parsesAnythingInUriFormat) +{ + auto s = "whatever://github.com/NixOS/nixpkgs.git"; + auto parsed = parseURL(s); +} - TEST(parseURL, parsesAnythingInUriFormatWithoutDoubleSlash) { - auto s = "whatever:github.com/NixOS/nixpkgs.git"; - auto parsed = parseURL(s); - } +TEST(parseURL, parsesAnythingInUriFormatWithoutDoubleSlash) +{ + auto s = "whatever:github.com/NixOS/nixpkgs.git"; + auto parsed = parseURL(s); +} - TEST(parseURL, emptyStringIsInvalidURL) { - ASSERT_THROW(parseURL(""), Error); - } +TEST(parseURL, emptyStringIsInvalidURL) +{ + ASSERT_THROW(parseURL(""), Error); +} - /* ---------------------------------------------------------------------------- - * decodeQuery - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * decodeQuery + * --------------------------------------------------------------------------*/ - TEST(decodeQuery, emptyStringYieldsEmptyMap) { - auto d = decodeQuery(""); - ASSERT_EQ(d, (StringMap) { }); - } +TEST(decodeQuery, emptyStringYieldsEmptyMap) +{ + auto d = decodeQuery(""); + ASSERT_EQ(d, (StringMap){}); +} - TEST(decodeQuery, simpleDecode) { - auto d = decodeQuery("yi=one&er=two"); - ASSERT_EQ(d, ((StringMap) { { "yi", "one" }, { "er", "two" } })); - } +TEST(decodeQuery, simpleDecode) +{ + auto d = decodeQuery("yi=one&er=two"); + ASSERT_EQ(d, ((StringMap){{"yi", "one"}, {"er", "two"}})); +} - TEST(decodeQuery, decodeUrlEncodedArgs) { - auto d = decodeQuery("arg=%3D%3D%40%3D%3D"); - ASSERT_EQ(d, ((StringMap) { { "arg", "==@==" } })); - } +TEST(decodeQuery, decodeUrlEncodedArgs) +{ + auto d = decodeQuery("arg=%3D%3D%40%3D%3D"); + ASSERT_EQ(d, ((StringMap){{"arg", "==@=="}})); +} - TEST(decodeQuery, decodeArgWithEmptyValue) { - auto d = decodeQuery("arg="); - ASSERT_EQ(d, ((StringMap) { { "arg", ""} })); - } +TEST(decodeQuery, decodeArgWithEmptyValue) +{ + auto d = decodeQuery("arg="); + ASSERT_EQ(d, ((StringMap){{"arg", ""}})); +} - /* ---------------------------------------------------------------------------- - * percentDecode - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * percentDecode + * --------------------------------------------------------------------------*/ - TEST(percentDecode, decodesUrlEncodedString) { - std::string s = "==@=="; - std::string d = percentDecode("%3D%3D%40%3D%3D"); - ASSERT_EQ(d, s); - } +TEST(percentDecode, decodesUrlEncodedString) +{ + std::string s = "==@=="; + std::string d = percentDecode("%3D%3D%40%3D%3D"); + ASSERT_EQ(d, s); +} - TEST(percentDecode, multipleDecodesAreIdempotent) { - std::string once = percentDecode("%3D%3D%40%3D%3D"); - std::string twice = percentDecode(once); +TEST(percentDecode, multipleDecodesAreIdempotent) +{ + std::string once = percentDecode("%3D%3D%40%3D%3D"); + std::string twice = percentDecode(once); - ASSERT_EQ(once, twice); - } + ASSERT_EQ(once, twice); +} - TEST(percentDecode, trailingPercent) { - std::string s = "==@==%"; - std::string d = percentDecode("%3D%3D%40%3D%3D%25"); +TEST(percentDecode, trailingPercent) +{ + std::string s = "==@==%"; + std::string d = percentDecode("%3D%3D%40%3D%3D%25"); - ASSERT_EQ(d, s); - } + ASSERT_EQ(d, s); +} } diff --git a/src/libutil/tests/xml-writer.cc b/src/libutil/tests/xml-writer.cc index adcde25c9f12..eb3c3cda0b90 100644 --- a/src/libutil/tests/xml-writer.cc +++ b/src/libutil/tests/xml-writer.cc @@ -4,102 +4,101 @@ namespace nix { - /* ---------------------------------------------------------------------------- - * XMLWriter - * --------------------------------------------------------------------------*/ +/* ---------------------------------------------------------------------------- + * XMLWriter + * --------------------------------------------------------------------------*/ + +TEST(XMLWriter, emptyObject) +{ + std::stringstream out; + { + XMLWriter t(false, out); + } - TEST(XMLWriter, emptyObject) { - std::stringstream out; - { - XMLWriter t(false, out); - } + ASSERT_EQ(out.str(), "\n"); +} - ASSERT_EQ(out.str(), "\n"); +TEST(XMLWriter, objectWithEmptyElement) +{ + std::stringstream out; + { + XMLWriter t(false, out); + t.openElement("foobar"); } - TEST(XMLWriter, objectWithEmptyElement) { - std::stringstream out; - { - XMLWriter t(false, out); - t.openElement("foobar"); - } + ASSERT_EQ(out.str(), "\n"); +} - ASSERT_EQ(out.str(), "\n"); +TEST(XMLWriter, objectWithElementWithAttrs) +{ + std::stringstream out; + { + XMLWriter t(false, out); + XMLAttrs attrs = {{"foo", "bar"}}; + t.openElement("foobar", attrs); } - TEST(XMLWriter, objectWithElementWithAttrs) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = { - { "foo", "bar" } - }; - t.openElement("foobar", attrs); - } - - ASSERT_EQ(out.str(), "\n"); + ASSERT_EQ(out.str(), "\n"); +} + +TEST(XMLWriter, objectWithElementWithEmptyAttrs) +{ + std::stringstream out; + { + XMLWriter t(false, out); + XMLAttrs attrs = {}; + t.openElement("foobar", attrs); } - TEST(XMLWriter, objectWithElementWithEmptyAttrs) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = {}; - t.openElement("foobar", attrs); - } + ASSERT_EQ(out.str(), "\n"); +} - ASSERT_EQ(out.str(), "\n"); +TEST(XMLWriter, objectWithElementWithAttrsEscaping) +{ + std::stringstream out; + { + XMLWriter t(false, out); + XMLAttrs attrs = {{"", ""}}; + t.openElement("foobar", attrs); } - TEST(XMLWriter, objectWithElementWithAttrsEscaping) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = { - { "", "" } - }; - t.openElement("foobar", attrs); - } - - // XXX: While "" is escaped, "" isn't which I think is a bug. - ASSERT_EQ(out.str(), "\n=\"<value>\">"); - } + // XXX: While "" is escaped, "" isn't which I think is a bug. + ASSERT_EQ(out.str(), "\n=\"<value>\">"); +} - TEST(XMLWriter, objectWithElementWithAttrsIndented) { - std::stringstream out; - { - XMLWriter t(true, out); - XMLAttrs attrs = { - { "foo", "bar" } - }; - t.openElement("foobar", attrs); - } - - ASSERT_EQ(out.str(), "\n\n\n"); +TEST(XMLWriter, objectWithElementWithAttrsIndented) +{ + std::stringstream out; + { + XMLWriter t(true, out); + XMLAttrs attrs = {{"foo", "bar"}}; + t.openElement("foobar", attrs); } - TEST(XMLWriter, writeEmptyElement) { - std::stringstream out; - { - XMLWriter t(false, out); - t.writeEmptyElement("foobar"); - } + ASSERT_EQ(out.str(), "\n\n\n"); +} - ASSERT_EQ(out.str(), "\n"); +TEST(XMLWriter, writeEmptyElement) +{ + std::stringstream out; + { + XMLWriter t(false, out); + t.writeEmptyElement("foobar"); } - TEST(XMLWriter, writeEmptyElementWithAttributes) { - std::stringstream out; - { - XMLWriter t(false, out); - XMLAttrs attrs = { - { "foo", "bar" } - }; - t.writeEmptyElement("foobar", attrs); - - } + ASSERT_EQ(out.str(), "\n"); +} - ASSERT_EQ(out.str(), "\n"); +TEST(XMLWriter, writeEmptyElementWithAttributes) +{ + std::stringstream out; + { + XMLWriter t(false, out); + XMLAttrs attrs = {{"foo", "bar"}}; + t.writeEmptyElement("foobar", attrs); } + ASSERT_EQ(out.str(), "\n"); +} + } diff --git a/src/libutil/thread-pool.cc b/src/libutil/thread-pool.cc index dc4067f1b3a1..8a3537ca9e09 100644 --- a/src/libutil/thread-pool.cc +++ b/src/libutil/thread-pool.cc @@ -7,7 +7,8 @@ ThreadPool::ThreadPool(size_t _maxThreads) { if (!maxThreads) { maxThreads = std::thread::hardware_concurrency(); - if (!maxThreads) maxThreads = 1; + if (!maxThreads) + maxThreads = 1; } debug("starting pool of %d threads", maxThreads - 1); @@ -27,7 +28,8 @@ void ThreadPool::shutdown() std::swap(workers, state->workers); } - if (workers.empty()) return; + if (workers.empty()) + return; debug("reaping %d worker threads", workers.size()); @@ -105,8 +107,7 @@ void ThreadPool::doWork(bool mainThread) try { std::rethrow_exception(exc); } catch (std::exception & e) { - if (!dynamic_cast(&e) && - !dynamic_cast(&e)) + if (!dynamic_cast(&e) && !dynamic_cast(&e)) ignoreException(); } catch (...) { } @@ -117,9 +118,11 @@ void ThreadPool::doWork(bool mainThread) /* Wait until a work item is available or we're asked to quit. */ while (true) { - if (quit) return; + if (quit) + return; - if (!state->pending.empty()) break; + if (!state->pending.empty()) + break; /* If there are no active or pending items, and the main thread is running process(), then no new items @@ -149,5 +152,3 @@ void ThreadPool::doWork(bool mainThread) } } - - diff --git a/src/libutil/thread-pool.hh b/src/libutil/thread-pool.hh index b22e0d162254..b1bab02d32f7 100644 --- a/src/libutil/thread-pool.hh +++ b/src/libutil/thread-pool.hh @@ -72,7 +72,8 @@ void processGraph( std::function(const T &)> getEdges, std::function processNode) { - struct Graph { + struct Graph + { std::set left; std::map> refs, rrefs; }; @@ -82,7 +83,6 @@ void processGraph( std::function worker; worker = [&](const T & node) { - { auto graph(graph_.lock()); auto i = graph->refs.find(node); @@ -91,22 +91,21 @@ void processGraph( goto doWork; } - getRefs: + getRefs : { + auto refs = getEdges(node); + refs.erase(node); + { - auto refs = getEdges(node); - refs.erase(node); - - { - auto graph(graph_.lock()); - for (auto & ref : refs) - if (graph->left.count(ref)) { - graph->refs[node].insert(ref); - graph->rrefs[ref].insert(node); - } - if (graph->refs[node].empty()) - goto doWork; - } + auto graph(graph_.lock()); + for (auto & ref : refs) + if (graph->left.count(ref)) { + graph->refs[node].insert(ref); + graph->rrefs[ref].insert(node); + } + if (graph->refs[node].empty()) + goto doWork; } + } return; diff --git a/src/libutil/topo-sort.hh b/src/libutil/topo-sort.hh index 7418be5e0886..04b54b87ca01 100644 --- a/src/libutil/topo-sort.hh +++ b/src/libutil/topo-sort.hh @@ -5,9 +5,10 @@ namespace nix { template -std::vector topoSort(std::set items, - std::function(const T &)> getChildren, - std::function makeCycleError) +std::vector topoSort( + std::set items, + std::function(const T &)> getChildren, + std::function makeCycleError) { std::vector sorted; std::set visited, parents; @@ -15,9 +16,11 @@ std::vector topoSort(std::set items, std::function dfsVisit; dfsVisit = [&](const T & path, const T * parent) { - if (parents.count(path)) throw makeCycleError(path, *parent); + if (parents.count(path)) + throw makeCycleError(path, *parent); - if (!visited.insert(path).second) return; + if (!visited.insert(path).second) + return; parents.insert(path); std::set references = getChildren(path); diff --git a/src/libutil/types.hh b/src/libutil/types.hh index 6bcbd7e1d5af..a7517c53411d 100644 --- a/src/libutil/types.hh +++ b/src/libutil/types.hh @@ -29,22 +29,25 @@ typedef std::vector> Headers; template struct OnStartup { - OnStartup(T && t) { t(); } + OnStartup(T && t) + { + t(); + } }; /* Wrap bools to prevent string literals (i.e. 'char *') from being cast to a bool in Attr. */ template -struct Explicit { +struct Explicit +{ T t; - bool operator ==(const Explicit & other) const + bool operator==(const Explicit & other) const { return t == other.t; } }; - /* This wants to be a little bit like rust's Cow type. Some parts of the evaluator benefit greatly from being able to reuse existing allocations for strings, but have to be able to also use @@ -53,26 +56,39 @@ struct Explicit { We do not define implicit conversions, even with ref qualifiers, since those can easily become ambiguous to the reader and can degrade into copying behaviour we want to avoid. */ -class BackedStringView { +class BackedStringView +{ private: std::variant data; /* Needed to introduce a temporary since operator-> must return a pointer. Without this we'd need to store the view object even when we already own a string. */ - class Ptr { + class Ptr + { private: std::string_view view; public: - Ptr(std::string_view view): view(view) {} - const std::string_view * operator->() const { return &view; } + Ptr(std::string_view view) + : view(view) + {} + const std::string_view * operator->() const + { + return &view; + } }; public: - BackedStringView(std::string && s): data(std::move(s)) {} - BackedStringView(std::string_view sv): data(sv) {} + BackedStringView(std::string && s) + : data(std::move(s)) + {} + BackedStringView(std::string_view sv) + : data(sv) + {} template - BackedStringView(const char (& lit)[N]): data(std::string_view(lit)) {} + BackedStringView(const char (&lit)[N]) + : data(std::string_view(lit)) + {} BackedStringView(const BackedStringView &) = delete; BackedStringView & operator=(const BackedStringView &) = delete; @@ -89,18 +105,17 @@ public: std::string toOwned() && { - return isOwned() - ? std::move(std::get(data)) - : std::string(std::get(data)); + return isOwned() ? std::move(std::get(data)) : std::string(std::get(data)); } std::string_view operator*() const { - return isOwned() - ? std::get(data) - : std::get(data); + return isOwned() ? std::get(data) : std::get(data); + } + Ptr operator->() const + { + return Ptr(**this); } - Ptr operator->() const { return Ptr(**this); } }; } diff --git a/src/libutil/url-parts.hh b/src/libutil/url-parts.hh index d5e6a2736eb0..8c0cea169d0e 100644 --- a/src/libutil/url-parts.hh +++ b/src/libutil/url-parts.hh @@ -29,7 +29,8 @@ extern std::regex refRegex; // Instead of defining what a good Git Ref is, we define what a bad Git Ref is // This is because of the definition of a ref in refs.c in https://github.com/git/git // See tests/fetchGitRefs.sh for the full definition -const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$"; +const static std::string badGitRefRegexS = + "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$"; extern std::regex badGitRefRegex; // A Git revision (a SHA-1 commit hash). diff --git a/src/libutil/url.cc b/src/libutil/url.cc index 5b7abeb4912f..992215294130 100644 --- a/src/libutil/url.cc +++ b/src/libutil/url.cc @@ -13,10 +13,8 @@ std::regex flakeIdRegex(flakeIdRegexS, std::regex::ECMAScript); ParsedURL parseURL(const std::string & url) { static std::regex uriRegex( - "((" + schemeRegex + "):" - + "(?:(?://(" + authorityRegex + ")(" + absPathRegex + "))|(/?" + pathRegex + ")))" - + "(?:\\?(" + queryRegex + "))?" - + "(?:#(" + queryRegex + "))?", + "((" + schemeRegex + "):" + "(?:(?://(" + authorityRegex + ")(" + absPathRegex + "))|(/?" + pathRegex + ")))" + + "(?:\\?(" + queryRegex + "))?" + "(?:#(" + queryRegex + "))?", std::regex::ECMAScript); std::smatch match; @@ -24,8 +22,7 @@ ParsedURL parseURL(const std::string & url) if (std::regex_match(url, match, uriRegex)) { auto & base = match[1]; std::string scheme = match[2]; - auto authority = match[3].matched - ? std::optional(match[3]) : std::nullopt; + auto authority = match[3].matched ? std::optional(match[3]) : std::nullopt; std::string path = match[4].matched ? match[4] : match[5]; auto & query = match[6]; auto & fragment = match[7]; @@ -33,8 +30,7 @@ ParsedURL parseURL(const std::string & url) auto isFile = scheme.find("file") != std::string::npos; if (authority && *authority != "" && isFile) - throw BadURL("file:// URL '%s' has unexpected authority '%s'", - url, *authority); + throw BadURL("file:// URL '%s' has unexpected authority '%s'", url, *authority); if (isFile && path.empty()) path = "/"; @@ -46,8 +42,7 @@ ParsedURL parseURL(const std::string & url) .authority = authority, .path = path, .query = decodeQuery(query), - .fragment = percentDecode(std::string(fragment)) - }; + .fragment = percentDecode(std::string(fragment))}; } else @@ -57,7 +52,7 @@ ParsedURL parseURL(const std::string & url) std::string percentDecode(std::string_view in) { std::string decoded; - for (size_t i = 0; i < in.size(); ) { + for (size_t i = 0; i < in.size();) { if (in[i] == '%') { if (i + 2 >= in.size()) throw BadURL("invalid URI parameter '%s'", in); @@ -80,9 +75,7 @@ std::map decodeQuery(const std::string & query) for (auto s : tokenizeString(query, "&")) { auto e = s.find('='); if (e != std::string::npos) - result.emplace( - s.substr(0, e), - percentDecode(std::string_view(s).substr(e + 1))); + result.emplace(s.substr(0, e), percentDecode(std::string_view(s).substr(e + 1))); } return result; @@ -92,9 +85,7 @@ std::string percentEncode(std::string_view s) { std::string res; for (auto & c : s) - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || strchr("-._~!$&'()*+,;=:@", c)) res += c; else @@ -107,7 +98,8 @@ std::string encodeQuery(const std::map & ss) std::string res; bool first = true; for (auto & [name, value] : ss) { - if (!first) res += '&'; + if (!first) + res += '&'; first = false; res += percentEncode(name); res += '='; @@ -118,23 +110,14 @@ std::string encodeQuery(const std::map & ss) std::string ParsedURL::to_string() const { - return - scheme - + ":" - + (authority ? "//" + *authority : "") - + path - + (query.empty() ? "" : "?" + encodeQuery(query)) - + (fragment.empty() ? "" : "#" + percentEncode(fragment)); + return scheme + ":" + (authority ? "//" + *authority : "") + path + (query.empty() ? "" : "?" + encodeQuery(query)) + + (fragment.empty() ? "" : "#" + percentEncode(fragment)); } -bool ParsedURL::operator ==(const ParsedURL & other) const +bool ParsedURL::operator==(const ParsedURL & other) const { - return - scheme == other.scheme - && authority == other.authority - && path == other.path - && query == other.query - && fragment == other.fragment; + return scheme == other.scheme && authority == other.authority && path == other.path && query == other.query + && fragment == other.fragment; } /** @@ -148,7 +131,7 @@ ParsedUrlScheme parseUrlScheme(std::string_view scheme) { auto application = splitPrefixTo(scheme, '+'); auto transport = scheme; - return ParsedUrlScheme { + return ParsedUrlScheme{ .application = application, .transport = transport, }; diff --git a/src/libutil/url.hh b/src/libutil/url.hh index 2a9fb34c1cfc..b89f1cf535e0 100644 --- a/src/libutil/url.hh +++ b/src/libutil/url.hh @@ -16,7 +16,7 @@ struct ParsedURL std::string to_string() const; - bool operator ==(const ParsedURL & other) const; + bool operator==(const ParsedURL & other) const; }; MakeError(BadURL, Error); @@ -35,7 +35,8 @@ ParsedURL parseURL(const std::string & url); * For example git uses `git+https` to designate remotes using a Git * protocol over http. */ -struct ParsedUrlScheme { +struct ParsedUrlScheme +{ std::optional application; std::string_view transport; }; diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 28df30fefbb4..568f3caac0c3 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -37,20 +37,18 @@ #include #endif - -extern char * * environ __attribute__((weak)); - +extern char ** environ __attribute__((weak)); namespace nix { std::optional getEnv(const std::string & key) { char * value = getenv(key.c_str()); - if (!value) return {}; + if (!value) + return {}; return std::string(value); } - std::map getEnv() { std::map env; @@ -65,7 +63,6 @@ std::map getEnv() return env; } - void clearEnv() { for (auto & name : getEnv()) @@ -79,7 +76,6 @@ void replaceEnv(const std::map & newEnv) setenv(newEnvVar.first.c_str(), newEnvVar.second.c_str(), 1); } - Path absPath(Path path, std::optional dir, bool resolveSymlinks) { if (path[0] != '/') { @@ -87,7 +83,7 @@ Path absPath(Path path, std::optional dir, bool resolveSymlinks) #ifdef __GNU__ /* GNU (aka. GNU/Hurd) doesn't have any limitation on path lengths and doesn't define `PATH_MAX'. */ - char *buf = getcwd(NULL, 0); + char * buf = getcwd(NULL, 0); if (buf == NULL) #else char buf[PATH_MAX]; @@ -104,7 +100,6 @@ Path absPath(Path path, std::optional dir, bool resolveSymlinks) return canonPath(path, resolveSymlinks); } - Path canonPath(PathView path, bool resolveSymlinks) { assert(path != ""); @@ -124,17 +119,19 @@ Path canonPath(PathView path, bool resolveSymlinks) while (1) { /* Skip slashes. */ - while (!path.empty() && path[0] == '/') path.remove_prefix(1); - if (path.empty()) break; + while (!path.empty() && path[0] == '/') + path.remove_prefix(1); + if (path.empty()) + break; /* Ignore `.'. */ if (path == "." || path.substr(0, 2) == "./") path.remove_prefix(1); /* If `..', delete the last component. */ - else if (path == ".." || path.substr(0, 3) == "../") - { - if (!s.empty()) s.erase(s.rfind('/')); + else if (path == ".." || path.substr(0, 3) == "../") { + if (!s.empty()) + s.erase(s.rfind('/')); path.remove_prefix(2); } @@ -156,10 +153,10 @@ Path canonPath(PathView path, bool resolveSymlinks) temp = concatStrings(readLink(s), path); path = temp; if (!temp.empty() && temp[0] == '/') { - s.clear(); /* restart for symlinks pointing to absolute path */ + s.clear(); /* restart for symlinks pointing to absolute path */ } else { s = dirOf(s); - if (s == "/") { // we don’t want trailing slashes here, which dirOf only produces if s = / + if (s == "/") { // we don’t want trailing slashes here, which dirOf only produces if s = / s.clear(); } } @@ -170,7 +167,6 @@ Path canonPath(PathView path, bool resolveSymlinks) return s.empty() ? "/" : std::move(s); } - Path dirOf(const PathView path) { Path::size_type pos = path.rfind('/'); @@ -179,7 +175,6 @@ Path dirOf(const PathView path) return pos == 0 ? "/" : Path(path, 0, pos); } - std::string_view baseNameOf(std::string_view path) { if (path.empty()) @@ -198,7 +193,6 @@ std::string_view baseNameOf(std::string_view path) return path.substr(pos, last - pos + 1); } - std::string expandTilde(std::string_view path) { // TODO: expand ~user ? @@ -209,22 +203,17 @@ std::string expandTilde(std::string_view path) return std::string(path); } - bool isInDir(std::string_view path, std::string_view dir) { - return path.substr(0, 1) == "/" - && path.substr(0, dir.size()) == dir - && path.size() >= dir.size() + 2 - && path[dir.size()] == '/'; + return path.substr(0, 1) == "/" && path.substr(0, dir.size()) == dir && path.size() >= dir.size() + 2 + && path[dir.size()] == '/'; } - bool isDirOrInDir(std::string_view path, std::string_view dir) { return path == dir || isInDir(path, dir); } - struct stat stat(const Path & path) { struct stat st; @@ -233,7 +222,6 @@ struct stat stat(const Path & path) return st; } - struct stat lstat(const Path & path) { struct stat st; @@ -242,24 +230,23 @@ struct stat lstat(const Path & path) return st; } - bool pathExists(const Path & path) { int res; struct stat st; res = lstat(path.c_str(), &st); - if (!res) return true; + if (!res) + return true; if (errno != ENOENT && errno != ENOTDIR) throw SysError("getting status of %1%", path); return false; } - Path readLink(const Path & path) { checkInterrupt(); std::vector buf; - for (ssize_t bufSize = PATH_MAX/4; true; bufSize += bufSize/2) { + for (ssize_t bufSize = PATH_MAX / 4; true; bufSize += bufSize / 2) { buf.resize(bufSize); ssize_t rlSize = readlink(path.c_str(), buf.data(), bufSize); if (rlSize == -1) @@ -272,15 +259,13 @@ Path readLink(const Path & path) } } - bool isLink(const Path & path) { struct stat st = lstat(path); return S_ISLNK(st.st_mode); } - -DirEntries readDirectory(DIR *dir, const Path & path) +DirEntries readDirectory(DIR * dir, const Path & path) { DirEntries entries; entries.reserve(64); @@ -289,8 +274,10 @@ DirEntries readDirectory(DIR *dir, const Path & path) while (errno = 0, dirent = readdir(dir)) { /* sic */ checkInterrupt(); std::string name = dirent->d_name; - if (name == "." || name == "..") continue; - entries.emplace_back(name, dirent->d_ino, + if (name == "." || name == "..") + continue; + entries.emplace_back( + name, dirent->d_ino, #ifdef HAVE_STRUCT_DIRENT_D_TYPE dirent->d_type #else @@ -298,7 +285,8 @@ DirEntries readDirectory(DIR *dir, const Path & path) #endif ); } - if (errno) throw SysError("reading directory '%1%'", path); + if (errno) + throw SysError("reading directory '%1%'", path); return entries; } @@ -306,22 +294,24 @@ DirEntries readDirectory(DIR *dir, const Path & path) DirEntries readDirectory(const Path & path) { AutoCloseDir dir(opendir(path.c_str())); - if (!dir) throw SysError("opening directory '%1%'", path); + if (!dir) + throw SysError("opening directory '%1%'", path); return readDirectory(dir.get(), path); } - unsigned char getFileType(const Path & path) { struct stat st = lstat(path); - if (S_ISDIR(st.st_mode)) return DT_DIR; - if (S_ISLNK(st.st_mode)) return DT_LNK; - if (S_ISREG(st.st_mode)) return DT_REG; + if (S_ISDIR(st.st_mode)) + return DT_DIR; + if (S_ISLNK(st.st_mode)) + return DT_LNK; + if (S_ISREG(st.st_mode)) + return DT_REG; return DT_UNKNOWN; } - std::string readFile(int fd) { struct stat st; @@ -331,7 +321,6 @@ std::string readFile(int fd) return drainFD(fd, true, st.st_size); } - std::string readFile(const Path & path) { AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); @@ -340,7 +329,6 @@ std::string readFile(const Path & path) return readFile(fd.get()); } - void readFile(const Path & path, Sink & sink) { AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC); @@ -349,7 +337,6 @@ void readFile(const Path & path, Sink & sink) drainFD(fd.get(), sink); } - void writeFile(const Path & path, std::string_view s, mode_t mode) { AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode); @@ -363,7 +350,6 @@ void writeFile(const Path & path, std::string_view s, mode_t mode) } } - void writeFile(const Path & path, Source & source, mode_t mode) { AutoCloseFD fd = open(path.c_str(), O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, mode); @@ -377,7 +363,9 @@ void writeFile(const Path & path, Source & source, mode_t mode) try { auto n = source.read(buf.data(), buf.size()); writeFull(fd.get(), {buf.data(), n}); - } catch (EndOfFile &) { break; } + } catch (EndOfFile &) { + break; + } } } catch (Error & e) { e.addTrace({}, "writing file '%1%'", path); @@ -399,20 +387,19 @@ std::string readLine(int fd) } else if (rd == 0) throw EndOfFile("unexpected EOF reading a line"); else { - if (ch == '\n') return s; + if (ch == '\n') + return s; s += ch; } } } - void writeLine(int fd, std::string s) { s += '\n'; writeFull(fd, s); } - static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed) { checkInterrupt(); @@ -421,7 +408,8 @@ static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed) struct stat st; if (fstatat(parentfd, name.c_str(), &st, AT_SYMLINK_NOFOLLOW) == -1) { - if (errno == ENOENT) return; + if (errno == ENOENT) + return; throw SysError("getting status of '%1%'", path); } @@ -429,23 +417,23 @@ static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed) /* We are about to delete a file. Will it likely free space? */ switch (st.st_nlink) { - /* Yes: last link. */ - case 1: - bytesFreed += st.st_size; - break; - /* Maybe: yes, if 'auto-optimise-store' or manual optimisation - was performed. Instead of checking for real let's assume - it's an optimised file and space will be freed. - - In worst case we will double count on freed space for files - with exactly two hardlinks for unoptimised packages. - */ - case 2: - bytesFreed += st.st_size; - break; - /* No: 3+ links. */ - default: - break; + /* Yes: last link. */ + case 1: + bytesFreed += st.st_size; + break; + /* Maybe: yes, if 'auto-optimise-store' or manual optimisation + was performed. Instead of checking for real let's assume + it's an optimised file and space will be freed. + + In worst case we will double count on freed space for files + with exactly two hardlinks for unoptimised packages. + */ + case 2: + bytesFreed += st.st_size; + break; + /* No: 3+ links. */ + default: + break; } } @@ -469,7 +457,8 @@ static void _deletePath(int parentfd, const Path & path, uint64_t & bytesFreed) int flags = S_ISDIR(st.st_mode) ? AT_REMOVEDIR : 0; if (unlinkat(parentfd, name.c_str(), flags) == -1) { - if (errno == ENOENT) return; + if (errno == ENOENT) + return; throw SysError("cannot unlink '%1%'", path); } } @@ -482,31 +471,28 @@ static void _deletePath(const Path & path, uint64_t & bytesFreed) AutoCloseFD dirfd{open(dir.c_str(), O_RDONLY)}; if (!dirfd) { - if (errno == ENOENT) return; + if (errno == ENOENT) + return; throw SysError("opening directory '%1%'", path); } _deletePath(dirfd.get(), path, bytesFreed); } - void deletePath(const Path & path) { uint64_t dummy; deletePath(path, dummy); } - void deletePath(const Path & path, uint64_t & bytesFreed) { - //Activity act(*logger, lvlDebug, format("recursively deleting path '%1%'") % path); + // Activity act(*logger, lvlDebug, format("recursively deleting path '%1%'") % path); bytesFreed = 0; _deletePath(path, bytesFreed); } - -static Path tempName(Path tmpRoot, const Path & prefix, bool includePid, - int & counter) +static Path tempName(Path tmpRoot, const Path & prefix, bool includePid, int & counter) { tmpRoot = canonPath(tmpRoot.empty() ? getEnv("TMPDIR").value_or("/tmp") : tmpRoot, true); if (includePid) @@ -515,9 +501,7 @@ static Path tempName(Path tmpRoot, const Path & prefix, bool includePid, return (format("%1%/%2%-%3%") % tmpRoot % prefix % counter++).str(); } - -Path createTempDir(const Path & tmpRoot, const Path & prefix, - bool includePid, bool useGlobalCounter, mode_t mode) +Path createTempDir(const Path & tmpRoot, const Path & prefix, bool includePid, bool useGlobalCounter, mode_t mode) { static int globalCounter = 0; int localCounter = 0; @@ -546,7 +530,6 @@ Path createTempDir(const Path & tmpRoot, const Path & prefix, } } - std::pair createTempFile(const Path & prefix) { Path tmpl(getEnv("TMPDIR").value_or("/tmp") + "/" + prefix + ".XXXXXX"); @@ -559,7 +542,6 @@ std::pair createTempFile(const Path & prefix) return {std::move(fd), tmpl}; } - std::string getUserName() { auto pw = getpwuid(geteuid()); @@ -569,11 +551,9 @@ std::string getUserName() return name; } - Path getHome() { - static Path homeDir = []() - { + static Path homeDir = []() { auto homeDir = getEnv("HOME"); if (homeDir) { // Only use $HOME if doesn't exist or is owned by the current user. @@ -581,11 +561,14 @@ Path getHome() int result = stat(homeDir->c_str(), &st); if (result != 0) { if (errno != ENOENT) { - warn("couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", *homeDir, errno); + warn( + "couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", + *homeDir, errno); homeDir.reset(); } } else if (st.st_uid != geteuid()) { - warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file", *homeDir); + warn( + "$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file", *homeDir); homeDir.reset(); } } @@ -593,8 +576,7 @@ Path getHome() std::vector buf(16384); struct passwd pwbuf; struct passwd * pw; - if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0 - || !pw || !pw->pw_dir || !pw->pw_dir[0]) + if (getpwuid_r(geteuid(), &pwbuf, buf.data(), buf.size(), &pw) != 0 || !pw || !pw->pw_dir || !pw->pw_dir[0]) throw Error("cannot determine user's home directory"); homeDir = pw->pw_dir; } @@ -603,14 +585,12 @@ Path getHome() return homeDir; } - Path getCacheDir() { auto cacheDir = getEnv("XDG_CACHE_HOME"); return cacheDir ? *cacheDir : getHome() + "/.cache"; } - Path getConfigDir() { auto configDir = getEnv("XDG_CONFIG_HOME"); @@ -626,39 +606,36 @@ std::vector getConfigDirs() return result; } - Path getDataDir() { auto dataDir = getEnv("XDG_DATA_HOME"); return dataDir ? *dataDir : getHome() + "/.local/share"; } - std::optional getSelfExe() { - static auto cached = []() -> std::optional - { - #if __linux__ + static auto cached = []() -> std::optional { +#if __linux__ return readLink("/proc/self/exe"); - #elif __APPLE__ +#elif __APPLE__ char buf[1024]; uint32_t size = sizeof(buf); if (_NSGetExecutablePath(buf, &size) == 0) return buf; else return std::nullopt; - #else +#else return std::nullopt; - #endif +#endif }(); return cached; } - Paths createDirs(const Path & path) { Paths created; - if (path == "/") return created; + if (path == "/") + return created; struct stat st; if (lstat(path.c_str(), &st) == -1) { @@ -672,14 +649,13 @@ Paths createDirs(const Path & path) if (S_ISLNK(st.st_mode) && stat(path.c_str(), &st) == -1) throw SysError("statting symlink '%1%'", path); - if (!S_ISDIR(st.st_mode)) throw Error("'%1%' is not a directory", path); + if (!S_ISDIR(st.st_mode)) + throw Error("'%1%' is not a directory", path); return created; } - -void createSymlink(const Path & target, const Path & link, - std::optional mtime) +void createSymlink(const Path & target, const Path & link, std::optional mtime) { if (symlink(target.c_str(), link.c_str())) throw SysError("creating symlink from '%1%' to '%2%'", link, target); @@ -694,9 +670,7 @@ void createSymlink(const Path & target, const Path & link, } } - -void replaceSymlink(const Path & target, const Path & link, - std::optional mtime) +void replaceSymlink(const Path & target, const Path & link, std::optional mtime) { for (unsigned int n = 0; true; n++) { Path tmp = canonPath(fmt("%s/.%d_%s", dirOf(link), n, baseNameOf(link))); @@ -704,7 +678,8 @@ void replaceSymlink(const Path & target, const Path & link, try { createSymlink(target, tmp, mtime); } catch (SysError & e) { - if (e.errNo == EEXIST) continue; + if (e.errNo == EEXIST) + continue; throw; } @@ -715,27 +690,28 @@ void replaceSymlink(const Path & target, const Path & link, } } - void readFull(int fd, char * buf, size_t count) { while (count) { checkInterrupt(); ssize_t res = read(fd, buf, count); if (res == -1) { - if (errno == EINTR) continue; + if (errno == EINTR) + continue; throw SysError("reading from file"); } - if (res == 0) throw EndOfFile("unexpected end-of-file"); + if (res == 0) + throw EndOfFile("unexpected end-of-file"); count -= res; buf += res; } } - void writeFull(int fd, std::string_view s, bool allowInterrupts) { while (!s.empty()) { - if (allowInterrupts) checkInterrupt(); + if (allowInterrupts) + checkInterrupt(); ssize_t res = write(fd, s.data(), s.size()); if (res == -1 && errno != EINTR) throw SysError("writing to file"); @@ -744,7 +720,6 @@ void writeFull(int fd, std::string_view s, bool allowInterrupts) } } - std::string drainFD(int fd, bool block, const size_t reserveSize) { // the parser needs two extra bytes to append terminating characters, other users will @@ -754,7 +729,6 @@ std::string drainFD(int fd, bool block, const size_t reserveSize) return std::move(sink.s); } - void drainFD(int fd, Sink & sink, bool block) { // silence GCC maybe-uninitialized warning in finally @@ -782,20 +756,21 @@ void drainFD(int fd, Sink & sink, bool block) break; if (errno != EINTR) throw SysError("reading from file"); - } - else if (rd == 0) break; - else sink({(char *) buf.data(), (size_t) rd}); + } else if (rd == 0) + break; + else + sink({(char *) buf.data(), (size_t) rd}); } } - - ////////////////////////////////////////////////////////////////////// +AutoDelete::AutoDelete() + : del{false} +{} -AutoDelete::AutoDelete() : del{false} {} - -AutoDelete::AutoDelete(const std::string & p, bool recursive) : path(p) +AutoDelete::AutoDelete(const std::string & p, bool recursive) + : path(p) { del = true; this->recursive = recursive; @@ -822,30 +797,30 @@ void AutoDelete::cancel() del = false; } -void AutoDelete::reset(const Path & p, bool recursive) { +void AutoDelete::reset(const Path & p, bool recursive) +{ path = p; this->recursive = recursive; del = true; } - - ////////////////////////////////////////////////////////////////////// +AutoCloseFD::AutoCloseFD() + : fd{-1} +{} -AutoCloseFD::AutoCloseFD() : fd{-1} {} - - -AutoCloseFD::AutoCloseFD(int fd) : fd{fd} {} +AutoCloseFD::AutoCloseFD(int fd) + : fd{fd} +{} - -AutoCloseFD::AutoCloseFD(AutoCloseFD && that) : fd{that.fd} +AutoCloseFD::AutoCloseFD(AutoCloseFD && that) + : fd{that.fd} { that.fd = -1; } - -AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that) +AutoCloseFD & AutoCloseFD::operator=(AutoCloseFD && that) { close(); fd = that.fd; @@ -853,7 +828,6 @@ AutoCloseFD & AutoCloseFD::operator =(AutoCloseFD && that) return *this; } - AutoCloseFD::~AutoCloseFD() { try { @@ -863,13 +837,11 @@ AutoCloseFD::~AutoCloseFD() } } - int AutoCloseFD::get() const { return fd; } - void AutoCloseFD::close() { if (fd != -1) { @@ -880,13 +852,11 @@ void AutoCloseFD::close() } } - AutoCloseFD::operator bool() const { return fd != -1; } - int AutoCloseFD::release() { int oldFD = fd; @@ -894,14 +864,15 @@ int AutoCloseFD::release() return oldFD; } - void Pipe::create() { int fds[2]; #if HAVE_PIPE2 - if (pipe2(fds, O_CLOEXEC) != 0) throw SysError("creating pipe"); + if (pipe2(fds, O_CLOEXEC) != 0) + throw SysError("creating pipe"); #else - if (pipe(fds) != 0) throw SysError("creating pipe"); + if (pipe(fds) != 0) + throw SysError("creating pipe"); closeOnExec(fds[0]); closeOnExec(fds[1]); #endif @@ -909,48 +880,39 @@ void Pipe::create() writeSide = fds[1]; } - void Pipe::close() { readSide.close(); writeSide.close(); } - ////////////////////////////////////////////////////////////////////// - -Pid::Pid() -{ -} - +Pid::Pid() {} Pid::Pid(pid_t pid) : pid(pid) -{ -} - +{} Pid::~Pid() { - if (pid != -1) kill(); + if (pid != -1) + kill(); } - -void Pid::operator =(pid_t pid) +void Pid::operator=(pid_t pid) { - if (this->pid != -1 && this->pid != pid) kill(); + if (this->pid != -1 && this->pid != pid) + kill(); this->pid = pid; killSignal = SIGKILL; // reset signal to default } - Pid::operator pid_t() { return pid; } - int Pid::kill() { assert(pid != -1); @@ -973,7 +935,6 @@ int Pid::kill() return wait(); } - int Pid::wait() { assert(pid != -1); @@ -990,19 +951,16 @@ int Pid::wait() } } - void Pid::setSeparatePG(bool separatePG) { this->separatePG = separatePG; } - void Pid::setKillSignal(int signal) { this->killSignal = signal; } - pid_t Pid::release() { pid_t p = pid; @@ -1010,7 +968,6 @@ pid_t Pid::release() return p; } - void killUser(uid_t uid) { debug("killing all processes running under uid '%1%'", uid); @@ -1022,7 +979,6 @@ void killUser(uid_t uid) fork a process, switch to uid, and send a mass kill. */ Pid pid = startProcess([&]() { - if (setuid(uid) == -1) throw SysError("setting uid"); @@ -1033,11 +989,14 @@ void killUser(uid_t uid) calling process. In the OSX libc, it's set to true, which means "follow POSIX", which we don't want here */ - if (syscall(SYS_kill, -1, SIGKILL, false) == 0) break; + if (syscall(SYS_kill, -1, SIGKILL, false) == 0) + break; #else - if (kill(-1, SIGKILL) == 0) break; + if (kill(-1, SIGKILL) == 0) + break; #endif - if (errno == ESRCH || errno == EPERM) break; /* no more processes */ + if (errno == ESRCH || errno == EPERM) + break; /* no more processes */ if (errno != EINTR) throw SysError("cannot kill processes for uid '%1%'", uid); } @@ -1055,10 +1014,8 @@ void killUser(uid_t uid) uid | grep -q $uid'. */ } - ////////////////////////////////////////////////////////////////////// - /* Wrapper around vfork to prevent the child process from clobbering the caller's stack frame in the parent. */ static pid_t doFork(bool allowVfork, std::function fun) __attribute__((noinline)); @@ -1069,12 +1026,12 @@ static pid_t doFork(bool allowVfork, std::function fun) #else pid_t pid = fork(); #endif - if (pid != 0) return pid; + if (pid != 0) + return pid; fun(); abort(); } - pid_t startProcess(std::function fun, const ProcessOptions & options) { auto wrapper = [&]() { @@ -1089,8 +1046,10 @@ pid_t startProcess(std::function fun, const ProcessOptions & options) } catch (std::exception & e) { try { std::cerr << options.errorPrefix << e.what() << "\n"; - } catch (...) { } - } catch (...) { } + } catch (...) { + } + } catch (...) { + } if (options.runExitHandlers) exit(1); else @@ -1098,24 +1057,24 @@ pid_t startProcess(std::function fun, const ProcessOptions & options) }; pid_t pid = doFork(options.allowVfork, wrapper); - if (pid == -1) throw SysError("unable to fork"); + if (pid == -1) + throw SysError("unable to fork"); return pid; } - std::vector stringsToCharPtrs(const Strings & ss) { std::vector res; - for (auto & s : ss) res.push_back((char *) s.c_str()); + for (auto & s : ss) + res.push_back((char *) s.c_str()); res.push_back(0); return res; } -std::string runProgram(Path program, bool searchPath, const Strings & args, - const std::optional & input) +std::string runProgram(Path program, bool searchPath, const Strings & args, const std::optional & input) { - auto res = runProgram(RunOptions {.program = program, .searchPath = searchPath, .args = args, .input = input}); + auto res = runProgram(RunOptions{.program = program, .searchPath = searchPath, .args = args, .input = input}); if (!statusOk(res.first)) throw ExecError(res.first, "program '%1%' %2%", program, statusToString(res.first)); @@ -1156,8 +1115,10 @@ void runProgram2(const RunOptions & options) /* Create a pipe. */ Pipe out, in; - if (options.standardOut) out.create(); - if (source) in.create(); + if (options.standardOut) + out.create(); + if (source) + in.create(); ProcessOptions processOptions; // vfork implies that the environment of the main process and the fork will @@ -1166,41 +1127,43 @@ void runProgram2(const RunOptions & options) processOptions.allowVfork = !options.environment; /* Fork. */ - Pid pid = startProcess([&]() { - if (options.environment) - replaceEnv(*options.environment); - if (options.standardOut && dup2(out.writeSide.get(), STDOUT_FILENO) == -1) - throw SysError("dupping stdout"); - if (options.mergeStderrToStdout) - if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) - throw SysError("cannot dup stdout into stderr"); - if (source && dup2(in.readSide.get(), STDIN_FILENO) == -1) - throw SysError("dupping stdin"); - - if (options.chdir && chdir((*options.chdir).c_str()) == -1) - throw SysError("chdir failed"); - if (options.gid && setgid(*options.gid) == -1) - throw SysError("setgid failed"); - /* Drop all other groups if we're setgid. */ - if (options.gid && setgroups(0, 0) == -1) - throw SysError("setgroups failed"); - if (options.uid && setuid(*options.uid) == -1) - throw SysError("setuid failed"); - - Strings args_(options.args); - args_.push_front(options.program); - - restoreProcessContext(); - - if (options.searchPath) - execvp(options.program.c_str(), stringsToCharPtrs(args_).data()); + Pid pid = startProcess( + [&]() { + if (options.environment) + replaceEnv(*options.environment); + if (options.standardOut && dup2(out.writeSide.get(), STDOUT_FILENO) == -1) + throw SysError("dupping stdout"); + if (options.mergeStderrToStdout) + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) + throw SysError("cannot dup stdout into stderr"); + if (source && dup2(in.readSide.get(), STDIN_FILENO) == -1) + throw SysError("dupping stdin"); + + if (options.chdir && chdir((*options.chdir).c_str()) == -1) + throw SysError("chdir failed"); + if (options.gid && setgid(*options.gid) == -1) + throw SysError("setgid failed"); + /* Drop all other groups if we're setgid. */ + if (options.gid && setgroups(0, 0) == -1) + throw SysError("setgroups failed"); + if (options.uid && setuid(*options.uid) == -1) + throw SysError("setuid failed"); + + Strings args_(options.args); + args_.push_front(options.program); + + restoreProcessContext(); + + if (options.searchPath) + execvp(options.program.c_str(), stringsToCharPtrs(args_).data()); // This allows you to refer to a program with a pathname relative // to the PATH variable. - else - execv(options.program.c_str(), stringsToCharPtrs(args_).data()); + else + execv(options.program.c_str(), stringsToCharPtrs(args_).data()); - throw SysError("executing '%1%'", options.program); - }, processOptions); + throw SysError("executing '%1%'", options.program); + }, + processOptions); out.writeSide.close(); @@ -1213,7 +1176,6 @@ void runProgram2(const RunOptions & options) writerThread.join(); }); - if (source) { in.readSide.close(); writerThread = std::thread([&]() { @@ -1243,13 +1205,13 @@ void runProgram2(const RunOptions & options) int status = pid.wait(); /* Wait for the writer thread to finish. */ - if (source) promise.get_future().get(); + if (source) + promise.get_future().get(); if (status) throw ExecError(status, "program '%1%' %2%", options.program, statusToString(status)); } - void closeMostFDs(const std::set & exceptions) { #if __linux__ @@ -1273,19 +1235,15 @@ void closeMostFDs(const std::set & exceptions) close(fd); /* ignore result */ } - void closeOnExec(int fd) { int prev; - if ((prev = fcntl(fd, F_GETFD, 0)) == -1 || - fcntl(fd, F_SETFD, prev | FD_CLOEXEC) == -1) + if ((prev = fcntl(fd, F_GETFD, 0)) == -1 || fcntl(fd, F_SETFD, prev | FD_CLOEXEC) == -1) throw SysError("setting close-on-exec flag"); } - ////////////////////////////////////////////////////////////////////// - std::atomic _isInterrupted = false; static thread_local bool interruptThrown = false; @@ -1307,17 +1265,17 @@ void _interrupted() } } - ////////////////////////////////////////////////////////////////////// - -template C tokenizeString(std::string_view s, std::string_view separators) +template +C tokenizeString(std::string_view s, std::string_view separators) { C result; auto pos = s.find_first_not_of(separators, 0); while (pos != std::string_view::npos) { auto end = s.find_first_of(separators, pos + 1); - if (end == std::string_view::npos) end = s.size(); + if (end == std::string_view::npos) + end = s.size(); result.insert(result.end(), std::string(s, pos, end - pos)); pos = s.find_first_not_of(separators, end); } @@ -1328,29 +1286,25 @@ template Strings tokenizeString(std::string_view s, std::string_view separators) template StringSet tokenizeString(std::string_view s, std::string_view separators); template std::vector tokenizeString(std::string_view s, std::string_view separators); - std::string chomp(std::string_view s) { size_t i = s.find_last_not_of(" \n\r\t"); return i == std::string_view::npos ? "" : std::string(s, 0, i + 1); } - std::string trim(std::string_view s, std::string_view whitespace) { auto i = s.find_first_not_of(whitespace); - if (i == s.npos) return ""; + if (i == s.npos) + return ""; auto j = s.find_last_not_of(whitespace); return std::string(s, i, j == s.npos ? j : j - i + 1); } - -std::string replaceStrings( - std::string res, - std::string_view from, - std::string_view to) +std::string replaceStrings(std::string res, std::string_view from, std::string_view to) { - if (from.empty()) return res; + if (from.empty()) + return res; size_t pos = 0; while ((pos = res.find(from, pos)) != std::string::npos) { res.replace(pos, from.size(), to); @@ -1359,11 +1313,11 @@ std::string replaceStrings( return res; } - std::string rewriteStrings(std::string s, const StringMap & rewrites) { for (auto & i : rewrites) { - if (i.first == i.second) continue; + if (i.first == i.second) + continue; size_t j = 0; while ((j = s.find(i.first, j)) != std::string::npos) s.replace(j, i.first.size(), i.second); @@ -1371,7 +1325,6 @@ std::string rewriteStrings(std::string s, const StringMap & rewrites) return s; } - std::string statusToString(int status) { if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { @@ -1385,32 +1338,27 @@ std::string statusToString(int status) #else return (format("failed due to signal %1%") % sig).str(); #endif - } - else + } else return "died abnormally"; - } else return "succeeded"; + } else + return "succeeded"; } - bool statusOk(int status) { return WIFEXITED(status) && WEXITSTATUS(status) == 0; } - bool hasPrefix(std::string_view s, std::string_view prefix) { return s.compare(0, prefix.size(), prefix) == 0; } - bool hasSuffix(std::string_view s, std::string_view suffix) { - return s.size() >= suffix.size() - && s.substr(s.size() - suffix.size()) == suffix; + return s.size() >= suffix.size() && s.substr(s.size() - suffix.size()) == suffix; } - std::string toLower(const std::string & s) { std::string r(s); @@ -1419,19 +1367,20 @@ std::string toLower(const std::string & s) return r; } - std::string shellEscape(const std::string_view s) { std::string r; r.reserve(s.size() + 2); r += "'"; for (auto & i : s) - if (i == '\'') r += "'\\''"; else r += i; + if (i == '\'') + r += "'\\''"; + else + r += i; r += '\''; return r; } - void ignoreException() { /* Make sure no exceptions leave this function. @@ -1442,14 +1391,13 @@ void ignoreException() } catch (std::exception & e) { printError("error (ignored): %1%", e.what()); } - } catch (...) { } + } catch (...) { + } } bool shouldANSI() { - return isatty(STDERR_FILENO) - && getEnv("TERM").value_or("dumb") != "dumb" - && !getEnv("NO_COLOR").has_value(); + return isatty(STDERR_FILENO) && getEnv("TERM").value_or("dumb") != "dumb" && !getEnv("NO_COLOR").has_value(); } std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned int width) @@ -1468,13 +1416,17 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in if (i != s.end() && *i == '[') { e += *i++; // eat parameter bytes - while (i != s.end() && *i >= 0x30 && *i <= 0x3f) e += *i++; + while (i != s.end() && *i >= 0x30 && *i <= 0x3f) + e += *i++; // eat intermediate bytes - while (i != s.end() && *i >= 0x20 && *i <= 0x2f) e += *i++; + while (i != s.end() && *i >= 0x20 && *i <= 0x2f) + e += *i++; // eat final byte - if (i != s.end() && *i >= 0x40 && *i <= 0x7e) e += last = *i++; + if (i != s.end() && *i >= 0x40 && *i <= 0x7e) + e += last = *i++; } else { - if (i != s.end() && *i >= 0x40 && *i <= 0x5f) e += *i++; + if (i != s.end() && *i >= 0x40 && *i <= 0x5f) + e += *i++; } if (!filterAll && last == 'm') @@ -1482,9 +1434,12 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in } else if (*i == '\t') { - i++; t += ' '; w++; + i++; + t += ' '; + w++; while (w < (size_t) width && w % 8) { - t += ' '; w++; + t += ' '; + w++; } } @@ -1497,12 +1452,14 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in // Copy one UTF-8 character. if ((*i & 0xe0) == 0xc0) { t += *i++; - if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++; + if (i != s.end() && ((*i & 0xc0) == 0x80)) + t += *i++; } else if ((*i & 0xf0) == 0xe0) { t += *i++; if (i != s.end() && ((*i & 0xc0) == 0x80)) { t += *i++; - if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++; + if (i != s.end() && ((*i & 0xc0) == 0x80)) + t += *i++; } } else if ((*i & 0xf8) == 0xf0) { t += *i++; @@ -1510,7 +1467,8 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in t += *i++; if (i != s.end() && ((*i & 0xc0) == 0x80)) { t += *i++; - if (i != s.end() && ((*i & 0xc0) == 0x80)) t += *i++; + if (i != s.end() && ((*i & 0xc0) == 0x80)) + t += *i++; } } } else @@ -1521,7 +1479,6 @@ std::string filterANSIEscapes(const std::string & s, bool filterAll, unsigned in return t; } - constexpr char base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string base64Encode(std::string_view s) @@ -1539,19 +1496,20 @@ std::string base64Encode(std::string_view s) } } - if (nbits) res.push_back(base64Chars[data << (6 - nbits) & 0x3f]); - while (res.size() % 4) res.push_back('='); + if (nbits) + res.push_back(base64Chars[data << (6 - nbits) & 0x3f]); + while (res.size() % 4) + res.push_back('='); return res; } - std::string base64Decode(std::string_view s) { constexpr char npos = -1; constexpr std::array base64DecodeChars = [&]() { - std::array result{}; - for (auto& c : result) + std::array result{}; + for (auto & c : result) c = npos; for (int i = 0; i < 64; i++) result[base64Chars[i]] = i; @@ -1565,8 +1523,10 @@ std::string base64Decode(std::string_view s) unsigned int d = 0, bits = 0; for (char c : s) { - if (c == '=') break; - if (c == '\n') continue; + if (c == '=') + break; + if (c == '\n') + continue; char digit = base64DecodeChars[(unsigned char) c]; if (digit == npos) @@ -1583,7 +1543,6 @@ std::string base64Decode(std::string_view s) return res; } - std::string stripIndentation(std::string_view s) { size_t minIndent = 10000; @@ -1611,7 +1570,8 @@ std::string stripIndentation(std::string_view s) size_t pos = 0; while (pos < s.size()) { auto eol = s.find('\n', pos); - if (eol == s.npos) eol = s.size(); + if (eol == s.npos) + eol = s.size(); if (eol - pos > minIndent) res.append(s.substr(pos + minIndent, eol - pos - minIndent)); res.push_back('\n'); @@ -1621,12 +1581,10 @@ std::string stripIndentation(std::string_view s) return res; } - ////////////////////////////////////////////////////////////////////// static Sync> windowSize{{0, 0}}; - static void updateWindowSize() { struct winsize ws; @@ -1637,18 +1595,17 @@ static void updateWindowSize() } } - std::pair getWindowSize() { return *windowSize.lock(); } - /* We keep track of interrupt callbacks using integer tokens, so we can iterate safely without having to lock the data structure while executing arbitrary functions. */ -struct InterruptCallbacks { +struct InterruptCallbacks +{ typedef int64_t Token; /* We use unique tokens so that we can't accidentally delete the wrong @@ -1737,14 +1694,14 @@ rlim_t savedStackSize = 0; void setStackSize(size_t stackSize) { - #if __linux__ +#if __linux__ struct rlimit limit; if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur < stackSize) { savedStackSize = limit.rlim_cur; limit.rlim_cur = stackSize; setrlimit(RLIMIT_STACK, &limit); } - #endif +#endif } #if __linux__ @@ -1796,7 +1753,7 @@ void restoreProcessContext(bool restoreMounts) restoreMountNamespace(); } - #if __linux__ +#if __linux__ if (savedStackSize) { struct rlimit limit; if (getrlimit(RLIMIT_STACK, &limit) == 0) { @@ -1804,7 +1761,7 @@ void restoreProcessContext(bool restoreMounts) setrlimit(RLIMIT_STACK, &limit); } } - #endif +#endif } /* RAII helper to automatically deregister a callback. */ @@ -1830,21 +1787,22 @@ std::unique_ptr createInterruptCallback(std::function return std::unique_ptr(res.release()); } - AutoCloseFD createUnixDomainSocket() { - AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM - #ifdef SOCK_CLOEXEC - | SOCK_CLOEXEC - #endif - , 0); + AutoCloseFD fdSocket = socket( + PF_UNIX, + SOCK_STREAM +#ifdef SOCK_CLOEXEC + | SOCK_CLOEXEC +#endif + , + 0); if (!fdSocket) throw SysError("cannot create Unix domain socket"); closeOnExec(fdSocket.get()); return fdSocket; } - AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) { auto fdSocket = nix::createUnixDomainSocket(); @@ -1860,7 +1818,6 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) return fdSocket; } - void bind(int fd, const std::string & path) { unlink(path.c_str()); @@ -1891,7 +1848,6 @@ void bind(int fd, const std::string & path) } } - void connect(int fd, const std::string & path) { struct sockaddr_un addr; @@ -1920,13 +1876,11 @@ void connect(int fd, const std::string & path) } } - std::string showBytes(uint64_t bytes) { return fmt("%.2f MiB", bytes / (1024.0 * 1024.0)); } - // FIXME: move to libstore/build void commonChildInit(Pipe & logPipe) { diff --git a/src/libutil/util.hh b/src/libutil/util.hh index d3ed15b0b07b..dbfa33f6180e 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -31,11 +31,9 @@ namespace nix { struct Sink; struct Source; - /* The system for which Nix is compiled. */ extern const std::string nativeSystem; - /* Return an environment variable. */ std::optional getEnv(const std::string & key); @@ -48,9 +46,7 @@ void clearEnv(); /* Return an absolutized path, resolving paths relative to the specified directory, or the current directory otherwise. The path is also canonicalised. */ -Path absPath(Path path, - std::optional dir = {}, - bool resolveSymlinks = false); +Path absPath(Path path, std::optional dir = {}, bool resolveSymlinks = false); /* Canonicalise a path by removing all `.' or `..' components and double or trailing slashes. Optionally resolves all symlink @@ -100,7 +96,10 @@ struct DirEntry ino_t ino; unsigned char type; // one of DT_* DirEntry(std::string name, ino_t ino, unsigned char type) - : name(std::move(name)), ino(ino), type(type) { } + : name(std::move(name)) + , ino(ino) + , type(type) + {} }; typedef std::vector DirEntries; @@ -161,13 +160,10 @@ inline Paths createDirs(PathView path) } /* Create a symlink. */ -void createSymlink(const Path & target, const Path & link, - std::optional mtime = {}); +void createSymlink(const Path & target, const Path & link, std::optional mtime = {}); /* Atomically create or replace a symlink. */ -void replaceSymlink(const Path & target, const Path & link, - std::optional mtime = {}); - +void replaceSymlink(const Path & target, const Path & link, std::optional mtime = {}); /* Wrappers arount read()/write() that read/write exactly the requested number of bytes. */ @@ -176,16 +172,13 @@ void writeFull(int fd, std::string_view s, bool allowInterrupts = true); MakeError(EndOfFile, Error); - /* Read a file descriptor until EOF occurs. */ -std::string drainFD(int fd, bool block = true, const size_t reserveSize=0); +std::string drainFD(int fd, bool block = true, const size_t reserveSize = 0); void drainFD(int fd, Sink & sink, bool block = true); - /* Automatic cleanup of resources. */ - class AutoDelete { Path path; @@ -197,11 +190,16 @@ public: ~AutoDelete(); void cancel(); void reset(const Path & p, bool recursive = true); - operator Path() const { return path; } - operator PathView() const { return path; } + operator Path() const + { + return path; + } + operator PathView() const + { + return path; + } }; - class AutoCloseFD { int fd; @@ -209,25 +207,27 @@ public: AutoCloseFD(); AutoCloseFD(int fd); AutoCloseFD(const AutoCloseFD & fd) = delete; - AutoCloseFD(AutoCloseFD&& fd); + AutoCloseFD(AutoCloseFD && fd); ~AutoCloseFD(); - AutoCloseFD& operator =(const AutoCloseFD & fd) = delete; - AutoCloseFD& operator =(AutoCloseFD&& fd); + AutoCloseFD & operator=(const AutoCloseFD & fd) = delete; + AutoCloseFD & operator=(AutoCloseFD && fd); int get() const; explicit operator bool() const; int release(); void close(); }; - /* Create a temporary directory. */ -Path createTempDir(const Path & tmpRoot = "", const Path & prefix = "nix", - bool includePid = true, bool useGlobalCounter = true, mode_t mode = 0755); +Path createTempDir( + const Path & tmpRoot = "", + const Path & prefix = "nix", + bool includePid = true, + bool useGlobalCounter = true, + mode_t mode = 0755); /* Create a temporary file, returning a file handle and its path. */ std::pair createTempFile(const Path & prefix = "nix"); - class Pipe { public: @@ -236,17 +236,16 @@ public: void close(); }; - struct DIRDeleter { - void operator()(DIR * dir) const { + void operator()(DIR * dir) const + { closedir(dir); } }; typedef std::unique_ptr AutoCloseDir; - class Pid { pid_t pid = -1; @@ -256,7 +255,7 @@ public: Pid(); Pid(pid_t pid); ~Pid(); - void operator =(pid_t pid); + void operator=(pid_t pid); operator pid_t(); int kill(); int wait(); @@ -266,12 +265,10 @@ public: pid_t release(); }; - /* Kill all processes running under the specified uid by sending them a SIGKILL. */ void killUser(uid_t uid); - /* Fork a process that runs the given function, and return the child pid to the caller. */ struct ProcessOptions @@ -284,10 +281,11 @@ struct ProcessOptions pid_t startProcess(std::function fun, const ProcessOptions & options = ProcessOptions()); - /* Run a program and return its stdout in a string (i.e., like the shell backtick operator). */ -std::string runProgram(Path program, bool searchPath = false, +std::string runProgram( + Path program, + bool searchPath = false, const Strings & args = Strings(), const std::optional & input = {}); @@ -310,11 +308,9 @@ std::pair runProgram(RunOptions && options); void runProgram2(const RunOptions & options); - /* Change the stack size. */ void setStackSize(size_t stackSize); - /* Restore the original inherited Unix process context (such as signal masks, stack size). */ void restoreProcessContext(bool restoreMounts = true); @@ -332,16 +328,16 @@ void restoreMountNamespace(); fail. */ void unshareFilesystem(); - class ExecError : public Error { public: int status; template - ExecError(int status, const Args & ... args) - : Error(args...), status(status) - { } + ExecError(int status, const Args &... args) + : Error(args...) + , status(status) + {} }; /* Convert a list of strings to a null-terminated vector of char @@ -356,7 +352,6 @@ void closeMostFDs(const std::set & exceptions); /* Set the close-on-exec flag for the given file descriptor. */ void closeOnExec(int fd); - /* User interruption. */ extern std::atomic _isInterrupted; @@ -375,13 +370,11 @@ void inline checkInterrupt() MakeError(Interrupted, BaseError); - MakeError(FormatError, Error); - /* String tokenizer. */ -template C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r"); - +template +C tokenizeString(std::string_view s, std::string_view separators = " \t\n\r"); /* Concatenate the given strings with a separator between the elements. */ @@ -390,27 +383,29 @@ std::string concatStringsSep(const std::string_view sep, const C & ss) { size_t size = 0; // need a cast to string_view since this is also called with Symbols - for (const auto & s : ss) size += sep.size() + std::string_view(s).size(); + for (const auto & s : ss) + size += sep.size() + std::string_view(s).size(); std::string s; s.reserve(size); for (auto & i : ss) { - if (s.size() != 0) s += sep; + if (s.size() != 0) + s += sep; s += i; } return s; } -template -auto concatStrings(Parts && ... parts) +template +auto concatStrings(Parts &&... parts) -> std::enable_if_t<(... && std::is_convertible_v), std::string> { - std::string_view views[sizeof...(parts)] = { parts... }; + std::string_view views[sizeof...(parts)] = {parts...}; return concatStringsSep({}, views); } - /* Add quotes around a collection of strings. */ -template Strings quoteStrings(const C & c) +template +Strings quoteStrings(const C & c) { Strings res; for (auto & s : c) @@ -418,33 +413,24 @@ template Strings quoteStrings(const C & c) return res; } - /* Remove trailing whitespace from a string. FIXME: return std::string_view. */ std::string chomp(std::string_view s); - /* Remove whitespace from the start and end of a string. */ std::string trim(std::string_view s, std::string_view whitespace = " \n\r\t"); - /* Replace all occurrences of a string inside another string. */ -std::string replaceStrings( - std::string s, - std::string_view from, - std::string_view to); - +std::string replaceStrings(std::string s, std::string_view from, std::string_view to); std::string rewriteStrings(std::string s, const StringMap & rewrites); - /* Convert the exit status of a child as returned by wait() into an error string. */ std::string statusToString(int status); bool statusOk(int status); - /* Parse a string into an integer. */ template std::optional string2Int(const std::string_view s) @@ -467,11 +453,16 @@ N string2IntWithUnitPrefix(std::string_view s) if (!s.empty()) { char u = std::toupper(*s.rbegin()); if (std::isalpha(u)) { - if (u == 'K') multiplier = 1ULL << 10; - else if (u == 'M') multiplier = 1ULL << 20; - else if (u == 'G') multiplier = 1ULL << 30; - else if (u == 'T') multiplier = 1ULL << 40; - else throw UsageError("invalid unit specifier '%1%'", u); + if (u == 'K') + multiplier = 1ULL << 10; + else if (u == 'M') + multiplier = 1ULL << 20; + else if (u == 'G') + multiplier = 1ULL << 30; + else if (u == 'T') + multiplier = 1ULL << 40; + else + throw UsageError("invalid unit specifier '%1%'", u); s.remove_suffix(1); } } @@ -491,29 +482,22 @@ std::optional string2Float(const std::string_view s) } } - /* Return true iff `s' starts with `prefix'. */ bool hasPrefix(std::string_view s, std::string_view prefix); - /* Return true iff `s' ends in `suffix'. */ bool hasSuffix(std::string_view s, std::string_view suffix); - /* Convert a string to lower case. */ std::string toLower(const std::string & s); - /* Escape a string as a shell word. */ std::string shellEscape(const std::string_view s); - /* Exception handling in destructors: print an error message, then ignore the exception. */ void ignoreException(); - - /* Tree formatting. */ constexpr char treeConn[] = "├───"; constexpr char treeLast[] = "└───"; @@ -529,90 +513,86 @@ 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, - bool filterAll = false, - unsigned int width = std::numeric_limits::max()); - +std::string filterANSIEscapes( + const std::string & s, bool filterAll = false, unsigned int width = std::numeric_limits::max()); /* Base64 encoding/decoding. */ std::string base64Encode(std::string_view s); std::string base64Decode(std::string_view s); - /* Remove common leading whitespace from the lines in the string 's'. For example, if every line is indented by at least 3 spaces, then we remove 3 spaces from the start of every line. */ std::string stripIndentation(std::string_view s); - /* Get a value for the specified key from an associate container. */ -template +template const typename T::mapped_type * get(const T & map, const typename T::key_type & key) { auto i = map.find(key); - if (i == map.end()) return nullptr; + if (i == map.end()) + return nullptr; return &i->second; } -template +template typename T::mapped_type * get(T & map, const typename T::key_type & key) { auto i = map.find(key); - if (i == map.end()) return nullptr; + if (i == map.end()) + return nullptr; return &i->second; } /* Get a value for the specified key from an associate container, or a default value if the key isn't present. */ -template -const typename T::mapped_type & getOr(T & map, - const typename T::key_type & key, - const typename T::mapped_type & defaultValue) +template +const typename T::mapped_type & +getOr(T & map, const typename T::key_type & key, const typename T::mapped_type & defaultValue) { auto i = map.find(key); - if (i == map.end()) return defaultValue; + if (i == map.end()) + return defaultValue; return i->second; } /* Remove and return the first item from a container. */ -template +template std::optional remove_begin(T & c) { auto i = c.begin(); - if (i == c.end()) return {}; + if (i == c.end()) + return {}; auto v = std::move(*i); c.erase(i); return v; } - /* Remove and return the first item from a container. */ -template +template std::optional pop(T & c) { - if (c.empty()) return {}; + if (c.empty()) + return {}; auto v = std::move(c.front()); c.pop(); return v; } - template class Callback; - /* Start a thread that handles various signals. Also block those signals on the current thread (and thus any threads created by it). */ void startSignalHandlerThread(); struct InterruptCallback { - virtual ~InterruptCallback() { }; + virtual ~InterruptCallback(){}; }; /* Register a function that gets called on SIGINT (in a non-signal context). */ -std::unique_ptr createInterruptCallback( - std::function callback); +std::unique_ptr createInterruptCallback(std::function callback); void triggerInterrupt(); @@ -627,11 +607,9 @@ struct ReceiveInterrupts ReceiveInterrupts() : target(pthread_self()) , callback(createInterruptCallback([&]() { pthread_kill(target, SIGUSR1); })) - { } + {} }; - - /* A RAII helper that increments a counter on construction and decrements it on destruction. */ template @@ -639,15 +617,21 @@ struct MaintainCount { T & counter; long delta; - MaintainCount(T & counter, long delta = 1) : counter(counter), delta(delta) { counter += delta; } - ~MaintainCount() { counter -= delta; } + MaintainCount(T & counter, long delta = 1) + : counter(counter) + , delta(delta) + { + counter += delta; + } + ~MaintainCount() + { + counter -= delta; + } }; - /* Return the number of rows and columns of the terminal. */ std::pair getWindowSize(); - /* Used in various places. */ typedef std::function PathFilter; @@ -668,52 +652,70 @@ void bind(int fd, const std::string & path); /* Connect to a Unix domain socket. */ void connect(int fd, const std::string & path); - // A Rust/Python-like enumerate() iterator adapter. // Borrowed from http://reedbeta.com/blog/python-like-enumerate-in-cpp17. -template ())), - typename = decltype(std::end(std::declval()))> +template< + typename T, + typename TIter = decltype(std::begin(std::declval())), + typename = decltype(std::end(std::declval()))> constexpr auto enumerate(T && iterable) { struct iterator { size_t i; TIter iter; - bool operator != (const iterator & other) const { return iter != other.iter; } - void operator ++ () { ++i; ++iter; } - auto operator * () const { return std::tie(i, *iter); } + bool operator!=(const iterator & other) const + { + return iter != other.iter; + } + void operator++() + { + ++i; + ++iter; + } + auto operator*() const + { + return std::tie(i, *iter); + } }; struct iterable_wrapper { T iterable; - auto begin() { return iterator{ 0, std::begin(iterable) }; } - auto end() { return iterator{ 0, std::end(iterable) }; } + auto begin() + { + return iterator{0, std::begin(iterable)}; + } + auto end() + { + return iterator{0, std::end(iterable)}; + } }; - return iterable_wrapper{ std::forward(iterable) }; + return iterable_wrapper{std::forward(iterable)}; } - // C++17 std::visit boilerplate -template struct overloaded : Ts... { using Ts::operator()...; }; -template overloaded(Ts...) -> overloaded; - +template +struct overloaded : Ts... +{ + using Ts::operator()...; +}; +template +overloaded(Ts...) -> overloaded; std::string showBytes(uint64_t bytes); - /* Provide an addition operator between strings and string_views inexplicably omitted from the standard library. */ -inline std::string operator + (const std::string & s1, std::string_view s2) +inline std::string operator+(const std::string & s1, std::string_view s2) { auto s = s1; s.append(s2); return s; } -inline std::string operator + (std::string && s, std::string_view s2) +inline std::string operator+(std::string && s, std::string_view s2) { s.append(s2); return std::move(s); diff --git a/src/libutil/xml-writer.cc b/src/libutil/xml-writer.cc index 7993bee9af0e..016958b75a77 100644 --- a/src/libutil/xml-writer.cc +++ b/src/libutil/xml-writer.cc @@ -2,95 +2,95 @@ #include "xml-writer.hh" - namespace nix { - XMLWriter::XMLWriter(bool indent, std::ostream & output) - : output(output), indent(indent) + : output(output) + , indent(indent) { output << "" << std::endl; closed = false; } - XMLWriter::~XMLWriter() { close(); } - void XMLWriter::close() { - if (closed) return; - while (!pendingElems.empty()) closeElement(); + if (closed) + return; + while (!pendingElems.empty()) + closeElement(); closed = true; } - void XMLWriter::indent_(size_t depth) { - if (!indent) return; + if (!indent) + return; output << std::string(depth * 2, ' '); } - -void XMLWriter::openElement( - std::string_view name, - const XMLAttrs & attrs) +void XMLWriter::openElement(std::string_view name, const XMLAttrs & attrs) { assert(!closed); indent_(pendingElems.size()); output << "<" << name; writeAttrs(attrs); output << ">"; - if (indent) output << std::endl; + if (indent) + output << std::endl; pendingElems.push_back(std::string(name)); } - void XMLWriter::closeElement() { assert(!pendingElems.empty()); indent_(pendingElems.size() - 1); output << ""; - if (indent) output << std::endl; + if (indent) + output << std::endl; pendingElems.pop_back(); - if (pendingElems.empty()) closed = true; + if (pendingElems.empty()) + closed = true; } - -void XMLWriter::writeEmptyElement( - std::string_view name, - const XMLAttrs & attrs) +void XMLWriter::writeEmptyElement(std::string_view name, const XMLAttrs & attrs) { assert(!closed); indent_(pendingElems.size()); output << "<" << name; writeAttrs(attrs); output << " />"; - if (indent) output << std::endl; + if (indent) + output << std::endl; } - void XMLWriter::writeAttrs(const XMLAttrs & attrs) { for (auto & i : attrs) { output << " " << i.first << "=\""; for (size_t j = 0; j < i.second.size(); ++j) { char c = i.second[j]; - if (c == '"') output << """; - else if (c == '<') output << "<"; - else if (c == '>') output << ">"; - else if (c == '&') output << "&"; + if (c == '"') + output << """; + else if (c == '<') + output << "<"; + else if (c == '>') + output << ">"; + else if (c == '&') + output << "&"; /* Escape newlines to prevent attribute normalisation (see XML spec, section 3.3.3. */ - else if (c == '\n') output << " "; - else output << c; + else if (c == '\n') + output << " "; + else + output << c; } output << "\""; } } - } diff --git a/src/libutil/xml-writer.hh b/src/libutil/xml-writer.hh index 4c91adee629a..4229c28cd0bf 100644 --- a/src/libutil/xml-writer.hh +++ b/src/libutil/xml-writer.hh @@ -5,13 +5,10 @@ #include #include - namespace nix { - typedef std::map XMLAttrs; - class XMLWriter { private: @@ -30,12 +27,10 @@ public: void close(); - void openElement(std::string_view name, - const XMLAttrs & attrs = XMLAttrs()); + void openElement(std::string_view name, const XMLAttrs & attrs = XMLAttrs()); void closeElement(); - void writeEmptyElement(std::string_view name, - const XMLAttrs & attrs = XMLAttrs()); + void writeEmptyElement(std::string_view name, const XMLAttrs & attrs = XMLAttrs()); private: void writeAttrs(const XMLAttrs & attrs); @@ -43,14 +38,12 @@ private: void indent_(size_t depth); }; - class XMLOpenElement { private: XMLWriter & writer; public: - XMLOpenElement(XMLWriter & writer, std::string_view name, - const XMLAttrs & attrs = XMLAttrs()) + XMLOpenElement(XMLWriter & writer, std::string_view name, const XMLAttrs & attrs = XMLAttrs()) : writer(writer) { writer.openElement(name, attrs); @@ -61,5 +54,4 @@ public: } }; - } diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 519855ea3b2d..f4b2677e5971 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -27,7 +27,7 @@ using namespace nix; using namespace std::string_literals; -extern char * * environ __attribute__((weak)); +extern char ** environ __attribute__((weak)); /* Recreate the effect of the perl shellwords function, breaking up a * string into arguments like a shell word, including escapes @@ -38,10 +38,7 @@ static std::vector shellwords(const std::string & s) auto begin = s.cbegin(); std::vector res; std::string cur; - enum state { - sBegin, - sQuote - }; + enum state { sBegin, sQuote }; state st = sBegin; auto it = begin; for (; it != s.cend(); ++it) { @@ -56,24 +53,25 @@ static std::vector shellwords(const std::string & s) } } switch (*it) { - case '"': - cur.append(begin, it); - begin = it + 1; - st = st == sBegin ? sQuote : sBegin; - break; - case '\\': - /* perl shellwords mostly just treats the next char as part of the string with no special processing */ - cur.append(begin, it); - begin = ++it; - break; + case '"': + cur.append(begin, it); + begin = it + 1; + st = st == sBegin ? sQuote : sBegin; + break; + case '\\': + /* perl shellwords mostly just treats the next char as part of the string with no special processing */ + cur.append(begin, it); + begin = ++it; + break; } } cur.append(begin, it); - if (!cur.empty()) res.push_back(cur); + if (!cur.empty()) + res.push_back(cur); return res; } -static void main_nix_build(int argc, char * * argv) +static void main_nix_build(int argc, char ** argv) { auto dryRun = false; auto runEnv = std::regex_search(argv[0], std::regex("nix-shell$")); @@ -104,11 +102,26 @@ static void main_nix_build(int argc, char * * argv) // List of environment variables kept for --pure std::set keepVars{ - "HOME", "XDG_RUNTIME_DIR", "USER", "LOGNAME", "DISPLAY", - "WAYLAND_DISPLAY", "WAYLAND_SOCKET", "PATH", "TERM", "IN_NIX_SHELL", - "NIX_SHELL_PRESERVE_PROMPT", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL", - "http_proxy", "https_proxy", "ftp_proxy", "all_proxy", "no_proxy" - }; + "HOME", + "XDG_RUNTIME_DIR", + "USER", + "LOGNAME", + "DISPLAY", + "WAYLAND_DISPLAY", + "WAYLAND_SOCKET", + "PATH", + "TERM", + "IN_NIX_SHELL", + "NIX_SHELL_PRESERVE_PROMPT", + "TZ", + "PAGER", + "NIX_BUILD_SHELL", + "SHLVL", + "http_proxy", + "https_proxy", + "ftp_proxy", + "all_proxy", + "no_proxy"}; Strings args; for (int i = 1; i < argc; ++i) @@ -135,7 +148,8 @@ static void main_nix_build(int argc, char * * argv) args.push_back(word); } } - } catch (SysError &) { } + } catch (SysError &) { + } } struct MyArgs : LegacyArgs, MixEvalArgs @@ -196,8 +210,10 @@ static void main_nix_build(int argc, char * * argv) else if (*arg == "--expr" || *arg == "-E") fromArgs = true; - else if (*arg == "--pure") pure = true; - else if (*arg == "--impure") pure = false; + else if (*arg == "--pure") + pure = true; + else if (*arg == "--impure") + pure = false; else if (runEnv && (*arg == "--packages" || *arg == "-p")) packages = true; @@ -223,9 +239,13 @@ 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 = (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 % shellEscape(script) % joined.str()).str(); + envCommand = + (format("exec %1% %2% %3% %4%") % execArgs % interpreter % shellEscape(script) % joined.str()) + .str(); } } @@ -260,13 +280,15 @@ static void main_nix_build(int argc, char * * argv) if (runEnv) { auto newArgs = state->buildBindings(autoArgs->size() + 1); newArgs.alloc("inNixShell").mkBool(true); - for (auto & i : *autoArgs) newArgs.insert(i); + for (auto & i : *autoArgs) + newArgs.insert(i); autoArgs = newArgs.finish(); } if (packages) { std::ostringstream joined; - joined << "{...}@args: with import args; (pkgs.runCommandCC or pkgs.runCommand) \"shell\" { buildInputs = [ "; + joined + << "{...}@args: with import args; (pkgs.runCommandCC or pkgs.runCommand) \"shell\" { buildInputs = [ "; for (const auto & i : left) joined << '(' << i << ") "; joined << "]; } \"\""; @@ -297,20 +319,22 @@ static void main_nix_build(int argc, char * * argv) auto absolute = i; try { absolute = canonPath(absPath(i), true); - } catch (Error & e) {}; + } catch (Error & e) { + }; auto [path, outputNames] = parsePathWithOutputs(absolute); if (evalStore->isStorePath(path) && hasSuffix(path, ".drv")) drvs.push_back(DrvInfo(*state, evalStore, absolute)); else /* If we're in a #! script, interpret filenames relative to the script. */ - exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, - inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i))))); + exprs.push_back(state->parseExprFromFile(resolveExprPath(state->checkSourcePath( + lookupFileArg(*state, inShebang && !packages ? absPath(i, absPath(dirOf(script))) : i))))); } } /* Evaluate them into derivations. */ - if (attrPaths.empty()) attrPaths = {""}; + if (attrPaths.empty()) + attrPaths = {""}; for (auto e : exprs) { Value vRoot; @@ -330,8 +354,7 @@ static void main_nix_build(int argc, char * * argv) fetch binary cache data. */ uint64_t downloadSize, narSize; StorePathSet willBuild, willSubstitute, unknown; - store->queryMissing(paths, - willBuild, willSubstitute, unknown, downloadSize, narSize); + store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize); if (settings.printMissing) printMissing(ref(store), willBuild, willSubstitute, unknown, downloadSize, narSize); @@ -369,7 +392,7 @@ static void main_nix_build(int argc, char * * argv) throw Error("the 'bashInteractive' attribute in did not evaluate to a derivation"); auto bashDrv = drv->requireDrvPath(); - pathsToBuild.push_back(DerivedPath::Built { + pathsToBuild.push_back(DerivedPath::Built{ .drvPath = bashDrv, .outputs = {}, }); @@ -388,15 +411,10 @@ static void main_nix_build(int argc, char * * argv) // To get around lambda capturing restrictions in the // standard. const auto & inputDrv = inputDrv0; - if (std::all_of(envExclude.cbegin(), envExclude.cend(), - [&](const std::string & exclude) { - return !std::regex_search(store->printStorePath(inputDrv), std::regex(exclude)); - })) - { - pathsToBuild.push_back(DerivedPath::Built { - .drvPath = inputDrv, - .outputs = inputOutputs - }); + if (std::all_of(envExclude.cbegin(), envExclude.cend(), [&](const std::string & exclude) { + return !std::regex_search(store->printStorePath(inputDrv), std::regex(exclude)); + })) { + pathsToBuild.push_back(DerivedPath::Built{.drvPath = inputDrv, .outputs = inputOutputs}); pathsToCopy.insert(inputDrv); } } @@ -407,7 +425,8 @@ static void main_nix_build(int argc, char * * argv) buildPaths(pathsToBuild); - if (dryRun) return; + if (dryRun) + return; if (shellDrv) { auto shellDrvOutputs = store->queryPartialDerivationOutputMap(shellDrv.value()); @@ -424,7 +443,8 @@ static void main_nix_build(int argc, char * * argv) auto env = getEnv(); auto tmp = getEnv("TMPDIR"); - if (!tmp) tmp = getEnv("XDG_RUNTIME_DIR").value_or("/tmp"); + if (!tmp) + tmp = getEnv("XDG_RUNTIME_DIR").value_or("/tmp"); if (pure) { decltype(env) newEnv; @@ -531,9 +551,7 @@ static void main_nix_build(int argc, char * * argv) for (auto & i : env) envStrs.push_back(i.first + "=" + i.second); - auto args = interactive - ? Strings{"bash", "--rcfile", rcfile} - : Strings{"bash", rcfile}; + auto args = interactive ? Strings{"bash", "--rcfile", rcfile} : Strings{"bash", rcfile}; auto envPtrs = stringsToCharPtrs(envStrs); @@ -578,7 +596,8 @@ static void main_nix_build(int argc, char * * argv) buildPaths(pathsToBuild); - if (dryRun) return; + if (dryRun) + return; std::vector outPaths; @@ -596,7 +615,8 @@ static void main_nix_build(int argc, char * * argv) if (auto store2 = store.dynamic_pointer_cast()) { std::string symlink = drvPrefix; - if (outputName != "out") symlink += "-" + outputName; + if (outputName != "out") + symlink += "-" + outputName; store2->addPermRoot(outputPath, absPath(symlink)); } diff --git a/src/nix-channel/nix-channel.cc b/src/nix-channel/nix-channel.cc old mode 100755 new mode 100644 index cf52b03b4904..999b6b8d9382 --- a/src/nix-channel/nix-channel.cc +++ b/src/nix-channel/nix-channel.cc @@ -19,7 +19,8 @@ static Path channelsList; // Reads the list of channels. static void readChannels() { - if (!pathExists(channelsList)) return; + if (!pathExists(channelsList)) + return; auto channelsFile = readFile(channelsList); for (const auto & line : tokenizeString>(channelsFile, "\n")) { @@ -64,7 +65,7 @@ static void removeChannel(const std::string & name) channels.erase(name); writeChannels(); - runProgram(settings.nixBinDir + "/nix-env", true, { "--profile", profile, "--uninstall", name }); + runProgram(settings.nixBinDir + "/nix-env", true, {"--profile", profile, "--uninstall", name}); } static Path nixDefExpr; @@ -77,9 +78,10 @@ static void update(const StringSet & channelNames) auto store = openStore(); auto [fd, unpackChannelPath] = createTempFile(); - writeFull(fd.get(), - #include "unpack-channel.nix.gen.hh" - ); + writeFull( + fd.get(), +#include "unpack-channel.nix.gen.hh" + ); fd = -1; AutoDelete del(unpackChannelPath, false); @@ -104,7 +106,10 @@ static void update(const StringSet & channelNames) // no need to update this channel, reuse the existing store path Path symlink = profile + "/" + name; Path storepath = dirOf(readLink(symlink)); - exprs.push_back("f: rec { name = \"" + cname + "\"; type = \"derivation\"; outputs = [\"out\"]; system = \"builtin\"; outPath = builtins.storePath \"" + storepath + "\"; out = { inherit outPath; };}"); + exprs.push_back( + "f: rec { name = \"" + cname + + "\"; type = \"derivation\"; outputs = [\"out\"]; system = \"builtin\"; outPath = builtins.storePath \"" + + storepath + "\"; out = { inherit outPath; };}"); } else { // We want to download the url to a file to see if it's a tarball while also checking if we // got redirected in the process, so that we can grab the various parts of a nix channel @@ -115,28 +120,36 @@ static void update(const StringSet & channelNames) bool unpacked = false; if (std::regex_search(filename, std::regex("\\.tar\\.(gz|bz2|xz)$"))) { - runProgram(settings.nixBinDir + "/nix-build", false, { "--no-out-link", "--expr", "import " + unpackChannelPath + - "{ name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; }" }); + runProgram( + settings.nixBinDir + "/nix-build", false, + {"--no-out-link", "--expr", + "import " + unpackChannelPath + "{ name = \"" + cname + "\"; channelName = \"" + name + + "\"; src = builtins.storePath \"" + filename + "\"; }"}); unpacked = true; } if (!unpacked) { // Download the channel tarball. try { - filename = store->toRealPath(fetchers::downloadFile(store, url + "/nixexprs.tar.xz", "nixexprs.tar.xz", false).storePath); + filename = store->toRealPath( + fetchers::downloadFile(store, url + "/nixexprs.tar.xz", "nixexprs.tar.xz", false).storePath); } catch (FileTransferError & e) { - filename = store->toRealPath(fetchers::downloadFile(store, url + "/nixexprs.tar.bz2", "nixexprs.tar.bz2", false).storePath); + filename = store->toRealPath( + fetchers::downloadFile(store, url + "/nixexprs.tar.bz2", "nixexprs.tar.bz2", false).storePath); } } // Regardless of where it came from, add the expression representing this channel to accumulated expression - exprs.push_back("f: f { name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + filename + "\"; " + extraAttrs + " }"); + exprs.push_back( + "f: f { name = \"" + cname + "\"; channelName = \"" + name + "\"; src = builtins.storePath \"" + + filename + "\"; " + extraAttrs + " }"); } } // Unpack the channel tarballs into the Nix store and install them // into the channels profile. std::cerr << "unpacking channels...\n"; - Strings envArgs{ "--profile", profile, "--file", unpackChannelPath, "--install", "--remove-all", "--from-expression" }; + Strings envArgs{"--profile", profile, "--file", unpackChannelPath, + "--install", "--remove-all", "--from-expression"}; for (auto & expr : exprs) envArgs.push_back(std::move(expr)); envArgs.push_back("--quiet"); @@ -168,14 +181,7 @@ static int main_nix_channel(int argc, char ** argv) // Figure out the name of the channels profile. profile = fmt("%s/profiles/per-user/%s/channels", settings.nixStateDir, getUserName()); - enum { - cNone, - cAdd, - cRemove, - cList, - cUpdate, - cRollback - } cmd = cNone; + enum { cNone, cAdd, cRemove, cList, cUpdate, cRollback } cmd = cNone; std::vector args; parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--help") { @@ -201,12 +207,12 @@ static int main_nix_channel(int argc, char ** argv) }); switch (cmd) { - case cNone: - throw UsageError("no command specified"); - case cAdd: - if (args.size() < 1 || args.size() > 2) - throw UsageError("'--add' requires one or two arguments"); - { + case cNone: + throw UsageError("no command specified"); + case cAdd: + if (args.size() < 1 || args.size() > 2) + throw UsageError("'--add' requires one or two arguments"); + { auto url = args[0]; std::string name; if (args.size() == 2) { @@ -217,35 +223,35 @@ static int main_nix_channel(int argc, char ** argv) name = std::regex_replace(name, std::regex("-stable$"), ""); } addChannel(url, name); - } - break; - case cRemove: - if (args.size() != 1) - throw UsageError("'--remove' requires one argument"); - removeChannel(args[0]); - break; - case cList: - if (!args.empty()) - throw UsageError("'--list' expects no arguments"); - readChannels(); - for (const auto & channel : channels) - std::cout << channel.first << ' ' << channel.second << '\n'; - break; - case cUpdate: - update(StringSet(args.begin(), args.end())); - break; - case cRollback: - if (args.size() > 1) - throw UsageError("'--rollback' has at most one argument"); - Strings envArgs{"--profile", profile}; - if (args.size() == 1) { - envArgs.push_back("--switch-generation"); - envArgs.push_back(args[0]); - } else { - envArgs.push_back("--rollback"); - } - runProgram(settings.nixBinDir + "/nix-env", false, envArgs); - break; + } + break; + case cRemove: + if (args.size() != 1) + throw UsageError("'--remove' requires one argument"); + removeChannel(args[0]); + break; + case cList: + if (!args.empty()) + throw UsageError("'--list' expects no arguments"); + readChannels(); + for (const auto & channel : channels) + std::cout << channel.first << ' ' << channel.second << '\n'; + break; + case cUpdate: + update(StringSet(args.begin(), args.end())); + break; + case cRollback: + if (args.size() > 1) + throw UsageError("'--rollback' has at most one argument"); + Strings envArgs{"--profile", profile}; + if (args.size() == 1) { + envArgs.push_back("--switch-generation"); + envArgs.push_back(args[0]); + } else { + envArgs.push_back("--rollback"); + } + runProgram(settings.nixBinDir + "/nix-env", false, envArgs); + break; } return 0; diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc index e413faffe878..ad9da235ef2a 100644 --- a/src/nix-collect-garbage/nix-collect-garbage.cc +++ b/src/nix-collect-garbage/nix-collect-garbage.cc @@ -14,14 +14,14 @@ using namespace nix; std::string deleteOlderThan; bool dryRun = false; - /* If `-d' was specified, remove all old generations of all profiles. * Of course, this makes rollbacks to before this point in time * impossible. */ void removeOldGenerations(std::string dir) { - if (access(dir.c_str(), R_OK) != 0) return; + if (access(dir.c_str(), R_OK) != 0) + return; bool canWrite = access(dir.c_str(), W_OK) == 0; @@ -36,7 +36,8 @@ void removeOldGenerations(std::string dir) try { link = readLink(path); } catch (SysError & e) { - if (e.errNo == ENOENT) continue; + if (e.errNo == ENOENT) + continue; throw; } if (link.find("link") != std::string::npos) { @@ -52,7 +53,7 @@ void removeOldGenerations(std::string dir) } } -static int main_nix_collect_garbage(int argc, char * * argv) +static int main_nix_collect_garbage(int argc, char ** argv) { { bool removeOld = false; @@ -64,12 +65,13 @@ static int main_nix_collect_garbage(int argc, char * * argv) showManPage("nix-collect-garbage"); else if (*arg == "--version") printVersion("nix-collect-garbage"); - else if (*arg == "--delete-old" || *arg == "-d") removeOld = true; + else if (*arg == "--delete-old" || *arg == "-d") + removeOld = true; else if (*arg == "--delete-older-than") { removeOld = true; deleteOlderThan = getArg(*arg, arg, end); - } - else if (*arg == "--dry-run") dryRun = true; + } else if (*arg == "--dry-run") + dryRun = true; else if (*arg == "--max-freed") options.maxFreed = std::max(getIntArg(*arg, arg, end, true), (int64_t) 0); else @@ -78,7 +80,8 @@ static int main_nix_collect_garbage(int argc, char * * argv) }); 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-env/nix-env.cc b/src/nix-env/nix-env.cc index a69d3700d010..3130e57a5167 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -30,27 +30,17 @@ using namespace nix; using std::cout; - -typedef enum { - srcNixExprDrvs, - srcNixExprs, - srcStorePaths, - srcProfile, - srcAttrPath, - srcUnknown -} InstallSourceType; - +typedef enum { srcNixExprDrvs, srcNixExprs, srcStorePaths, srcProfile, srcAttrPath, srcUnknown } InstallSourceType; struct InstallSourceInfo { InstallSourceType type; - Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ - Path profile; /* for srcProfile */ + Path nixExprPath; /* for srcNixExprDrvs, srcNixExprs */ + Path profile; /* for srcProfile */ std::string systemFilter; /* for srcNixExprDrvs */ Bindings * autoArgs; }; - struct Globals { InstallSourceInfo instSource; @@ -63,55 +53,48 @@ struct Globals bool prebuiltOnly; }; +typedef void (*Operation)(Globals & globals, Strings opFlags, Strings opArgs); -typedef void (* Operation) (Globals & globals, - Strings opFlags, Strings opArgs); - - -static std::string needArg(Strings::iterator & i, - Strings & args, const std::string & arg) +static std::string needArg(Strings::iterator & i, Strings & args, const std::string & arg) { - if (i == args.end()) throw UsageError("'%1%' requires an argument", arg); + if (i == args.end()) + throw UsageError("'%1%' requires an argument", arg); return *i++; } - -static bool parseInstallSourceOptions(Globals & globals, - Strings::iterator & i, Strings & args, const std::string & arg) +static bool parseInstallSourceOptions(Globals & globals, Strings::iterator & i, Strings & args, const std::string & arg) { if (arg == "--from-expression" || arg == "-E") globals.instSource.type = srcNixExprs; else if (arg == "--from-profile") { globals.instSource.type = srcProfile; globals.instSource.profile = needArg(i, args, arg); - } - else if (arg == "--attr" || arg == "-A") + } else if (arg == "--attr" || arg == "-A") globals.instSource.type = srcAttrPath; - else return false; + else + return false; return true; } - static bool isNixExpr(const Path & path, struct stat & st) { return S_ISREG(st.st_mode) || (S_ISDIR(st.st_mode) && pathExists(path + "/default.nix")); } - static constexpr size_t maxAttrs = 1024; - -static void getAllExprs(EvalState & state, - const Path & path, StringSet & seen, BindingsBuilder & attrs) +static void getAllExprs(EvalState & state, const Path & path, StringSet & seen, BindingsBuilder & attrs) { StringSet namesSorted; - for (auto & i : readDirectory(path)) namesSorted.insert(i.name); + for (auto & i : readDirectory(path)) + namesSorted.insert(i.name); for (auto & i : namesSorted) { /* Ignore the manifest.nix used by profiles. This is necessary to prevent it from showing up in channels (which are implemented using profiles). */ - if (i == "manifest.nix") continue; + if (i == "manifest.nix") + continue; Path path2 = path + "/" + i; @@ -130,10 +113,13 @@ static void getAllExprs(EvalState & state, if (!seen.insert(attrName).second) { std::string suggestionMessage = ""; if (path2.find("channels") != std::string::npos && path.find("channels") != std::string::npos) { - suggestionMessage = fmt("\nsuggestion: remove '%s' from either the root channels or the user channels", attrName); + suggestionMessage = + fmt("\nsuggestion: remove '%s' from either the root channels or the user channels", attrName); } - printError("warning: name collision in input Nix expressions, skipping '%1%'" - "%2%", path2, suggestionMessage); + printError( + "warning: name collision in input Nix expressions, skipping '%1%'" + "%2%", + path2, suggestionMessage); continue; } /* Load the expression on demand. */ @@ -142,16 +128,13 @@ static void getAllExprs(EvalState & state, if (seen.size() == maxAttrs) throw Error("too many Nix expressions in directory '%1%'", path); attrs.alloc(attrName).mkApp(&state.getBuiltin("import"), vArg); - } - else if (S_ISDIR(st.st_mode)) + } else if (S_ISDIR(st.st_mode)) /* `path2' is a directory (with no default.nix in it); recurse into it. */ getAllExprs(state, path2, seen, attrs); } } - - static void loadSourceExpr(EvalState & state, const Path & path, Value & v) { struct stat st; @@ -175,13 +158,17 @@ static void loadSourceExpr(EvalState & state, const Path & path, Value & v) v.mkAttrs(attrs); } - else throw Error("path '%s' is not a directory or a Nix expression", path); + else + throw Error("path '%s' is not a directory or a Nix expression", path); } - -static void loadDerivations(EvalState & state, Path nixExprPath, - std::string systemFilter, Bindings & autoArgs, - const std::string & pathPrefix, DrvInfos & elems) +static void loadDerivations( + EvalState & state, + Path nixExprPath, + std::string systemFilter, + Bindings & autoArgs, + const std::string & pathPrefix, + DrvInfos & elems) { Value vRoot; loadSourceExpr(state, nixExprPath, vRoot); @@ -193,35 +180,33 @@ static void loadDerivations(EvalState & state, Path nixExprPath, /* Filter out all derivations not applicable to the current system. */ for (DrvInfos::iterator i = elems.begin(), j; i != elems.end(); i = j) { - j = i; j++; + j = i; + j++; if (systemFilter != "*" && i->querySystem() != systemFilter) elems.erase(i); } } - static long getPriority(EvalState & state, DrvInfo & drv) { return drv.queryMetaInt("priority", 0); } - static long comparePriorities(EvalState & state, DrvInfo & drv1, DrvInfo & drv2) { return getPriority(state, drv2) - getPriority(state, drv1); } - // FIXME: this function is rather slow since it checks a single path // at a time. static bool isPrebuilt(EvalState & state, DrvInfo & elem) { auto path = elem.queryOutPath(); - if (state.store->isValidPath(path)) return true; + if (state.store->isValidPath(path)) + return true; return state.store->querySubstitutablePaths({path}).count(path); } - static void checkSelectorUse(DrvNames & selectors) { /* Check that all selectors have been used. */ @@ -230,14 +215,14 @@ static void checkSelectorUse(DrvNames & selectors) throw Error("selector '%1%' matches no derivations", i.fullName); } - namespace { -std::set searchByPrefix(const DrvInfos & allElems, std::string_view prefix) { +std::set searchByPrefix(const DrvInfos & allElems, std::string_view prefix) +{ constexpr std::size_t maxResults = 3; std::set result; for (const auto & drvInfo : allElems) { - const auto drvName = DrvName { drvInfo.queryName() }; + const auto drvName = DrvName{drvInfo.queryName()}; if (hasPrefix(drvName.name, prefix)) { result.emplace(drvName.name); @@ -255,8 +240,8 @@ struct Match std::size_t index; Match(DrvInfo drvInfo_, std::size_t index_) - : drvInfo{std::move(drvInfo_)} - , index{index_} + : drvInfo{std::move(drvInfo_)} + , index{index_} {} }; @@ -267,7 +252,8 @@ struct Match derivations, pick the one with the highest version. Finally, if there are still multiple derivations, arbitrarily pick the first one. */ -std::vector pickNewestOnly(EvalState & state, std::vector matches) { +std::vector pickNewestOnly(EvalState & state, std::vector matches) +{ /* Map from package names to derivations. */ std::map newest; StringSet multiple; @@ -275,7 +261,7 @@ std::vector pickNewestOnly(EvalState & state, std::vector matches) for (auto & match : matches) { auto & oneDrv = match.drvInfo; - const auto drvName = DrvName { oneDrv.queryName() }; + const auto drvName = DrvName{oneDrv.queryName()}; long comparison = 1; const auto itOther = newest.find(drvName.name); @@ -283,14 +269,14 @@ std::vector pickNewestOnly(EvalState & state, std::vector matches) if (itOther != newest.end()) { auto & newestDrv = itOther->second.drvInfo; - comparison = - oneDrv.querySystem() == newestDrv.querySystem() ? 0 : - oneDrv.querySystem() == settings.thisSystem ? 1 : - newestDrv.querySystem() == settings.thisSystem ? -1 : 0; + comparison = oneDrv.querySystem() == newestDrv.querySystem() ? 0 + : oneDrv.querySystem() == settings.thisSystem ? 1 + : newestDrv.querySystem() == settings.thisSystem ? -1 + : 0; if (comparison == 0) comparison = comparePriorities(state, oneDrv, newestDrv); if (comparison == 0) - comparison = compareVersions(drvName.version, DrvName { newestDrv.queryName() }.version); + comparison = compareVersions(drvName.version, DrvName{newestDrv.queryName()}.version); } if (comparison > 0) { @@ -305,9 +291,7 @@ std::vector pickNewestOnly(EvalState & state, std::vector matches) matches.clear(); for (auto & [name, match] : newest) { if (multiple.find(name) != multiple.end()) - warn( - "there are multiple derivations named '%1%'; using the first one", - name); + warn("there are multiple derivations named '%1%'; using the first one", name); matches.push_back(match); } @@ -316,8 +300,7 @@ std::vector pickNewestOnly(EvalState & state, std::vector matches) } // end namespace -static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, - const Strings & args, bool newestOnly) +static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, const Strings & args, bool newestOnly) { DrvNames selectors = drvNamesFromArgs(args); if (selectors.empty()) @@ -329,7 +312,7 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, for (auto & selector : selectors) { std::vector matches; for (const auto & [index, drvInfo] : enumerate(allElems)) { - const auto drvName = DrvName { drvInfo.queryName() }; + const auto drvName = DrvName{drvInfo.queryName()}; if (selector.matches(drvName)) { ++selector.hits; matches.emplace_back(drvInfo, index); @@ -364,16 +347,13 @@ static DrvInfos filterBySelector(EvalState & state, const DrvInfos & allElems, return elems; } - static bool isPath(std::string_view s) { return s.find('/') != std::string_view::npos; } - -static void queryInstSources(EvalState & state, - InstallSourceInfo & instSource, const Strings & args, - DrvInfos & elems, bool newestOnly) +static void queryInstSources( + EvalState & state, InstallSourceInfo & instSource, const Strings & args, DrvInfos & elems, bool newestOnly) { InstallSourceType type = instSource.type; if (type == srcUnknown && args.size() > 0 && isPath(args.front())) @@ -381,98 +361,93 @@ static void queryInstSources(EvalState & state, switch (type) { - /* Get the available user environment elements from the - derivations specified in a Nix expression, including only - those with names matching any of the names in `args'. */ - case srcUnknown: - case srcNixExprDrvs: { + /* Get the available user environment elements from the + derivations specified in a Nix expression, including only + those with names matching any of the names in `args'. */ + case srcUnknown: + case srcNixExprDrvs: { - /* Load the derivations from the (default or specified) - Nix expression. */ - DrvInfos allElems; - loadDerivations(state, instSource.nixExprPath, - instSource.systemFilter, *instSource.autoArgs, "", allElems); + /* Load the derivations from the (default or specified) + Nix expression. */ + DrvInfos allElems; + loadDerivations(state, instSource.nixExprPath, instSource.systemFilter, *instSource.autoArgs, "", allElems); - elems = filterBySelector(state, allElems, args, newestOnly); - - break; - } + elems = filterBySelector(state, allElems, args, newestOnly); - /* Get the available user environment elements from the Nix - expressions specified on the command line; these should be - functions that take the default Nix expression file as - argument, e.g., if the file is `./foo.nix', then the - argument `x: x.bar' is equivalent to `(x: x.bar) - (import ./foo.nix)' = `(import ./foo.nix).bar'. */ - case srcNixExprs: { - - Value vArg; - loadSourceExpr(state, instSource.nixExprPath, vArg); - - for (auto & i : args) { - Expr * eFun = state.parseExprFromString(i, absPath(".")); - Value vFun, vTmp; - state.eval(eFun, vFun); - vTmp.mkApp(&vFun, &vArg); - getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true); - } + break; + } - break; + /* Get the available user environment elements from the Nix + expressions specified on the command line; these should be + functions that take the default Nix expression file as + argument, e.g., if the file is `./foo.nix', then the + argument `x: x.bar' is equivalent to `(x: x.bar) + (import ./foo.nix)' = `(import ./foo.nix).bar'. */ + case srcNixExprs: { + + Value vArg; + loadSourceExpr(state, instSource.nixExprPath, vArg); + + for (auto & i : args) { + Expr * eFun = state.parseExprFromString(i, absPath(".")); + Value vFun, vTmp; + state.eval(eFun, vFun); + vTmp.mkApp(&vFun, &vArg); + getDerivations(state, vTmp, "", *instSource.autoArgs, elems, true); } - /* The available user environment elements are specified as a - list of store paths (which may or may not be - derivations). */ - case srcStorePaths: { + break; + } - for (auto & i : args) { - auto path = state.store->followLinksToStorePath(i); + /* The available user environment elements are specified as a + list of store paths (which may or may not be + derivations). */ + case srcStorePaths: { - std::string name(path.name()); + for (auto & i : args) { + auto path = state.store->followLinksToStorePath(i); - DrvInfo elem(state, "", nullptr); - elem.setName(name); + std::string name(path.name()); - if (path.isDerivation()) { - elem.setDrvPath(path); - auto outputs = state.store->queryDerivationOutputMap(path); - elem.setOutPath(outputs.at("out")); - if (name.size() >= drvExtension.size() && - std::string(name, name.size() - drvExtension.size()) == drvExtension) - name = name.substr(0, name.size() - drvExtension.size()); - } - else - elem.setOutPath(path); + DrvInfo elem(state, "", nullptr); + elem.setName(name); - elems.push_back(elem); - } + if (path.isDerivation()) { + elem.setDrvPath(path); + auto outputs = state.store->queryDerivationOutputMap(path); + elem.setOutPath(outputs.at("out")); + if (name.size() >= drvExtension.size() + && std::string(name, name.size() - drvExtension.size()) == drvExtension) + name = name.substr(0, name.size() - drvExtension.size()); + } else + elem.setOutPath(path); - break; + elems.push_back(elem); } - /* Get the available user environment elements from another - user environment. These are then filtered as in the - `srcNixExprDrvs' case. */ - case srcProfile: { - elems = filterBySelector(state, - queryInstalled(state, instSource.profile), - args, newestOnly); - break; - } + break; + } - case srcAttrPath: { - Value vRoot; - loadSourceExpr(state, instSource.nixExprPath, vRoot); - for (auto & i : args) { - Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first); - getDerivations(state, v, "", *instSource.autoArgs, elems, true); - } - break; + /* Get the available user environment elements from another + user environment. These are then filtered as in the + `srcNixExprDrvs' case. */ + case srcProfile: { + elems = filterBySelector(state, queryInstalled(state, instSource.profile), args, newestOnly); + break; + } + + case srcAttrPath: { + Value vRoot; + loadSourceExpr(state, instSource.nixExprPath, vRoot); + for (auto & i : args) { + Value & v(*findAlongAttrPath(state, i, *instSource.autoArgs, vRoot).first); + getDerivations(state, v, "", *instSource.autoArgs, elems, true); } + break; + } } } - static void printMissing(EvalState & state, DrvInfos & elems) { std::vector targets; @@ -485,15 +460,12 @@ static void printMissing(EvalState & state, DrvInfos & elems) printMissing(state.store, targets); } - static bool keep(DrvInfo & drv) { return drv.queryMetaBool("keep", false); } - -static void installDerivations(Globals & globals, - const Strings & args, const Path & profile) +static void installDerivations(Globals & globals, const Strings & args, const Path & profile) { debug(format("installing derivations")); @@ -517,7 +489,6 @@ static void installDerivations(Globals & globals, newNames.insert(DrvName(i.queryName()).name); } - while (true) { auto lockToken = optimisticLockProfile(profile); @@ -530,9 +501,7 @@ static void installDerivations(Globals & globals, for (auto & i : installedElems) { DrvName drvName(i.queryName()); - if (!globals.preserveInstalled && - newNames.find(drvName.name) != newNames.end() && - !keep(i)) + if (!globals.preserveInstalled && newNames.find(drvName.name) != newNames.end() && !keep(i)) printInfo("replacing old '%s'", i.queryName()); else allElems.push_back(i); @@ -544,35 +513,34 @@ static void installDerivations(Globals & globals, printMissing(*globals.state, newElems); - if (globals.dryRun) return; + if (globals.dryRun) + return; - if (createUserEnv(*globals.state, allElems, - profile, settings.envKeepDerivations, lockToken)) break; + if (createUserEnv(*globals.state, allElems, profile, settings.envKeepDerivations, lockToken)) + break; } } - static void opInstall(Globals & globals, Strings opFlags, Strings opArgs) { - for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { + for (Strings::iterator i = opFlags.begin(); i != opFlags.end();) { auto arg = *i++; - if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; + if (parseInstallSourceOptions(globals, i, opFlags, arg)) + ; else if (arg == "--preserve-installed" || arg == "-P") globals.preserveInstalled = true; else if (arg == "--remove-all" || arg == "-r") globals.removeAll = true; - else throw UsageError("unknown flag '%1%'", arg); + else + throw UsageError("unknown flag '%1%'", arg); } installDerivations(globals, opArgs, globals.profile); } - typedef enum { utLt, utLeq, utEq, utAlways } UpgradeType; - -static void upgradeDerivations(Globals & globals, - const Strings & args, UpgradeType upgradeType) +static void upgradeDerivations(Globals & globals, const Strings & args, UpgradeType upgradeType) { debug(format("upgrading derivations")); @@ -617,15 +585,13 @@ static void upgradeDerivations(Globals & globals, DrvName newName(j->queryName()); if (newName.name == drvName.name) { int d = compareVersions(drvName.version, newName.version); - if ((upgradeType == utLt && d < 0) || - (upgradeType == utLeq && d <= 0) || - (upgradeType == utEq && d == 0) || - upgradeType == utAlways) - { + if ((upgradeType == utLt && d < 0) || (upgradeType == utLeq && d <= 0) + || (upgradeType == utEq && d == 0) || upgradeType == utAlways) { long d2 = -1; if (bestElem != availElems.end()) { d2 = comparePriorities(*globals.state, *bestElem, *j); - if (d2 == 0) d2 = compareVersions(bestVersion, newName.version); + if (d2 == 0) + d2 = compareVersions(bestVersion, newName.version); } if (d2 < 0 && (!globals.prebuiltOnly || isPrebuilt(*globals.state, *j))) { bestElem = j; @@ -635,16 +601,13 @@ static void upgradeDerivations(Globals & globals, } } - if (bestElem != availElems.end() && - i.queryOutPath() != - bestElem->queryOutPath()) - { - const char * action = compareVersions(drvName.version, bestVersion) <= 0 - ? "upgrading" : "downgrading"; - printInfo("%1% '%2%' to '%3%'", - action, i.queryName(), bestElem->queryName()); + if (bestElem != availElems.end() && i.queryOutPath() != bestElem->queryOutPath()) { + const char * action = + compareVersions(drvName.version, bestVersion) <= 0 ? "upgrading" : "downgrading"; + printInfo("%1% '%2%' to '%3%'", action, i.queryName(), bestElem->queryName()); newElems.push_back(*bestElem); - } else newElems.push_back(i); + } else + newElems.push_back(i); } catch (Error & e) { e.addTrace(std::nullopt, "while trying to find an upgrade for '%s'", i.queryName()); @@ -654,40 +617,43 @@ static void upgradeDerivations(Globals & globals, printMissing(*globals.state, newElems); - if (globals.dryRun) return; + if (globals.dryRun) + return; - if (createUserEnv(*globals.state, newElems, - globals.profile, settings.envKeepDerivations, lockToken)) break; + if (createUserEnv(*globals.state, newElems, globals.profile, settings.envKeepDerivations, lockToken)) + break; } } - static void opUpgrade(Globals & globals, Strings opFlags, Strings opArgs) { UpgradeType upgradeType = utLt; - for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { + for (Strings::iterator i = opFlags.begin(); i != opFlags.end();) { std::string arg = *i++; - if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; - else if (arg == "--lt") upgradeType = utLt; - else if (arg == "--leq") upgradeType = utLeq; - else if (arg == "--eq") upgradeType = utEq; - else if (arg == "--always") upgradeType = utAlways; - else throw UsageError("unknown flag '%1%'", arg); + if (parseInstallSourceOptions(globals, i, opFlags, arg)) + ; + else if (arg == "--lt") + upgradeType = utLt; + else if (arg == "--leq") + upgradeType = utLeq; + else if (arg == "--eq") + upgradeType = utEq; + else if (arg == "--always") + upgradeType = utAlways; + else + throw UsageError("unknown flag '%1%'", arg); } upgradeDerivations(globals, opArgs, upgradeType); } - -static void setMetaFlag(EvalState & state, DrvInfo & drv, - const std::string & name, const std::string & value) +static void setMetaFlag(EvalState & state, DrvInfo & drv, const std::string & name, const std::string & value) { auto v = state.allocValue(); v->mkString(value); drv.setMeta(name, v); } - static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -720,21 +686,23 @@ static void opSetFlag(Globals & globals, Strings opFlags, Strings opArgs) checkSelectorUse(selectors); /* Write the new user environment. */ - if (createUserEnv(*globals.state, installedElems, - globals.profile, settings.envKeepDerivations, lockToken)) break; + if (createUserEnv(*globals.state, installedElems, globals.profile, settings.envKeepDerivations, lockToken)) + break; } } - static void opSet(Globals & globals, Strings opFlags, Strings opArgs) { auto store2 = globals.state->store.dynamic_pointer_cast(); - if (!store2) throw Error("--set is not supported for this Nix store"); + if (!store2) + throw Error("--set is not supported for this Nix store"); - for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { + for (Strings::iterator i = opFlags.begin(); i != opFlags.end();) { std::string arg = *i++; - if (parseInstallSourceOptions(globals, i, opFlags, arg)) ; - else throw UsageError("unknown flag '%1%'", arg); + if (parseInstallSourceOptions(globals, i, opFlags, arg)) + ; + else + throw UsageError("unknown flag '%1%'", arg); } DrvInfos elems; @@ -749,26 +717,21 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs) drv.setName(globals.forceName); auto drvPath = drv.queryDrvPath(); - std::vector paths { - drvPath - ? (DerivedPath) (DerivedPath::Built { *drvPath }) - : (DerivedPath) (DerivedPath::Opaque { drv.queryOutPath() }), + std::vector paths{ + drvPath ? (DerivedPath) (DerivedPath::Built{*drvPath}) + : (DerivedPath) (DerivedPath::Opaque{drv.queryOutPath()}), }; printMissing(globals.state->store, paths); - if (globals.dryRun) return; + if (globals.dryRun) + return; globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal); debug(format("switching to new user environment")); - Path generation = createGeneration( - ref(store2), - globals.profile, - drv.queryOutPath()); + Path generation = createGeneration(ref(store2), globals.profile, drv.queryOutPath()); switchLink(globals.profile, generation); } - -static void uninstallDerivations(Globals & globals, Strings & selectors, - Path & profile) +static void uninstallDerivations(Globals & globals, Strings & selectors, Path & profile) { while (true) { auto lockToken = optimisticLockProfile(profile); @@ -781,19 +744,13 @@ static void uninstallDerivations(Globals & globals, Strings & selectors, StorePath selectorStorePath = globals.state->store->followLinksToStorePath(selector); split = std::partition( workingElems.begin(), workingElems.end(), - [&selectorStorePath, globals](auto &elem) { - return selectorStorePath != elem.queryOutPath(); - } - ); + [&selectorStorePath, globals](auto & elem) { return selectorStorePath != elem.queryOutPath(); }); } else { DrvName selectorName(selector); - split = std::partition( - workingElems.begin(), workingElems.end(), - [&selectorName](auto &elem){ - DrvName elemName(elem.queryName()); - return !selectorName.matches(elemName); - } - ); + split = std::partition(workingElems.begin(), workingElems.end(), [&selectorName](auto & elem) { + DrvName elemName(elem.queryName()); + return !selectorName.matches(elemName); + }); } if (split == workingElems.end()) warn("selector '%s' matched no installed derivations", selector); @@ -803,14 +760,14 @@ static void uninstallDerivations(Globals & globals, Strings & selectors, workingElems.erase(split, workingElems.end()); } - if (globals.dryRun) return; + if (globals.dryRun) + return; - if (createUserEnv(*globals.state, workingElems, - profile, settings.envKeepDerivations, lockToken)) break; + if (createUserEnv(*globals.state, workingElems, profile, settings.envKeepDerivations, lockToken)) + break; } } - static void opUninstall(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -818,26 +775,20 @@ static void opUninstall(Globals & globals, Strings opFlags, Strings opArgs) uninstallDerivations(globals, opArgs, globals.profile); } - static bool cmpChars(char a, char b) { return toupper(a) < toupper(b); } - static bool cmpElemByName(const DrvInfo & a, const DrvInfo & b) { auto a_name = a.queryName(); auto b_name = b.queryName(); - return lexicographical_compare( - a_name.begin(), a_name.end(), - b_name.begin(), b_name.end(), cmpChars); + return lexicographical_compare(a_name.begin(), a_name.end(), b_name.begin(), b_name.end(), cmpChars); } - typedef std::list Table; - void printTable(Table & table) { auto nrColumns = table.size() > 0 ? table.front().size() : 0; @@ -850,7 +801,8 @@ void printTable(Table & table) Strings::iterator j; size_t column; for (j = i.begin(), column = 0; j != i.end(); ++j, ++column) - if (j->size() > widths[column]) widths[column] = j->size(); + if (j->size() > widths[column]) + widths[column] = j->size(); } for (auto & i : table) { @@ -867,7 +819,6 @@ void printTable(Table & table) } } - /* This function compares the version of an element against the versions in the given set of elements. `cvLess' means that only lower versions are in the set, `cvEqual' means that at most an @@ -877,8 +828,7 @@ void printTable(Table & table) typedef enum { cvLess, cvEqual, cvGreater, cvUnavail } VersionDiff; -static VersionDiff compareVersionAgainstSet( - const DrvInfo & elem, const DrvInfos & elems, std::string & version) +static VersionDiff compareVersionAgainstSet(const DrvInfo & elem, const DrvInfos & elems, std::string & version) { DrvName name(elem.queryName()); @@ -892,12 +842,10 @@ static VersionDiff compareVersionAgainstSet( if (d < 0) { diff = cvGreater; version = name2.version; - } - else if (diff != cvGreater && d == 0) { + } else if (diff != cvGreater && d == 0) { diff = cvEqual; version = name2.version; - } - else if (diff != cvGreater && diff != cvEqual && d > 0) { + } else if (diff != cvGreater && diff != cvEqual && d > 0) { diff = cvLess; if (version == "" || compareVersions(version, name2.version) < 0) version = name2.version; @@ -908,13 +856,13 @@ static VersionDiff compareVersionAgainstSet( return diff; } - static void queryJSON(Globals & globals, std::vector & elems, bool printOutPath, bool printMeta) { JSONObject topObj(cout, true); for (auto & i : elems) { try { - if (i.hasFailed()) continue; + if (i.hasFailed()) + continue; JSONObject pkgObj = topObj.object(i.attrPath); @@ -960,10 +908,9 @@ static void queryJSON(Globals & globals, std::vector & elems, bool prin } } - static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) { - auto & store { *globals.state->store }; + auto & store{*globals.state->store}; Strings remaining; std::string attrPath; @@ -984,21 +931,34 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) settings.readOnlyMode = true; /* makes evaluation a bit faster */ - for (Strings::iterator i = opFlags.begin(); i != opFlags.end(); ) { + for (Strings::iterator i = opFlags.begin(); i != opFlags.end();) { auto arg = *i++; - if (arg == "--status" || arg == "-s") printStatus = true; - else if (arg == "--no-name") printName = false; - else if (arg == "--system") printSystem = true; - else if (arg == "--description") printDescription = true; - else if (arg == "--compare-versions" || arg == "-c") compareVersions = true; - else if (arg == "--drv-path") printDrvPath = true; - else if (arg == "--out-path") printOutPath = true; - else if (arg == "--meta") printMeta = true; - else if (arg == "--installed") source = sInstalled; - else if (arg == "--available" || arg == "-a") source = sAvailable; - else if (arg == "--xml") xmlOutput = true; - else if (arg == "--json") jsonOutput = true; - else if (arg == "--attr-path" || arg == "-P") printAttrPath = true; + if (arg == "--status" || arg == "-s") + printStatus = true; + else if (arg == "--no-name") + printName = false; + else if (arg == "--system") + printSystem = true; + else if (arg == "--description") + printDescription = true; + else if (arg == "--compare-versions" || arg == "-c") + compareVersions = true; + else if (arg == "--drv-path") + printDrvPath = true; + else if (arg == "--out-path") + printOutPath = true; + else if (arg == "--meta") + printMeta = true; + else if (arg == "--installed") + source = sInstalled; + else if (arg == "--available" || arg == "-a") + source = sAvailable; + else if (arg == "--xml") + xmlOutput = true; + else if (arg == "--json") + jsonOutput = true; + else if (arg == "--attr-path" || arg == "-P") + printAttrPath = true; else if (arg == "--attr" || arg == "-A") attrPath = needArg(i, opFlags, arg); else @@ -1015,24 +975,22 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) installedElems = queryInstalled(*globals.state, globals.profile); if (source == sAvailable || compareVersions) - loadDerivations(*globals.state, globals.instSource.nixExprPath, - globals.instSource.systemFilter, *globals.instSource.autoArgs, - attrPath, availElems); + loadDerivations( + *globals.state, globals.instSource.nixExprPath, globals.instSource.systemFilter, + *globals.instSource.autoArgs, attrPath, availElems); - DrvInfos elems_ = filterBySelector(*globals.state, - source == sInstalled ? installedElems : availElems, - opArgs, false); + DrvInfos elems_ = + filterBySelector(*globals.state, source == sInstalled ? installedElems : availElems, opArgs, false); DrvInfos & otherElems(source == sInstalled ? availElems : installedElems); - /* Sort them by name. */ /* !!! */ std::vector elems; - for (auto & i : elems_) elems.push_back(i); + for (auto & i : elems_) + elems.push_back(i); sort(elems.begin(), elems.end(), cmpElemByName); - /* We only need to know the installed paths when we are querying the status of the derivation. */ StorePathSet installed; /* installed paths */ @@ -1041,7 +999,6 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) for (auto & i : installedElems) installed.insert(i.queryOutPath()); - /* Query which paths have substitutes. */ StorePathSet validPaths; StorePathSet substitutablePaths; @@ -1051,14 +1008,14 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) try { paths.insert(i.queryOutPath()); } catch (AssertionError & e) { - printMsg(lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName()); + printMsg( + lvlTalkative, "skipping derivation named '%s' which gives an assertion failure", i.queryName()); i.setFailed(); } validPaths = store.queryValidPaths(paths); substitutablePaths = store.querySubstitutablePaths(paths); } - /* Print the desired columns, or XML output. */ if (jsonOutput) { queryJSON(globals, elems, printOutPath, printMeta); @@ -1076,13 +1033,13 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) for (auto & i : elems) { try { - if (i.hasFailed()) continue; + if (i.hasFailed()) + continue; - //Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath); + // Activity act(*logger, lvlDebug, format("outputting query result '%1%'") % i.attrPath); - if (globals.prebuiltOnly && - !validPaths.count(i.queryOutPath()) && - !substitutablePaths.count(i.queryOutPath())) + if (globals.prebuiltOnly && !validPaths.count(i.queryOutPath()) + && !substitutablePaths.count(i.queryOutPath())) continue; /* For table output. */ @@ -1102,9 +1059,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) attrs["substitutable"] = hasSubs ? "1" : "0"; } else columns.push_back( - (std::string) (isInstalled ? "I" : "-") - + (isValid ? "P" : "-") - + (hasSubs ? "S" : "-")); + (std::string)(isInstalled ? "I" : "-") + (isValid ? "P" : "-") + (hasSubs ? "S" : "-")); } if (xmlOutput) @@ -1131,11 +1086,20 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) char ch; switch (diff) { - case cvLess: ch = '>'; break; - case cvEqual: ch = '='; break; - case cvGreater: ch = '<'; break; - case cvUnavail: ch = '-'; break; - default: abort(); + case cvLess: + ch = '>'; + break; + case cvEqual: + ch = '='; + break; + case cvGreater: + ch = '<'; + break; + case cvUnavail: + ch = '-'; + break; + default: + abort(); } if (xmlOutput) { @@ -1152,15 +1116,16 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) } if (xmlOutput) { - if (i.querySystem() != "") attrs["system"] = i.querySystem(); - } - else if (printSystem) + if (i.querySystem() != "") + attrs["system"] = i.querySystem(); + } else if (printSystem) columns.push_back(i.querySystem()); if (printDrvPath) { auto drvPath = i.queryDrvPath(); if (xmlOutput) { - if (drvPath) attrs["drvPath"] = store.printStorePath(*drvPath); + if (drvPath) + attrs["drvPath"] = store.printStorePath(*drvPath); } else columns.push_back(drvPath ? store.printStorePath(*drvPath) : "-"); } @@ -1172,8 +1137,12 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) DrvInfo::Outputs outputs = i.queryOutputs(); std::string s; for (auto & j : outputs) { - if (!s.empty()) s += ';'; - if (j.first != "out") { s += j.first; s += "="; } + if (!s.empty()) + s += ';'; + if (j.first != "out") { + s += j.first; + s += "="; + } s += store.printStorePath(*j.second); } columns.push_back(s); @@ -1182,7 +1151,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) if (printDescription) { auto descr = i.queryMetaString("description"); if (xmlOutput) { - if (descr != "") attrs["description"] = descr; + if (descr != "") + attrs["description"] = descr; } else columns.push_back(descr); } @@ -1204,9 +1174,7 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) attrs2["name"] = j; Value * v = i.queryMeta(j); if (!v) - printError( - "derivation '%s' has invalid meta attribute '%s'", - i.queryName(), j); + printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j); else { if (v->type() == nString) { attrs2["type"] = "string"; @@ -1228,7 +1196,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); for (auto elem : v->listItems()) { - if (elem->type() != nString) continue; + if (elem->type() != nString) + continue; XMLAttrs attrs3; attrs3["value"] = elem->string.s; xml.writeEmptyElement("string", attrs3); @@ -1237,14 +1206,15 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); Bindings & attrs = *v->attrs; - for (auto &i : attrs) { + for (auto & i : attrs) { Attr & a(*attrs.find(i.name)); - if(a.value->type() != nString) continue; + if (a.value->type() != nString) + continue; XMLAttrs attrs3; attrs3["type"] = globals.state->symbols[i.name]; attrs3["value"] = a.value->string.s; xml.writeEmptyElement("string", attrs3); - } + } } } } @@ -1262,10 +1232,10 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) } } - if (!xmlOutput) printTable(table); + if (!xmlOutput) + printTable(table); } - static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -1279,7 +1249,6 @@ static void opSwitchProfile(Globals & globals, Strings opFlags, Strings opArgs) switchLink(profileLink, profile); } - static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -1293,7 +1262,6 @@ static void opSwitchGeneration(Globals & globals, Strings opFlags, Strings opArg throw UsageError("expected a generation number"); } - static void opRollback(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -1304,7 +1272,6 @@ static void opRollback(Globals & globals, Strings opFlags, Strings opArgs) switchGeneration(globals.profile, {}, globals.dryRun); } - static void opListGenerations(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -1321,16 +1288,14 @@ 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)" : ""); + 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)" : ""); } } - static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opArgs) { if (opFlags.size() > 0) @@ -1360,14 +1325,12 @@ static void opDeleteGenerations(Globals & globals, Strings opFlags, Strings opAr } } - static void opVersion(Globals & globals, Strings opFlags, Strings opArgs) { printVersion("nix-env"); } - -static int main_nix_env(int argc, char * * argv) +static int main_nix_env(int argc, char ** argv) { { Strings opFlags, opArgs; @@ -1391,7 +1354,8 @@ static int main_nix_env(int argc, char * * argv) replaceSymlink( fmt("%s/profiles/per-user/root/channels", settings.nixStateDir), globals.instSource.nixExprPath + "/channels_root"); - } catch (Error &) { } + } catch (Error &) { + } } globals.dryRun = false; @@ -1442,8 +1406,7 @@ static int main_nix_env(int argc, char * * argv) else if (*arg == "--dry-run") { printInfo("(dry run; not doing anything)"); globals.dryRun = true; - } - else if (*arg == "--system-filter") + } else if (*arg == "--system-filter") globals.instSource.systemFilter = getArg(*arg, arg, end); else if (*arg == "--prebuilt-only" || *arg == "-b") globals.prebuiltOnly = true; @@ -1452,11 +1415,9 @@ static int main_nix_env(int argc, char * * argv) else if (*arg != "" && arg->at(0) == '-') { opFlags.push_back(*arg); /* FIXME: hacky */ - if (*arg == "--from-profile" || - (op == opQuery && (*arg == "--attr" || *arg == "-A"))) + if (*arg == "--from-profile" || (op == opQuery && (*arg == "--attr" || *arg == "-A"))) opFlags.push_back(getArg(*arg, arg, end)); - } - else + } else opArgs.push_back(*arg); if (oldOp && oldOp != op) @@ -1467,7 +1428,8 @@ static int main_nix_env(int argc, char * * argv) myArgs.parseCmdline(argvToStrings(argc, argv)); - if (!op) throw UsageError("no operation specified"); + if (!op) + throw UsageError("no operation specified"); auto store = openStore(); diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 4b1202be39d5..ac1c5859c2fb 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -10,10 +10,8 @@ #include "eval-inline.hh" #include "profiles.hh" - namespace nix { - DrvInfos queryInstalled(EvalState & state, const Path & userEnv) { DrvInfos elems; @@ -29,10 +27,8 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv) return elems; } - -bool createUserEnv(EvalState & state, DrvInfos & elems, - const Path & profile, bool keepDerivations, - const std::string & lockToken) +bool createUserEnv( + EvalState & state, DrvInfos & elems, const Path & profile, bool keepDerivations, const std::string & lockToken) { /* Build the components in the user environment, if they don't exist already. */ @@ -42,9 +38,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, drvsToBuild.push_back({*drvPath}); debug(format("building user environment dependencies")); - state.store->buildPaths( - toDerivedPaths(drvsToBuild), - state.repair ? bmRepair : bmNormal); + state.store->buildPaths(toDerivedPaths(drvsToBuild), state.repair ? bmRepair : bmNormal); /* Construct the whole top level derivation. */ StorePathSet references; @@ -91,7 +85,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, auto meta = state.buildBindings(metaNames.size()); for (auto & j : metaNames) { Value * v = i.queryMeta(j); - if (!v) continue; + if (!v) + continue; meta.insert(state.symbols.create(j), v); } @@ -99,7 +94,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, (manifest.listElems()[n++] = state.allocValue())->mkAttrs(attrs); - if (drvPath) references.insert(*drvPath); + if (drvPath) + references.insert(*drvPath); } /* Also write a copy of the list of user environment elements to @@ -107,21 +103,21 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, environment. */ std::ostringstream str; manifest.print(state.symbols, str, true); - auto manifestFile = state.store->addTextToStore("env-manifest.nix", - str.str(), references); + auto manifestFile = state.store->addTextToStore("env-manifest.nix", str.str(), references); /* Get the environment builder expression. */ Value envBuilder; - state.eval(state.parseExprFromString( - #include "buildenv.nix.gen.hh" - , "/"), envBuilder); + state.eval( + state.parseExprFromString( +#include "buildenv.nix.gen.hh" + , "/"), + envBuilder); /* Construct a Nix expression that calls the user environment builder with the manifest as argument. */ auto attrs = state.buildBindings(3); - attrs.alloc("manifest").mkString( - state.store->printStorePath(manifestFile), - {state.store->printStorePath(manifestFile)}); + attrs.alloc("manifest") + .mkString(state.store->printStorePath(manifestFile), {state.store->printStorePath(manifestFile)}); attrs.insert(state.symbols.create("derivations"), &manifest); Value args; args.mkAttrs(attrs); @@ -142,9 +138,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, debug("building user environment"); std::vector topLevelDrvs; topLevelDrvs.push_back({topLevelDrv}); - state.store->buildPaths( - toDerivedPaths(topLevelDrvs), - state.repair ? bmRepair : bmNormal); + state.store->buildPaths(toDerivedPaths(topLevelDrvs), state.repair ? bmRepair : bmNormal); /* Switch the current user environment to the output path. */ auto store2 = state.store.dynamic_pointer_cast(); @@ -167,5 +161,4 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, return true; } - } diff --git a/src/nix-env/user-env.hh b/src/nix-env/user-env.hh index 10646f713134..1c4f966d7c8d 100644 --- a/src/nix-env/user-env.hh +++ b/src/nix-env/user-env.hh @@ -6,8 +6,7 @@ namespace nix { DrvInfos queryInstalled(EvalState & state, const Path & userEnv); -bool createUserEnv(EvalState & state, DrvInfos & elems, - const Path & profile, bool keepDerivations, - const std::string & lockToken); +bool createUserEnv( + EvalState & state, DrvInfos & elems, const Path & profile, bool keepDerivations, const std::string & lockToken); } diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index d3144e131a23..fd2a7a3a7832 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -15,20 +15,23 @@ #include #include - using namespace nix; - static Path gcRoot; static int rootNr = 0; - enum OutputKind { okPlain, okXML, okJSON }; - -void processExpr(EvalState & state, const Strings & attrPaths, - bool parseOnly, bool strict, Bindings & autoArgs, - bool evalOnly, OutputKind output, bool location, Expr * e) +void processExpr( + EvalState & state, + const Strings & attrPaths, + bool parseOnly, + bool strict, + Bindings & autoArgs, + bool evalOnly, + OutputKind output, + bool location, + Expr * e) { if (parseOnly) { e->show(state.symbols, std::cout); @@ -55,7 +58,8 @@ void processExpr(EvalState & state, const Strings & attrPaths, else if (output == okJSON) printValueAsJSON(state, strict, vRes, v.determinePos(noPos), std::cout, context); else { - if (strict) state.forceValueDeep(vRes); + if (strict) + state.forceValueDeep(vRes); vRes.print(state.symbols, std::cout); std::cout << std::endl; } @@ -75,7 +79,8 @@ void processExpr(EvalState & state, const Strings & attrPaths, printGCWarning(); else { Path rootName = absPath(gcRoot); - if (++rootNr > 1) rootName += "-" + std::to_string(rootNr); + if (++rootNr > 1) + rootName += "-" + std::to_string(rootNr); auto store2 = state.store.dynamic_pointer_cast(); if (store2) drvPathS = store2->addPermRoot(drvPath, rootName); @@ -86,8 +91,7 @@ void processExpr(EvalState & state, const Strings & attrPaths, } } - -static int main_nix_instantiate(int argc, char * * argv) +static int main_nix_instantiate(int argc, char ** argv) { { Strings files; @@ -163,12 +167,14 @@ static int main_nix_instantiate(int argc, char * * argv) Bindings & autoArgs = *myArgs.getAutoArgs(*state); - if (attrPaths.empty()) attrPaths = {""}; + if (attrPaths.empty()) + attrPaths = {""}; if (findFile) { for (auto & i : files) { Path p = state->findFile(i); - if (p == "") throw Error("unable to find '%1%'", i); + if (p == "") + throw Error("unable to find '%1%'", i); std::cout << p << std::endl; } return 0; @@ -176,17 +182,17 @@ static int main_nix_instantiate(int argc, char * * argv) if (readStdin) { Expr * e = state->parseStdin(); - processExpr(*state, attrPaths, parseOnly, strict, autoArgs, - evalOnly, outputKind, xmlOutputSourceLocation, e); + processExpr( + *state, attrPaths, parseOnly, strict, autoArgs, evalOnly, outputKind, xmlOutputSourceLocation, e); } else if (files.empty() && !fromArgs) files.push_back("./default.nix"); for (auto & i : files) { - Expr * e = fromArgs - ? state->parseExprFromString(i, absPath(".")) - : state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i)))); - processExpr(*state, attrPaths, parseOnly, strict, autoArgs, - evalOnly, outputKind, xmlOutputSourceLocation, e); + Expr * e = + fromArgs ? state->parseExprFromString(i, absPath(".")) + : state->parseExprFromFile(resolveExprPath(state->checkSourcePath(lookupFileArg(*state, i)))); + processExpr( + *state, attrPaths, parseOnly, strict, autoArgs, evalOnly, outputKind, xmlOutputSourceLocation, e); } state->printStats(); diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc index 577cadceb313..87f8d0fa7ade 100644 --- a/src/nix-store/dotgraph.cc +++ b/src/nix-store/dotgraph.cc @@ -4,44 +4,35 @@ #include - using std::cout; namespace nix { - static std::string dotQuote(std::string_view s) { return "\"" + std::string(s) + "\""; } - static const std::string & nextColour() { static int n = 0; - static std::vector colours - { "black", "red", "green", "blue" - , "magenta", "burlywood" }; + static std::vector colours{"black", "red", "green", "blue", "magenta", "burlywood"}; return colours[n++ % colours.size()]; } - static std::string makeEdge(std::string_view src, std::string_view dst) { - return fmt("%1% -> %2% [color = %3%];\n", - dotQuote(src), dotQuote(dst), dotQuote(nextColour())); + return fmt("%1% -> %2% [color = %3%];\n", dotQuote(src), dotQuote(dst), dotQuote(nextColour())); } - -static std::string makeNode(std::string_view id, std::string_view label, - std::string_view colour) +static std::string makeNode(std::string_view id, std::string_view label, std::string_view colour) { - return fmt("%1% [label = %2%, shape = box, " + return fmt( + "%1% [label = %2%, shape = box, " "style = filled, fillcolor = %3%];\n", dotQuote(id), dotQuote(label), dotQuote(colour)); } - void printDotGraph(ref store, StorePathSet && roots) { StorePathSet workList(std::move(roots)); @@ -52,7 +43,8 @@ void printDotGraph(ref store, StorePathSet && roots) while (!workList.empty()) { auto path = std::move(workList.extract(workList.begin()).value()); - if (!doneSet.insert(path).second) continue; + if (!doneSet.insert(path).second) + continue; cout << makeNode(std::string(path.to_string()), path.name(), "#ff0000"); @@ -67,5 +59,4 @@ void printDotGraph(ref store, StorePathSet && roots) cout << "}\n"; } - } diff --git a/src/nix-store/graphml.cc b/src/nix-store/graphml.cc index 425d61e53eda..4f23a7a84e93 100644 --- a/src/nix-store/graphml.cc +++ b/src/nix-store/graphml.cc @@ -5,12 +5,10 @@ #include - using std::cout; namespace nix { - static inline std::string_view xmlQuote(std::string_view s) { // Luckily, store paths shouldn't contain any character that needs to be @@ -18,20 +16,16 @@ static inline std::string_view xmlQuote(std::string_view s) return s; } - static std::string symbolicName(std::string_view p) { return std::string(p.substr(0, p.find('-') + 1)); } - static std::string makeEdge(std::string_view src, std::string_view dst) { - return fmt(" \n", - xmlQuote(src), xmlQuote(dst)); + return fmt(" \n", xmlQuote(src), xmlQuote(dst)); } - static std::string makeNode(const ValidPathInfo & info) { return fmt( @@ -40,13 +34,10 @@ static std::string makeNode(const ValidPathInfo & info) " %3%\n" " %4%\n" " \n", - info.path.to_string(), - info.narSize, - symbolicName(std::string(info.path.name())), + info.path.to_string(), info.narSize, symbolicName(std::string(info.path.name())), (info.path.isDerivation() ? "derivation" : "output-path")); } - void printGraphML(ref store, StorePathSet && roots) { StorePathSet workList(std::move(roots)); @@ -66,7 +57,8 @@ void printGraphML(ref store, StorePathSet && roots) auto path = std::move(workList.extract(workList.begin()).value()); ret = doneSet.insert(path); - if (ret.second == false) continue; + if (ret.second == false) + continue; auto info = store->queryPathInfo(path); cout << makeNode(*info); @@ -77,12 +69,10 @@ void printGraphML(ref store, StorePathSet && roots) cout << makeEdge(path.to_string(), p.to_string()); } } - } cout << "\n"; cout << "\n"; } - } diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index b453ea1ca30d..a159ed979713 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -24,42 +24,37 @@ #include #include - namespace nix_store { - using namespace nix; using std::cin; using std::cout; - -typedef void (* Operation) (Strings opFlags, Strings opArgs); - +typedef void (*Operation)(Strings opFlags, Strings opArgs); static Path gcRoot; static int rootNr = 0; static bool noOutput = false; static std::shared_ptr store; - ref ensureLocalStore() { auto store2 = std::dynamic_pointer_cast(store); - if (!store2) throw Error("you don't have sufficient rights to use this command"); + if (!store2) + throw Error("you don't have sufficient rights to use this command"); return ref(store2); } - static StorePath useDeriver(const StorePath & path) { - if (path.isDerivation()) return path; + if (path.isDerivation()) + return path; auto info = store->queryPathInfo(path); if (!info->deriver) throw Error("deriver of path '%s' is not known", store->printStorePath(path)); return *info->deriver; } - /* Realise the given path. For a derivation that means build it; for other paths it means ensure their validity. */ static PathSet realisePath(StorePathWithOutputs path, bool build = true) @@ -67,20 +62,21 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) auto store2 = std::dynamic_pointer_cast(store); if (path.path.isDerivation()) { - if (build) store->buildPaths({path.toDerivedPath()}); + if (build) + store->buildPaths({path.toDerivedPath()}); auto outputPaths = store->queryDerivationOutputMap(path.path); Derivation drv = store->derivationFromPath(path.path); rootNr++; if (path.outputs.empty()) - for (auto & i : drv.outputs) path.outputs.insert(i.first); + for (auto & i : drv.outputs) + path.outputs.insert(i.first); PathSet outputs; for (auto & j : path.outputs) { DerivationOutputs::iterator i = drv.outputs.find(j); if (i == drv.outputs.end()) - throw Error("derivation '%s' does not have an output named '%s'", - store2->printStorePath(path.path), j); + throw Error("derivation '%s' does not have an output named '%s'", store2->printStorePath(path.path), j); auto outPath = outputPaths.at(i->first); auto retPath = store->printStorePath(outPath); if (store2) { @@ -88,8 +84,10 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) printGCWarning(); else { Path rootName = gcRoot; - if (rootNr > 1) rootName += "-" + std::to_string(rootNr); - if (i->first != "out") rootName += "-" + i->first; + if (rootNr > 1) + rootName += "-" + std::to_string(rootNr); + if (i->first != "out") + rootName += "-" + i->first; retPath = store2->addPermRoot(outPath, rootName); } } @@ -99,7 +97,8 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) } else { - if (build) store->ensurePath(path.path); + if (build) + store->ensurePath(path.path); else if (!store->isValidPath(path.path)) throw Error("path '%s' does not exist and cannot be created", store->printStorePath(path.path)); if (store2) { @@ -108,7 +107,8 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) else { Path rootName = gcRoot; rootNr++; - if (rootNr > 1) rootName += "-" + std::to_string(rootNr); + if (rootNr > 1) + rootName += "-" + std::to_string(rootNr); return {store2->addPermRoot(path.path, rootName)}; } } @@ -116,7 +116,6 @@ static PathSet realisePath(StorePathWithOutputs path, bool build = true) } } - /* Realise the given paths. */ static void opRealise(Strings opFlags, Strings opArgs) { @@ -125,11 +124,16 @@ static void opRealise(Strings opFlags, Strings opArgs) bool ignoreUnknown = false; for (auto & i : opFlags) - if (i == "--dry-run") dryRun = true; - else if (i == "--repair") buildMode = bmRepair; - else if (i == "--check") buildMode = bmCheck; - else if (i == "--ignore-unknown") ignoreUnknown = true; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--dry-run") + dryRun = true; + else if (i == "--repair") + buildMode = bmRepair; + else if (i == "--check") + buildMode = bmCheck; + else if (i == "--ignore-unknown") + ignoreUnknown = true; + else + throw UsageError("unknown flag '%1%'", i); std::vector paths; for (auto & i : opArgs) @@ -137,14 +141,13 @@ static void opRealise(Strings opFlags, Strings opArgs) uint64_t downloadSize, narSize; StorePathSet willBuild, willSubstitute, unknown; - store->queryMissing( - toDerivedPaths(paths), - willBuild, willSubstitute, unknown, downloadSize, narSize); + store->queryMissing(toDerivedPaths(paths), willBuild, willSubstitute, unknown, downloadSize, narSize); if (ignoreUnknown) { std::vector paths2; for (auto & i : paths) - if (!unknown.count(i.path)) paths2.push_back(i); + if (!unknown.count(i.path)) + paths2.push_back(i); paths = std::move(paths2); unknown = StorePathSet(); } @@ -152,7 +155,8 @@ static void opRealise(Strings opFlags, Strings opArgs) if (settings.printMissing) printMissing(ref(store), willBuild, willSubstitute, unknown, downloadSize, narSize); - if (dryRun) return; + if (dryRun) + return; /* Build all paths at the same time to exploit parallelism. */ store->buildPaths(toDerivedPaths(paths), buildMode); @@ -166,17 +170,16 @@ static void opRealise(Strings opFlags, Strings opArgs) } } - /* Add files to the Nix store and print the resulting paths. */ static void opAdd(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); for (auto & i : opArgs) cout << fmt("%s\n", store->printStorePath(store->addToStore(std::string(baseNameOf(i)), i))); } - /* Preload the output of a fixed-output derivation into the Nix store. */ static void opAddFixed(Strings opFlags, Strings opArgs) @@ -184,8 +187,10 @@ static void opAddFixed(Strings opFlags, Strings opArgs) auto method = FileIngestionMethod::Flat; for (auto & i : opFlags) - if (i == "--recursive") method = FileIngestionMethod::Recursive; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--recursive") + method = FileIngestionMethod::Recursive; + else + throw UsageError("unknown flag '%1%'", i); if (opArgs.empty()) throw UsageError("first argument must be hash algorithm"); @@ -197,15 +202,16 @@ static void opAddFixed(Strings opFlags, Strings opArgs) std::cout << fmt("%s\n", store->printStorePath(store->addToStoreSlow(baseNameOf(i), i, method, hashAlgo).path)); } - /* Hack to support caching in `nix-prefetch-url'. */ static void opPrintFixedPath(Strings opFlags, Strings opArgs) { auto recursive = FileIngestionMethod::Flat; for (auto i : opFlags) - if (i == "--recursive") recursive = FileIngestionMethod::Recursive; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--recursive") + recursive = FileIngestionMethod::Recursive; + else + throw UsageError("unknown flag '%1%'", i); if (opArgs.size() != 3) throw UsageError("'--print-fixed-path' requires three arguments"); @@ -215,13 +221,14 @@ static void opPrintFixedPath(Strings opFlags, Strings opArgs) std::string hash = *i++; std::string name = *i++; - cout << fmt("%s\n", store->printStorePath(store->makeFixedOutputPath(recursive, Hash::parseAny(hash, hashAlgo), name))); + cout << fmt( + "%s\n", store->printStorePath(store->makeFixedOutputPath(recursive, Hash::parseAny(hash, hashAlgo), name))); } - static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput, bool forceRealise) { - if (forceRealise) realisePath({storePath}); + if (forceRealise) + realisePath({storePath}); if (useOutput && storePath.isDerivation()) { auto drv = store->derivationFromPath(storePath); StorePathSet outputs; @@ -229,20 +236,20 @@ static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput, return store->queryDerivationOutputs(storePath); for (auto & i : drv.outputsAndOptPaths(*store)) { if (!i.second.second) - throw UsageError("Cannot use output path of floating content-addressed derivation until we know what it is (e.g. by building it)"); + throw UsageError( + "Cannot use output path of floating content-addressed derivation until we know what it is (e.g. by building it)"); outputs.insert(*i.second.second); } return outputs; - } - else return {storePath}; + } else + return {storePath}; } - /* Some code to print a tree representation of a derivation dependency graph. Topological sorting is used to keep the tree relatively flat. */ -static void printTree(const StorePath & path, - const std::string & firstPad, const std::string & tailPad, StorePathSet & done) +static void +printTree(const StorePath & path, const std::string & firstPad, const std::string & tailPad, StorePathSet & done) { if (!done.insert(path).second) { cout << fmt("%s%s [...]\n", firstPad, store->printStorePath(path)); @@ -260,23 +267,32 @@ static void printTree(const StorePath & path, auto sorted = store->topoSortPaths(info->references); reverse(sorted.begin(), sorted.end()); - for (const auto &[n, i] : enumerate(sorted)) { + for (const auto & [n, i] : enumerate(sorted)) { bool last = n + 1 == sorted.size(); - printTree(i, - tailPad + (last ? treeLast : treeConn), - tailPad + (last ? treeNull : treeLine), - done); + printTree(i, tailPad + (last ? treeLast : treeConn), tailPad + (last ? treeNull : treeLine), done); } } - /* Perform various sorts of queries. */ static void opQuery(Strings opFlags, Strings opArgs) { - enum QueryType - { qDefault, qOutputs, qRequisites, qReferences, qReferrers - , qReferrersClosure, qDeriver, qBinding, qHash, qSize - , qTree, qGraph, qGraphML, qResolve, qRoots }; + enum QueryType { + qDefault, + qOutputs, + qRequisites, + qReferences, + qReferrers, + qReferrersClosure, + qDeriver, + qBinding, + qHash, + qSize, + qTree, + qGraph, + qGraphML, + qResolve, + qRoots + }; QueryType query = qDefault; bool useOutput = false; bool includeOutputs = false; @@ -285,171 +301,187 @@ static void opQuery(Strings opFlags, Strings opArgs) for (auto & i : opFlags) { QueryType prev = query; - if (i == "--outputs") query = qOutputs; - else if (i == "--requisites" || i == "-R") query = qRequisites; - else if (i == "--references") query = qReferences; - else if (i == "--referrers" || i == "--referers") query = qReferrers; - else if (i == "--referrers-closure" || i == "--referers-closure") query = qReferrersClosure; - else if (i == "--deriver" || i == "-d") query = qDeriver; + if (i == "--outputs") + query = qOutputs; + else if (i == "--requisites" || i == "-R") + query = qRequisites; + else if (i == "--references") + query = qReferences; + else if (i == "--referrers" || i == "--referers") + query = qReferrers; + else if (i == "--referrers-closure" || i == "--referers-closure") + query = qReferrersClosure; + else if (i == "--deriver" || i == "-d") + query = qDeriver; else if (i == "--binding" || i == "-b") { if (opArgs.size() == 0) throw UsageError("expected binding name"); bindingName = opArgs.front(); opArgs.pop_front(); query = qBinding; - } - else if (i == "--hash") query = qHash; - else if (i == "--size") query = qSize; - else if (i == "--tree") query = qTree; - else if (i == "--graph") query = qGraph; - else if (i == "--graphml") query = qGraphML; - else if (i == "--resolve") query = qResolve; - else if (i == "--roots") query = qRoots; - else if (i == "--use-output" || i == "-u") useOutput = true; - else if (i == "--force-realise" || i == "--force-realize" || i == "-f") forceRealise = true; - else if (i == "--include-outputs") includeOutputs = true; - else throw UsageError("unknown flag '%1%'", i); + } else if (i == "--hash") + query = qHash; + else if (i == "--size") + query = qSize; + else if (i == "--tree") + query = qTree; + else if (i == "--graph") + query = qGraph; + else if (i == "--graphml") + query = qGraphML; + else if (i == "--resolve") + query = qResolve; + else if (i == "--roots") + query = qRoots; + else if (i == "--use-output" || i == "-u") + useOutput = true; + else if (i == "--force-realise" || i == "--force-realize" || i == "-f") + forceRealise = true; + else if (i == "--include-outputs") + includeOutputs = true; + else + throw UsageError("unknown flag '%1%'", i); if (prev != qDefault && prev != query) throw UsageError("query type '%1%' conflicts with earlier flag", i); } - if (query == qDefault) query = qOutputs; + if (query == qDefault) + query = qOutputs; RunPager pager; switch (query) { - case qOutputs: { - for (auto & i : opArgs) { - auto outputs = maybeUseOutputs(store->followLinksToStorePath(i), true, forceRealise); - for (auto & outputPath : outputs) - cout << fmt("%1%\n", store->printStorePath(outputPath)); - } - break; + case qOutputs: { + for (auto & i : opArgs) { + auto outputs = maybeUseOutputs(store->followLinksToStorePath(i), true, forceRealise); + for (auto & outputPath : outputs) + cout << fmt("%1%\n", store->printStorePath(outputPath)); } + break; + } - case qRequisites: - case qReferences: - case qReferrers: - case qReferrersClosure: { - StorePathSet paths; - for (auto & i : opArgs) { - auto ps = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise); - for (auto & j : ps) { - if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs); - else if (query == qReferences) { - for (auto & p : store->queryPathInfo(j)->references) - paths.insert(p); - } - else if (query == qReferrers) { - StorePathSet tmp; - store->queryReferrers(j, tmp); - for (auto & i : tmp) - paths.insert(i); - } - else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true); - } + case qRequisites: + case qReferences: + case qReferrers: + case qReferrersClosure: { + StorePathSet paths; + for (auto & i : opArgs) { + auto ps = maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise); + for (auto & j : ps) { + if (query == qRequisites) + store->computeFSClosure(j, paths, false, includeOutputs); + else if (query == qReferences) { + for (auto & p : store->queryPathInfo(j)->references) + paths.insert(p); + } else if (query == qReferrers) { + StorePathSet tmp; + store->queryReferrers(j, tmp); + for (auto & i : tmp) + paths.insert(i); + } else if (query == qReferrersClosure) + store->computeFSClosure(j, paths, true); } - auto sorted = store->topoSortPaths(paths); - for (StorePaths::reverse_iterator i = sorted.rbegin(); - i != sorted.rend(); ++i) - cout << fmt("%s\n", store->printStorePath(*i)); - break; } + auto sorted = store->topoSortPaths(paths); + for (StorePaths::reverse_iterator i = sorted.rbegin(); i != sorted.rend(); ++i) + cout << fmt("%s\n", store->printStorePath(*i)); + break; + } - case qDeriver: - for (auto & i : opArgs) { - auto info = store->queryPathInfo(store->followLinksToStorePath(i)); - cout << fmt("%s\n", info->deriver ? store->printStorePath(*info->deriver) : "unknown-deriver"); - } - break; - - case qBinding: - for (auto & i : opArgs) { - auto path = useDeriver(store->followLinksToStorePath(i)); - Derivation drv = store->derivationFromPath(path); - StringPairs::iterator j = drv.env.find(bindingName); - if (j == drv.env.end()) - throw Error("derivation '%s' has no environment binding named '%s'", - store->printStorePath(path), bindingName); - cout << fmt("%s\n", j->second); + case qDeriver: + for (auto & i : opArgs) { + auto info = store->queryPathInfo(store->followLinksToStorePath(i)); + cout << fmt("%s\n", info->deriver ? store->printStorePath(*info->deriver) : "unknown-deriver"); + } + break; + + case qBinding: + for (auto & i : opArgs) { + auto path = useDeriver(store->followLinksToStorePath(i)); + Derivation drv = store->derivationFromPath(path); + StringPairs::iterator j = drv.env.find(bindingName); + if (j == drv.env.end()) + throw Error( + "derivation '%s' has no environment binding named '%s'", store->printStorePath(path), bindingName); + cout << fmt("%s\n", j->second); + } + break; + + case qHash: + case qSize: + for (auto & i : opArgs) { + for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) { + auto info = store->queryPathInfo(j); + if (query == qHash) { + assert(info->narHash.type == htSHA256); + cout << fmt("%s\n", info->narHash.to_string(Base32, true)); + } else if (query == qSize) + cout << fmt("%d\n", info->narSize); } - break; + } + break; - case qHash: - case qSize: - for (auto & i : opArgs) { - for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) { - auto info = store->queryPathInfo(j); - if (query == qHash) { - assert(info->narHash.type == htSHA256); - cout << fmt("%s\n", info->narHash.to_string(Base32, true)); - } else if (query == qSize) - cout << fmt("%d\n", info->narSize); - } - } - break; + case qTree: { + StorePathSet done; + for (auto & i : opArgs) + printTree(store->followLinksToStorePath(i), "", "", done); + break; + } - case qTree: { - StorePathSet done; - for (auto & i : opArgs) - printTree(store->followLinksToStorePath(i), "", "", done); - break; - } + case qGraph: { + StorePathSet roots; + for (auto & i : opArgs) + for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) + roots.insert(j); + printDotGraph(ref(store), std::move(roots)); + break; + } - case qGraph: { - StorePathSet roots; - for (auto & i : opArgs) - for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) - roots.insert(j); - printDotGraph(ref(store), std::move(roots)); - break; - } + case qGraphML: { + StorePathSet roots; + for (auto & i : opArgs) + for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) + roots.insert(j); + printGraphML(ref(store), std::move(roots)); + break; + } - case qGraphML: { - StorePathSet roots; - for (auto & i : opArgs) - for (auto & j : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) - roots.insert(j); - printGraphML(ref(store), std::move(roots)); - break; - } + case qResolve: { + for (auto & i : opArgs) + cout << fmt("%s\n", store->printStorePath(store->followLinksToStorePath(i))); + break; + } - case qResolve: { - for (auto & i : opArgs) - cout << fmt("%s\n", store->printStorePath(store->followLinksToStorePath(i))); - break; - } + case qRoots: { + StorePathSet args; + for (auto & i : opArgs) + for (auto & p : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) + args.insert(p); - case qRoots: { - StorePathSet args; - for (auto & i : opArgs) - for (auto & p : maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise)) - args.insert(p); + StorePathSet referrers; + store->computeFSClosure(args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations); - StorePathSet referrers; - store->computeFSClosure( - args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations); - - auto & gcStore = require(*store); - Roots roots = gcStore.findRoots(false); - for (auto & [target, links] : roots) - if (referrers.find(target) != referrers.end()) - for (auto & link : links) - cout << fmt("%1% -> %2%\n", link, gcStore.printStorePath(target)); - break; - } + auto & gcStore = require(*store); + Roots roots = gcStore.findRoots(false); + for (auto & [target, links] : roots) + if (referrers.find(target) != referrers.end()) + for (auto & link : links) + cout << fmt("%1% -> %2%\n", link, gcStore.printStorePath(target)); + break; + } - default: - abort(); + default: + abort(); } } - static void opPrintEnv(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); - if (opArgs.size() != 1) throw UsageError("'--print-env' requires one derivation store path"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); + if (opArgs.size() != 1) + throw UsageError("'--print-env' requires one derivation store path"); Path drvPath = opArgs.front(); Derivation drv = store->derivationFromPath(store->parseStorePath(drvPath)); @@ -464,17 +496,18 @@ static void opPrintEnv(Strings opFlags, Strings opArgs) cout << "export _args; _args='"; bool first = true; for (auto & i : drv.args) { - if (!first) cout << ' '; + if (!first) + cout << ' '; first = false; cout << shellEscape(i); } cout << "'\n"; } - static void opReadLog(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); auto & logStore = require(*store); @@ -489,10 +522,10 @@ static void opReadLog(Strings opFlags, Strings opArgs) } } - static void opDumpDB(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); if (!opArgs.empty()) { for (auto & i : opArgs) cout << store->makeValidityRegistration({store->followLinksToStorePath(i)}, true, true); @@ -502,7 +535,6 @@ static void opDumpDB(Strings opFlags, Strings opArgs) } } - static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) { ValidPathInfos infos; @@ -510,9 +542,10 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) while (1) { // We use a dummy value because we'll set it below. FIXME be correct by // construction and avoid dummy value. - auto hashResultOpt = !hashGiven ? std::optional { {Hash::dummy, -1} } : std::nullopt; + auto hashResultOpt = !hashGiven ? std::optional{{Hash::dummy, -1}} : std::nullopt; auto info = decodeValidPathInfo(*store, cin, hashResultOpt); - if (!info) break; + if (!info) + break; if (!store->isValidPath(info->path) || reregister) { /* !!! races */ if (canonicalise) @@ -529,39 +562,43 @@ static void registerValidity(bool reregister, bool hashGiven, bool canonicalise) ensureLocalStore()->registerValidPaths(infos); } - static void opLoadDB(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); if (!opArgs.empty()) throw UsageError("no arguments expected"); registerValidity(true, true, false); } - static void opRegisterValidity(Strings opFlags, Strings opArgs) { bool reregister = false; // !!! maybe this should be the default bool hashGiven = false; for (auto & i : opFlags) - if (i == "--reregister") reregister = true; - else if (i == "--hash-given") hashGiven = true; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--reregister") + reregister = true; + else if (i == "--hash-given") + hashGiven = true; + else + throw UsageError("unknown flag '%1%'", i); - if (!opArgs.empty()) throw UsageError("no arguments expected"); + if (!opArgs.empty()) + throw UsageError("no arguments expected"); registerValidity(reregister, hashGiven, true); } - static void opCheckValidity(Strings opFlags, Strings opArgs) { bool printInvalid = false; for (auto & i : opFlags) - if (i == "--print-invalid") printInvalid = true; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--print-invalid") + printInvalid = true; + else + throw UsageError("unknown flag '%1%'", i); for (auto & i : opArgs) { auto path = store->followLinksToStorePath(i); @@ -574,7 +611,6 @@ static void opCheckValidity(Strings opFlags, Strings opArgs) } } - static void opGC(Strings opFlags, Strings opArgs) { bool printRoots = false; @@ -585,14 +621,19 @@ static void opGC(Strings opFlags, Strings opArgs) /* Do what? */ for (auto i = opFlags.begin(); i != opFlags.end(); ++i) - if (*i == "--print-roots") printRoots = true; - else if (*i == "--print-live") options.action = GCOptions::gcReturnLive; - else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead; + if (*i == "--print-roots") + printRoots = true; + else if (*i == "--print-live") + options.action = GCOptions::gcReturnLive; + else if (*i == "--print-dead") + options.action = GCOptions::gcReturnDead; else if (*i == "--max-freed") options.maxFreed = std::max(getIntArg(*i, i, opFlags.end(), true), (int64_t) 0); - else throw UsageError("bad sub-operation '%1%' in GC", *i); + else + throw UsageError("bad sub-operation '%1%' in GC", *i); - if (!opArgs.empty()) throw UsageError("no arguments expected"); + if (!opArgs.empty()) + throw UsageError("no arguments expected"); auto & gcStore = require(*store); @@ -617,7 +658,6 @@ static void opGC(Strings opFlags, Strings opArgs) } } - /* Remove paths from the Nix store if possible (i.e., if they do not have any remaining referrers and are not reachable from any GC roots). */ @@ -627,8 +667,10 @@ static void opDelete(Strings opFlags, Strings opArgs) options.action = GCOptions::gcDeleteSpecific; for (auto & i : opFlags) - if (i == "--ignore-liveness") options.ignoreLiveness = true; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--ignore-liveness") + options.ignoreLiveness = true; + else + throw UsageError("unknown flag '%1%'", i); for (auto & i : opArgs) options.pathsToDelete.insert(store->followLinksToStorePath(i)); @@ -640,12 +682,13 @@ static void opDelete(Strings opFlags, Strings opArgs) gcStore.collectGarbage(options, results); } - /* Dump a path as a Nix archive. The archive is written to stdout */ static void opDump(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); - if (opArgs.size() != 1) throw UsageError("only one argument allowed"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); + if (opArgs.size() != 1) + throw UsageError("only one argument allowed"); FdSink sink(STDOUT_FILENO); std::string path = *opArgs.begin(); @@ -653,18 +696,18 @@ static void opDump(Strings opFlags, Strings opArgs) sink.flush(); } - /* Restore a value from a Nix archive. The archive is read from stdin. */ static void opRestore(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); - if (opArgs.size() != 1) throw UsageError("only one argument allowed"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); + if (opArgs.size() != 1) + throw UsageError("only one argument allowed"); FdSource source(STDIN_FILENO); restorePath(*opArgs.begin(), source); } - static void opExport(Strings opFlags, Strings opArgs) { for (auto & i : opFlags) @@ -680,13 +723,13 @@ static void opExport(Strings opFlags, Strings opArgs) sink.flush(); } - static void opImport(Strings opFlags, Strings opArgs) { for (auto & i : opFlags) throw UsageError("unknown flag '%1%'", i); - if (!opArgs.empty()) throw UsageError("no arguments expected"); + if (!opArgs.empty()) + throw UsageError("no arguments expected"); FdSource source(STDIN_FILENO); auto paths = store->importPaths(source, NoCheckSigs); @@ -695,18 +738,17 @@ static void opImport(Strings opFlags, Strings opArgs) cout << fmt("%s\n", store->printStorePath(i)) << std::flush; } - /* Initialise the Nix databases. */ static void opInit(Strings opFlags, Strings opArgs) { - if (!opFlags.empty()) throw UsageError("unknown flag"); + if (!opFlags.empty()) + throw UsageError("unknown flag"); if (!opArgs.empty()) throw UsageError("no arguments expected"); /* Doesn't do anything right now; database tables are initialised automatically. */ } - /* Verify the consistency of the Nix environment. */ static void opVerify(Strings opFlags, Strings opArgs) { @@ -717,9 +759,12 @@ static void opVerify(Strings opFlags, Strings opArgs) RepairFlag repair = NoRepair; for (auto & i : opFlags) - if (i == "--check-contents") checkContents = true; - else if (i == "--repair") repair = Repair; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--check-contents") + checkContents = true; + else if (i == "--repair") + repair = Repair; + else + throw UsageError("unknown flag '%1%'", i); if (store->verifyStore(checkContents, repair)) { warn("not all store errors were fixed"); @@ -727,7 +772,6 @@ static void opVerify(Strings opFlags, Strings opArgs) } } - /* Verify whether the contents of the given store path have not changed. */ static void opVerifyPath(Strings opFlags, Strings opArgs) { @@ -744,10 +788,9 @@ static void opVerifyPath(Strings opFlags, Strings opArgs) store->narFromPath(path, sink); auto current = sink.finish(); if (current.first != info->narHash) { - printError("path '%s' was modified! expected hash '%s', got '%s'", - store->printStorePath(path), - info->narHash.to_string(Base32, true), - current.first.to_string(Base32, true)); + printError( + "path '%s' was modified! expected hash '%s', got '%s'", store->printStorePath(path), + info->narHash.to_string(Base32, true), current.first.to_string(Base32, true)); status = 1; } } @@ -755,7 +798,6 @@ static void opVerifyPath(Strings opFlags, Strings opArgs) throw Exit(status); } - /* Repair the contents of the given path by redownloading it using a substituter (if available). */ static void opRepairPath(Strings opFlags, Strings opArgs) @@ -782,17 +824,21 @@ static void opServe(Strings opFlags, Strings opArgs) { bool writeAllowed = false; for (auto & i : opFlags) - if (i == "--write") writeAllowed = true; - else throw UsageError("unknown flag '%1%'", i); + if (i == "--write") + writeAllowed = true; + else + throw UsageError("unknown flag '%1%'", i); - if (!opArgs.empty()) throw UsageError("no arguments expected"); + if (!opArgs.empty()) + throw UsageError("no arguments expected"); FdSource in(STDIN_FILENO); FdSink out(STDOUT_FILENO); /* Exchange the greeting. */ unsigned int magic = readInt(in); - if (magic != SERVE_MAGIC_1) throw Error("protocol mismatch"); + if (magic != SERVE_MAGIC_1) + throw Error("protocol mismatch"); out << SERVE_MAGIC_2 << SERVE_PROTOCOL_VERSION; out.flush(); unsigned int clientVersion = readInt(in); @@ -828,163 +874,164 @@ static void opServe(Strings opFlags, Strings opArgs) switch (cmd) { - case cmdQueryValidPaths: { - bool lock = readInt(in); - bool substitute = readInt(in); - auto paths = worker_proto::read(*store, in, Phantom {}); - if (lock && writeAllowed) - for (auto & path : paths) - store->addTempRoot(path); + case cmdQueryValidPaths: { + bool lock = readInt(in); + bool substitute = readInt(in); + auto paths = worker_proto::read(*store, in, Phantom{}); + if (lock && writeAllowed) + for (auto & path : paths) + store->addTempRoot(path); - if (substitute && writeAllowed) { - store->substitutePaths(paths); - } - - worker_proto::write(*store, out, store->queryValidPaths(paths)); - break; + if (substitute && writeAllowed) { + store->substitutePaths(paths); } - case cmdQueryPathInfos: { - auto paths = worker_proto::read(*store, in, Phantom {}); - // !!! Maybe we want a queryPathInfos? - for (auto & i : paths) { - try { - auto info = store->queryPathInfo(i); - out << store->printStorePath(info->path) - << (info->deriver ? store->printStorePath(*info->deriver) : ""); - worker_proto::write(*store, out, info->references); - // !!! Maybe we want compression? - out << info->narSize // downloadSize - << info->narSize; - if (GET_PROTOCOL_MINOR(clientVersion) >= 4) - out << info->narHash.to_string(Base32, true) - << renderContentAddress(info->ca) - << info->sigs; - } catch (InvalidPath &) { - } + worker_proto::write(*store, out, store->queryValidPaths(paths)); + break; + } + + case cmdQueryPathInfos: { + auto paths = worker_proto::read(*store, in, Phantom{}); + // !!! Maybe we want a queryPathInfos? + for (auto & i : paths) { + try { + auto info = store->queryPathInfo(i); + out << store->printStorePath(info->path) + << (info->deriver ? store->printStorePath(*info->deriver) : ""); + worker_proto::write(*store, out, info->references); + // !!! Maybe we want compression? + out << info->narSize // downloadSize + << info->narSize; + if (GET_PROTOCOL_MINOR(clientVersion) >= 4) + out << info->narHash.to_string(Base32, true) << renderContentAddress(info->ca) << info->sigs; + } catch (InvalidPath &) { } - out << ""; - break; } + out << ""; + break; + } - case cmdDumpStorePath: - store->narFromPath(store->parseStorePath(readString(in)), out); - break; + case cmdDumpStorePath: + store->narFromPath(store->parseStorePath(readString(in)), out); + break; - case cmdImportPaths: { - if (!writeAllowed) throw Error("importing paths is not allowed"); - store->importPaths(in, NoCheckSigs); // FIXME: should we skip sig checking? - out << 1; // indicate success - break; - } + case cmdImportPaths: { + if (!writeAllowed) + throw Error("importing paths is not allowed"); + store->importPaths(in, NoCheckSigs); // FIXME: should we skip sig checking? + out << 1; // indicate success + break; + } - case cmdExportPaths: { - readInt(in); // obsolete - store->exportPaths(worker_proto::read(*store, in, Phantom {}), out); - break; - } + case cmdExportPaths: { + readInt(in); // obsolete + store->exportPaths(worker_proto::read(*store, in, Phantom{}), out); + break; + } - case cmdBuildPaths: { + case cmdBuildPaths: { - if (!writeAllowed) throw Error("building paths is not allowed"); + if (!writeAllowed) + throw Error("building paths is not allowed"); - std::vector paths; - for (auto & s : readStrings(in)) - paths.push_back(parsePathWithOutputs(*store, s)); + std::vector paths; + for (auto & s : readStrings(in)) + paths.push_back(parsePathWithOutputs(*store, s)); - getBuildSettings(); + getBuildSettings(); - try { - MonitorFdHup monitor(in.fd); - store->buildPaths(toDerivedPaths(paths)); - out << 0; - } catch (Error & e) { - assert(e.status); - out << e.status << e.msg(); - } - break; + try { + MonitorFdHup monitor(in.fd); + store->buildPaths(toDerivedPaths(paths)); + out << 0; + } catch (Error & e) { + assert(e.status); + out << e.status << e.msg(); } + break; + } - case cmdBuildDerivation: { /* Used by hydra-queue-runner. */ - - if (!writeAllowed) throw Error("building paths is not allowed"); - - auto drvPath = store->parseStorePath(readString(in)); - BasicDerivation drv; - readDerivation(in, *store, drv, Derivation::nameFromPath(drvPath)); + case cmdBuildDerivation: { /* Used by hydra-queue-runner. */ - getBuildSettings(); + if (!writeAllowed) + throw Error("building paths is not allowed"); - MonitorFdHup monitor(in.fd); - auto status = store->buildDerivation(drvPath, drv); + auto drvPath = store->parseStorePath(readString(in)); + BasicDerivation drv; + readDerivation(in, *store, drv, Derivation::nameFromPath(drvPath)); - out << status.status << status.errorMsg; + getBuildSettings(); - if (GET_PROTOCOL_MINOR(clientVersion) >= 3) - out << status.timesBuilt << status.isNonDeterministic << status.startTime << status.stopTime; - if (GET_PROTOCOL_MINOR(clientVersion >= 6)) { - worker_proto::write(*store, out, status.builtOutputs); - } + MonitorFdHup monitor(in.fd); + auto status = store->buildDerivation(drvPath, drv); + out << status.status << status.errorMsg; - break; + if (GET_PROTOCOL_MINOR(clientVersion) >= 3) + out << status.timesBuilt << status.isNonDeterministic << status.startTime << status.stopTime; + if (GET_PROTOCOL_MINOR(clientVersion >= 6)) { + worker_proto::write(*store, out, status.builtOutputs); } - case cmdQueryClosure: { - bool includeOutputs = readInt(in); - StorePathSet closure; - store->computeFSClosure(worker_proto::read(*store, in, Phantom {}), - closure, false, includeOutputs); - worker_proto::write(*store, out, closure); - break; - } + break; + } + + case cmdQueryClosure: { + bool includeOutputs = readInt(in); + StorePathSet closure; + store->computeFSClosure( + worker_proto::read(*store, in, Phantom{}), closure, false, includeOutputs); + worker_proto::write(*store, out, closure); + break; + } - case cmdAddToStoreNar: { - if (!writeAllowed) throw Error("importing paths is not allowed"); + case cmdAddToStoreNar: { + if (!writeAllowed) + throw Error("importing paths is not allowed"); - auto path = readString(in); - auto deriver = readString(in); - ValidPathInfo info { - store->parseStorePath(path), - Hash::parseAny(readString(in), htSHA256), - }; - if (deriver != "") - info.deriver = store->parseStorePath(deriver); - info.references = worker_proto::read(*store, in, Phantom {}); - in >> info.registrationTime >> info.narSize >> info.ultimate; - info.sigs = readStrings(in); - info.ca = parseContentAddressOpt(readString(in)); + auto path = readString(in); + auto deriver = readString(in); + ValidPathInfo info{ + store->parseStorePath(path), + Hash::parseAny(readString(in), htSHA256), + }; + if (deriver != "") + info.deriver = store->parseStorePath(deriver); + info.references = worker_proto::read(*store, in, Phantom{}); + in >> info.registrationTime >> info.narSize >> info.ultimate; + info.sigs = readStrings(in); + info.ca = parseContentAddressOpt(readString(in)); - if (info.narSize == 0) - throw Error("narInfo is too old and missing the narSize field"); + if (info.narSize == 0) + throw Error("narInfo is too old and missing the narSize field"); - SizedSource sizedSource(in, info.narSize); + SizedSource sizedSource(in, info.narSize); - store->addToStore(info, sizedSource, NoRepair, NoCheckSigs); + store->addToStore(info, sizedSource, NoRepair, NoCheckSigs); - // consume all the data that has been sent before continuing. - sizedSource.drainAll(); + // consume all the data that has been sent before continuing. + sizedSource.drainAll(); - out << 1; // indicate success + out << 1; // indicate success - break; - } + break; + } - default: - throw Error("unknown serve command %1%", cmd); + default: + throw Error("unknown serve command %1%", cmd); } out.flush(); } } - static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs) { for (auto & i : opFlags) throw UsageError("unknown flag '%1%'", i); - if (opArgs.size() != 3) throw UsageError("three arguments expected"); + if (opArgs.size() != 3) + throw UsageError("three arguments expected"); auto i = opArgs.begin(); std::string keyName = *i++; std::string secretKeyFile = *i++; @@ -997,17 +1044,15 @@ static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs) writeFile(secretKeyFile, secretKey.to_string()); } - static void opVersion(Strings opFlags, Strings opArgs) { printVersion("nix-store"); } - /* Scan the arguments; find the operation, set global flags, put all other flags in a list, and put all other arguments in another list. */ -static int main_nix_store(int argc, char * * argv) +static int main_nix_store(int argc, char ** argv) { { Strings opFlags, opArgs; @@ -1078,8 +1123,7 @@ static int main_nix_store(int argc, char * * argv) opFlags.push_back(*arg); if (*arg == "--max-freed" || *arg == "--max-links" || *arg == "--max-atime") /* !!! hack */ opFlags.push_back(getArg(*arg, arg, end)); - } - else + } else opArgs.push_back(*arg); if (oldOp && oldOp != op) @@ -1088,7 +1132,8 @@ static int main_nix_store(int argc, char * * argv) return true; }); - if (!op) throw UsageError("no operation specified"); + if (!op) + throw UsageError("no operation specified"); if (op != opDump && op != opRestore) /* !!! hack */ store = openStore(); diff --git a/src/nix/add-to-store.cc b/src/nix/add-to-store.cc index 5168413d2de0..8fe2311f0daf 100644 --- a/src/nix/add-to-store.cc +++ b/src/nix/add-to-store.cc @@ -27,7 +27,8 @@ struct CmdAddToStore : MixDryRun, StoreCommand void run(ref store) override { - if (!namePart) namePart = baseNameOf(path); + if (!namePart) + namePart = baseNameOf(path); StringSink sink; dumpPath(path, sink); @@ -41,15 +42,15 @@ struct CmdAddToStore : MixDryRun, StoreCommand hash = hsink.finish().first; } - ValidPathInfo info { + ValidPathInfo info{ store->makeFixedOutputPath(ingestionMethod, hash, *namePart), narHash, }; info.narSize = sink.s.size(); - info.ca = std::optional { FixedOutputHash { + info.ca = std::optional{FixedOutputHash{ .method = ingestionMethod, .hash = hash, - } }; + }}; if (!dryRun) { auto source = StringSource(sink.s); @@ -75,8 +76,8 @@ struct CmdAddFile : CmdAddToStore std::string doc() override { return - #include "add-file.md" - ; +#include "add-file.md" + ; } }; @@ -95,8 +96,8 @@ struct CmdAddPath : CmdAddToStore std::string doc() override { return - #include "add-path.md" - ; +#include "add-path.md" + ; } }; diff --git a/src/nix/app.cc b/src/nix/app.cc index 821964f86257..1111a70dbf8b 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -16,12 +16,13 @@ struct InstallableDerivedPath : Installable InstallableDerivedPath(ref store, const DerivedPath & derivedPath) : store(store) , derivedPath(derivedPath) + {} + + std::string what() const override { + return derivedPath.to_string(*store); } - - std::string what() const override { return derivedPath.to_string(*store); } - DerivedPaths toDerivedPaths() override { return {derivedPath}; @@ -42,11 +43,9 @@ StringPairs resolveRewrites(Store & store, const BuiltPaths dependencies) StringPairs res; for (auto & dep : dependencies) if (auto drvDep = std::get_if(&dep)) - for (auto & [ outputName, outputPath ] : drvDep->outputs) + for (auto & [outputName, outputPath] : drvDep->outputs) res.emplace( - downstreamPlaceholder(store, drvDep->drvPath, outputName), - store.printStorePath(outputPath) - ); + downstreamPlaceholder(store, drvDep->drvPath, outputName), store.printStorePath(outputPath)); return res; } @@ -77,7 +76,7 @@ UnresolvedApp Installable::toApp(EvalState & state) for (auto & [path, name] : context) context2.push_back({path, {name}}); - return UnresolvedApp{App { + return UnresolvedApp{App{ .context = std::move(context2), .program = program, }}; @@ -91,15 +90,10 @@ UnresolvedApp Installable::toApp(EvalState & state) auto aPname = cursor->maybeGetAttr("pname"); auto aMeta = cursor->maybeGetAttr(state.sMeta); auto aMainProgram = aMeta ? aMeta->maybeGetAttr("mainProgram") : nullptr; - auto mainProgram = - aMainProgram - ? aMainProgram->getString() - : aPname - ? aPname->getString() - : DrvName(name).name; + auto mainProgram = aMainProgram ? aMainProgram->getString() : aPname ? aPname->getString() : DrvName(name).name; auto program = outPath + "/bin/" + mainProgram; - return UnresolvedApp { App { - .context = { { drvPath, {outputName} } }, + return UnresolvedApp{App{ + .context = {{drvPath, {outputName}}}, .program = program, }}; } @@ -116,8 +110,7 @@ App UnresolvedApp::resolve(ref evalStore, ref store) std::vector> installableContext; for (auto & ctxElt : unresolved.context) - installableContext.push_back( - std::make_shared(store, ctxElt.toDerivedPath())); + installableContext.push_back(std::make_shared(store, ctxElt.toDerivedPath())); auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext); res.program = resolveString(*store, unresolved.program, builtContext); diff --git a/src/nix/build.cc b/src/nix/build.cc index 9c648d28ebc8..35dc8936a51a 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -18,14 +18,13 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile CmdBuild() { - addFlag({ - .longName = "out-link", - .shortName = 'o', - .description = "Use *path* as prefix for the symlinks to the build results. It defaults to `result`.", - .labels = {"path"}, - .handler = {&outLink}, - .completer = completePath - }); + addFlag( + {.longName = "out-link", + .shortName = 'o', + .description = "Use *path* as prefix for the symlinks to the build results. It defaults to `result`.", + .labels = {"path"}, + .handler = {&outLink}, + .completer = completePath}); addFlag({ .longName = "no-link", @@ -54,8 +53,8 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile std::string doc() override { return - #include "build.md" - ; +#include "build.md" + ; } void run(ref store) override @@ -73,47 +72,50 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile return; } - auto buildables = Installable::build( - getEvalStore(), store, - Realise::Outputs, - installables, buildMode); + auto buildables = Installable::build(getEvalStore(), store, Realise::Outputs, installables, buildMode); - if (json) logger->cout("%s", derivedPathsWithHintsToJSON(buildables, store).dump()); + if (json) + logger->cout("%s", derivedPathsWithHintsToJSON(buildables, store).dump()); if (outLink != "") if (auto store2 = store.dynamic_pointer_cast()) for (const auto & [_i, buildable] : enumerate(buildables)) { auto i = _i; - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - std::string symlink = outLink; - if (i) symlink += fmt("-%d", i); - store2->addPermRoot(bo.path, absPath(symlink)); - }, - [&](const BuiltPath::Built & bfd) { - for (auto & output : bfd.outputs) { + std::visit( + overloaded{ + [&](const BuiltPath::Opaque & bo) { std::string symlink = outLink; - if (i) symlink += fmt("-%d", i); - if (output.first != "out") symlink += fmt("-%s", output.first); - store2->addPermRoot(output.second, absPath(symlink)); - } + if (i) + symlink += fmt("-%d", i); + store2->addPermRoot(bo.path, absPath(symlink)); + }, + [&](const BuiltPath::Built & bfd) { + for (auto & output : bfd.outputs) { + std::string symlink = outLink; + if (i) + symlink += fmt("-%d", i); + if (output.first != "out") + symlink += fmt("-%s", output.first); + store2->addPermRoot(output.second, absPath(symlink)); + } + }, }, - }, buildable.raw()); + buildable.raw()); } if (printOutputPaths) { stopProgressBar(); for (auto & buildable : buildables) { - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - std::cout << store->printStorePath(bo.path) << std::endl; - }, - [&](const BuiltPath::Built & bfd) { - for (auto & output : bfd.outputs) { - std::cout << store->printStorePath(output.second) << std::endl; - } + std::visit( + overloaded{ + [&](const BuiltPath::Opaque & bo) { std::cout << store->printStorePath(bo.path) << std::endl; }, + [&](const BuiltPath::Built & bfd) { + for (auto & output : bfd.outputs) { + std::cout << store->printStorePath(output.second) << std::endl; + } + }, }, - }, buildable.raw()); + buildable.raw()); } } diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index 2e48e4c74103..7282a9779a62 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -14,25 +14,21 @@ struct CmdBundle : InstallableCommand CmdBundle() { - addFlag({ - .longName = "bundler", - .description = fmt("Use a custom bundler instead of the default (`%s`).", bundler), - .labels = {"flake-url"}, - .handler = {&bundler}, - .completer = {[&](size_t, std::string_view prefix) { - completeFlakeRef(getStore(), prefix); - }} - }); - - addFlag({ - .longName = "out-link", - .shortName = 'o', - .description = "Override the name of the symlink to the build result. It defaults to the base name of the app.", - .labels = {"path"}, - .handler = {&outLink}, - .completer = completePath - }); - + addFlag( + {.longName = "bundler", + .description = fmt("Use a custom bundler instead of the default (`%s`).", bundler), + .labels = {"flake-url"}, + .handler = {&bundler}, + .completer = {[&](size_t, std::string_view prefix) { completeFlakeRef(getStore(), prefix); }}}); + + addFlag( + {.longName = "out-link", + .shortName = 'o', + .description = + "Override the name of the symlink to the build result. It defaults to the base name of the app.", + .labels = {"path"}, + .handler = {&outLink}, + .completer = completePath}); } std::string description() override @@ -43,19 +39,19 @@ struct CmdBundle : InstallableCommand std::string doc() override { return - #include "bundle.md" - ; +#include "bundle.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } // FIXME: cut&paste from CmdRun. Strings getDefaultFlakeAttrPaths() override { - Strings res{ - "apps." + settings.thisSystem.get() + ".default", - "defaultApp." + settings.thisSystem.get() - }; + Strings res{"apps." + settings.thisSystem.get() + ".default", "defaultApp." + settings.thisSystem.get()}; for (auto & s : SourceExprCommand::getDefaultFlakeAttrPaths()) res.push_back(s); return res; @@ -75,16 +71,18 @@ struct CmdBundle : InstallableCommand auto val = installable->toValue(*evalState).first; - auto [bundlerFlakeRef, bundlerName, outputsSpec] = parseFlakeRefWithFragmentAndOutputsSpec(bundler, absPath(".")); - const flake::LockFlags lockFlags{ .writeLockFile = false }; - InstallableFlake bundler{this, - evalState, std::move(bundlerFlakeRef), bundlerName, outputsSpec, - {"bundlers." + settings.thisSystem.get() + ".default", - "defaultBundler." + settings.thisSystem.get() - }, + auto [bundlerFlakeRef, bundlerName, outputsSpec] = + parseFlakeRefWithFragmentAndOutputsSpec(bundler, absPath(".")); + const flake::LockFlags lockFlags{.writeLockFile = false}; + InstallableFlake bundler{ + this, + evalState, + std::move(bundlerFlakeRef), + bundlerName, + outputsSpec, + {"bundlers." + settings.thisSystem.get() + ".default", "defaultBundler." + settings.thisSystem.get()}, {"bundlers." + settings.thisSystem.get() + "."}, - lockFlags - }; + lockFlags}; auto vRes = evalState->allocValue(); evalState->callFunction(*bundler.toValue(*evalState).first, *val, *vRes, noPos); @@ -105,7 +103,7 @@ struct CmdBundle : InstallableCommand auto outPath = evalState->coerceToStorePath(attr2->pos, *attr2->value, context2); - store->buildPaths({ DerivedPath::Built { drvPath } }); + store->buildPaths({DerivedPath::Built{drvPath}}); auto outPathS = store->printStorePath(outPath); diff --git a/src/nix/cat.cc b/src/nix/cat.cc index 6420a0f79891..2f63bf5c02af 100644 --- a/src/nix/cat.cc +++ b/src/nix/cat.cc @@ -25,11 +25,7 @@ struct CmdCatStore : StoreCommand, MixCat { CmdCatStore() { - expectArgs({ - .label = "path", - .handler = {&path}, - .completer = completePath - }); + expectArgs({.label = "path", .handler = {&path}, .completer = completePath}); } std::string description() override @@ -40,8 +36,8 @@ struct CmdCatStore : StoreCommand, MixCat std::string doc() override { return - #include "store-cat.md" - ; +#include "store-cat.md" + ; } void run(ref store) override @@ -56,11 +52,7 @@ struct CmdCatNar : StoreCommand, MixCat CmdCatNar() { - expectArgs({ - .label = "nar", - .handler = {&narPath}, - .completer = completePath - }); + expectArgs({.label = "nar", .handler = {&narPath}, .completer = completePath}); expectArg("path", &path); } @@ -72,8 +64,8 @@ struct CmdCatNar : StoreCommand, MixCat std::string doc() override { return - #include "nar-cat.md" - ; +#include "nar-cat.md" + ; } void run(ref store) override diff --git a/src/nix/copy.cc b/src/nix/copy.cc index 8730a9a5c339..7161d1267b6c 100644 --- a/src/nix/copy.cc +++ b/src/nix/copy.cc @@ -39,11 +39,14 @@ struct CmdCopy : virtual CopyCommand, virtual BuiltPathsCommand std::string doc() override { return - #include "copy.md" - ; +#include "copy.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run(ref srcStore, BuiltPaths && paths) override { @@ -56,8 +59,7 @@ struct CmdCopy : virtual CopyCommand, virtual BuiltPathsCommand stuffToCopy.insert(theseRealisations.begin(), theseRealisations.end()); } - copyPaths( - *srcStore, *dstStore, stuffToCopy, NoRepair, checkSigs, substitute); + copyPaths(*srcStore, *dstStore, stuffToCopy, NoRepair, checkSigs, substitute); } }; diff --git a/src/nix/daemon.cc b/src/nix/daemon.cc index 940923d3b56f..de9e6ec1da92 100644 --- a/src/nix/daemon.cc +++ b/src/nix/daemon.cc @@ -36,7 +36,7 @@ using namespace nix::daemon; #ifndef __linux__ #define SPLICE_F_MOVE 0 -static ssize_t splice(int fd_in, void *off_in, int fd_out, void *off_out, size_t len, unsigned int flags) +static ssize_t splice(int fd_in, void * off_in, int fd_out, void * off_out, size_t len, unsigned int flags) { // We ignore most parameters, we just have them for conformance with the linux syscall std::vector buf(8192); @@ -54,17 +54,16 @@ static ssize_t splice(int fd_in, void *off_in, int fd_out, void *off_out, size_t } #endif - static void sigChldHandler(int sigNo) { // Ensure we don't modify errno of whatever we've interrupted auto saved_errno = errno; // Reap all dead children. - while (waitpid(-1, 0, WNOHANG) > 0) ; + while (waitpid(-1, 0, WNOHANG) > 0) + ; errno = saved_errno; } - static void setSigChldAction(bool autoReap) { struct sigaction act, oact; @@ -75,7 +74,6 @@ static void setSigChldAction(bool autoReap) throw SysError("setting SIGCHLD handler"); } - bool matchUser(const std::string & user, const std::string & group, const Strings & users) { if (find(users.begin(), users.end(), "*") != users.end()) @@ -86,17 +84,19 @@ bool matchUser(const std::string & user, const std::string & group, const String for (auto & i : users) if (i.substr(0, 1) == "@") { - if (group == i.substr(1)) return true; + if (group == i.substr(1)) + return true; struct group * gr = getgrnam(i.c_str() + 1); - if (!gr) continue; - for (char * * mem = gr->gr_mem; *mem; mem++) - if (user == std::string(*mem)) return true; + if (!gr) + continue; + for (char ** mem = gr->gr_mem; *mem; mem++) + if (user == std::string(*mem)) + return true; } return false; } - struct PeerInfo { bool pidKnown; @@ -107,11 +107,10 @@ struct PeerInfo gid_t gid; }; - // Get the identity of the caller, if possible. static PeerInfo getPeerInfo(int remote) { - PeerInfo peer = { false, 0, false, 0, false, 0 }; + PeerInfo peer = {false, 0, false, 0, false, 0}; #if defined(SO_PEERCRED) @@ -119,7 +118,7 @@ static PeerInfo getPeerInfo(int remote) socklen_t credLen = sizeof(cred); if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == -1) throw SysError("getting peer credentials"); - peer = { true, cred.pid, true, cred.uid, true, cred.gid }; + peer = {true, cred.pid, true, cred.uid, true, cred.gid}; #elif defined(LOCAL_PEERCRED) @@ -131,17 +130,15 @@ static PeerInfo getPeerInfo(int remote) socklen_t credLen = sizeof(cred); if (getsockopt(remote, SOL_LOCAL, LOCAL_PEERCRED, &cred, &credLen) == -1) throw SysError("getting peer credentials"); - peer = { false, 0, true, cred.cr_uid, false, 0 }; + peer = {false, 0, true, cred.cr_uid, false, 0}; #endif return peer; } - #define SD_LISTEN_FDS_START 3 - static ref openUncachedStore() { Store::Params params; // FIXME: get params from somewhere @@ -150,7 +147,6 @@ static ref openUncachedStore() return openStore(settings.storeUri, params); } - static void daemonLoop() { if (chdir("/") == -1) @@ -184,11 +180,11 @@ static void daemonLoop() struct sockaddr_un remoteAddr; socklen_t remoteAddrLen = sizeof(remoteAddr); - AutoCloseFD remote = accept(fdSocket.get(), - (struct sockaddr *) &remoteAddr, &remoteAddrLen); + AutoCloseFD remote = accept(fdSocket.get(), (struct sockaddr *) &remoteAddr, &remoteAddrLen); checkInterrupt(); if (!remote) { - if (errno == EINTR) continue; + if (errno == EINTR) + continue; throw SysError("accepting connection"); } @@ -212,9 +208,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) : "") - % (peer.uidKnown ? user : "")); + printInfo( + format((std::string) "accepted connection from pid %1%, user %2%" + (trusted ? " (trusted)" : "")) + % (peer.pidKnown ? std::to_string(peer.pid) : "") % (peer.uidKnown ? user : "")); // Fork a child to handle the connection. ProcessOptions options; @@ -222,37 +218,39 @@ static void daemonLoop() options.dieWithParent = false; options.runExitHandlers = true; options.allowVfork = false; - startProcess([&]() { - fdSocket = -1; - - // Background the daemon. - if (setsid() == -1) - throw SysError("creating a new session"); - - // Restore normal handling of SIGCHLD. - setSigChldAction(false); - - // For debugging, stuff the pid into argv[1]. - if (peer.pidKnown && savedArgv[1]) { - auto processName = std::to_string(peer.pid); - strncpy(savedArgv[1], processName.c_str(), strlen(savedArgv[1])); - } - - // Handle the connection. - FdSource from(remote.get()); - FdSink to(remote.get()); - processConnection(openUncachedStore(), from, to, trusted, NotRecursive, [&](Store & store) { + startProcess( + [&]() { + fdSocket = -1; + + // Background the daemon. + if (setsid() == -1) + throw SysError("creating a new session"); + + // Restore normal handling of SIGCHLD. + setSigChldAction(false); + + // For debugging, stuff the pid into argv[1]. + if (peer.pidKnown && savedArgv[1]) { + auto processName = std::to_string(peer.pid); + strncpy(savedArgv[1], processName.c_str(), strlen(savedArgv[1])); + } + + // Handle the connection. + FdSource from(remote.get()); + FdSink to(remote.get()); + processConnection(openUncachedStore(), from, to, trusted, NotRecursive, [&](Store & store) { #if 0 /* Prevent users from doing something very dangerous. */ if (geteuid() == 0 && querySetting("build-users-group", "") == "") throw Error("if you run 'nix-daemon' as root, then you MUST set 'build-users-group'!"); #endif - store.createUser(user, peer.uid); - }); + store.createUser(user, peer.uid); + }); - exit(0); - }, options); + exit(0); + }, + options); } catch (Interrupted & e) { return; @@ -302,13 +300,13 @@ static void runDaemon(bool stdio) /* Auth hook is empty because in this mode we blindly trust the standard streams. Limiting access to those is explicitly not `nix-daemon`'s responsibility. */ - processConnection(openUncachedStore(), from, to, Trusted, NotRecursive, [&](Store & _){}); + processConnection(openUncachedStore(), from, to, Trusted, NotRecursive, [&](Store & _) {}); } } else daemonLoop(); } -static int main_nix_daemon(int argc, char * * argv) +static int main_nix_daemon(int argc, char ** argv) { { auto stdio = false; @@ -322,7 +320,8 @@ static int main_nix_daemon(int argc, char * * argv) printVersion("nix-daemon"); else if (*arg == "--stdio") stdio = true; - else return false; + else + return false; return true; }); @@ -341,13 +340,16 @@ struct CmdDaemon : StoreCommand return "daemon to perform store operations on behalf of non-root clients"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } std::string doc() override { return - #include "daemon.md" - ; +#include "daemon.md" + ; } void run(ref store) override diff --git a/src/nix/describe-stores.cc b/src/nix/describe-stores.cc index 1dd384c0e340..8705a0039a08 100644 --- a/src/nix/describe-stores.cc +++ b/src/nix/describe-stores.cc @@ -14,7 +14,10 @@ struct CmdDescribeStores : Command, MixJSON return "show registered store types and their available options"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { @@ -32,7 +35,7 @@ struct CmdDescribeStores : Command, MixJSON for (auto & [optionName, optionDesc] : storeConfig.items()) { std::cout << "### " << optionName << std::endl << std::endl; std::cout << optionDesc["description"].get() << std::endl; - std::cout << "default: " << optionDesc["defaultValue"] << std::endl < bashPrompt{this, "", "bash-prompt", - "The bash prompt (`PS1`) in `nix develop` shells."}; + Setting bashPrompt{this, "", "bash-prompt", "The bash prompt (`PS1`) in `nix develop` shells."}; - Setting bashPromptPrefix{this, "", "bash-prompt-prefix", - "Prefix prepended to the `PS1` environment variable in `nix develop` shells."}; + Setting bashPromptPrefix{ + this, "", "bash-prompt-prefix", "Prefix prepended to the `PS1` environment variable in `nix develop` shells."}; - Setting bashPromptSuffix{this, "", "bash-prompt-suffix", - "Suffix appended to the `PS1` environment variable in `nix develop` shells."}; + Setting bashPromptSuffix{ + this, "", "bash-prompt-suffix", "Suffix appended to the `PS1` environment variable in `nix develop` shells."}; }; static DevelopSettings developSettings; @@ -36,7 +35,7 @@ struct BuildEnvironment bool exported; std::string value; - bool operator == (const String & other) const + bool operator==(const String & other) const { return exported == other.exported && value == other.value; } @@ -62,7 +61,8 @@ struct BuildEnvironment for (auto & [name, info] : json["variables"].items()) { std::string type = info["type"]; if (type == "var" || type == "exported") - res.vars.insert({name, BuildEnvironment::String { .exported = type == "exported", .value = info["value"] }}); + res.vars.insert( + {name, BuildEnvironment::String{.exported = type == "exported", .value = info["value"]}}); else if (type == "array") res.vars.insert({name, (Array) info["value"]}); else if (type == "associative") @@ -86,12 +86,10 @@ struct BuildEnvironment if (auto str = std::get_if(&value)) { info["type"] = str->exported ? "exported" : "var"; info["value"] = str->value; - } - else if (auto arr = std::get_if(&value)) { + } else if (auto arr = std::get_if(&value)) { info["type"] = "array"; info["value"] = *arr; - } - else if (auto arr = std::get_if(&value)) { + } else if (auto arr = std::get_if(&value)) { info["type"] = "associative"; info["value"] = *arr; } @@ -116,14 +114,12 @@ struct BuildEnvironment out << fmt("%s=%s\n", name, shellEscape(str->value)); if (str->exported) out << fmt("export %s\n", name); - } - else if (auto arr = std::get_if(&value)) { + } else if (auto arr = std::get_if(&value)) { out << "declare -a " << name << "=("; for (auto & s : *arr) out << shellEscape(s) << " "; out << ")\n"; - } - else if (auto arr = std::get_if(&value)) { + } else if (auto arr = std::get_if(&value)) { out << "declare -A " << name << "=("; for (auto & [n, v] : *arr) out << "[" << shellEscape(n) << "]=" << shellEscape(v) << " "; @@ -155,19 +151,18 @@ struct BuildEnvironment Array assocKeys; std::for_each(assoc->begin(), assoc->end(), [&](auto & n) { assocKeys.push_back(n.first); }); return assocKeys; - } - else + } else throw Error("bash variable is not a string or array"); } - bool operator == (const BuildEnvironment & other) const + bool operator==(const BuildEnvironment & other) const { return vars == other.vars && bashFunctions == other.bashFunctions; } }; const static std::string getEnvSh = - #include "get-env.sh.gen.hh" +#include "get-env.sh.gen.hh" ; /* Given an existing derivation, return the shell environment as @@ -199,12 +194,11 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore drv.inputSrcs.insert(std::move(getEnvShPath)); if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { for (auto & output : drv.outputs) { - output.second = DerivationOutput::Deferred {}, - drv.env[output.first] = hashPlaceholder(output.first); + output.second = DerivationOutput::Deferred{}, drv.env[output.first] = hashPlaceholder(output.first); } } else { for (auto & output : drv.outputs) { - output.second = DerivationOutput::Deferred { }; + output.second = DerivationOutput::Deferred{}; drv.env[output.first] = ""; } auto hashesModulo = hashDerivationModulo(*evalStore, drv, true); @@ -212,7 +206,7 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore for (auto & output : drv.outputs) { Hash h = hashesModulo.hashes.at(output.first); auto outPath = store->makeOutputPath(output.first, h, drv.name); - output.second = DerivationOutput::InputAddressed { + output.second = DerivationOutput::InputAddressed{ .path = outPath, }; drv.env[output.first] = store->printStorePath(outPath); @@ -241,19 +235,13 @@ struct Common : InstallableCommand, MixProfile std::set ignoreVars{ "BASHOPTS", "HOME", // FIXME: don't ignore in pure mode? - "NIX_BUILD_TOP", - "NIX_ENFORCE_PURITY", - "NIX_LOG_FD", - "NIX_REMOTE", - "PPID", - "SHELLOPTS", + "NIX_BUILD_TOP", "NIX_ENFORCE_PURITY", + "NIX_LOG_FD", "NIX_REMOTE", + "PPID", "SHELLOPTS", "SSL_CERT_FILE", // FIXME: only want to ignore /no-cert-file.crt - "TEMP", - "TEMPDIR", - "TERM", - "TMP", - "TMPDIR", - "TZ", + "TEMP", "TEMPDIR", + "TERM", "TMP", + "TMPDIR", "TZ", "UID", }; @@ -261,14 +249,13 @@ struct Common : InstallableCommand, MixProfile Common() { - addFlag({ - .longName = "redirect", - .description = "Redirect a store path to a mutable location.", - .labels = {"installable", "outputs-dir"}, - .handler = {[&](std::string installable, std::string outputsDir) { - redirects.push_back({installable, outputsDir}); - }} - }); + addFlag( + {.longName = "redirect", + .description = "Redirect a store path to a mutable location.", + .labels = {"installable", "outputs-dir"}, + .handler = {[&](std::string installable, std::string outputsDir) { + redirects.push_back({installable, outputsDir}); + }}}); } std::string makeRcScript( @@ -311,9 +298,9 @@ struct Common : InstallableCommand, MixProfile for (auto & [installable_, dir_] : redirects) { auto dir = absPath(dir_); auto installable = parseInstallable(store, installable_); - auto builtPaths = Installable::toStorePaths( - getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable}); - for (auto & path: builtPaths) { + auto builtPaths = + Installable::toStorePaths(getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable}); + for (auto & path : builtPaths) { auto from = store->printStorePath(path); if (script.find(from) == std::string::npos) warn("'%s' (path '%s') is not used by this build environment", installable->what(), from); @@ -354,7 +341,8 @@ struct Common : InstallableCommand, MixProfile auto drvs = Installable::toDerivations(store, {installable}); if (drvs.size() != 1) - throw Error("'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations", + throw Error( + "'%s' needs to evaluate to a single derivation, but it evaluated to %d derivations", installable->what(), drvs.size()); auto & drvPath = *drvs.begin(); @@ -384,16 +372,16 @@ struct CmdDevelop : Common, MixEnvironment CmdDevelop() { - addFlag({ - .longName = "command", - .shortName = 'c', - .description = "Instead of starting an interactive shell, start the specified command and arguments.", - .labels = {"command", "args"}, - .handler = {[&](std::vector ss) { - if (ss.empty()) throw UsageError("--command requires at least one argument"); - command = ss; - }} - }); + addFlag( + {.longName = "command", + .shortName = 'c', + .description = "Instead of starting an interactive shell, start the specified command and arguments.", + .labels = {"command", "args"}, + .handler = {[&](std::vector ss) { + if (ss.empty()) + throw UsageError("--command requires at least one argument"); + command = ss; + }}}); addFlag({ .longName = "phase", @@ -447,8 +435,8 @@ struct CmdDevelop : Common, MixEnvironment std::string doc() override { return - #include "develop.md" - ; +#include "develop.md" + ; } void run(ref store) override @@ -483,14 +471,12 @@ struct CmdDevelop : Common, MixEnvironment else { script = "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n" + script; if (developSettings.bashPrompt != "") - script += fmt("[ -n \"$PS1\" ] && PS1=%s;\n", - shellEscape(developSettings.bashPrompt.get())); + script += fmt("[ -n \"$PS1\" ] && PS1=%s;\n", shellEscape(developSettings.bashPrompt.get())); if (developSettings.bashPromptPrefix != "") - script += fmt("[ -n \"$PS1\" ] && PS1=%s\"$PS1\";\n", - shellEscape(developSettings.bashPromptPrefix.get())); + script += + fmt("[ -n \"$PS1\" ] && PS1=%s\"$PS1\";\n", shellEscape(developSettings.bashPromptPrefix.get())); if (developSettings.bashPromptSuffix != "") - script += fmt("[ -n \"$PS1\" ] && PS1+=%s;\n", - shellEscape(developSettings.bashPromptSuffix.get())); + script += fmt("[ -n \"$PS1\" ] && PS1+=%s;\n", shellEscape(developSettings.bashPromptSuffix.get())); } writeFull(rcFileFd.get(), script); @@ -509,18 +495,13 @@ struct CmdDevelop : Common, MixEnvironment nixpkgsLockFlags.inputUpdates = {}; auto bashInstallable = std::make_shared( - this, - state, - installable->nixpkgsFlakeRef(), - "bashInteractive", - DefaultOutputs(), - Strings{}, - Strings{"legacyPackages." + settings.thisSystem.get() + "."}, - nixpkgsLockFlags); + this, state, installable->nixpkgsFlakeRef(), "bashInteractive", DefaultOutputs(), Strings{}, + Strings{"legacyPackages." + settings.thisSystem.get() + "."}, nixpkgsLockFlags); bool found = false; - for (auto & path : Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, {bashInstallable})) { + for (auto & path : Installable::toStorePaths( + getEvalStore(), store, Realise::Outputs, OperateOn::Output, {bashInstallable})) { auto s = store->printStorePath(path) + "/bin/bash"; if (pathExists(s)) { shell = s; @@ -539,7 +520,7 @@ struct CmdDevelop : Common, MixEnvironment // If running a phase or single command, don't want an interactive shell running after // Ctrl-C, so don't pass --rcfile auto args = phase || !command.empty() ? Strings{std::string(baseNameOf(shell)), rcFilePath} - : Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; + : Strings{std::string(baseNameOf(shell)), "--rcfile", rcFilePath}; // Need to chdir since phases assume in flake directory if (phase) { @@ -569,11 +550,14 @@ struct CmdPrintDevEnv : Common, MixJSON std::string doc() override { return - #include "print-dev-env.md" - ; +#include "print-dev-env.md" + ; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run(ref store) override { @@ -581,10 +565,7 @@ struct CmdPrintDevEnv : Common, MixJSON stopProgressBar(); - logger->writeToStdout( - json - ? buildEnvironment.toJSON() - : makeRcScript(store, buildEnvironment)); + logger->writeToStdout(json ? buildEnvironment.toJSON() : makeRcScript(store, buildEnvironment)); } }; diff --git a/src/nix/diff-closures.cc b/src/nix/diff-closures.cc index 0621d662c653..5dac755901af 100644 --- a/src/nix/diff-closures.cc +++ b/src/nix/diff-closures.cc @@ -37,7 +37,7 @@ GroupedPaths getClosureInfo(ref store, const StorePath & toplevel) } DrvName drvName(name); - groupedPaths[drvName.name][drvName.version].emplace(path, Info { .outputName = outputName }); + groupedPaths[drvName.name][drvName.version].emplace(path, Info{.outputName = outputName}); } return groupedPaths; @@ -45,7 +45,8 @@ GroupedPaths getClosureInfo(ref store, const StorePath & toplevel) std::string showVersions(const std::set & versions) { - if (versions.empty()) return "∅"; + if (versions.empty()) + return "∅"; std::set versions2; for (auto & version : versions) versions2.insert(version.empty() ? "ε" : version); @@ -53,24 +54,22 @@ std::string showVersions(const std::set & versions) } void printClosureDiff( - ref store, - const StorePath & beforePath, - const StorePath & afterPath, - std::string_view indent) + ref store, const StorePath & beforePath, const StorePath & afterPath, std::string_view indent) { auto beforeClosure = getClosureInfo(store, beforePath); auto afterClosure = getClosureInfo(store, afterPath); std::set allNames; - for (auto & [name, _] : beforeClosure) allNames.insert(name); - for (auto & [name, _] : afterClosure) allNames.insert(name); + for (auto & [name, _] : beforeClosure) + allNames.insert(name); + for (auto & [name, _] : afterClosure) + allNames.insert(name); for (auto & name : allNames) { auto & beforeVersions = beforeClosure[name]; auto & afterVersions = afterClosure[name]; - auto totalSize = [&](const std::map> & versions) - { + auto totalSize = [&](const std::map> & versions) { uint64_t sum = 0; for (auto & [_, paths] : versions) for (auto & [path, _] : paths) @@ -85,18 +84,23 @@ void printClosureDiff( std::set removed, unchanged; for (auto & [version, _] : beforeVersions) - if (!afterVersions.count(version)) removed.insert(version); else unchanged.insert(version); + if (!afterVersions.count(version)) + removed.insert(version); + else + unchanged.insert(version); std::set added; for (auto & [version, _] : afterVersions) - if (!beforeVersions.count(version)) added.insert(version); + if (!beforeVersions.count(version)) + added.insert(version); if (showDelta || !removed.empty() || !added.empty()) { std::vector items; if (!removed.empty() || !added.empty()) 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)); + 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)); } } @@ -124,8 +128,8 @@ struct CmdDiffClosures : SourceExprCommand std::string doc() override { return - #include "diff-closures.md" - ; +#include "diff-closures.md" + ; } void run(ref store) override diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc index ea87e3d87449..d5aa118c15cb 100644 --- a/src/nix/doctor.cc +++ b/src/nix/doctor.cc @@ -23,12 +23,14 @@ std::string formatProtocol(unsigned int proto) return "unknown"; } -bool checkPass(const std::string & msg) { +bool checkPass(const std::string & msg) +{ notice(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg); return true; } -bool checkFail(const std::string & msg) { +bool checkFail(const std::string & msg) +{ notice(ANSI_RED "[FAIL] " ANSI_NORMAL + msg); return false; } @@ -44,7 +46,10 @@ struct CmdDoctor : StoreCommand return "check your system for potential problems and print a PASS or FAIL for each check"; } - Category category() override { return catNixInstallation; } + Category category() override + { + return catNixInstallation; + } void run(ref store) override { @@ -95,7 +100,8 @@ struct CmdDoctor : StoreCommand if (profileDir.find("/profiles/") == std::string::npos) dirs.insert(dir); } - } catch (SysError &) {} + } catch (SysError &) { + } } if (!dirs.empty()) { @@ -115,8 +121,8 @@ struct CmdDoctor : StoreCommand bool checkStoreProtocol(unsigned int storeProto) { unsigned int clientProto = GET_PROTOCOL_MAJOR(SERVE_PROTOCOL_VERSION) == GET_PROTOCOL_MAJOR(storeProto) - ? SERVE_PROTOCOL_VERSION - : PROTOCOL_VERSION; + ? SERVE_PROTOCOL_VERSION + : PROTOCOL_VERSION; if (clientProto != storeProto) { std::stringstream ss; diff --git a/src/nix/dump-path.cc b/src/nix/dump-path.cc index c4edc894b896..fd771531ad88 100644 --- a/src/nix/dump-path.cc +++ b/src/nix/dump-path.cc @@ -14,8 +14,8 @@ struct CmdDumpPath : StorePathCommand std::string doc() override { return - #include "store-dump-path.md" - ; +#include "store-dump-path.md" + ; } void run(ref store, const StorePath & storePath) override @@ -34,11 +34,7 @@ struct CmdDumpPath2 : Command CmdDumpPath2() { - expectArgs({ - .label = "path", - .handler = {&path}, - .completer = completePath - }); + expectArgs({.label = "path", .handler = {&path}, .completer = completePath}); } std::string description() override @@ -49,8 +45,8 @@ struct CmdDumpPath2 : Command std::string doc() override { return - #include "nar-dump-path.md" - ; +#include "nar-dump-path.md" + ; } void run() override diff --git a/src/nix/edit.cc b/src/nix/edit.cc index 76a134b1f67c..246915f33740 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -18,11 +18,14 @@ struct CmdEdit : InstallableCommand std::string doc() override { return - #include "edit.md" - ; +#include "edit.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run(ref store) override { @@ -47,7 +50,8 @@ struct CmdEdit : InstallableCommand execvp(args.front().c_str(), stringsToCharPtrs(args).data()); std::string command; - for (const auto &arg : args) command += " '" + arg + "'"; + for (const auto & arg : args) + command += " '" + arg + "'"; throw SysError("cannot run command%s", command); } }; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 967dc851907f..a7891c3014af 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -16,7 +16,8 @@ struct CmdEval : MixJSON, InstallableCommand std::optional apply; std::optional writeTo; - CmdEval() : InstallableCommand(true /* supportReadOnlyMode */) + CmdEval() + : InstallableCommand(true /* supportReadOnlyMode */) { addFlag({ .longName = "raw", @@ -47,11 +48,14 @@ struct CmdEval : MixJSON, InstallableCommand std::string doc() override { return - #include "eval.md" - ; +#include "eval.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run(ref store) override { @@ -79,8 +83,7 @@ struct CmdEval : MixJSON, InstallableCommand std::function recurse; - recurse = [&](Value & v, const PosIdx pos, const Path & path) - { + recurse = [&](Value & v, const PosIdx pos, const Path & path) { state->forceValue(v, pos); if (v.type() == nString) // FIXME: disallow strings with contexts? @@ -96,13 +99,11 @@ struct CmdEval : MixJSON, InstallableCommand recurse(*attr.value, attr.pos, concatStrings(path, "/", name)); } catch (Error & e) { e.addTrace( - state->positions[attr.pos], - hintfmt("while evaluating the attribute '%s'", name)); + state->positions[attr.pos], hintfmt("while evaluating the attribute '%s'", name)); throw; } } - } - else + } else throw TypeError("value at '%s' is not a string or an attribute set", state->positions[pos]); }; diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 8370b8dcf02f..6b399f72f6a7 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -30,19 +30,16 @@ class FlakeCommand : virtual Args, public MixFlakeOptions FlakeCommand() { - expectArgs({ - .label = "flake-url", - .optional = true, - .handler = {&flakeUrl}, - .completer = {[&](size_t, std::string_view prefix) { - completeFlakeRef(getStore(), prefix); - }} - }); + expectArgs( + {.label = "flake-url", + .optional = true, + .handler = {&flakeUrl}, + .completer = {[&](size_t, std::string_view prefix) { completeFlakeRef(getStore(), prefix); }}}); } FlakeRef getFlakeRef() { - return parseFlakeRef(flakeUrl, absPath(".")); //FIXME + return parseFlakeRef(flakeUrl, absPath(".")); // FIXME } LockedFlake lockFlake() @@ -75,8 +72,8 @@ struct CmdFlakeUpdate : FlakeCommand std::string doc() override { return - #include "flake-update.md" - ; +#include "flake-update.md" + ; } void run(nix::ref store) override @@ -107,8 +104,8 @@ struct CmdFlakeLock : FlakeCommand std::string doc() override { return - #include "flake-lock.md" - ; +#include "flake-lock.md" + ; } void run(nix::ref store) override @@ -122,7 +119,9 @@ struct CmdFlakeLock : FlakeCommand } }; -static void enumerateOutputs(EvalState & state, Value & vFlake, +static void enumerateOutputs( + EvalState & state, + Value & vFlake, std::function callback) { auto pos = vFlake.determinePos(noPos); @@ -157,8 +156,8 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON std::string doc() override { return - #include "flake-metadata.md" - ; +#include "flake-metadata.md" + ; } void run(nix::ref store) override @@ -186,27 +185,16 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON j["locks"] = lockedFlake.lockFile.toJSON(); logger->cout("%s", j.dump()); } else { - logger->cout( - ANSI_BOLD "Resolved URL:" ANSI_NORMAL " %s", - flake.resolvedRef.to_string()); - logger->cout( - ANSI_BOLD "Locked URL:" ANSI_NORMAL " %s", - flake.lockedRef.to_string()); + logger->cout(ANSI_BOLD "Resolved URL:" ANSI_NORMAL " %s", flake.resolvedRef.to_string()); + logger->cout(ANSI_BOLD "Locked URL:" ANSI_NORMAL " %s", flake.lockedRef.to_string()); if (flake.description) - logger->cout( - ANSI_BOLD "Description:" ANSI_NORMAL " %s", - *flake.description); + logger->cout(ANSI_BOLD "Description:" ANSI_NORMAL " %s", *flake.description); logger->cout( - ANSI_BOLD "Path:" ANSI_NORMAL " %s", - store->printStorePath(flake.sourceInfo->storePath)); + ANSI_BOLD "Path:" ANSI_NORMAL " %s", store->printStorePath(flake.sourceInfo->storePath)); if (auto rev = flake.lockedRef.input.getRev()) - logger->cout( - ANSI_BOLD "Revision:" ANSI_NORMAL " %s", - rev->to_string(Base16, false)); + logger->cout(ANSI_BOLD "Revision:" ANSI_NORMAL " %s", rev->to_string(Base16, false)); if (auto revCount = flake.lockedRef.input.getRevCount()) - logger->cout( - ANSI_BOLD "Revisions:" ANSI_NORMAL " %s", - *revCount); + logger->cout(ANSI_BOLD "Revisions:" ANSI_NORMAL " %s", *revCount); if (auto lastModified = flake.lockedRef.input.getLastModified()) logger->cout( ANSI_BOLD "Last modified:" ANSI_NORMAL " %s", @@ -218,23 +206,23 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON std::function recurse; - recurse = [&](const Node & node, const std::string & prefix) - { + recurse = [&](const Node & node, const std::string & prefix) { for (const auto & [i, input] : enumerate(node.inputs)) { bool last = i + 1 == node.inputs.size(); if (auto lockedNode = std::get_if<0>(&input.second)) { - logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s", - prefix + (last ? treeLast : treeConn), input.first, + logger->cout( + "%s" ANSI_BOLD "%s" ANSI_NORMAL ": %s", prefix + (last ? treeLast : treeConn), input.first, *lockedNode ? (*lockedNode)->lockedRef : flake.lockedRef); bool firstVisit = visited.insert(*lockedNode).second; - if (firstVisit) recurse(**lockedNode, prefix + (last ? treeNull : treeLine)); + if (firstVisit) + recurse(**lockedNode, prefix + (last ? treeNull : treeLine)); } else if (auto follows = std::get_if<1>(&input.second)) { - logger->cout("%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'", - prefix + (last ? treeLast : treeConn), input.first, - printInputPath(*follows)); + logger->cout( + "%s" ANSI_BOLD "%s" ANSI_NORMAL " follows input '%s'", + prefix + (last ? treeLast : treeConn), input.first, printInputPath(*follows)); } } }; @@ -260,11 +248,7 @@ struct CmdFlakeCheck : FlakeCommand CmdFlakeCheck() { - addFlag({ - .longName = "no-build", - .description = "Do not build checks.", - .handler = {&build, false} - }); + addFlag({.longName = "no-build", .description = "Do not build checks.", .handler = {&build, false}}); } std::string description() override @@ -275,8 +259,8 @@ struct CmdFlakeCheck : FlakeCommand std::string doc() override { return - #include "flake-check.md" - ; +#include "flake-check.md" + ; } void run(nix::ref store) override @@ -299,24 +283,18 @@ struct CmdFlakeCheck : FlakeCommand if (settings.keepGoing) { ignoreException(); hasErrors = true; - } - else + } else throw; } }; // FIXME: rewrite to use EvalCache. - auto resolve = [&] (PosIdx p) { - return state->positions[p]; - }; + auto resolve = [&](PosIdx p) { return state->positions[p]; }; - auto argHasName = [&] (Symbol arg, std::string_view expected) { + auto argHasName = [&](Symbol arg, std::string_view expected) { std::string_view name = state->symbols[arg]; - return - name == expected - || name == "_" - || (hasPrefix(name, "_") && name.substr(1) == expected); + return name == expected || name == "_" || (hasPrefix(name, "_") && name.substr(1) == expected); }; auto checkSystemName = [&](const std::string & system, const PosIdx pos) { @@ -325,7 +303,8 @@ struct CmdFlakeCheck : FlakeCommand reportError(Error("'%s' is not a valid system type, at %s", system, resolve(pos))); }; - auto checkDerivation = [&](const std::string & attrPath, Value & v, const PosIdx pos) -> std::optional { + auto checkDerivation = [&](const std::string & attrPath, Value & v, + const PosIdx pos) -> std::optional { try { auto drvInfo = getDerivation(*state, v, false); if (!drvInfo) @@ -343,14 +322,14 @@ struct CmdFlakeCheck : FlakeCommand auto checkApp = [&](const std::string & attrPath, Value & v, const PosIdx pos) { try { - #if 0 +#if 0 // FIXME auto app = App(*state, v); for (auto & i : app.context) { auto [drvPathS, outputName] = decodeContext(i); store->parseStorePath(drvPathS); } - #endif +#endif } catch (Error & e) { e.addTrace(resolve(pos), hintfmt("while checking the app definition '%s'", attrPath)); reportError(e); @@ -360,14 +339,10 @@ struct CmdFlakeCheck : FlakeCommand auto checkOverlay = [&](const std::string & attrPath, Value & v, const PosIdx pos) { try { state->forceValue(v, pos); - if (!v.isLambda() - || v.lambda.fun->hasFormals() - || !argHasName(v.lambda.fun->arg, "final")) + if (!v.isLambda() || v.lambda.fun->hasFormals() || !argHasName(v.lambda.fun->arg, "final")) throw Error("overlay does not take an argument named 'final'"); auto body = dynamic_cast(v.lambda.fun->body); - if (!body - || body->hasFormals() - || !argHasName(body->arg, "prev")) + if (!body || body->hasFormals() || !argHasName(body->arg, "prev")) throw Error("overlay does not take an argument named 'prev'"); // FIXME: if we have a 'nixpkgs' input, use it to // evaluate the overlay. @@ -416,8 +391,7 @@ struct CmdFlakeCheck : FlakeCommand state->forceAttrs(*attr.value, attr.pos); auto attrPath2 = concatStrings(attrPath, ".", state->symbols[attr.name]); if (state->isDerivation(*attr.value)) { - Activity act(*logger, lvlChatty, actUnknown, - fmt("checking Hydra job '%s'", attrPath2)); + Activity act(*logger, lvlChatty, actUnknown, fmt("checking Hydra job '%s'", attrPath2)); checkDerivation(attrPath2, *attr.value, attr.pos); } else checkHydraJobs(attrPath2, *attr.value, attr.pos); @@ -431,8 +405,7 @@ struct CmdFlakeCheck : FlakeCommand auto checkNixOSConfiguration = [&](const std::string & attrPath, Value & v, const PosIdx pos) { try { - Activity act(*logger, lvlChatty, actUnknown, - fmt("checking NixOS configuration '%s'", attrPath)); + Activity act(*logger, lvlChatty, actUnknown, fmt("checking NixOS configuration '%s'", attrPath)); Bindings & bindings(*state->allocBindings(0)); auto vToplevel = findAlongAttrPath(*state, "config.system.build.toplevel", bindings, v).first; state->forceAttrs(*vToplevel, pos); @@ -446,8 +419,7 @@ struct CmdFlakeCheck : FlakeCommand auto checkTemplate = [&](const std::string & attrPath, Value & v, const PosIdx pos) { try { - Activity act(*logger, lvlChatty, actUnknown, - fmt("checking template '%s'", attrPath)); + Activity act(*logger, lvlChatty, actUnknown, fmt("checking template '%s'", attrPath)); state->forceAttrs(v, pos); @@ -496,185 +468,170 @@ struct CmdFlakeCheck : FlakeCommand auto vFlake = state->allocValue(); flake::callFlake(*state, flake, *vFlake); - enumerateOutputs(*state, - *vFlake, - [&](const std::string & name, Value & vOutput, const PosIdx pos) { - Activity act(*logger, lvlChatty, actUnknown, - fmt("checking flake output '%s'", name)); - - try { - evalSettings.enableImportFromDerivation.setDefault(name != "hydraJobs"); - - state->forceValue(vOutput, pos); - - std::string_view replacement = - name == "defaultPackage" ? "packages..default" : - name == "defaultApp" ? "apps..default" : - name == "defaultTemplate" ? "templates.default" : - name == "defaultBundler" ? "bundlers..default" : - name == "overlay" ? "overlays.default" : - name == "devShell" ? "devShells..default" : - name == "nixosModule" ? "nixosModules.default" : - ""; - if (replacement != "") - warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement); - - if (name == "checks") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - state->forceAttrs(*attr.value, attr.pos); - for (auto & attr2 : *attr.value->attrs) { - auto drvPath = checkDerivation( - fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), - *attr2.value, attr2.pos); - if (drvPath && attr_name == settings.thisSystem.get()) - drvPaths.push_back(DerivedPath::Built{*drvPath}); - } + enumerateOutputs(*state, *vFlake, [&](const std::string & name, Value & vOutput, const PosIdx pos) { + Activity act(*logger, lvlChatty, actUnknown, fmt("checking flake output '%s'", name)); + + try { + evalSettings.enableImportFromDerivation.setDefault(name != "hydraJobs"); + + state->forceValue(vOutput, pos); + + std::string_view replacement = name == "defaultPackage" ? "packages..default" + : name == "defaultApp" ? "apps..default" + : name == "defaultTemplate" ? "templates.default" + : name == "defaultBundler" ? "bundlers..default" + : name == "overlay" ? "overlays.default" + : name == "devShell" ? "devShells..default" + : name == "nixosModule" ? "nixosModules.default" + : ""; + if (replacement != "") + warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement); + + if (name == "checks") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + state->forceAttrs(*attr.value, attr.pos); + for (auto & attr2 : *attr.value->attrs) { + auto drvPath = checkDerivation( + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, + attr2.pos); + if (drvPath && attr_name == settings.thisSystem.get()) + drvPaths.push_back(DerivedPath::Built{*drvPath}); } } + } - else if (name == "formatter") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - checkApp( - fmt("%s.%s", name, attr_name), - *attr.value, attr.pos); - } + else if (name == "formatter") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + checkApp(fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } + } - else if (name == "packages" || name == "devShells") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - state->forceAttrs(*attr.value, attr.pos); - for (auto & attr2 : *attr.value->attrs) - checkDerivation( - fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), - *attr2.value, attr2.pos); - } + else if (name == "packages" || name == "devShells") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + state->forceAttrs(*attr.value, attr.pos); + for (auto & attr2 : *attr.value->attrs) + checkDerivation( + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, + attr2.pos); } + } - else if (name == "apps") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - state->forceAttrs(*attr.value, attr.pos); - for (auto & attr2 : *attr.value->attrs) - checkApp( - fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), - *attr2.value, attr2.pos); - } + else if (name == "apps") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + state->forceAttrs(*attr.value, attr.pos); + for (auto & attr2 : *attr.value->attrs) + checkApp( + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, + attr2.pos); } + } - else if (name == "defaultPackage" || name == "devShell") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - checkDerivation( - fmt("%s.%s", name, attr_name), - *attr.value, attr.pos); - } + else if (name == "defaultPackage" || name == "devShell") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + checkDerivation(fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } + } - else if (name == "defaultApp") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - checkApp( - fmt("%s.%s", name, attr_name), - *attr.value, attr.pos); - } + else if (name == "defaultApp") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + checkApp(fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } + } - else if (name == "legacyPackages") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - checkSystemName(state->symbols[attr.name], attr.pos); - // FIXME: do getDerivations? - } + else if (name == "legacyPackages") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + checkSystemName(state->symbols[attr.name], attr.pos); + // FIXME: do getDerivations? } + } - else if (name == "overlay") - checkOverlay(name, vOutput, pos); + else if (name == "overlay") + checkOverlay(name, vOutput, pos); - else if (name == "overlays") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) - checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]), - *attr.value, attr.pos); - } + else if (name == "overlays") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) + checkOverlay(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); + } - else if (name == "nixosModule") - checkModule(name, vOutput, pos); + else if (name == "nixosModule") + checkModule(name, vOutput, pos); - else if (name == "nixosModules") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) - checkModule(fmt("%s.%s", name, state->symbols[attr.name]), - *attr.value, attr.pos); - } + else if (name == "nixosModules") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) + checkModule(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); + } - else if (name == "nixosConfigurations") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) - checkNixOSConfiguration(fmt("%s.%s", name, state->symbols[attr.name]), - *attr.value, attr.pos); - } + else if (name == "nixosConfigurations") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) + checkNixOSConfiguration( + fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); + } - else if (name == "hydraJobs") - checkHydraJobs(name, vOutput, pos); + else if (name == "hydraJobs") + checkHydraJobs(name, vOutput, pos); - else if (name == "defaultTemplate") - checkTemplate(name, vOutput, pos); + else if (name == "defaultTemplate") + checkTemplate(name, vOutput, pos); - else if (name == "templates") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) - checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]), - *attr.value, attr.pos); - } + else if (name == "templates") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) + checkTemplate(fmt("%s.%s", name, state->symbols[attr.name]), *attr.value, attr.pos); + } - else if (name == "defaultBundler") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - checkBundler( - fmt("%s.%s", name, attr_name), - *attr.value, attr.pos); - } + else if (name == "defaultBundler") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + checkBundler(fmt("%s.%s", name, attr_name), *attr.value, attr.pos); } + } - else if (name == "bundlers") { - state->forceAttrs(vOutput, pos); - for (auto & attr : *vOutput.attrs) { - const auto & attr_name = state->symbols[attr.name]; - checkSystemName(attr_name, attr.pos); - state->forceAttrs(*attr.value, attr.pos); - for (auto & attr2 : *attr.value->attrs) { - checkBundler( - fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), - *attr2.value, attr2.pos); - } + else if (name == "bundlers") { + state->forceAttrs(vOutput, pos); + for (auto & attr : *vOutput.attrs) { + const auto & attr_name = state->symbols[attr.name]; + checkSystemName(attr_name, attr.pos); + state->forceAttrs(*attr.value, attr.pos); + for (auto & attr2 : *attr.value->attrs) { + checkBundler( + fmt("%s.%s.%s", name, attr_name, state->symbols[attr2.name]), *attr2.value, + attr2.pos); } } + } - else - warn("unknown flake output '%s'", name); + else + warn("unknown flake output '%s'", name); - } catch (Error & e) { - e.addTrace(resolve(pos), hintfmt("while checking flake output '%s'", name)); - reportError(e); - } - }); + } catch (Error & e) { + e.addTrace(resolve(pos), hintfmt("while checking flake output '%s'", name)); + reportError(e); + } + }); } if (build && !drvPaths.empty()) { @@ -694,25 +651,20 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand std::string templateUrl = "templates"; Path destDir; - const LockFlags lockFlags{ .writeLockFile = false }; + const LockFlags lockFlags{.writeLockFile = false}; CmdFlakeInitCommon() { - addFlag({ - .longName = "template", - .shortName = 't', - .description = "The template to use.", - .labels = {"template"}, - .handler = {&templateUrl}, - .completer = {[&](size_t, std::string_view prefix) { - completeFlakeRefWithFragment( - getEvalState(), - lockFlags, - defaultTemplateAttrPathsPrefixes, - defaultTemplateAttrPaths, - prefix); - }} - }); + addFlag( + {.longName = "template", + .shortName = 't', + .description = "The template to use.", + .labels = {"template"}, + .handler = {&templateUrl}, + .completer = {[&](size_t, std::string_view prefix) { + completeFlakeRefWithFragment( + getEvalState(), lockFlags, defaultTemplateAttrPathsPrefixes, defaultTemplateAttrPaths, prefix); + }}}); } void run(nix::ref store) override @@ -723,11 +675,9 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment(templateUrl, absPath(".")); - auto installable = InstallableFlake(nullptr, - evalState, std::move(templateFlakeRef), templateName, DefaultOutputs(), - defaultTemplateAttrPaths, - defaultTemplateAttrPathsPrefixes, - lockFlags); + auto installable = InstallableFlake( + nullptr, evalState, std::move(templateFlakeRef), templateName, DefaultOutputs(), defaultTemplateAttrPaths, + defaultTemplateAttrPathsPrefixes, lockFlags); auto cursor = installable.getCursor(*evalState); @@ -743,8 +693,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand std::vector files; std::function copyDir; - copyDir = [&](const Path & from, const Path & to) - { + copyDir = [&](const Path & from, const Path & to) { createDirs(to); for (auto & entry : readDirectory(from)) { @@ -761,16 +710,14 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand throw Error("refusing to overwrite existing file '%s'", to2); } else writeFile(to2, contents); - } - else if (S_ISLNK(st.st_mode)) { + } else if (S_ISLNK(st.st_mode)) { auto target = readLink(from2); if (pathExists(to2)) { if (readLink(to2) != target) throw Error("refusing to overwrite existing symlink '%s'", to2); } else - createSymlink(target, to2); - } - else + createSymlink(target, to2); + } else throw Error("file '%s' has unsupported type", from2); files.push_back(to2); notice("wrote: %s", to2); @@ -780,8 +727,9 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand copyDir(templateDir, flakeDir); if (pathExists(flakeDir + "/.git")) { - Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--force", "--" }; - for (auto & s : files) args.push_back(s); + Strings args = {"-C", flakeDir, "add", "--intent-to-add", "--force", "--"}; + for (auto & s : files) + args.push_back(s); runProgram("git", true, args); } auto welcomeText = cursor->maybeGetAttr("welcomeText"); @@ -802,8 +750,8 @@ struct CmdFlakeInit : CmdFlakeInitCommon std::string doc() override { return - #include "flake-init.md" - ; +#include "flake-init.md" + ; } CmdFlakeInit() @@ -822,17 +770,13 @@ struct CmdFlakeNew : CmdFlakeInitCommon std::string doc() override { return - #include "flake-new.md" - ; +#include "flake-new.md" + ; } CmdFlakeNew() { - expectArgs({ - .label = "dest-dir", - .handler = {&destDir}, - .completer = completePath - }); + expectArgs({.label = "dest-dir", .handler = {&destDir}, .completer = completePath}); } }; @@ -848,19 +792,18 @@ struct CmdFlakeClone : FlakeCommand std::string doc() override { return - #include "flake-clone.md" - ; +#include "flake-clone.md" + ; } CmdFlakeClone() { - addFlag({ - .longName = "dest", - .shortName = 'f', - .description = "Clone the flake to path *dest*.", - .labels = {"path"}, - .handler = {&destDir} - }); + addFlag( + {.longName = "dest", + .shortName = 'f', + .description = "Clone the flake to path *dest*.", + .labels = {"path"}, + .handler = {&destDir}}); } void run(nix::ref store) override @@ -878,12 +821,11 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun CmdFlakeArchive() { - addFlag({ - .longName = "to", - .description = "URI of the destination Nix store", - .labels = {"store-uri"}, - .handler = {&dstUri} - }); + addFlag( + {.longName = "to", + .description = "URI of the destination Nix store", + .labels = {"store-uri"}, + .handler = {&dstUri}}); } std::string description() override @@ -894,8 +836,8 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun std::string doc() override { return - #include "flake-archive.md" - ; +#include "flake-archive.md" + ; } void run(nix::ref store) override @@ -912,16 +854,13 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun // FIXME: use graph output, handle cycles. std::function & jsonObj)> traverse; - traverse = [&](const Node & node, std::optional & jsonObj) - { + traverse = [&](const Node & node, std::optional & jsonObj) { auto jsonObj2 = jsonObj ? jsonObj->object("inputs") : std::optional(); for (auto & [inputName, input] : node.inputs) { if (auto inputNode = std::get_if<0>(&input)) { auto jsonObj3 = jsonObj2 ? jsonObj2->object(inputName) : std::optional(); - auto storePath = - dryRun - ? (*inputNode)->lockedRef.input.computeStorePath(*store) - : (*inputNode)->lockedRef.input.fetch(store).first.storePath; + auto storePath = dryRun ? (*inputNode)->lockedRef.input.computeStorePath(*store) + : (*inputNode)->lockedRef.input.fetch(store).first.storePath; if (jsonObj3) jsonObj3->attr("path", store->printStorePath(storePath)); sources.insert(std::move(storePath)); @@ -945,11 +884,10 @@ struct CmdFlakeShow : FlakeCommand, MixJSON CmdFlakeShow() { - addFlag({ - .longName = "legacy", - .description = "Show the contents of the `legacyPackages` output.", - .handler = {&showLegacy, true} - }); + addFlag( + {.longName = "legacy", + .description = "Show the contents of the `legacyPackages` output.", + .handler = {&showLegacy, true}}); } std::string description() override @@ -960,8 +898,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON std::string doc() override { return - #include "flake-show.md" - ; +#include "flake-show.md" + ; } void run(nix::ref store) override @@ -972,28 +910,20 @@ struct CmdFlakeShow : FlakeCommand, MixJSON auto flake = std::make_shared(lockFlake()); std::function & attrPath, - const std::string & headerPrefix, - const std::string & nextPrefix)> visit; - - visit = [&]( - eval_cache::AttrCursor & visitor, - const std::vector & attrPath, - const std::string & headerPrefix, - const std::string & nextPrefix) - -> nlohmann::json - { + eval_cache::AttrCursor & visitor, const std::vector & attrPath, const std::string & headerPrefix, + const std::string & nextPrefix)> + visit; + + visit = [&](eval_cache::AttrCursor & visitor, const std::vector & attrPath, + const std::string & headerPrefix, const std::string & nextPrefix) -> nlohmann::json { auto j = nlohmann::json::object(); auto attrPathS = state->symbols.resolve(attrPath); - Activity act(*logger, lvlInfo, actUnknown, - fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); + Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); try { - auto recurse = [&]() - { + auto recurse = [&]() { if (!json) logger->cout("%s", headerPrefix); auto attrs = visitor.getAttrs(); @@ -1003,15 +933,17 @@ struct CmdFlakeShow : FlakeCommand, MixJSON auto visitor2 = visitor.getAttr(attrName); auto attrPath2(attrPath); attrPath2.push_back(attr); - auto j2 = visit(*visitor2, attrPath2, - fmt(ANSI_GREEN "%s%s" ANSI_NORMAL ANSI_BOLD "%s" ANSI_NORMAL, nextPrefix, last ? treeLast : treeConn, attrName), + auto j2 = visit( + *visitor2, attrPath2, + fmt(ANSI_GREEN "%s%s" ANSI_NORMAL ANSI_BOLD "%s" ANSI_NORMAL, nextPrefix, + last ? treeLast : treeConn, attrName), nextPrefix + (last ? treeNull : treeLine)); - if (json) j.emplace(attrName, std::move(j2)); + if (json) + j.emplace(attrName, std::move(j2)); } }; - auto showDerivation = [&]() - { + auto showDerivation = [&]() { auto name = visitor.getAttr(state->sName)->getString(); if (json) { std::optional description; @@ -1024,42 +956,34 @@ struct CmdFlakeShow : FlakeCommand, MixJSON if (description) j.emplace("description", *description); } else { - logger->cout("%s: %s '%s'", - headerPrefix, - attrPath.size() == 2 && attrPathS[0] == "devShell" ? "development environment" : - attrPath.size() >= 2 && attrPathS[0] == "devShells" ? "development environment" : - attrPath.size() == 3 && attrPathS[0] == "checks" ? "derivation" : - attrPath.size() >= 1 && attrPathS[0] == "hydraJobs" ? "derivation" : - "package", + logger->cout( + "%s: %s '%s'", headerPrefix, + attrPath.size() == 2 && attrPathS[0] == "devShell" ? "development environment" + : attrPath.size() >= 2 && attrPathS[0] == "devShells" ? "development environment" + : attrPath.size() == 3 && attrPathS[0] == "checks" ? "derivation" + : attrPath.size() >= 1 && attrPathS[0] == "hydraJobs" ? "derivation" + : "package", name); } }; if (attrPath.size() == 0 - || (attrPath.size() == 1 && ( - attrPathS[0] == "defaultPackage" - || attrPathS[0] == "devShell" - || attrPathS[0] == "formatter" - || attrPathS[0] == "nixosConfigurations" - || attrPathS[0] == "nixosModules" - || attrPathS[0] == "defaultApp" - || attrPathS[0] == "templates" - || attrPathS[0] == "overlays")) + || (attrPath.size() == 1 + && (attrPathS[0] == "defaultPackage" || attrPathS[0] == "devShell" + || attrPathS[0] == "formatter" || attrPathS[0] == "nixosConfigurations" + || attrPathS[0] == "nixosModules" || attrPathS[0] == "defaultApp" + || attrPathS[0] == "templates" || attrPathS[0] == "overlays")) || ((attrPath.size() == 1 || attrPath.size() == 2) - && (attrPathS[0] == "checks" - || attrPathS[0] == "packages" - || attrPathS[0] == "devShells" - || attrPathS[0] == "apps")) - ) - { + && (attrPathS[0] == "checks" || attrPathS[0] == "packages" || attrPathS[0] == "devShells" + || attrPathS[0] == "apps"))) { recurse(); } else if ( - (attrPath.size() == 2 && (attrPathS[0] == "defaultPackage" || attrPathS[0] == "devShell" || attrPathS[0] == "formatter")) - || (attrPath.size() == 3 && (attrPathS[0] == "checks" || attrPathS[0] == "packages" || attrPathS[0] == "devShells")) - ) - { + (attrPath.size() == 2 + && (attrPathS[0] == "defaultPackage" || attrPathS[0] == "devShell" || attrPathS[0] == "formatter")) + || (attrPath.size() == 3 + && (attrPathS[0] == "checks" || attrPathS[0] == "packages" || attrPathS[0] == "devShells"))) { if (visitor.isDerivation()) showDerivation(); else @@ -1076,9 +1000,10 @@ struct CmdFlakeShow : FlakeCommand, MixJSON else if (attrPath.size() > 0 && attrPathS[0] == "legacyPackages") { if (attrPath.size() == 1) recurse(); - else if (!showLegacy){ + else if (!showLegacy) { if (!json) - logger->cout(fmt("%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix)); + logger->cout(fmt( + "%s " ANSI_WARNING "omitted" ANSI_NORMAL " (use '--legacy' to show)", headerPrefix)); else { logger->warn(fmt("%s omitted (use '--legacy' to show)", concatStringsSep(".", attrPathS))); } @@ -1092,9 +1017,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON } else if ( - (attrPath.size() == 2 && attrPathS[0] == "defaultApp") || - (attrPath.size() == 3 && attrPathS[0] == "apps")) - { + (attrPath.size() == 2 && attrPathS[0] == "defaultApp") + || (attrPath.size() == 3 && attrPathS[0] == "apps")) { auto aType = visitor.maybeGetAttr("type"); if (!aType || aType->getString() != "app") throw EvalError("not an app definition"); @@ -1106,9 +1030,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON } else if ( - (attrPath.size() == 1 && attrPathS[0] == "defaultTemplate") || - (attrPath.size() == 2 && attrPathS[0] == "templates")) - { + (attrPath.size() == 1 && attrPathS[0] == "defaultTemplate") + || (attrPath.size() == 2 && attrPathS[0] == "templates")) { auto description = visitor.getAttr("description")->getString(); if (json) { j.emplace("type", "template"); @@ -1119,13 +1042,15 @@ struct CmdFlakeShow : FlakeCommand, MixJSON } else { - auto [type, description] = - (attrPath.size() == 1 && attrPathS[0] == "overlay") - || (attrPath.size() == 2 && attrPathS[0] == "overlays") ? std::make_pair("nixpkgs-overlay", "Nixpkgs overlay") : - attrPath.size() == 2 && attrPathS[0] == "nixosConfigurations" ? std::make_pair("nixos-configuration", "NixOS configuration") : - (attrPath.size() == 1 && attrPathS[0] == "nixosModule") - || (attrPath.size() == 2 && attrPathS[0] == "nixosModules") ? std::make_pair("nixos-module", "NixOS module") : - std::make_pair("unknown", "unknown"); + auto [type, description] = (attrPath.size() == 1 && attrPathS[0] == "overlay") + || (attrPath.size() == 2 && attrPathS[0] == "overlays") + ? std::make_pair("nixpkgs-overlay", "Nixpkgs overlay") + : attrPath.size() == 2 && attrPathS[0] == "nixosConfigurations" + ? std::make_pair("nixos-configuration", "NixOS configuration") + : (attrPath.size() == 1 && attrPathS[0] == "nixosModule") + || (attrPath.size() == 2 && attrPathS[0] == "nixosModules") + ? std::make_pair("nixos-module", "NixOS module") + : std::make_pair("unknown", "unknown"); if (json) { j.emplace("type", type); } else { @@ -1150,9 +1075,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON struct CmdFlakePrefetch : FlakeCommand, MixJSON { - CmdFlakePrefetch() - { - } + CmdFlakePrefetch() {} std::string description() override { @@ -1162,8 +1085,8 @@ struct CmdFlakePrefetch : FlakeCommand, MixJSON std::string doc() override { return - #include "flake-prefetch.md" - ; +#include "flake-prefetch.md" + ; } void run(ref store) override @@ -1179,9 +1102,8 @@ struct CmdFlakePrefetch : FlakeCommand, MixJSON res["hash"] = hash.to_string(SRI, true); logger->cout(res.dump()); } else { - notice("Downloaded '%s' to '%s' (hash '%s').", - lockedRef.to_string(), - store->printStorePath(tree.storePath), + notice( + "Downloaded '%s' to '%s' (hash '%s').", lockedRef.to_string(), store->printStorePath(tree.storePath), hash.to_string(SRI, true)); } } @@ -1191,20 +1113,19 @@ struct CmdFlake : NixMultiCommand { CmdFlake() : MultiCommand({ - {"update", []() { return make_ref(); }}, - {"lock", []() { return make_ref(); }}, - {"metadata", []() { return make_ref(); }}, - {"info", []() { return make_ref(); }}, - {"check", []() { return make_ref(); }}, - {"init", []() { return make_ref(); }}, - {"new", []() { return make_ref(); }}, - {"clone", []() { return make_ref(); }}, - {"archive", []() { return make_ref(); }}, - {"show", []() { return make_ref(); }}, - {"prefetch", []() { return make_ref(); }}, - }) - { - } + {"update", []() { return make_ref(); }}, + {"lock", []() { return make_ref(); }}, + {"metadata", []() { return make_ref(); }}, + {"info", []() { return make_ref(); }}, + {"check", []() { return make_ref(); }}, + {"init", []() { return make_ref(); }}, + {"new", []() { return make_ref(); }}, + {"clone", []() { return make_ref(); }}, + {"archive", []() { return make_ref(); }}, + {"show", []() { return make_ref(); }}, + {"prefetch", []() { return make_ref(); }}, + }) + {} std::string description() override { @@ -1214,8 +1135,8 @@ struct CmdFlake : NixMultiCommand std::string doc() override { return - #include "flake.md" - ; +#include "flake.md" + ; } void run() override diff --git a/src/nix/fmt.cc b/src/nix/fmt.cc index 6f6a4a632273..7d694d126313 100644 --- a/src/nix/fmt.cc +++ b/src/nix/fmt.cc @@ -3,28 +3,41 @@ using namespace nix; -struct CmdFmt : SourceExprCommand { +struct CmdFmt : SourceExprCommand +{ std::vector args; - CmdFmt() { expectArgs({.label = "args", .handler = {&args}}); } + CmdFmt() + { + expectArgs({.label = "args", .handler = {&args}}); + } - std::string description() override { + std::string description() override + { return "reformat your code in the standard style"; } - std::string doc() override { + std::string doc() override + { return - #include "fmt.md" - ; +#include "fmt.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } - Strings getDefaultFlakeAttrPaths() override { + Strings getDefaultFlakeAttrPaths() override + { return Strings{"formatter." + settings.thisSystem.get()}; } - Strings getDefaultFlakeAttrPathPrefixes() override { return Strings{}; } + Strings getDefaultFlakeAttrPathPrefixes() override + { + return Strings{}; + } void run(ref store) override { @@ -42,7 +55,7 @@ struct CmdFmt : SourceExprCommand { programArgs.push_back("."); } else { // User wants more power, let them decide which paths to include/exclude - for (auto &i : args) { + for (auto & i : args) { programArgs.push_back(i); } } diff --git a/src/nix/hash.cc b/src/nix/hash.cc index 60d9593a772a..e22c623b5516 100644 --- a/src/nix/hash.cc +++ b/src/nix/hash.cc @@ -17,7 +17,8 @@ struct CmdHashBase : Command std::vector paths; std::optional modulus; - CmdHashBase(FileIngestionMethod mode) : mode(mode) + CmdHashBase(FileIngestionMethod mode) + : mode(mode) { addFlag({ .longName = "sri", @@ -45,27 +46,23 @@ struct CmdHashBase : Command addFlag(Flag::mkHashTypeFlag("type", &ht)); - #if 0 +#if 0 addFlag({ .longName = "modulo", .description = "Compute the hash modulo the specified string.", .labels = {"modulus"}, .handler = {&modulus}, }); - #endif\ +#endif - expectArgs({ - .label = "paths", - .handler = {&paths}, - .completer = completePath - }); + expectArgs({.label = "paths", .handler = {&paths}, .completer = completePath}); } std::string description() override { switch (mode) { case FileIngestionMethod::Flat: - return "print cryptographic hash of a regular file"; + return "print cryptographic hash of a regular file"; case FileIngestionMethod::Recursive: return "print cryptographic hash of the NAR serialisation of a path"; default: @@ -93,7 +90,8 @@ struct CmdHashBase : Command } Hash h = hashSink->finish().first; - if (truncate && h.hashSize > 20) h = compressHash(h, 20); + if (truncate && h.hashSize > 20) + h = compressHash(h, 20); logger->cout(h.to_string(base, base == SRI)); } } @@ -105,7 +103,8 @@ struct CmdToBase : Command std::optional ht; std::vector args; - CmdToBase(Base base) : base(base) + CmdToBase(Base base) + : base(base) { addFlag(Flag::mkHashTypeOptFlag("type", &ht)); expectArgs("strings", &args); @@ -113,11 +112,11 @@ struct CmdToBase : Command std::string description() override { - return fmt("convert a hash to %s representation", - base == Base16 ? "base-16" : - base == Base32 ? "base-32" : - base == Base64 ? "base-64" : - "SRI"); + return fmt( + "convert a hash to %s representation", base == Base16 ? "base-16" + : base == Base32 ? "base-32" + : base == Base64 ? "base-64" + : "SRI"); } void run() override @@ -131,21 +130,28 @@ struct CmdHash : NixMultiCommand { CmdHash() : MultiCommand({ - {"file", []() { return make_ref(FileIngestionMethod::Flat);; }}, - {"path", []() { return make_ref(FileIngestionMethod::Recursive); }}, - {"to-base16", []() { return make_ref(Base16); }}, - {"to-base32", []() { return make_ref(Base32); }}, - {"to-base64", []() { return make_ref(Base64); }}, - {"to-sri", []() { return make_ref(SRI); }}, - }) - { } + {"file", + []() { + return make_ref(FileIngestionMethod::Flat); + ; + }}, + {"path", []() { return make_ref(FileIngestionMethod::Recursive); }}, + {"to-base16", []() { return make_ref(Base16); }}, + {"to-base32", []() { return make_ref(Base32); }}, + {"to-base64", []() { return make_ref(Base64); }}, + {"to-sri", []() { return make_ref(SRI); }}, + }) + {} std::string description() override { return "compute and convert cryptographic hashes"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { @@ -159,7 +165,7 @@ struct CmdHash : NixMultiCommand static auto rCmdHash = registerCommand("hash"); /* Legacy nix-hash command. */ -static int compatNixHash(int argc, char * * argv) +static int compatNixHash(int argc, char ** argv) { HashType ht = htMD5; bool flat = false; @@ -173,15 +179,19 @@ static int compatNixHash(int argc, char * * argv) showManPage("nix-hash"); else if (*arg == "--version") printVersion("nix-hash"); - else if (*arg == "--flat") flat = true; - else if (*arg == "--base32") base32 = true; - else if (*arg == "--truncate") truncate = true; + else if (*arg == "--flat") + flat = true; + else if (*arg == "--base32") + base32 = true; + else if (*arg == "--truncate") + truncate = true; else if (*arg == "--type") { std::string s = getArg(*arg, arg, end); ht = parseHashType(s); - } - else if (*arg == "--to-base16") op = opTo16; - else if (*arg == "--to-base32") op = opTo32; + } else if (*arg == "--to-base16") + op = opTo16; + else if (*arg == "--to-base32") + op = opTo32; else if (*arg != "" && arg->at(0) == '-') return false; else diff --git a/src/nix/log.cc b/src/nix/log.cc index 72d02ef11bb7..a458f22987ba 100644 --- a/src/nix/log.cc +++ b/src/nix/log.cc @@ -17,11 +17,14 @@ struct CmdLog : InstallableCommand std::string doc() override { return - #include "log.md" - ; +#include "log.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run(ref store) override { @@ -42,15 +45,14 @@ struct CmdLog : InstallableCommand } auto & logSub = *logSubP; - auto log = std::visit(overloaded { - [&](const DerivedPath::Opaque & bo) { - return logSub.getBuildLog(bo.path); + auto log = std::visit( + overloaded{ + [&](const DerivedPath::Opaque & bo) { return logSub.getBuildLog(bo.path); }, + [&](const DerivedPath::Built & bfd) { return logSub.getBuildLog(bfd.drvPath); }, }, - [&](const DerivedPath::Built & bfd) { - return logSub.getBuildLog(bfd.drvPath); - }, - }, b.raw()); - if (!log) continue; + b.raw()); + if (!log) + continue; stopProgressBar(); printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri()); std::cout << *log; diff --git a/src/nix/ls.cc b/src/nix/ls.cc index 07554994b3d8..3e01ebb43d62 100644 --- a/src/nix/ls.cc +++ b/src/nix/ls.cc @@ -46,11 +46,9 @@ struct MixLs : virtual Args, MixJSON auto showFile = [&](const Path & curPath, const std::string & relPath) { if (verbose) { auto st = accessor->stat(curPath); - std::string tp = - st.type == FSAccessor::Type::tRegular ? - (st.isExecutable ? "-r-xr-xr-x" : "-r--r--r--") : - st.type == FSAccessor::Type::tSymlink ? "lrwxrwxrwx" : - "dr-xr-xr-x"; + std::string tp = st.type == FSAccessor::Type::tRegular ? (st.isExecutable ? "-r-xr-xr-x" : "-r--r--r--") + : st.type == FSAccessor::Type::tSymlink ? "lrwxrwxrwx" + : "dr-xr-xr-x"; auto line = fmt("%s %20d %s", tp, st.fileSize, relPath); if (st.type == FSAccessor::Type::tSymlink) line += " -> " + accessor->readLink(curPath); @@ -67,9 +65,8 @@ struct MixLs : virtual Args, MixJSON } }; - doPath = [&](const FSAccessor::Stat & st, const Path & curPath, - const std::string & relPath, bool showDirectory) - { + doPath = [&](const FSAccessor::Stat & st, const Path & curPath, const std::string & relPath, + bool showDirectory) { if (st.type == FSAccessor::Type::tDirectory && !showDirectory) { auto names = accessor->readDirectory(curPath); for (auto & name : names) @@ -81,14 +78,13 @@ struct MixLs : virtual Args, MixJSON auto st = accessor->stat(path); if (st.type == FSAccessor::Type::tMissing) throw Error("path '%1%' does not exist", path); - doPath(st, path, - st.type == FSAccessor::Type::tDirectory ? "." : std::string(baseNameOf(path)), - showDirectory); + doPath(st, path, st.type == FSAccessor::Type::tDirectory ? "." : std::string(baseNameOf(path)), showDirectory); } void list(ref accessor) { - if (path == "/") path = ""; + if (path == "/") + path = ""; if (json) { JSONPlaceholder jsonRoot(std::cout); @@ -104,11 +100,7 @@ struct CmdLsStore : StoreCommand, MixLs { CmdLsStore() { - expectArgs({ - .label = "path", - .handler = {&path}, - .completer = completePath - }); + expectArgs({.label = "path", .handler = {&path}, .completer = completePath}); } std::string description() override @@ -119,8 +111,8 @@ struct CmdLsStore : StoreCommand, MixLs std::string doc() override { return - #include "store-ls.md" - ; +#include "store-ls.md" + ; } void run(ref store) override @@ -135,19 +127,15 @@ struct CmdLsNar : Command, MixLs CmdLsNar() { - expectArgs({ - .label = "nar", - .handler = {&narPath}, - .completer = completePath - }); + expectArgs({.label = "nar", .handler = {&narPath}, .completer = completePath}); expectArg("path", &path); } std::string doc() override { return - #include "nar-ls.md" - ; +#include "nar-ls.md" + ; } std::string description() override diff --git a/src/nix/main.cc b/src/nix/main.cc index 17c92ebc6128..d0890b914e3b 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -22,7 +22,7 @@ extern std::string chrootHelperName; -void chrootHelper(int argc, char * * argv); +void chrootHelper(int argc, char ** argv); namespace nix { @@ -37,14 +37,15 @@ static bool haveInternet() Finally free([&]() { freeifaddrs(addrs); }); for (auto i = addrs; i; i = i->ifa_next) { - if (!i->ifa_addr) continue; + if (!i->ifa_addr) + continue; if (i->ifa_addr->sa_family == AF_INET) { if (ntohl(((sockaddr_in *) i->ifa_addr)->sin_addr.s_addr) != INADDR_LOOPBACK) { return true; } } else if (i->ifa_addr->sa_family == AF_INET6) { - if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr) && - !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr)) + if (!IN6_IS_ADDR_LOOPBACK(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr) + && !IN6_IS_ADDR_LINKLOCAL(&((sockaddr_in6 *) i->ifa_addr)->sin6_addr)) return true; } } @@ -53,9 +54,10 @@ static bool haveInternet() } std::string programPath; -char * * savedArgv; +char ** savedArgv; -struct HelpRequested { }; +struct HelpRequested +{}; struct NixArgs : virtual MultiCommand, virtual MixCommonArgs { @@ -63,7 +65,9 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs bool refresh = false; bool showVersion = false; - NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix") + NixArgs() + : MultiCommand(RegisterCommand::getCommandsFor({})) + , MixCommonArgs("nix") { categories.clear(); categories[Command::catDefault] = "Main commands"; @@ -82,7 +86,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs .shortName = 'L', .description = "Print full build logs on standard error.", .category = loggingCategory, - .handler = {[&]() {setLogFormat(LogFormat::barWithLogs); }}, + .handler = {[&]() { setLogFormat(LogFormat::barWithLogs); }}, }); addFlag({ @@ -131,12 +135,13 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs Strings::iterator rewriteArgs(Strings & args, Strings::iterator pos) override { - if (aliasUsed || command || pos == args.end()) return pos; + if (aliasUsed || command || pos == args.end()) + return pos; auto arg = *pos; auto i = aliases.find(arg); - if (i == aliases.end()) return pos; - warn("'%s' is a deprecated alias for '%s'", - arg, concatStringsSep(" ", i->second)); + if (i == aliases.end()) + return pos; + warn("'%s' is a deprecated alias for '%s'", arg, concatStringsSep(" ", i->second)); pos = args.erase(pos); for (auto j = i->second.rbegin(); j != i->second.rend(); ++j) pos = args.insert(pos, *j); @@ -152,8 +157,8 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs std::string doc() override { return - #include "nix.md" - ; +#include "nix.md" + ; } // Plugins may add new subcommands. @@ -174,15 +179,17 @@ static void showHelp(std::vector subcommand, MultiCommand & topleve EvalState state({}, openStore("dummy://")); auto vGenerateManpage = state.allocValue(); - state.eval(state.parseExprFromString( - #include "generate-manpage.nix.gen.hh" - , "/"), *vGenerateManpage); + state.eval( + state.parseExprFromString( +#include "generate-manpage.nix.gen.hh" + , "/"), + *vGenerateManpage); auto vUtils = state.allocValue(); state.cacheFile( "/utils.nix", "/utils.nix", state.parseExprFromString( - #include "utils.nix.gen.hh" +#include "utils.nix.gen.hh" , "/"), *vUtils); @@ -222,22 +229,23 @@ struct CmdHelp : Command std::string doc() override { return - #include "help.md" - ; +#include "help.md" + ; } void run() override { assert(parent); MultiCommand * toplevel = parent; - while (toplevel->parent) toplevel = toplevel->parent; + while (toplevel->parent) + toplevel = toplevel->parent; showHelp(subcommand, *toplevel); } }; static auto rCmdHelp = registerCommand("help"); -void mainWrapped(int argc, char * * argv) +void mainWrapped(int argc, char ** argv) { savedArgv = argv; @@ -251,15 +259,16 @@ void mainWrapped(int argc, char * * argv) initNix(); initGC(); - #if __linux__ +#if __linux__ if (getuid() == 0) { try { saveMountNamespace(); if (unshare(CLONE_NEWNS) == -1) throw SysError("setting up a private mount namespace"); - } catch (Error & e) { } + } catch (Error & e) { + } } - #endif +#endif Finally f([] { logger->stop(); }); @@ -268,12 +277,14 @@ void mainWrapped(int argc, char * * argv) if (argc > 0 && std::string_view(argv[0]) == "__build-remote") { programName = "build-remote"; - argv++; argc--; + argv++; + argc--; } { auto legacy = (*RegisterLegacyCommand::commands)[programName]; - if (legacy) return legacy(argc, argv); + if (legacy) + return legacy(argc, argv); } evalSettings.pureEval = true; @@ -301,9 +312,11 @@ void mainWrapped(int argc, char * * argv) auto builtins = state.baseEnv.values[0]->attrs; for (auto & builtin : *builtins) { auto b = nlohmann::json::object(); - if (!builtin.value->isPrimOp()) continue; + if (!builtin.value->isPrimOp()) + continue; auto primOp = builtin.value->primOp; - if (!primOp->doc) continue; + if (!primOp->doc) + continue; b["arity"] = primOp->arity; b["args"] = primOp->args; b["doc"] = trim(stripIndentation(primOp->doc)); @@ -313,16 +326,18 @@ void mainWrapped(int argc, char * * argv) return; } - Finally printCompletions([&]() - { + Finally printCompletions([&]() { if (completions) { switch (completionType) { case ctNormal: - std::cout << "normal\n"; break; + std::cout << "normal\n"; + break; case ctFilenames: - std::cout << "filenames\n"; break; + std::cout << "filenames\n"; + break; case ctAttrs: - std::cout << "attrs\n"; break; + std::cout << "attrs\n"; + break; } for (auto & s : *completions) std::cout << s.completion << "\t" << s.description << "\n"; @@ -344,10 +359,12 @@ void mainWrapped(int argc, char * * argv) showHelp(subcommand, args); return; } catch (UsageError &) { - if (!completions) throw; + if (!completions) + throw; } - if (completions) return; + if (completions) + return; if (args.showVersion) { printVersion(programName); @@ -357,9 +374,7 @@ void mainWrapped(int argc, char * * argv) if (!args.command) throw UsageError("no subcommand specified"); - if (args.command->first != "repl" - && args.command->first != "doctor" - && args.command->first != "upgrade-nix") + if (args.command->first != "repl" && args.command->first != "doctor" && args.command->first != "upgrade-nix") settings.requireExperimentalFeature(Xp::NixCommand); if (args.useNet && !haveInternet()) { @@ -394,13 +409,11 @@ void mainWrapped(int argc, char * * argv) } -int main(int argc, char * * argv) +int main(int argc, char ** argv) { // Increase the default stack size for the evaluator and for // libstdc++'s std::regex. nix::setStackSize(64 * 1024 * 1024); - return nix::handleExceptions(argv[0], [&]() { - nix::mainWrapped(argc, argv); - }); + return nix::handleExceptions(argv[0], [&]() { nix::mainWrapped(argc, argv); }); } diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc index 34860c38f289..8dfc59e2f66c 100644 --- a/src/nix/make-content-addressed.cc +++ b/src/nix/make-content-addressed.cc @@ -21,16 +21,16 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, std::string doc() override { return - #include "make-content-addressed.md" - ; +#include "make-content-addressed.md" + ; } void run(ref srcStore, StorePaths && storePaths) override { auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri); - auto remappings = makeContentAddressed(*srcStore, *dstStore, - StorePathSet(storePaths.begin(), storePaths.end())); + auto remappings = + makeContentAddressed(*srcStore, *dstStore, StorePathSet(storePaths.begin(), storePaths.end())); if (json) { JSONObject jsonRoot(std::cout); @@ -44,9 +44,7 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, for (auto & path : storePaths) { auto i = remappings.find(path); assert(i != remappings.end()); - notice("rewrote '%s' to '%s'", - srcStore->printStorePath(path), - srcStore->printStorePath(i->second)); + notice("rewrote '%s' to '%s'", srcStore->printStorePath(path), srcStore->printStorePath(i->second)); } } } diff --git a/src/nix/nar.cc b/src/nix/nar.cc index dbb043d9b9d8..4ceaaa046aed 100644 --- a/src/nix/nar.cc +++ b/src/nix/nar.cc @@ -4,8 +4,9 @@ using namespace nix; struct CmdNar : NixMultiCommand { - CmdNar() : MultiCommand(RegisterCommand::getCommandsFor({"nar"})) - { } + CmdNar() + : MultiCommand(RegisterCommand::getCommandsFor({"nar"})) + {} std::string description() override { @@ -15,11 +16,14 @@ struct CmdNar : NixMultiCommand std::string doc() override { return - #include "nar.md" - ; +#include "nar.md" + ; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { diff --git a/src/nix/optimise-store.cc b/src/nix/optimise-store.cc index 985006e5a544..e96f4e42fcf0 100644 --- a/src/nix/optimise-store.cc +++ b/src/nix/optimise-store.cc @@ -16,8 +16,8 @@ struct CmdOptimiseStore : StoreCommand std::string doc() override { return - #include "optimise-store.md" - ; +#include "optimise-store.md" + ; } void run(ref store) override diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc index d690fe59494b..40e2bb258625 100644 --- a/src/nix/path-info.cc +++ b/src/nix/path-info.cc @@ -54,11 +54,14 @@ struct CmdPathInfo : StorePathsCommand, MixJSON std::string doc() override { return - #include "path-info.md" - ; +#include "path-info.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void printSize(uint64_t value) { @@ -67,9 +70,7 @@ struct CmdPathInfo : StorePathsCommand, MixJSON return; } - static const std::array idents{{ - ' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' - }}; + static const std::array idents{{' ', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'}}; size_t power = 0; double res = value; while (res > 1024 && power < idents.size()) { @@ -87,10 +88,10 @@ struct CmdPathInfo : StorePathsCommand, MixJSON if (json) { JSONPlaceholder jsonRoot(std::cout); - store->pathInfoToJSON(jsonRoot, + store->pathInfoToJSON( + jsonRoot, // FIXME: preserve order? - StorePathSet(storePaths.begin(), storePaths.end()), - true, showClosureSize, SRI, AllowInvalid); + StorePathSet(storePaths.begin(), storePaths.end()), true, showClosureSize, SRI, AllowInvalid); } else { @@ -113,15 +114,17 @@ struct CmdPathInfo : StorePathsCommand, MixJSON if (showSigs) { std::cout << '\t'; Strings ss; - if (info->ultimate) ss.push_back("ultimate"); - if (info->ca) ss.push_back("ca:" + renderContentAddress(*info->ca)); - for (auto & sig : info->sigs) ss.push_back(sig); + if (info->ultimate) + ss.push_back("ultimate"); + if (info->ca) + ss.push_back("ca:" + renderContentAddress(*info->ca)); + for (auto & sig : info->sigs) + ss.push_back(sig); std::cout << concatStringsSep(" ", ss); } std::cout << std::endl; } - } } }; diff --git a/src/nix/ping-store.cc b/src/nix/ping-store.cc index 3c3b7bb45eea..183ddaaee960 100644 --- a/src/nix/ping-store.cc +++ b/src/nix/ping-store.cc @@ -14,8 +14,8 @@ struct CmdPingStore : StoreCommand std::string doc() override { return - #include "ping-store.md" - ; +#include "ping-store.md" + ; } void run(ref store) override diff --git a/src/nix/prefetch.cc b/src/nix/prefetch.cc index ce3288dc1bc2..985ebde3c086 100644 --- a/src/nix/prefetch.cc +++ b/src/nix/prefetch.cc @@ -18,11 +18,13 @@ using namespace nix; mirrors defined in Nixpkgs. */ std::string resolveMirrorUrl(EvalState & state, const std::string & url) { - if (url.substr(0, 9) != "mirror://") return url; + if (url.substr(0, 9) != "mirror://") + return url; std::string s(url, 9); auto p = s.find('/'); - if (p == std::string::npos) throw Error("invalid mirror URL '%s'", url); + if (p == std::string::npos) + throw Error("invalid mirror URL '%s'", url); std::string mirrorName(s, 0, p); Value vMirrors; @@ -86,7 +88,8 @@ std::tuple prefetchFile( mode = 0700; AutoCloseFD fd = open(tmpFile.c_str(), O_WRONLY | O_CREAT | O_EXCL, mode); - if (!fd) throw SysError("creating temporary file '%s'", tmpFile); + if (!fd) + throw SysError("creating temporary file '%s'", tmpFile); FdSink sink(fd.get()); @@ -97,8 +100,7 @@ std::tuple prefetchFile( /* Optionally unpack the file. */ if (unpack) { - Activity act(*logger, lvlChatty, actUnknown, - fmt("unpacking '%s'", url)); + Activity act(*logger, lvlChatty, actUnknown, fmt("unpacking '%s'", url)); Path unpacked = (Path) tmpDir + "/unpacked"; createDirs(unpacked); unpackTarfile(tmpFile, unpacked); @@ -112,8 +114,7 @@ std::tuple prefetchFile( tmpFile = unpacked; } - Activity act(*logger, lvlChatty, actUnknown, - fmt("adding '%s' to the store", url)); + Activity act(*logger, lvlChatty, actUnknown, fmt("adding '%s' to the store", url)); auto info = store->addToStoreSlow(*name, tmpFile, ingestionMethod, hashType, expectedHash); storePath = info.path; @@ -124,7 +125,7 @@ std::tuple prefetchFile( return {storePath.value(), hash.value()}; } -static int main_nix_prefetch_url(int argc, char * * argv) +static int main_nix_prefetch_url(int argc, char ** argv) { { HashType ht = htSHA256; @@ -149,14 +150,12 @@ static int main_nix_prefetch_url(int argc, char * * argv) else if (*arg == "--type") { auto s = getArg(*arg, arg, end); ht = parseHashType(s); - } - else if (*arg == "--print-path") + } else if (*arg == "--print-path") printPath = true; else if (*arg == "--attr" || *arg == "-A") { fromExpr = true; attrPath = getArg(*arg, arg, end); - } - else if (*arg == "--unpack") + } else if (*arg == "--unpack") unpack = true; else if (*arg == "--executable") executable = true; @@ -177,7 +176,7 @@ static int main_nix_prefetch_url(int argc, char * * argv) Finally f([]() { stopProgressBar(); }); if (isatty(STDERR_FILENO)) - startProgressBar(); + startProgressBar(); auto store = openStore(); auto state = std::make_unique(myArgs.searchPath, store); @@ -226,8 +225,8 @@ static int main_nix_prefetch_url(int argc, char * * argv) if (args.size() == 2) expectedHash = Hash::parseAny(args[1], ht); - auto [storePath, hash] = prefetchFile( - store, resolveMirrorUrl(*state, url), name, ht, expectedHash, unpack, executable); + auto [storePath, hash] = + prefetchFile(store, resolveMirrorUrl(*state, url), name, ht, expectedHash, unpack, executable); stopProgressBar(); @@ -254,29 +253,25 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON CmdStorePrefetchFile() { - addFlag({ - .longName = "name", - .description = "Override the name component of the resulting store path. It defaults to the base name of *url*.", - .labels = {"name"}, - .handler = {&name} - }); - - addFlag({ - .longName = "expected-hash", - .description = "The expected hash of the file.", - .labels = {"hash"}, - .handler = {[&](std::string s) { - expectedHash = Hash::parseAny(s, hashType); - }} - }); + addFlag( + {.longName = "name", + .description = + "Override the name component of the resulting store path. It defaults to the base name of *url*.", + .labels = {"name"}, + .handler = {&name}}); + + addFlag( + {.longName = "expected-hash", + .description = "The expected hash of the file.", + .labels = {"hash"}, + .handler = {[&](std::string s) { expectedHash = Hash::parseAny(s, hashType); }}}); addFlag(Flag::mkHashTypeFlag("hash-type", &hashType)); addFlag({ .longName = "executable", - .description = - "Make the resulting file executable. Note that this causes the " - "resulting hash to be a NAR hash rather than a flat file hash.", + .description = "Make the resulting file executable. Note that this causes the " + "resulting hash to be a NAR hash rather than a flat file hash.", .handler = {&executable, true}, }); @@ -291,8 +286,8 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON std::string doc() override { return - #include "store-prefetch-file.md" - ; +#include "store-prefetch-file.md" + ; } void run(ref store) override { @@ -304,9 +299,8 @@ struct CmdStorePrefetchFile : StoreCommand, MixJSON res["hash"] = hash.to_string(SRI, true); logger->cout(res.dump()); } else { - notice("Downloaded '%s' to '%s' (hash '%s').", - url, - store->printStorePath(storePath), + notice( + "Downloaded '%s' to '%s' (hash '%s').", url, store->printStorePath(storePath), hash.to_string(SRI, true)); } } diff --git a/src/nix/profile.cc b/src/nix/profile.cc index 3814e7d5a6fd..c49d8ef3faf0 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -24,11 +24,10 @@ struct ProfileElementSource std::string attrPath; OutputsSpec outputs; - bool operator < (const ProfileElementSource & other) const + bool operator<(const ProfileElementSource & other) const { - return - std::tuple(originalRef.to_string(), attrPath, outputs) < - std::tuple(other.originalRef.to_string(), other.attrPath, other.outputs); + return std::tuple(originalRef.to_string(), attrPath, outputs) + < std::tuple(other.originalRef.to_string(), other.attrPath, other.outputs); } }; @@ -57,27 +56,24 @@ struct ProfileElement return showVersions(versions); } - bool operator < (const ProfileElement & other) const + bool operator<(const ProfileElement & other) const { return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths); } - void updateStorePaths( - ref evalStore, - ref store, - const BuiltPaths & builtPaths) + void updateStorePaths(ref evalStore, ref store, const BuiltPaths & builtPaths) { storePaths.clear(); for (auto & buildable : builtPaths) { - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - storePaths.insert(bo.path); - }, - [&](const BuiltPath::Built & bfd) { - for (auto & output : bfd.outputs) - storePaths.insert(output.second); + std::visit( + overloaded{ + [&](const BuiltPath::Opaque & bo) { storePaths.insert(bo.path); }, + [&](const BuiltPath::Built & bfd) { + for (auto & output : bfd.outputs) + storePaths.insert(output.second); + }, }, - }, buildable.raw()); + buildable.raw()); } } }; @@ -86,7 +82,7 @@ struct ProfileManifest { std::vector elements; - ProfileManifest() { } + ProfileManifest() {} ProfileManifest(EvalState & state, const Path & profile) { @@ -99,16 +95,16 @@ struct ProfileManifest std::string sUrl; std::string sOriginalUrl; switch (version) { - case 1: - sUrl = "uri"; - sOriginalUrl = "originalUri"; - break; - case 2: - sUrl = "url"; - sOriginalUrl = "originalUrl"; - break; - default: - throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version); + case 1: + sUrl = "uri"; + sOriginalUrl = "originalUri"; + break; + case 2: + sUrl = "url"; + sOriginalUrl = "originalUrl"; + break; + default: + throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version); } for (auto & e : json["elements"]) { @@ -116,16 +112,13 @@ struct ProfileManifest for (auto & p : e["storePaths"]) element.storePaths.insert(state.store->parseStorePath((std::string) p)); element.active = e["active"]; - if(e.contains("priority")) { + if (e.contains("priority")) { element.priority = e["priority"]; } if (e.value(sUrl, "") != "") { - element.source = ProfileElementSource { - parseFlakeRef(e[sOriginalUrl]), - parseFlakeRef(e[sUrl]), - e["attrPath"], - e["outputs"].get() - }; + element.source = ProfileElementSource{ + parseFlakeRef(e[sOriginalUrl]), parseFlakeRef(e[sUrl]), e["attrPath"], + e["outputs"].get()}; } elements.emplace_back(std::move(element)); } @@ -196,13 +189,13 @@ struct ProfileManifest auto narHash = hashString(htSHA256, sink.s); - ValidPathInfo info { + ValidPathInfo info{ store->makeFixedOutputPath(FileIngestionMethod::Recursive, narHash, "profile", references), narHash, }; info.references = std::move(references); info.narSize = sink.s.size(); - info.ca = FixedOutputHash { .method = FileIngestionMethod::Recursive, .hash = info.narHash }; + info.ca = FixedOutputHash{.method = FileIngestionMethod::Recursive, .hash = info.narHash}; StringSource source(sink.s); store->addToStore(info, source); @@ -228,13 +221,11 @@ struct ProfileManifest std::cout << fmt("%s%s: ∅ -> %s\n", indent, j->describe(), j->versions()); changes = true; ++j; - } - else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) { + } else if (i != prevElems.end() && (j == curElems.end() || i->describe() < j->describe())) { std::cout << fmt("%s%s: %s -> ∅\n", indent, i->describe(), i->versions()); changes = true; ++i; - } - else { + } else { auto v1 = i->versions(); auto v2 = j->versions(); if (v1 != v2) { @@ -252,8 +243,7 @@ struct ProfileManifest }; static std::map -builtPathsPerInstallable( - const std::vector, BuiltPath>> & builtPaths) +builtPathsPerInstallable(const std::vector, BuiltPath>> & builtPaths) { std::map res; for (auto & [installable, builtPath] : builtPaths) @@ -265,7 +255,8 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile { std::optional priority; - CmdProfileInstall() { + CmdProfileInstall() + { addFlag({ .longName = "priority", .description = "The priority of the package to install.", @@ -282,8 +273,8 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile std::string doc() override { return - #include "profile-install.md" - ; +#include "profile-install.md" + ; } void run(ref store) override @@ -291,30 +282,23 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile ProfileManifest manifest(*getEvalState(), *profile); auto builtPaths = builtPathsPerInstallable( - Installable::build2( - getEvalStore(), store, Realise::Outputs, installables, bmNormal)); + Installable::build2(getEvalStore(), store, Realise::Outputs, installables, bmNormal)); for (auto & installable : installables) { ProfileElement element; - - if (auto installable2 = std::dynamic_pointer_cast(installable)) { // FIXME: make build() return this? auto [attrPath, resolvedRef, drv] = installable2->toDerivation(); - element.source = ProfileElementSource { - installable2->flakeRef, - resolvedRef, - attrPath, - installable2->outputsSpec - }; - - if(drv.priority) { + element.source = + ProfileElementSource{installable2->flakeRef, resolvedRef, attrPath, installable2->outputsSpec}; + + if (drv.priority) { element.priority = *drv.priority; } } - if(priority) { // if --priority was specified we want to override the priority of the installable + if (priority) { // if --priority was specified we want to override the priority of the installable element.priority = *priority; }; @@ -338,9 +322,10 @@ class MixProfileElementMatchers : virtual Args expectArgs("elements", &_matchers); } - struct RegexPattern { + struct RegexPattern + { std::string pattern; - std::regex reg; + std::regex reg; }; typedef std::variant Matcher; @@ -354,7 +339,7 @@ class MixProfileElementMatchers : virtual Args else if (store->isStorePath(s)) res.push_back(s); else - res.push_back(RegexPattern{s,std::regex(s, std::regex::extended | std::regex::icase)}); + res.push_back(RegexPattern{s, std::regex(s, std::regex::extended | std::regex::icase)}); } return res; @@ -364,12 +349,13 @@ class MixProfileElementMatchers : virtual Args { for (auto & matcher : matchers) { if (auto n = std::get_if(&matcher)) { - if (*n == pos) return true; + if (*n == pos) + return true; } else if (auto path = std::get_if(&matcher)) { - if (element.storePaths.count(store.parseStorePath(*path))) return true; + if (element.storePaths.count(store.parseStorePath(*path))) + return true; } else if (auto regex = std::get_if(&matcher)) { - if (element.source - && std::regex_match(element.source->attrPath, regex->reg)) + if (element.source && std::regex_match(element.source->attrPath, regex->reg)) return true; } } @@ -388,8 +374,8 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem std::string doc() override { return - #include "profile-remove.md" - ; +#include "profile-remove.md" + ; } void run(ref store) override @@ -410,21 +396,19 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem } auto removedCount = oldManifest.elements.size() - newManifest.elements.size(); - printInfo("removed %d packages, kept %d packages", - removedCount, - newManifest.elements.size()); + printInfo("removed %d packages, kept %d packages", removedCount, newManifest.elements.size()); if (removedCount == 0) { - for (auto matcher: matchers) { - if (const size_t * index = std::get_if(&matcher)){ + for (auto matcher : matchers) { + if (const size_t * index = std::get_if(&matcher)) { warn("'%d' is not a valid index", *index); - } else if (const Path * path = std::get_if(&matcher)){ + } else if (const Path * path = std::get_if(&matcher)) { warn("'%s' does not match any paths", *path); - } else if (const RegexPattern * regex = std::get_if(&matcher)){ + } else if (const RegexPattern * regex = std::get_if(&matcher)) { warn("'%s' does not match any packages", regex->pattern); } } - warn ("Use 'nix profile list' to see the current profile."); + warn("Use 'nix profile list' to see the current profile."); } updateProfile(newManifest.build(store)); } @@ -440,8 +424,8 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf std::string doc() override { return - #include "profile-upgrade.md" - ; +#include "profile-upgrade.md" + ; } void run(ref store) override @@ -457,38 +441,28 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf for (size_t i = 0; i < manifest.elements.size(); ++i) { auto & element(manifest.elements[i]); - if (element.source - && !element.source->originalRef.input.isLocked() - && matches(*store, element, i, matchers)) - { + if (element.source && !element.source->originalRef.input.isLocked() + && matches(*store, element, i, matchers)) { upgradedCount++; - Activity act(*logger, lvlChatty, actUnknown, - fmt("checking '%s' for updates", element.source->attrPath)); + Activity act( + *logger, lvlChatty, actUnknown, fmt("checking '%s' for updates", element.source->attrPath)); auto installable = std::make_shared( - this, - getEvalState(), - FlakeRef(element.source->originalRef), - "", - element.source->outputs, - Strings{element.source->attrPath}, - Strings{}, - lockFlags); + this, getEvalState(), FlakeRef(element.source->originalRef), "", element.source->outputs, + Strings{element.source->attrPath}, Strings{}, lockFlags); auto [attrPath, resolvedRef, drv] = installable->toDerivation(); - if (element.source->resolvedRef == resolvedRef) continue; + if (element.source->resolvedRef == resolvedRef) + continue; - printInfo("upgrading '%s' from flake '%s' to '%s'", - element.source->attrPath, element.source->resolvedRef, resolvedRef); + printInfo( + "upgrading '%s' from flake '%s' to '%s'", element.source->attrPath, element.source->resolvedRef, + resolvedRef); - element.source = ProfileElementSource { - installable->flakeRef, - resolvedRef, - attrPath, - installable->outputsSpec - }; + element.source = + ProfileElementSource{installable->flakeRef, resolvedRef, attrPath, installable->outputsSpec}; installables.push_back(installable); indices.push_back(i); @@ -497,20 +471,19 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf if (upgradedCount == 0) { for (auto & matcher : matchers) { - if (const size_t * index = std::get_if(&matcher)){ + if (const size_t * index = std::get_if(&matcher)) { warn("'%d' is not a valid index", *index); - } else if (const Path * path = std::get_if(&matcher)){ + } else if (const Path * path = std::get_if(&matcher)) { warn("'%s' does not match any paths", *path); - } else if (const RegexPattern * regex = std::get_if(&matcher)){ + } else if (const RegexPattern * regex = std::get_if(&matcher)) { warn("'%s' does not match any packages", regex->pattern); } } - warn ("Use 'nix profile list' to see the current profile."); + warn("Use 'nix profile list' to see the current profile."); } auto builtPaths = builtPathsPerInstallable( - Installable::build2( - getEvalStore(), store, Realise::Outputs, installables, bmNormal)); + Installable::build2(getEvalStore(), store, Realise::Outputs, installables, bmNormal)); for (size_t i = 0; i < installables.size(); ++i) { auto & installable = installables.at(i); @@ -532,8 +505,8 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro std::string doc() override { return - #include "profile-list.md" - ; +#include "profile-list.md" + ; } void run(ref store) override @@ -542,9 +515,14 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro for (size_t i = 0; i < manifest.elements.size(); ++i) { auto & element(manifest.elements[i]); - logger->cout("%d %s %s %s", i, - element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath + printOutputsSpec(element.source->outputs) : "-", - element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath + printOutputsSpec(element.source->outputs) : "-", + logger->cout( + "%d %s %s %s", i, + element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath + + printOutputsSpec(element.source->outputs) + : "-", + element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath + + printOutputsSpec(element.source->outputs) + : "-", concatStringsSep(" ", store->printStorePathSet(element.storePaths))); } } @@ -560,8 +538,8 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile std::string doc() override { return - #include "profile-diff-closures.md" - ; +#include "profile-diff-closures.md" + ; } void run(ref store) override @@ -573,13 +551,12 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile for (auto & gen : gens) { if (prevGen) { - if (!first) std::cout << "\n"; + if (!first) + std::cout << "\n"; first = false; std::cout << fmt("Version %d -> %d:\n", prevGen->number, gen.number); - printClosureDiff(store, - store->followLinksToStorePath(prevGen->path), - store->followLinksToStorePath(gen.path), - " "); + printClosureDiff( + store, store->followLinksToStorePath(prevGen->path), store->followLinksToStorePath(gen.path), " "); } prevGen = gen; @@ -597,8 +574,8 @@ struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile std::string doc() override { return - #include "profile-history.md" - ; +#include "profile-history.md" + ; } void run(ref store) override @@ -611,19 +588,16 @@ struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile for (auto & gen : gens) { ProfileManifest manifest(*getEvalState(), gen.path); - if (!first) std::cout << "\n"; + if (!first) + std::cout << "\n"; first = false; - std::cout << fmt("Version %s%d" ANSI_NORMAL " (%s)%s:\n", - gen.number == curGen ? ANSI_GREEN : ANSI_BOLD, - gen.number, + std::cout << fmt( + "Version %s%d" ANSI_NORMAL " (%s)%s:\n", gen.number == curGen ? ANSI_GREEN : ANSI_BOLD, gen.number, std::put_time(std::gmtime(&gen.creationTime), "%Y-%m-%d"), prevGen ? fmt(" <- %d", prevGen->first.number) : ""); - ProfileManifest::printDiff( - prevGen ? prevGen->second : ProfileManifest(), - manifest, - " "); + ProfileManifest::printDiff(prevGen ? prevGen->second : ProfileManifest(), manifest, " "); prevGen = {gen, std::move(manifest)}; } @@ -652,8 +626,8 @@ struct CmdProfileRollback : virtual StoreCommand, MixDefaultProfile, MixDryRun std::string doc() override { return - #include "profile-rollback.md" - ; +#include "profile-rollback.md" + ; } void run(ref store) override @@ -670,10 +644,9 @@ struct CmdProfileWipeHistory : virtual StoreCommand, MixDefaultProfile, MixDryRu { addFlag({ .longName = "older-than", - .description = - "Delete versions older than the specified age. *age* " - "must be in the format *N*`d`, where *N* denotes a number " - "of days.", + .description = "Delete versions older than the specified age. *age* " + "must be in the format *N*`d`, where *N* denotes a number " + "of days.", .labels = {"age"}, .handler = {&minAge}, }); @@ -687,8 +660,8 @@ struct CmdProfileWipeHistory : virtual StoreCommand, MixDefaultProfile, MixDryRu std::string doc() override { return - #include "profile-wipe-history.md" - ; +#include "profile-wipe-history.md" + ; } void run(ref store) override @@ -704,16 +677,16 @@ struct CmdProfile : NixMultiCommand { CmdProfile() : MultiCommand({ - {"install", []() { return make_ref(); }}, - {"remove", []() { return make_ref(); }}, - {"upgrade", []() { return make_ref(); }}, - {"list", []() { return make_ref(); }}, - {"diff-closures", []() { return make_ref(); }}, - {"history", []() { return make_ref(); }}, - {"rollback", []() { return make_ref(); }}, - {"wipe-history", []() { return make_ref(); }}, - }) - { } + {"install", []() { return make_ref(); }}, + {"remove", []() { return make_ref(); }}, + {"upgrade", []() { return make_ref(); }}, + {"list", []() { return make_ref(); }}, + {"diff-closures", []() { return make_ref(); }}, + {"history", []() { return make_ref(); }}, + {"rollback", []() { return make_ref(); }}, + {"wipe-history", []() { return make_ref(); }}, + }) + {} std::string description() override { @@ -723,8 +696,8 @@ struct CmdProfile : NixMultiCommand std::string doc() override { return - #include "profile.md" - ; +#include "profile.md" + ; } void run() override diff --git a/src/nix/realisation.cc b/src/nix/realisation.cc index c9a7157cdcd6..47f8afde8246 100644 --- a/src/nix/realisation.cc +++ b/src/nix/realisation.cc @@ -7,15 +7,19 @@ using namespace nix; struct CmdRealisation : virtual NixMultiCommand { - CmdRealisation() : MultiCommand(RegisterCommand::getCommandsFor({"realisation"})) - { } + CmdRealisation() + : MultiCommand(RegisterCommand::getCommandsFor({"realisation"})) + {} std::string description() override { return "manipulate a Nix realisation"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { @@ -38,11 +42,14 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON std::string doc() override { return - #include "realisation/info.md" +#include "realisation/info.md" ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run(ref store, BuiltPaths && paths) override { @@ -66,13 +73,10 @@ struct CmdRealisationInfo : BuiltPathsCommand, MixJSON res.push_back(currentPath); } std::cout << res.dump(); - } - else { + } else { for (auto & path : realisations) { if (auto realisation = std::get_if(&path.raw)) { - std::cout << - realisation->id.to_string() << " " << - store->printStorePath(realisation->outPath); + std::cout << realisation->id.to_string() << " " << store->printStorePath(realisation->outPath); } else std::cout << store->printStorePath(path.path()); diff --git a/src/nix/registry.cc b/src/nix/registry.cc index c496f94f82a4..d9a752bcaf4b 100644 --- a/src/nix/registry.cc +++ b/src/nix/registry.cc @@ -10,7 +10,6 @@ using namespace nix; using namespace nix::flake; - class RegistryCommand : virtual Args { std::string registry_path; @@ -31,7 +30,8 @@ class RegistryCommand : virtual Args std::shared_ptr getRegistry() { - if (registry) return registry; + if (registry) + return registry; if (registry_path.empty()) { registry = fetchers::getUserRegistry(); } else { @@ -60,8 +60,8 @@ struct CmdRegistryList : StoreCommand std::string doc() override { return - #include "registry-list.md" - ; +#include "registry-list.md" + ; } void run(nix::ref store) override @@ -73,13 +73,13 @@ struct CmdRegistryList : StoreCommand for (auto & registry : registries) { for (auto & entry : registry->entries) { // FIXME: format nicely - logger->cout("%s %s %s", - registry->type == Registry::Flag ? "flags " : - registry->type == Registry::User ? "user " : - registry->type == Registry::System ? "system" : - "global", - entry.from.toURLString(), - entry.to.toURLString(attrsToQuery(entry.extraAttrs))); + logger->cout( + "%s %s %s", + registry->type == Registry::Flag ? "flags " + : registry->type == Registry::User ? "user " + : registry->type == Registry::System ? "system" + : "global", + entry.from.toURLString(), entry.to.toURLString(attrsToQuery(entry.extraAttrs))); } } } @@ -97,8 +97,8 @@ struct CmdRegistryAdd : MixEvalArgs, Command, RegistryCommand std::string doc() override { return - #include "registry-add.md" - ; +#include "registry-add.md" + ; } CmdRegistryAdd() @@ -113,7 +113,8 @@ struct CmdRegistryAdd : MixEvalArgs, Command, RegistryCommand auto toRef = parseFlakeRef(toUrl); auto registry = getRegistry(); fetchers::Attrs extraAttrs; - if (toRef.subdir != "") extraAttrs["dir"] = toRef.subdir; + if (toRef.subdir != "") + extraAttrs["dir"] = toRef.subdir; registry->remove(fromRef.input); registry->add(fromRef.input, toRef.input, extraAttrs); registry->write(getRegistryPath()); @@ -132,8 +133,8 @@ struct CmdRegistryRemove : RegistryCommand, Command std::string doc() override { return - #include "registry-remove.md" - ; +#include "registry-remove.md" + ; } CmdRegistryRemove() @@ -163,22 +164,19 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand std::string doc() override { return - #include "registry-pin.md" - ; +#include "registry-pin.md" + ; } CmdRegistryPin() { expectArg("url", &url); - expectArgs({ - .label = "locked", - .optional = true, - .handler = {&locked}, - .completer = {[&](size_t, std::string_view prefix) { - completeFlakeRef(getStore(), prefix); - }} - }); + expectArgs( + {.label = "locked", + .optional = true, + .handler = {&locked}, + .completer = {[&](size_t, std::string_view prefix) { completeFlakeRef(getStore(), prefix); }}}); } void run(nix::ref store) override @@ -192,7 +190,8 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand registry->remove(ref.input); auto [tree, resolved] = locked_ref.resolve(store).input.fetch(store); fetchers::Attrs extraAttrs; - if (ref.subdir != "") extraAttrs["dir"] = ref.subdir; + if (ref.subdir != "") + extraAttrs["dir"] = ref.subdir; registry->add(ref.input, resolved, extraAttrs); registry->write(getRegistryPath()); } @@ -202,13 +201,12 @@ struct CmdRegistry : virtual NixMultiCommand { CmdRegistry() : MultiCommand({ - {"list", []() { return make_ref(); }}, - {"add", []() { return make_ref(); }}, - {"remove", []() { return make_ref(); }}, - {"pin", []() { return make_ref(); }}, - }) - { - } + {"list", []() { return make_ref(); }}, + {"add", []() { return make_ref(); }}, + {"remove", []() { return make_ref(); }}, + {"pin", []() { return make_ref(); }}, + }) + {} std::string description() override { @@ -218,11 +216,14 @@ struct CmdRegistry : virtual NixMultiCommand std::string doc() override { return - #include "registry.md" - ; +#include "registry.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run() override { diff --git a/src/nix/run.cc b/src/nix/run.cc index 45d2dfd0d295..c1cea5c972ea 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -22,9 +22,7 @@ std::string chrootHelperName = "__run_in_chroot"; namespace nix { -void runProgramInStore(ref store, - const std::string & program, - const Strings & args) +void runProgramInStore(ref store, const std::string & program, const Strings & args) { stopProgressBar(); @@ -44,8 +42,9 @@ void runProgramInStore(ref store, throw Error("store '%s' is not a local store so it does not support command execution", store->getUri()); if (store->storeDir != store2->getRealStoreDir()) { - Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program }; - for (auto & arg : args) helperArgs.push_back(arg); + Strings helperArgs = {chrootHelperName, store->storeDir, store2->getRealStoreDir(), program}; + for (auto & arg : args) + helperArgs.push_back(arg); execv(getSelfExe().value_or("nix").c_str(), stringsToCharPtrs(helperArgs).data()); @@ -64,20 +63,20 @@ struct CmdShell : InstallablesCommand, MixEnvironment using InstallablesCommand::run; - std::vector command = { getEnv("SHELL").value_or("bash") }; + std::vector command = {getEnv("SHELL").value_or("bash")}; CmdShell() { - addFlag({ - .longName = "command", - .shortName = 'c', - .description = "Command and arguments to be executed, defaulting to `$SHELL`", - .labels = {"command", "args"}, - .handler = {[&](std::vector ss) { - if (ss.empty()) throw UsageError("--command requires at least one argument"); - command = ss; - }} - }); + addFlag( + {.longName = "command", + .shortName = 'c', + .description = "Command and arguments to be executed, defaulting to `$SHELL`", + .labels = {"command", "args"}, + .handler = {[&](std::vector ss) { + if (ss.empty()) + throw UsageError("--command requires at least one argument"); + command = ss; + }}}); } std::string description() override @@ -88,19 +87,21 @@ struct CmdShell : InstallablesCommand, MixEnvironment std::string doc() override { return - #include "shell.md" - ; +#include "shell.md" + ; } void run(ref store) override { - auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); + auto outPaths = + Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); auto accessor = store->getFSAccessor(); std::unordered_set done; std::queue todo; - for (auto & path : outPaths) todo.push(path); + for (auto & path : outPaths) + todo.push(path); setEnviron(); @@ -109,7 +110,8 @@ struct CmdShell : InstallablesCommand, MixEnvironment while (!todo.empty()) { auto path = todo.front(); todo.pop(); - if (!done.insert(path).second) continue; + if (!done.insert(path).second) + continue; if (true) unixPath.push_front(store->printStorePath(path) + "/bin"); @@ -124,7 +126,8 @@ struct CmdShell : InstallablesCommand, MixEnvironment setenv("PATH", concatStringsSep(":", unixPath).c_str(), 1); Strings args; - for (auto & arg : command) args.push_back(arg); + for (auto & arg : command) + args.push_back(arg); runProgramInStore(store, *command.begin(), args); } @@ -140,11 +143,7 @@ struct CmdRun : InstallableCommand CmdRun() { - expectArgs({ - .label = "args", - .handler = {&args}, - .completer = completePath - }); + expectArgs({.label = "args", .handler = {&args}, .completer = completePath}); } std::string description() override @@ -155,8 +154,8 @@ struct CmdRun : InstallableCommand std::string doc() override { return - #include "run.md" - ; +#include "run.md" + ; } Strings getDefaultFlakeAttrPaths() override @@ -186,7 +185,8 @@ struct CmdRun : InstallableCommand auto app = installable->toApp(*state).resolve(getEvalStore(), store); Strings allArgs{app.program}; - for (auto & i : args) allArgs.push_back(i); + for (auto & i : args) + allArgs.push_back(i); runProgramInStore(store, app.program, allArgs); } @@ -194,7 +194,7 @@ struct CmdRun : InstallableCommand static auto rCmdRun = registerCommand("run"); -void chrootHelper(int argc, char * * argv) +void chrootHelper(int argc, char ** argv) { int p = 1; std::string storeDir = argv[p++]; @@ -234,7 +234,8 @@ void chrootHelper(int argc, char * * argv) for (auto entry : readDirectory("/")) { auto src = "/" + entry.name; Path dst = tmpDir + "/" + entry.name; - if (pathExists(dst)) continue; + if (pathExists(dst)) + continue; auto st = lstat(src); if (S_ISDIR(st.st_mode)) { if (mkdir(dst.c_str(), 0700) == -1) @@ -246,7 +247,8 @@ void chrootHelper(int argc, char * * argv) } char * cwd = getcwd(0, 0); - if (!cwd) throw SysError("getting current directory"); + if (!cwd) + throw SysError("getting current directory"); Finally freeCwd([&]() { free(cwd); }); if (chroot(tmpDir.c_str()) == -1) @@ -254,9 +256,8 @@ void chrootHelper(int argc, char * * argv) if (chdir(cwd) == -1) throw SysError("chdir to '%s' in chroot", cwd); - } else - if (mount(realStoreDir.c_str(), storeDir.c_str(), "", MS_BIND, 0) == -1) - throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir); + } else if (mount(realStoreDir.c_str(), storeDir.c_str(), "", MS_BIND, 0) == -1) + throw SysError("mounting '%s' on '%s'", realStoreDir, storeDir); writeFile("/proc/self/setgroups", "deny"); writeFile("/proc/self/uid_map", fmt("%d %d %d", uid, uid, 1)); diff --git a/src/nix/run.hh b/src/nix/run.hh index 6180a87dd5a2..91bb4d5e81fb 100644 --- a/src/nix/run.hh +++ b/src/nix/run.hh @@ -4,8 +4,6 @@ namespace nix { -void runProgramInStore(ref store, - const std::string & program, - const Strings & args); +void runProgramInStore(ref store, const std::string & program, const Strings & args); } diff --git a/src/nix/search.cc b/src/nix/search.cc index bdd45cbed957..6d0c2037f24d 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -29,14 +29,12 @@ struct CmdSearch : InstallableCommand, MixJSON CmdSearch() { expectArgs("regex", &res); - addFlag(Flag { + addFlag(Flag{ .longName = "exclude", .shortName = 'e', .description = "Hide packages whose attribute path, name or description contain *regex*.", .labels = {"regex"}, - .handler = {[this](std::string s) { - excludeRes.push_back(s); - }}, + .handler = {[this](std::string s) { excludeRes.push_back(s); }}, }); } @@ -48,16 +46,13 @@ struct CmdSearch : InstallableCommand, MixJSON std::string doc() override { return - #include "search.md" - ; +#include "search.md" + ; } Strings getDefaultFlakeAttrPaths() override { - return { - "packages." + settings.thisSystem.get() + ".", - "legacyPackages." + settings.thisSystem.get() + "." - }; + return {"packages." + settings.thisSystem.get() + ".", "legacyPackages." + settings.thisSystem.get() + "."}; } void run(ref store) override @@ -88,17 +83,15 @@ struct CmdSearch : InstallableCommand, MixJSON uint64_t results = 0; - std::function & attrPath, bool initialRecurse)> visit; + std::function & attrPath, bool initialRecurse)> + visit; - visit = [&](eval_cache::AttrCursor & cursor, const std::vector & attrPath, bool initialRecurse) - { + visit = [&](eval_cache::AttrCursor & cursor, const std::vector & attrPath, bool initialRecurse) { auto attrPathS = state->symbols.resolve(attrPath); - Activity act(*logger, lvlInfo, actUnknown, - fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); + Activity act(*logger, lvlInfo, actUnknown, fmt("evaluating '%s'", concatStringsSep(".", attrPathS))); try { - auto recurse = [&]() - { + auto recurse = [&]() { for (const auto & attr : cursor.getAttrs()) { auto cursor2 = cursor.getAttr(state->symbols[attr]); auto attrPath2(attrPath); @@ -122,9 +115,7 @@ struct CmdSearch : InstallableCommand, MixJSON bool found = false; for (auto & regex : excludeRegexes) { - if ( - std::regex_search(attrPath2, regex) - || std::regex_search(name.name, regex) + if (std::regex_search(attrPath2, regex) || std::regex_search(name.name, regex) || std::regex_search(description, regex)) return; } @@ -147,8 +138,7 @@ struct CmdSearch : InstallableCommand, MixJSON break; } - if (found) - { + if (found) { results++; if (json) { auto jsonElem = jsonOut->object(attrPath2); @@ -157,7 +147,8 @@ struct CmdSearch : InstallableCommand, MixJSON jsonElem.attr("description", description); } else { auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m"); - if (results > 1) logger->cout(""); + if (results > 1) + logger->cout(""); logger->cout( "* %s%s", wrap("\e[0;1m", hiliteMatches(attrPath2, attrPathMatches, ANSI_GREEN, "\e[0;1m")), @@ -170,8 +161,7 @@ struct CmdSearch : InstallableCommand, MixJSON } else if ( - attrPath.size() == 0 - || (attrPathS[0] == "legacyPackages" && attrPath.size() <= 2) + attrPath.size() == 0 || (attrPathS[0] == "legacyPackages" && attrPath.size() <= 2) || (attrPathS[0] == "packages" && attrPath.size() <= 2)) recurse(); diff --git a/src/nix/show-config.cc b/src/nix/show-config.cc index 29944e7488a7..5ebd310b14ad 100644 --- a/src/nix/show-config.cc +++ b/src/nix/show-config.cc @@ -14,7 +14,10 @@ struct CmdShowConfig : Command, MixJSON return "show the Nix configuration"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc index fb46b4dbf34f..ceabad1ab277 100644 --- a/src/nix/show-derivation.cc +++ b/src/nix/show-derivation.cc @@ -16,12 +16,11 @@ struct CmdShowDerivation : InstallablesCommand CmdShowDerivation() { - addFlag({ - .longName = "recursive", - .shortName = 'r', - .description = "Include the dependencies of the specified derivations.", - .handler = {&recursive, true} - }); + addFlag( + {.longName = "recursive", + .shortName = 'r', + .description = "Include the dependencies of the specified derivations.", + .handler = {&recursive, true}}); } std::string description() override @@ -32,11 +31,14 @@ struct CmdShowDerivation : InstallablesCommand std::string doc() override { return - #include "show-derivation.md" - ; +#include "show-derivation.md" + ; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run(ref store) override { @@ -50,74 +52,79 @@ struct CmdShowDerivation : InstallablesCommand { - JSONObject jsonRoot(std::cout, true); - - for (auto & drvPath : drvPaths) { - if (!drvPath.isDerivation()) continue; - - auto drvObj(jsonRoot.object(store->printStorePath(drvPath))); - - auto drv = store->readDerivation(drvPath); - - { - auto outputsObj(drvObj.object("outputs")); - for (auto & [_outputName, output] : drv.outputs) { - auto & outputName = _outputName; // work around clang bug - auto outputObj { outputsObj.object(outputName) }; - std::visit(overloaded { - [&](const DerivationOutput::InputAddressed & doi) { - outputObj.attr("path", store->printStorePath(doi.path)); - }, - [&](const DerivationOutput::CAFixed & dof) { - outputObj.attr("path", store->printStorePath(dof.path(*store, drv.name, outputName))); - outputObj.attr("hashAlgo", dof.hash.printMethodAlgo()); - outputObj.attr("hash", dof.hash.hash.to_string(Base16, false)); - }, - [&](const DerivationOutput::CAFloating & dof) { - outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)); - }, - [&](const DerivationOutput::Deferred &) {}, - [&](const DerivationOutput::Impure & doi) { - outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); - outputObj.attr("impure", true); - }, - }, output.raw()); + JSONObject jsonRoot(std::cout, true); + + for (auto & drvPath : drvPaths) { + if (!drvPath.isDerivation()) + continue; + + auto drvObj(jsonRoot.object(store->printStorePath(drvPath))); + + auto drv = store->readDerivation(drvPath); + + { + auto outputsObj(drvObj.object("outputs")); + for (auto & [_outputName, output] : drv.outputs) { + auto & outputName = _outputName; // work around clang bug + auto outputObj{outputsObj.object(outputName)}; + std::visit( + overloaded{ + [&](const DerivationOutput::InputAddressed & doi) { + outputObj.attr("path", store->printStorePath(doi.path)); + }, + [&](const DerivationOutput::CAFixed & dof) { + outputObj.attr( + "path", store->printStorePath(dof.path(*store, drv.name, outputName))); + outputObj.attr("hashAlgo", dof.hash.printMethodAlgo()); + outputObj.attr("hash", dof.hash.hash.to_string(Base16, false)); + }, + [&](const DerivationOutput::CAFloating & dof) { + outputObj.attr( + "hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType)); + }, + [&](const DerivationOutput::Deferred &) {}, + [&](const DerivationOutput::Impure & doi) { + outputObj.attr( + "hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); + outputObj.attr("impure", true); + }, + }, + output.raw()); + } } - } - { - auto inputsList(drvObj.list("inputSrcs")); - for (auto & input : drv.inputSrcs) - inputsList.elem(store->printStorePath(input)); - } + { + auto inputsList(drvObj.list("inputSrcs")); + for (auto & input : drv.inputSrcs) + inputsList.elem(store->printStorePath(input)); + } - { - auto inputDrvsObj(drvObj.object("inputDrvs")); - for (auto & input : drv.inputDrvs) { - auto inputList(inputDrvsObj.list(store->printStorePath(input.first))); - for (auto & outputId : input.second) - inputList.elem(outputId); + { + auto inputDrvsObj(drvObj.object("inputDrvs")); + for (auto & input : drv.inputDrvs) { + auto inputList(inputDrvsObj.list(store->printStorePath(input.first))); + for (auto & outputId : input.second) + inputList.elem(outputId); + } } - } - drvObj.attr("system", drv.platform); - drvObj.attr("builder", drv.builder); + drvObj.attr("system", drv.platform); + drvObj.attr("builder", drv.builder); - { - auto argsList(drvObj.list("args")); - for (auto & arg : drv.args) - argsList.elem(arg); - } + { + auto argsList(drvObj.list("args")); + for (auto & arg : drv.args) + argsList.elem(arg); + } - { - auto envObj(drvObj.object("env")); - for (auto & var : drv.env) - envObj.attr(var.first, var.second); + { + auto envObj(drvObj.object("env")); + for (auto & var : drv.env) + envObj.attr(var.first, var.second); + } } } - } - std::cout << "\n"; } }; diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc index 3d659d6d2410..e72d7e32fc5b 100644 --- a/src/nix/sigs.cc +++ b/src/nix/sigs.cc @@ -42,10 +42,10 @@ struct CmdCopySigs : StorePathsCommand std::string doneLabel = "done"; std::atomic added{0}; - //logger->setExpected(doneLabel, storePaths.size()); + // logger->setExpected(doneLabel, storePaths.size()); auto doPath = [&](const Path & storePathS) { - //Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath); + // Activity act(*logger, lvlInfo, format("getting signatures for '%s'") % storePath); checkInterrupt(); @@ -61,9 +61,8 @@ struct CmdCopySigs : StorePathsCommand /* Don't import signatures that don't match this binary. */ - if (info->narHash != info2->narHash || - info->narSize != info2->narSize || - info->references != info2->references) + if (info->narHash != info2->narHash || info->narSize != info2->narSize + || info->references != info2->references) continue; for (auto & sig : info2->sigs) @@ -78,7 +77,7 @@ struct CmdCopySigs : StorePathsCommand added += newSigs.size(); } - //logger->incProgress(doneLabel); + // logger->incProgress(doneLabel); }; for (auto & storePath : storePaths) @@ -98,14 +97,13 @@ struct CmdSign : StorePathsCommand CmdSign() { - addFlag({ - .longName = "key-file", - .shortName = 'k', - .description = "File containing the secret signing key.", - .labels = {"file"}, - .handler = {&secretKeyFile}, - .completer = completePath - }); + addFlag( + {.longName = "key-file", + .shortName = 'k', + .description = "File containing the secret signing key.", + .labels = {"file"}, + .handler = {&secretKeyFile}, + .completer = completePath}); } std::string description() override @@ -164,8 +162,8 @@ struct CmdKeyGenerateSecret : Command std::string doc() override { return - #include "key-generate-secret.md" - ; +#include "key-generate-secret.md" + ; } void run() override @@ -187,8 +185,8 @@ struct CmdKeyConvertSecretToPublic : Command std::string doc() override { return - #include "key-convert-secret-to-public.md" - ; +#include "key-convert-secret-to-public.md" + ; } void run() override @@ -202,18 +200,20 @@ struct CmdKey : NixMultiCommand { CmdKey() : MultiCommand({ - {"generate-secret", []() { return make_ref(); }}, - {"convert-secret-to-public", []() { return make_ref(); }}, - }) - { - } + {"generate-secret", []() { return make_ref(); }}, + {"convert-secret-to-public", []() { return make_ref(); }}, + }) + {} std::string description() override { return "generate and convert Nix signing keys"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc index 2e288f743917..6f6db2bdb92f 100644 --- a/src/nix/store-copy-log.cc +++ b/src/nix/store-copy-log.cc @@ -20,11 +20,14 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand std::string doc() override { return - #include "store-copy-log.md" - ; +#include "store-copy-log.md" + ; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run(ref srcStore) override { diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc index ca43f1530eef..0cac736b41dd 100644 --- a/src/nix/store-delete.cc +++ b/src/nix/store-delete.cc @@ -9,15 +9,14 @@ using namespace nix; struct CmdStoreDelete : StorePathsCommand { - GCOptions options { .action = GCOptions::gcDeleteSpecific }; + GCOptions options{.action = GCOptions::gcDeleteSpecific}; CmdStoreDelete() { - addFlag({ - .longName = "ignore-liveness", - .description = "Do not check whether the paths are reachable from a root.", - .handler = {&options.ignoreLiveness, true} - }); + addFlag( + {.longName = "ignore-liveness", + .description = "Do not check whether the paths are reachable from a root.", + .handler = {&options.ignoreLiveness, true}}); } std::string description() override @@ -28,8 +27,8 @@ struct CmdStoreDelete : StorePathsCommand std::string doc() override { return - #include "store-delete.md" - ; +#include "store-delete.md" + ; } void run(ref store, std::vector && storePaths) override diff --git a/src/nix/store-gc.cc b/src/nix/store-gc.cc index 8b9b5d1642a8..8d5e0b487b1b 100644 --- a/src/nix/store-gc.cc +++ b/src/nix/store-gc.cc @@ -13,12 +13,11 @@ struct CmdStoreGC : StoreCommand, MixDryRun CmdStoreGC() { - addFlag({ - .longName = "max", - .description = "Stop after freeing *n* bytes of disk space.", - .labels = {"n"}, - .handler = {&options.maxFreed} - }); + addFlag( + {.longName = "max", + .description = "Stop after freeing *n* bytes of disk space.", + .labels = {"n"}, + .handler = {&options.maxFreed}}); } std::string description() override @@ -29,8 +28,8 @@ struct CmdStoreGC : StoreCommand, MixDryRun std::string doc() override { return - #include "store-gc.md" - ; +#include "store-gc.md" + ; } void run(ref store) override diff --git a/src/nix/store-repair.cc b/src/nix/store-repair.cc index 8fcb3639a43f..d968b60d0c9b 100644 --- a/src/nix/store-repair.cc +++ b/src/nix/store-repair.cc @@ -13,8 +13,8 @@ struct CmdStoreRepair : StorePathsCommand std::string doc() override { return - #include "store-repair.md" - ; +#include "store-repair.md" + ; } void run(ref store, std::vector && storePaths) override diff --git a/src/nix/store.cc b/src/nix/store.cc index 44e53c7c7586..f81b1610ac7d 100644 --- a/src/nix/store.cc +++ b/src/nix/store.cc @@ -4,15 +4,19 @@ using namespace nix; struct CmdStore : virtual NixMultiCommand { - CmdStore() : MultiCommand(RegisterCommand::getCommandsFor({"store"})) - { } + CmdStore() + : MultiCommand(RegisterCommand::getCommandsFor({"store"})) + {} std::string description() override { return "manipulate a Nix store"; } - Category category() override { return catUtility; } + Category category() override + { + return catUtility; + } void run() override { diff --git a/src/nix/upgrade-nix.cc b/src/nix/upgrade-nix.cc index 2d2453395f3a..4e0af68e710d 100644 --- a/src/nix/upgrade-nix.cc +++ b/src/nix/upgrade-nix.cc @@ -12,24 +12,23 @@ using namespace nix; struct CmdUpgradeNix : MixDryRun, StoreCommand { Path profileDir; - std::string storePathsUrl = "https://github.com/NixOS/nixpkgs/raw/master/nixos/modules/installer/tools/nix-fallback-paths.nix"; + std::string storePathsUrl = + "https://github.com/NixOS/nixpkgs/raw/master/nixos/modules/installer/tools/nix-fallback-paths.nix"; CmdUpgradeNix() { - addFlag({ - .longName = "profile", - .shortName = 'p', - .description = "The path to the Nix profile to upgrade.", - .labels = {"profile-dir"}, - .handler = {&profileDir} - }); - - addFlag({ - .longName = "nix-store-paths-url", - .description = "The URL of the file that contains the store paths of the latest Nix release.", - .labels = {"url"}, - .handler = {&storePathsUrl} - }); + addFlag( + {.longName = "profile", + .shortName = 'p', + .description = "The path to the Nix profile to upgrade.", + .labels = {"profile-dir"}, + .handler = {&profileDir}}); + + addFlag( + {.longName = "nix-store-paths-url", + .description = "The URL of the file that contains the store paths of the latest Nix release.", + .labels = {"url"}, + .handler = {&storePathsUrl}}); } std::string description() override @@ -40,11 +39,14 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand std::string doc() override { return - #include "upgrade-nix.md" - ; +#include "upgrade-nix.md" + ; } - Category category() override { return catNixInstallation; } + Category category() override + { + return catNixInstallation; + } void run(ref store) override { @@ -71,7 +73,8 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand } { - Activity act(*logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", store->printStorePath(storePath))); + Activity act( + *logger, lvlInfo, actUnknown, fmt("verifying that '%s' works...", store->printStorePath(storePath))); auto program = store->printStorePath(storePath) + "/bin/nix-env"; auto s = runProgram(program, false, {"--version"}); if (s.find("Nix") == std::string::npos) @@ -81,9 +84,11 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand stopProgressBar(); { - Activity act(*logger, lvlInfo, actUnknown, + Activity act( + *logger, lvlInfo, actUnknown, fmt("installing '%s' into profile '%s'...", store->printStorePath(storePath), profileDir)); - runProgram(settings.nixBinDir + "/nix-env", false, + runProgram( + settings.nixBinDir + "/nix-env", false, {"--profile", profileDir, "-i", store->printStorePath(storePath), "--no-sandbox"}); } @@ -119,8 +124,7 @@ struct CmdUpgradeNix : MixDryRun, StoreCommand Path userEnv = canonPath(profileDir, true); - if (baseNameOf(where) != "bin" || - !hasSuffix(userEnv, "user-environment")) + if (baseNameOf(where) != "bin" || !hasSuffix(userEnv, "user-environment")) throw Error("directory '%s' does not appear to be part of a Nix profile", where); if (!store->isValidPath(store->parseStorePath(userEnv))) diff --git a/src/nix/verify.cc b/src/nix/verify.cc index e92df1303144..1791e0d1a29e 100644 --- a/src/nix/verify.cc +++ b/src/nix/verify.cc @@ -30,21 +30,19 @@ struct CmdVerify : StorePathsCommand .handler = {&noTrust, true}, }); - addFlag({ - .longName = "substituter", - .shortName = 's', - .description = "Use signatures from the specified store.", - .labels = {"store-uri"}, - .handler = {[&](std::string s) { substituterUris.push_back(s); }} - }); - - addFlag({ - .longName = "sigs-needed", - .shortName = 'n', - .description = "Require that each path has at least *n* valid signatures.", - .labels = {"n"}, - .handler = {&sigsNeeded} - }); + addFlag( + {.longName = "substituter", + .shortName = 's', + .description = "Use signatures from the specified store.", + .labels = {"store-uri"}, + .handler = {[&](std::string s) { substituterUris.push_back(s); }}}); + + addFlag( + {.longName = "sigs-needed", + .shortName = 'n', + .description = "Require that each path has at least *n* valid signatures.", + .labels = {"n"}, + .handler = {&sigsNeeded}}); } std::string description() override @@ -55,8 +53,8 @@ struct CmdVerify : StorePathsCommand std::string doc() override { return - #include "verify.md" - ; +#include "verify.md" + ; } void run(ref store, StorePaths && storePaths) override @@ -75,9 +73,7 @@ struct CmdVerify : StorePathsCommand std::atomic failed{0}; std::atomic active{0}; - auto update = [&]() { - act.progress(done, storePaths.size(), active, failed); - }; + auto update = [&]() { act.progress(done, storePaths.size(), active, failed); }; ThreadPool pool; @@ -106,10 +102,9 @@ struct CmdVerify : StorePathsCommand if (hash.first != info->narHash) { corrupted++; act2.result(resCorruptedPath, store->printStorePath(info->path)); - printError("path '%s' was modified! expected hash '%s', got '%s'", - store->printStorePath(info->path), - info->narHash.to_string(Base32, true), - hash.first.to_string(Base32, true)); + printError( + "path '%s' was modified! expected hash '%s', got '%s'", store->printStorePath(info->path), + info->narHash.to_string(Base32, true), hash.first.to_string(Base32, true)); } } @@ -128,21 +123,25 @@ struct CmdVerify : StorePathsCommand auto doSigs = [&](StringSet sigs) { for (auto sig : sigs) { - if (!sigsSeen.insert(sig).second) continue; + if (!sigsSeen.insert(sig).second) + continue; if (validSigs < ValidPathInfo::maxSigs && info->checkSignature(*store, publicKeys, sig)) validSigs++; } }; - if (info->isContentAddressed(*store)) validSigs = ValidPathInfo::maxSigs; + if (info->isContentAddressed(*store)) + validSigs = ValidPathInfo::maxSigs; doSigs(info->sigs); for (auto & store2 : substituters) { - if (validSigs >= actualSigsNeeded) break; + if (validSigs >= actualSigsNeeded) + break; try { auto info2 = store2->queryPathInfo(info->path); - if (info2->isContentAddressed(*store)) validSigs = ValidPathInfo::maxSigs; + if (info2->isContentAddressed(*store)) + validSigs = ValidPathInfo::maxSigs; doSigs(info2->sigs); } catch (InvalidPath &) { } catch (Error & e) { @@ -159,7 +158,6 @@ struct CmdVerify : StorePathsCommand act2.result(resUntrustedPath, store->printStorePath(info->path)); printError("path '%s' is untrusted", store->printStorePath(info->path)); } - } done++; @@ -177,10 +175,7 @@ struct CmdVerify : StorePathsCommand pool.process(); - throw Exit( - (corrupted ? 1 : 0) | - (untrusted ? 2 : 0) | - (failed ? 4 : 0)); + throw Exit((corrupted ? 1 : 0) | (untrusted ? 2 : 0) | (failed ? 4 : 0)); } }; diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc index 1d9ab28baa05..f7be93d4f4b4 100644 --- a/src/nix/why-depends.cc +++ b/src/nix/why-depends.cc @@ -8,15 +8,9 @@ using namespace nix; -static std::string hilite(const std::string & s, size_t pos, size_t len, - const std::string & colour = ANSI_RED) +static std::string hilite(const std::string & s, size_t pos, size_t len, const std::string & colour = ANSI_RED) { - return - std::string(s, 0, pos) - + colour - + std::string(s, pos, len) - + ANSI_NORMAL - + std::string(s, pos + len); + return std::string(s, 0, pos) + colour + std::string(s, pos, len) + ANSI_NORMAL + std::string(s, pos + len); } static std::string filterPrintable(const std::string & s) @@ -35,32 +29,27 @@ struct CmdWhyDepends : SourceExprCommand CmdWhyDepends() { - expectArgs({ - .label = "package", - .handler = {&_package}, - .completer = {[&](size_t, std::string_view prefix) { - completeInstallable(prefix); - }} - }); + expectArgs({.label = "package", .handler = {&_package}, .completer = {[&](size_t, std::string_view prefix) { + completeInstallable(prefix); + }}}); - expectArgs({ - .label = "dependency", - .handler = {&_dependency}, - .completer = {[&](size_t, std::string_view prefix) { - completeInstallable(prefix); - }} - }); + expectArgs( + {.label = "dependency", .handler = {&_dependency}, .completer = {[&](size_t, std::string_view prefix) { + completeInstallable(prefix); + }}}); addFlag({ .longName = "all", .shortName = 'a', - .description = "Show all edges in the dependency graph leading from *package* to *dependency*, rather than just a shortest path.", + .description = + "Show all edges in the dependency graph leading from *package* to *dependency*, rather than just a shortest path.", .handler = {&all, true}, }); addFlag({ .longName = "precise", - .description = "For each edge in the dependency graph, show the files in the parent that cause the dependency.", + .description = + "For each edge in the dependency graph, show the files in the parent that cause the dependency.", .handler = {&precise, true}, }); } @@ -73,26 +62,30 @@ struct CmdWhyDepends : SourceExprCommand std::string doc() override { return - #include "why-depends.md" - ; +#include "why-depends.md" + ; } - Category category() override { return catSecondary; } + Category category() override + { + return catSecondary; + } void run(ref store) override { auto package = parseInstallable(store, _package); auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package); auto dependency = parseInstallable(store, _dependency); - auto dependencyPath = Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency); + auto dependencyPath = + Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency); auto dependencyPathHash = dependencyPath.hashPart(); StorePathSet closure; store->computeFSClosure({packagePath}, closure, false, false); if (!closure.count(dependencyPath)) { - printError("'%s' does not depend on '%s'", - store->printStorePath(packagePath), + printError( + "'%s' does not depend on '%s'", store->printStorePath(packagePath), store->printStorePath(dependencyPath)); return; } @@ -117,11 +110,11 @@ struct CmdWhyDepends : SourceExprCommand std::map graph; for (auto & path : closure) - graph.emplace(path, Node { - .path = path, - .refs = store->queryPathInfo(path)->references, - .dist = path == dependencyPath ? 0 : inf - }); + graph.emplace( + path, Node{ + .path = path, + .refs = store->queryPathInfo(path)->references, + .dist = path == dependencyPath ? 0 : inf}); // Transpose the graph. for (auto & node : graph) @@ -149,7 +142,6 @@ struct CmdWhyDepends : SourceExprCommand queue.push(&node2); } } - } } @@ -159,26 +151,26 @@ struct CmdWhyDepends : SourceExprCommand and `dependency`. */ std::function printNode; - struct BailOut { }; + struct BailOut + {}; printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) { auto pathS = store->printStorePath(node.path); assert(node.dist != inf); if (precise) { - logger->cout("%s%s%s%s" ANSI_NORMAL, - firstPad, - node.visited ? "\e[38;5;244m" : "", - firstPad != "" ? "→ " : "", + logger->cout( + "%s%s%s%s" ANSI_NORMAL, firstPad, node.visited ? "\e[38;5;244m" : "", firstPad != "" ? "→ " : "", pathS); } - if (node.path == dependencyPath && !all - && packagePath != dependencyPath) + if (node.path == dependencyPath && !all && packagePath != dependencyPath) throw BailOut(); - if (node.visited) return; - if (precise) node.visited = true; + if (node.visited) + return; + if (precise) + node.visited = true; /* Sort the references by distance to `dependency` to ensure that the shortest path is printed first. */ @@ -186,9 +178,11 @@ struct CmdWhyDepends : SourceExprCommand std::set hashes; for (auto & ref : node.refs) { - if (ref == node.path && packagePath != dependencyPath) continue; + if (ref == node.path && packagePath != dependencyPath) + continue; auto & node2 = graph.at(ref); - if (node2.dist == inf) continue; + if (node2.dist == inf) + continue; refs.emplace(node2.dist, &node2); hashes.insert(std::string(node2.path.hashPart())); } @@ -222,12 +216,11 @@ struct CmdWhyDepends : SourceExprCommand if (pos != std::string::npos) { size_t margin = 32; auto pos2 = pos >= margin ? pos - margin : 0; - hits[hash].emplace_back(fmt("%s: …%s…\n", - p2, - hilite(filterPrintable( - std::string(contents, pos2, pos - pos2 + hash.size() + margin)), - pos - pos2, StorePath::HashLen, - getColour(hash)))); + hits[hash].emplace_back( + fmt("%s: …%s…\n", p2, + hilite( + filterPrintable(std::string(contents, pos2, pos - pos2 + hash.size() + margin)), + pos - pos2, StorePath::HashLen, getColour(hash)))); } } } @@ -238,15 +231,16 @@ struct CmdWhyDepends : SourceExprCommand for (auto & hash : hashes) { auto pos = target.find(hash); if (pos != std::string::npos) - hits[hash].emplace_back(fmt("%s -> %s\n", p2, - hilite(target, pos, StorePath::HashLen, getColour(hash)))); + hits[hash].emplace_back( + fmt("%s -> %s\n", p2, hilite(target, pos, StorePath::HashLen, getColour(hash)))); } } }; // FIXME: should use scanForReferences(). - if (precise) visitPath(pathS); + if (precise) + visitPath(pathS); for (auto & ref : refs) { std::string hash(ref.second->path.hashPart()); @@ -255,25 +249,21 @@ struct CmdWhyDepends : SourceExprCommand for (auto & hit : hits[hash]) { bool first = hit == *hits[hash].begin(); - std::cout << tailPad - << (first ? (last ? treeLast : treeConn) : (last ? treeNull : treeLine)) + std::cout << tailPad << (first ? (last ? treeLast : treeConn) : (last ? treeNull : treeLine)) << hit; - if (!all) break; + if (!all) + break; } if (!precise) { auto pathS = store->printStorePath(ref.second->path); - logger->cout("%s%s%s%s" ANSI_NORMAL, - firstPad, - ref.second->visited ? "\e[38;5;244m" : "", - last ? treeLast : treeConn, - pathS); + logger->cout( + "%s%s%s%s" ANSI_NORMAL, firstPad, ref.second->visited ? "\e[38;5;244m" : "", + last ? treeLast : treeConn, pathS); node.visited = true; } - printNode(*ref.second, - tailPad + (last ? treeNull : treeLine), - tailPad + (last ? treeNull : treeLine)); + printNode(*ref.second, tailPad + (last ? treeNull : treeLine), tailPad + (last ? treeNull : treeLine)); } }; @@ -283,7 +273,8 @@ struct CmdWhyDepends : SourceExprCommand logger->cout("%s", store->printStorePath(graph.at(packagePath).path)); } printNode(graph.at(packagePath), "", ""); - } catch (BailOut & ) { } + } catch (BailOut &) { + } } }; diff --git a/src/resolve-system-dependencies/resolve-system-dependencies.cc b/src/resolve-system-dependencies/resolve-system-dependencies.cc index c6023eb03874..e2a9731de4e2 100644 --- a/src/resolve-system-dependencies/resolve-system-dependencies.cc +++ b/src/resolve-system-dependencies/resolve-system-dependencies.cc @@ -48,18 +48,18 @@ std::set runResolver(const Path & filename) return {}; } - char* obj = (char*) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0); + char * obj = (char *) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd.get(), 0); if (!obj) throw SysError("mmapping '%s'", filename); ptrdiff_t mach64_offset = 0; - uint32_t magic = ((mach_header_64*) obj)->magic; + uint32_t magic = ((mach_header_64 *) obj)->magic; if (magic == FAT_CIGAM || magic == FAT_MAGIC) { bool should_swap = magic == FAT_CIGAM; uint32_t narches = DO_SWAP(should_swap, ((fat_header *) obj)->nfat_arch); for (uint32_t i = 0; i < narches; i++) { - fat_arch* arch = (fat_arch*) (obj + sizeof(fat_header) + sizeof(fat_arch) * i); + fat_arch * arch = (fat_arch *) (obj + sizeof(fat_header) + sizeof(fat_arch) * i); if (DO_SWAP(should_swap, arch->cputype) == CPU_TYPE_X86_64) { mach64_offset = (ptrdiff_t) DO_SWAP(should_swap, arch->offset); break; @@ -84,12 +84,12 @@ std::set runResolver(const Path & filename) std::set libs; for (uint32_t i = 0; i < DO_SWAP(should_swap, m_header->ncmds); i++) { load_command * cmd = (load_command *) (obj + cmd_offset); - switch(DO_SWAP(should_swap, cmd->cmd)) { - case LC_LOAD_UPWARD_DYLIB: - case LC_LOAD_DYLIB: - case LC_REEXPORT_DYLIB: - libs.insert(std::string((char *) cmd + ((dylib_command*) cmd)->dylib.name.offset)); - break; + switch (DO_SWAP(should_swap, cmd->cmd)) { + case LC_LOAD_UPWARD_DYLIB: + case LC_LOAD_DYLIB: + case LC_REEXPORT_DYLIB: + libs.insert(std::string((char *) cmd + ((dylib_command *) cmd)->dylib.name.offset)); + break; } cmd_offset += DO_SWAP(should_swap, cmd->cmdsize); } @@ -105,15 +105,14 @@ bool isSymlink(const Path & path) Path resolveSymlink(const Path & path) { auto target = readLink(path); - return hasPrefix(target, "/") - ? target - : concatStrings(dirOf(path), "/", target); + return hasPrefix(target, "/") ? target : concatStrings(dirOf(path), "/", target); } std::set resolveTree(const Path & path, PathSet & deps) { std::set results; - if (!deps.insert(path).second) return {}; + if (!deps.insert(path).second) + return {}; for (auto & lib : runResolver(path)) { results.insert(lib); for (auto & p : resolveTree(lib, deps)) { @@ -125,7 +124,8 @@ std::set resolveTree(const Path & path, PathSet & deps) std::set getPath(const Path & path) { - if (hasPrefix(path, "/dev")) return {}; + if (hasPrefix(path, "/dev")) + return {}; Path cacheFile = resolveCacheFile(path); if (pathExists(cacheFile)) @@ -159,11 +159,8 @@ int main(int argc, char ** argv) auto cacheParentDir = (format("%1%/dependency-maps") % settings.nixStateDir).str(); - cacheDir = (format("%1%/%2%-%3%-%4%") - % cacheParentDir - % _uname.machine - % _uname.sysname - % _uname.release).str(); + cacheDir = + (format("%1%/%2%-%3%-%4%") % cacheParentDir % _uname.machine % _uname.sysname % _uname.release).str(); mkdir(cacheParentDir.c_str(), 0755); mkdir(cacheDir.c_str(), 0755); diff --git a/tests/plugins/plugintest.cc b/tests/plugins/plugintest.cc index 04b7910216bd..faac6fe57f00 100644 --- a/tests/plugins/plugintest.cc +++ b/tests/plugins/plugintest.cc @@ -5,15 +5,14 @@ using namespace nix; struct MySettings : Config { - Setting settingSet{this, false, "setting-set", - "Whether the plugin-defined setting was set"}; + Setting settingSet{this, false, "setting-set", "Whether the plugin-defined setting was set"}; }; MySettings mySettings; static GlobalConfig::Register rs(&mySettings); -static void prim_anotherNull (EvalState & state, const PosIdx pos, Value ** args, Value & v) +static void prim_anotherNull(EvalState & state, const PosIdx pos, Value ** args, Value & v) { if (mySettings.settingSet) v.mkNull();