aboutsummaryrefslogtreecommitdiff
path: root/src/libcmd
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2023-02-28 11:34:34 -0500
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-02-28 11:34:34 -0500
commitd12f57c2c0ef32180875aa4a0b803c838a7d988f (patch)
tree2c046d98bc0bd9171881ff0b6d56fa89c7c642e6 /src/libcmd
parentc36b584f8eb103afa152ef4304cf9fd5c3ebaaf0 (diff)
parent4489def1b36aeaee2254159efc1c21c868cc8585 (diff)
Merge remote-tracking branch 'upstream/master' into path-info
Diffstat (limited to 'src/libcmd')
-rw-r--r--src/libcmd/command.cc27
-rw-r--r--src/libcmd/command.hh30
-rw-r--r--src/libcmd/editor-for.cc20
-rw-r--r--src/libcmd/editor-for.hh11
-rw-r--r--src/libcmd/installable-attr-path.cc109
-rw-r--r--src/libcmd/installable-attr-path.hh56
-rw-r--r--src/libcmd/installable-derived-path.cc70
-rw-r--r--src/libcmd/installable-derived-path.hh28
-rw-r--r--src/libcmd/installable-flake.cc236
-rw-r--r--src/libcmd/installable-flake.hh50
-rw-r--r--src/libcmd/installable-value.hh14
-rw-r--r--src/libcmd/installables.cc408
-rw-r--r--src/libcmd/installables.hh50
-rw-r--r--src/libcmd/local.mk2
-rw-r--r--src/libcmd/nix-cmd.pc.in2
-rw-r--r--src/libcmd/repl.cc128
-rw-r--r--src/libcmd/repl.hh39
17 files changed, 715 insertions, 565 deletions
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 0740ea960..ab51c229d 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -4,6 +4,7 @@
#include "derivations.hh"
#include "nixexpr.hh"
#include "profiles.hh"
+#include "repl.hh"
#include <nlohmann/json.hpp>
@@ -121,12 +122,22 @@ ref<EvalState> EvalCommand::getEvalState()
;
if (startReplOnEvalErrors) {
- evalState->debugRepl = &runRepl;
+ evalState->debugRepl = &AbstractNixRepl::runSimple;
};
}
return ref<EvalState>(evalState);
}
+MixOperateOnOptions::MixOperateOnOptions()
+{
+ addFlag({
+ .longName = "derivation",
+ .description = "Operate on the [store derivation](../../glossary.md#gloss-store-derivation) rather than its outputs.",
+ .category = installablesCategory,
+ .handler = {&operateOn, OperateOn::Derivation},
+ });
+}
+
BuiltPathsCommand::BuiltPathsCommand(bool recursive)
: recursive(recursive)
{
@@ -208,20 +219,6 @@ void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePath
run(store, *storePaths.begin());
}
-Strings editorFor(const Path & file, uint32_t line)
-{
- auto editor = getEnv("EDITOR").value_or("cat");
- auto args = tokenizeString<Strings>(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))
- args.push_back(fmt("+%d", line));
- args.push_back(file);
- return args;
-}
-
MixProfile::MixProfile()
{
addFlag({
diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh
index 3b4b40981..b6d554aab 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -94,12 +94,8 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
{
std::optional<Path> file;
std::optional<std::string> expr;
- bool readOnlyMode = false;
- // FIXME: move this; not all commands (e.g. 'nix run') use it.
- OperateOn operateOn = OperateOn::Output;
-
- SourceExprCommand(bool supportReadOnlyMode = false);
+ SourceExprCommand();
std::vector<std::shared_ptr<Installable>> parseInstallables(
ref<Store> store, std::vector<std::string> ss);
@@ -114,6 +110,11 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
void completeInstallable(std::string_view prefix);
};
+struct MixReadOnlyOption : virtual Args
+{
+ MixReadOnlyOption();
+};
+
/* A command that operates on a list of "installables", which can be
store paths, attribute paths, Nix expressions, etc. */
struct InstallablesCommand : virtual Args, SourceExprCommand
@@ -139,7 +140,7 @@ struct InstallableCommand : virtual Args, SourceExprCommand
{
std::shared_ptr<Installable> installable;
- InstallableCommand(bool supportReadOnlyMode = false);
+ InstallableCommand();
void prepare() override;
@@ -153,8 +154,15 @@ private:
std::string _installable{"."};
};
+struct MixOperateOnOptions : virtual Args
+{
+ OperateOn operateOn = OperateOn::Output;
+
+ MixOperateOnOptions();
+};
+
/* A command that operates on zero or more store paths. */
-struct BuiltPathsCommand : public InstallablesCommand
+struct BuiltPathsCommand : InstallablesCommand, virtual MixOperateOnOptions
{
private:
@@ -227,10 +235,6 @@ static RegisterCommand registerCommand2(std::vector<std::string> && name)
return RegisterCommand(std::move(name), [](){ return make_ref<T>(); });
}
-/* Helper function to generate args that invoke $EDITOR on
- filename:lineno. */
-Strings editorFor(const Path & file, uint32_t line);
-
struct MixProfile : virtual StoreCommand
{
std::optional<Path> profile;
@@ -280,8 +284,4 @@ void printClosureDiff(
const StorePath & afterPath,
std::string_view indent);
-
-void runRepl(
- ref<EvalState> evalState,
- const ValMap & extraEnv);
}
diff --git a/src/libcmd/editor-for.cc b/src/libcmd/editor-for.cc
new file mode 100644
index 000000000..f674f32bd
--- /dev/null
+++ b/src/libcmd/editor-for.cc
@@ -0,0 +1,20 @@
+#include "util.hh"
+#include "editor-for.hh"
+
+namespace nix {
+
+Strings editorFor(const Path & file, uint32_t line)
+{
+ auto editor = getEnv("EDITOR").value_or("cat");
+ auto args = tokenizeString<Strings>(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))
+ args.push_back(fmt("+%d", line));
+ args.push_back(file);
+ return args;
+}
+
+}
diff --git a/src/libcmd/editor-for.hh b/src/libcmd/editor-for.hh
new file mode 100644
index 000000000..8fbd08792
--- /dev/null
+++ b/src/libcmd/editor-for.hh
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "types.hh"
+
+namespace nix {
+
+/* Helper function to generate args that invoke $EDITOR on
+ filename:lineno. */
+Strings editorFor(const Path & file, uint32_t line);
+
+}
diff --git a/src/libcmd/installable-attr-path.cc b/src/libcmd/installable-attr-path.cc
new file mode 100644
index 000000000..d9377f0d6
--- /dev/null
+++ b/src/libcmd/installable-attr-path.cc
@@ -0,0 +1,109 @@
+#include "globals.hh"
+#include "installable-attr-path.hh"
+#include "outputs-spec.hh"
+#include "util.hh"
+#include "command.hh"
+#include "attr-path.hh"
+#include "common-eval-args.hh"
+#include "derivations.hh"
+#include "eval-inline.hh"
+#include "eval.hh"
+#include "get-drvs.hh"
+#include "store-api.hh"
+#include "shared.hh"
+#include "flake/flake.hh"
+#include "eval-cache.hh"
+#include "url.hh"
+#include "registry.hh"
+#include "build-result.hh"
+
+#include <regex>
+#include <queue>
+
+#include <nlohmann/json.hpp>
+
+namespace nix {
+
+InstallableAttrPath::InstallableAttrPath(
+ ref<EvalState> state,
+ SourceExprCommand & cmd,
+ Value * v,
+ const std::string & attrPath,
+ ExtendedOutputsSpec extendedOutputsSpec)
+ : InstallableValue(state)
+ , cmd(cmd)
+ , v(allocRootValue(v))
+ , attrPath(attrPath)
+ , extendedOutputsSpec(std::move(extendedOutputsSpec))
+{ }
+
+std::pair<Value *, PosIdx> InstallableAttrPath::toValue(EvalState & state)
+{
+ auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
+ state.forceValue(*vRes, pos);
+ return {vRes, pos};
+}
+
+DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
+{
+ auto v = toValue(*state).first;
+
+ Bindings & autoArgs = *cmd.getAutoArgs(*state);
+
+ DrvInfos drvInfos;
+ getDerivations(*state, *v, "", autoArgs, drvInfos, false);
+
+ // Backward compatibility hack: group results by drvPath. This
+ // helps keep .all output together.
+ std::map<StorePath, OutputsSpec> byDrvPath;
+
+ for (auto & drvInfo : drvInfos) {
+ auto drvPath = drvInfo.queryDrvPath();
+ if (!drvPath)
+ throw Error("'%s' is not a derivation", what());
+
+ auto newOutputs = std::visit(overloaded {
+ [&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
+ std::set<std::string> outputsToInstall;
+ for (auto & output : drvInfo.queryOutputs(false, true))
+ outputsToInstall.insert(output.first);
+ return OutputsSpec::Names { std::move(outputsToInstall) };
+ },
+ [&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
+ return e;
+ },
+ }, extendedOutputsSpec.raw());
+
+ auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
+
+ if (!didInsert)
+ iter->second = iter->second.union_(newOutputs);
+ }
+
+ DerivedPathsWithInfo res;
+ for (auto & [drvPath, outputs] : byDrvPath)
+ res.push_back({
+ .path = DerivedPath::Built {
+ .drvPath = drvPath,
+ .outputs = outputs,
+ },
+ });
+
+ return res;
+}
+
+InstallableAttrPath InstallableAttrPath::parse(
+ ref<EvalState> state,
+ SourceExprCommand & cmd,
+ Value * v,
+ std::string_view prefix,
+ ExtendedOutputsSpec extendedOutputsSpec)
+{
+ return {
+ state, cmd, v,
+ prefix == "." ? "" : std::string { prefix },
+ extendedOutputsSpec
+ };
+}
+
+}
diff --git a/src/libcmd/installable-attr-path.hh b/src/libcmd/installable-attr-path.hh
new file mode 100644
index 000000000..c06132ec8
--- /dev/null
+++ b/src/libcmd/installable-attr-path.hh
@@ -0,0 +1,56 @@
+#include "globals.hh"
+#include "installable-value.hh"
+#include "outputs-spec.hh"
+#include "util.hh"
+#include "command.hh"
+#include "attr-path.hh"
+#include "common-eval-args.hh"
+#include "derivations.hh"
+#include "eval-inline.hh"
+#include "eval.hh"
+#include "get-drvs.hh"
+#include "store-api.hh"
+#include "shared.hh"
+#include "eval-cache.hh"
+#include "url.hh"
+#include "registry.hh"
+#include "build-result.hh"
+
+#include <regex>
+#include <queue>
+
+#include <nlohmann/json.hpp>
+
+namespace nix {
+
+class InstallableAttrPath : public InstallableValue
+{
+ SourceExprCommand & cmd;
+ RootValue v;
+ std::string attrPath;
+ ExtendedOutputsSpec extendedOutputsSpec;
+
+ InstallableAttrPath(
+ ref<EvalState> state,
+ SourceExprCommand & cmd,
+ Value * v,
+ const std::string & attrPath,
+ ExtendedOutputsSpec extendedOutputsSpec);
+
+ std::string what() const override { return attrPath; };
+
+ std::pair<Value *, PosIdx> toValue(EvalState & state) override;
+
+ DerivedPathsWithInfo toDerivedPaths() override;
+
+public:
+
+ static InstallableAttrPath parse(
+ ref<EvalState> state,
+ SourceExprCommand & cmd,
+ Value * v,
+ std::string_view prefix,
+ ExtendedOutputsSpec extendedOutputsSpec);
+};
+
+}
diff --git a/src/libcmd/installable-derived-path.cc b/src/libcmd/installable-derived-path.cc
new file mode 100644
index 000000000..a9921b901
--- /dev/null
+++ b/src/libcmd/installable-derived-path.cc
@@ -0,0 +1,70 @@
+#include "installable-derived-path.hh"
+#include "derivations.hh"
+
+namespace nix {
+
+std::string InstallableDerivedPath::what() const
+{
+ return derivedPath.to_string(*store);
+}
+
+DerivedPathsWithInfo InstallableDerivedPath::toDerivedPaths()
+{
+ return {{.path = derivedPath, .info = {} }};
+}
+
+std::optional<StorePath> InstallableDerivedPath::getStorePath()
+{
+ return std::visit(overloaded {
+ [&](const DerivedPath::Built & bfd) {
+ return bfd.drvPath;
+ },
+ [&](const DerivedPath::Opaque & bo) {
+ return bo.path;
+ },
+ }, derivedPath.raw());
+}
+
+InstallableDerivedPath InstallableDerivedPath::parse(
+ ref<Store> store,
+ std::string_view prefix,
+ ExtendedOutputsSpec extendedOutputsSpec)
+{
+ auto derivedPath = std::visit(overloaded {
+ // If the user did not use ^, we treat the output more liberally.
+ [&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
+ // First, we accept a symlink chain or an actual store path.
+ auto storePath = store->followLinksToStorePath(prefix);
+ // Second, we see if the store path ends in `.drv` to decide what sort
+ // of derived path they want.
+ //
+ // This handling predates the `^` syntax. The `^*` in
+ // `/nix/store/hash-foo.drv^*` unambiguously means "do the
+ // `DerivedPath::Built` case", so plain `/nix/store/hash-foo.drv` could
+ // also unambiguously mean "do the DerivedPath::Opaque` case".
+ //
+ // Issue #7261 tracks reconsidering this `.drv` dispatching.
+ return storePath.isDerivation()
+ ? (DerivedPath) DerivedPath::Built {
+ .drvPath = std::move(storePath),
+ .outputs = OutputsSpec::All {},
+ }
+ : (DerivedPath) DerivedPath::Opaque {
+ .path = std::move(storePath),
+ };
+ },
+ // If the user did use ^, we just do exactly what is written.
+ [&](const ExtendedOutputsSpec::Explicit & outputSpec) -> DerivedPath {
+ return DerivedPath::Built {
+ .drvPath = store->parseStorePath(prefix),
+ .outputs = outputSpec,
+ };
+ },
+ }, extendedOutputsSpec.raw());
+ return InstallableDerivedPath {
+ store,
+ std::move(derivedPath),
+ };
+}
+
+}
diff --git a/src/libcmd/installable-derived-path.hh b/src/libcmd/installable-derived-path.hh
new file mode 100644
index 000000000..042878b91
--- /dev/null
+++ b/src/libcmd/installable-derived-path.hh
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "installables.hh"
+
+namespace nix {
+
+struct InstallableDerivedPath : Installable
+{
+ ref<Store> store;
+ DerivedPath derivedPath;
+
+ InstallableDerivedPath(ref<Store> store, DerivedPath && derivedPath)
+ : store(store), derivedPath(std::move(derivedPath))
+ { }
+
+ std::string what() const override;
+
+ DerivedPathsWithInfo toDerivedPaths() override;
+
+ std::optional<StorePath> getStorePath() override;
+
+ static InstallableDerivedPath parse(
+ ref<Store> store,
+ std::string_view prefix,
+ ExtendedOutputsSpec extendedOutputsSpec);
+};
+
+}
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
new file mode 100644
index 000000000..60a97deaf
--- /dev/null
+++ b/src/libcmd/installable-flake.cc
@@ -0,0 +1,236 @@
+#include "globals.hh"
+#include "installable-flake.hh"
+#include "installable-derived-path.hh"
+#include "outputs-spec.hh"
+#include "util.hh"
+#include "command.hh"
+#include "attr-path.hh"
+#include "common-eval-args.hh"
+#include "derivations.hh"
+#include "eval-inline.hh"
+#include "eval.hh"
+#include "get-drvs.hh"
+#include "store-api.hh"
+#include "shared.hh"
+#include "flake/flake.hh"
+#include "eval-cache.hh"
+#include "url.hh"
+#include "registry.hh"
+#include "build-result.hh"
+
+#include <regex>
+#include <queue>
+
+#include <nlohmann/json.hpp>
+
+namespace nix {
+
+std::vector<std::string> InstallableFlake::getActualAttrPaths()
+{
+ std::vector<std::string> res;
+
+ for (auto & prefix : prefixes)
+ res.push_back(prefix + *attrPaths.begin());
+
+ for (auto & s : attrPaths)
+ res.push_back(s);
+
+ return res;
+}
+
+Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake)
+{
+ auto vFlake = state.allocValue();
+
+ callFlake(state, lockedFlake, *vFlake);
+
+ auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
+ assert(aOutputs);
+
+ state.forceValue(*aOutputs->value, [&]() { return aOutputs->value->determinePos(noPos); });
+
+ return aOutputs->value;
+}
+
+static std::string showAttrPaths(const std::vector<std::string> & paths)
+{
+ std::string s;
+ for (const auto & [n, i] : enumerate(paths)) {
+ if (n > 0) s += n + 1 == paths.size() ? " or " : ", ";
+ s += '\''; s += i; s += '\'';
+ }
+ return s;
+}
+
+InstallableFlake::InstallableFlake(
+ SourceExprCommand * cmd,
+ ref<EvalState> state,
+ FlakeRef && flakeRef,
+ std::string_view fragment,
+ ExtendedOutputsSpec extendedOutputsSpec,
+ Strings attrPaths,
+ Strings prefixes,
+ const flake::LockFlags & lockFlags)
+ : InstallableValue(state),
+ flakeRef(flakeRef),
+ attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}),
+ prefixes(fragment == "" ? Strings{} : prefixes),
+ extendedOutputsSpec(std::move(extendedOutputsSpec)),
+ lockFlags(lockFlags)
+{
+ if (cmd && cmd->getAutoArgs(*state)->size())
+ throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
+}
+
+DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
+{
+ Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
+
+ auto attr = getCursor(*state);
+
+ auto attrPath = attr->getAttrPathStr();
+
+ if (!attr->isDerivation()) {
+
+ // FIXME: use eval cache?
+ auto v = attr->forceValue();
+
+ if (v.type() == nPath) {
+ PathSet context;
+ auto storePath = state->copyPathToStore(context, Path(v.path));
+ return {{
+ .path = DerivedPath::Opaque {
+ .path = std::move(storePath),
+ }
+ }};
+ }
+
+ else if (v.type() == nString) {
+ PathSet context;
+ auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
+ auto storePath = state->store->maybeParseStorePath(s);
+ if (storePath && context.count(std::string(s))) {
+ return {{
+ .path = DerivedPath::Opaque {
+ .path = std::move(*storePath),
+ }
+ }};
+ } else
+ throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
+ }
+
+ else
+ throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
+ }
+
+ auto drvPath = attr->forceDerivation();
+
+ std::optional<NixInt> priority;
+
+ if (attr->maybeGetAttr(state->sOutputSpecified)) {
+ } else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
+ if (auto aPriority = aMeta->maybeGetAttr("priority"))
+ priority = aPriority->getInt();
+ }
+
+ return {{
+ .path = DerivedPath::Built {
+ .drvPath = std::move(drvPath),
+ .outputs = std::visit(overloaded {
+ [&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
+ std::set<std::string> outputsToInstall;
+ if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
+ if (aOutputSpecified->getBool()) {
+ if (auto aOutputName = attr->maybeGetAttr("outputName"))
+ outputsToInstall = { aOutputName->getString() };
+ }
+ } else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
+ if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
+ for (auto & s : aOutputsToInstall->getListOfStrings())
+ outputsToInstall.insert(s);
+ }
+
+ if (outputsToInstall.empty())
+ outputsToInstall.insert("out");
+
+ return OutputsSpec::Names { std::move(outputsToInstall) };
+ },
+ [&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
+ return e;
+ },
+ }, extendedOutputsSpec.raw()),
+ },
+ .info = {
+ .priority = priority,
+ .originalRef = flakeRef,
+ .resolvedRef = getLockedFlake()->flake.lockedRef,
+ .attrPath = attrPath,
+ .extendedOutputsSpec = extendedOutputsSpec,
+ }
+ }};
+}
+
+std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
+{
+ return {&getCursor(state)->forceValue(), noPos};
+}
+
+std::vector<ref<eval_cache::AttrCursor>>
+InstallableFlake::getCursors(EvalState & state)
+{
+ auto evalCache = openEvalCache(state,
+ std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
+
+ auto root = evalCache->getRoot();
+
+ std::vector<ref<eval_cache::AttrCursor>> res;
+
+ Suggestions suggestions;
+ auto attrPaths = getActualAttrPaths();
+
+ for (auto & attrPath : attrPaths) {
+ debug("trying flake output attribute '%s'", attrPath);
+
+ auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
+ if (attr) {
+ res.push_back(ref(*attr));
+ } else {
+ suggestions += attr.getSuggestions();
+ }
+ }
+
+ if (res.size() == 0)
+ throw Error(
+ suggestions,
+ "flake '%s' does not provide attribute %s",
+ flakeRef,
+ showAttrPaths(attrPaths));
+
+ return res;
+}
+
+std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
+{
+ if (!_lockedFlake) {
+ flake::LockFlags lockFlagsApplyConfig = lockFlags;
+ lockFlagsApplyConfig.applyNixConfig = true;
+ _lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlagsApplyConfig));
+ }
+ return _lockedFlake;
+}
+
+FlakeRef InstallableFlake::nixpkgsFlakeRef() const
+{
+ auto lockedFlake = getLockedFlake();
+
+ if (auto nixpkgsInput = lockedFlake->lockFile.findInput({"nixpkgs"})) {
+ if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
+ debug("using nixpkgs flake '%s'", lockedNode->lockedRef);
+ return std::move(lockedNode->lockedRef);
+ }
+ }
+
+ return Installable::nixpkgsFlakeRef();
+}
+
+}
diff --git a/src/libcmd/installable-flake.hh b/src/libcmd/installable-flake.hh
new file mode 100644
index 000000000..c75765086
--- /dev/null
+++ b/src/libcmd/installable-flake.hh
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "installable-value.hh"
+
+namespace nix {
+
+struct InstallableFlake : InstallableValue
+{
+ FlakeRef flakeRef;
+ Strings attrPaths;
+ Strings prefixes;
+ ExtendedOutputsSpec extendedOutputsSpec;
+ const flake::LockFlags & lockFlags;
+ mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
+
+ InstallableFlake(
+ SourceExprCommand * cmd,
+ ref<EvalState> state,
+ FlakeRef && flakeRef,
+ std::string_view fragment,
+ ExtendedOutputsSpec extendedOutputsSpec,
+ Strings attrPaths,
+ Strings prefixes,
+ const flake::LockFlags & lockFlags);
+
+ std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
+
+ std::vector<std::string> getActualAttrPaths();
+
+ Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
+
+ DerivedPathsWithInfo toDerivedPaths() override;
+
+ std::pair<Value *, PosIdx> toValue(EvalState & state) override;
+
+ /* Get a cursor to every attrpath in getActualAttrPaths()
+ that exists. However if none exists, throw an exception. */
+ std::vector<ref<eval_cache::AttrCursor>>
+ getCursors(EvalState & state) override;
+
+ std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
+
+ FlakeRef nixpkgsFlakeRef() const override;
+};
+
+ref<eval_cache::EvalCache> openEvalCache(
+ EvalState & state,
+ std::shared_ptr<flake::LockedFlake> lockedFlake);
+
+}
diff --git a/src/libcmd/installable-value.hh b/src/libcmd/installable-value.hh
new file mode 100644
index 000000000..c6cdc4797
--- /dev/null
+++ b/src/libcmd/installable-value.hh
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "installables.hh"
+
+namespace nix {
+
+struct InstallableValue : Installable
+{
+ ref<EvalState> state;
+
+ InstallableValue(ref<EvalState> state) : state(state) {}
+};
+
+}
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 24f458f1a..00c6f9516 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -1,5 +1,8 @@
#include "globals.hh"
#include "installables.hh"
+#include "installable-derived-path.hh"
+#include "installable-attr-path.hh"
+#include "installable-flake.hh"
#include "outputs-spec.hh"
#include "util.hh"
#include "command.hh"
@@ -144,7 +147,7 @@ void MixFlakeOptions::completionHook()
completeFlakeInput(*prefix);
}
-SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
+SourceExprCommand::SourceExprCommand()
{
addFlag({
.longName = "file",
@@ -166,24 +169,18 @@ SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
.labels = {"expr"},
.handler = {&expr}
});
+}
+MixReadOnlyOption::MixReadOnlyOption()
+{
addFlag({
- .longName = "derivation",
- .description = "Operate on the [store derivation](../../glossary.md#gloss-store-derivation) rather than its outputs.",
- .category = installablesCategory,
- .handler = {&operateOn, OperateOn::Derivation},
+ .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.",
+ .handler = {&settings.readOnlyMode, true},
});
-
- 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.",
- .handler = {&readOnlyMode, true},
- });
- }
}
Strings SourceExprCommand::getDefaultFlakeAttrPaths()
@@ -396,143 +393,6 @@ static StorePath getDeriver(
return *derivers.begin();
}
-struct InstallableStorePath : Installable
-{
- ref<Store> store;
- DerivedPath req;
-
- InstallableStorePath(ref<Store> store, DerivedPath && req)
- : store(store), req(std::move(req))
- { }
-
- std::string what() const override
- {
- return req.to_string(*store);
- }
-
- DerivedPathsWithInfo toDerivedPaths() override
- {
- return {{.path = req, .info = {} }};
- }
-
- std::optional<StorePath> getStorePath() override
- {
- return std::visit(overloaded {
- [&](const DerivedPath::Built & bfd) {
- return bfd.drvPath;
- },
- [&](const DerivedPath::Opaque & bo) {
- return bo.path;
- },
- }, req.raw());
- }
-};
-
-struct InstallableAttrPath : InstallableValue
-{
- SourceExprCommand & cmd;
- RootValue v;
- std::string attrPath;
- ExtendedOutputsSpec extendedOutputsSpec;
-
- InstallableAttrPath(
- ref<EvalState> state,
- SourceExprCommand & cmd,
- Value * v,
- const std::string & attrPath,
- ExtendedOutputsSpec extendedOutputsSpec)
- : InstallableValue(state)
- , cmd(cmd)
- , v(allocRootValue(v))
- , attrPath(attrPath)
- , extendedOutputsSpec(std::move(extendedOutputsSpec))
- { }
-
- std::string what() const override { return attrPath; }
-
- std::pair<Value *, PosIdx> toValue(EvalState & state) override
- {
- auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v);
- state.forceValue(*vRes, pos);
- return {vRes, pos};
- }
-
- DerivedPathsWithInfo toDerivedPaths() override
- {
- auto v = toValue(*state).first;
-
- Bindings & autoArgs = *cmd.getAutoArgs(*state);
-
- DrvInfos drvInfos;
- getDerivations(*state, *v, "", autoArgs, drvInfos, false);
-
- // Backward compatibility hack: group results by drvPath. This
- // helps keep .all output together.
- std::map<StorePath, OutputsSpec> byDrvPath;
-
- for (auto & drvInfo : drvInfos) {
- auto drvPath = drvInfo.queryDrvPath();
- if (!drvPath)
- throw Error("'%s' is not a derivation", what());
-
- auto newOutputs = std::visit(overloaded {
- [&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
- std::set<std::string> outputsToInstall;
- for (auto & output : drvInfo.queryOutputs(false, true))
- outputsToInstall.insert(output.first);
- return OutputsSpec::Names { std::move(outputsToInstall) };
- },
- [&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
- return e;
- },
- }, extendedOutputsSpec.raw());
-
- auto [iter, didInsert] = byDrvPath.emplace(*drvPath, newOutputs);
-
- if (!didInsert)
- iter->second = iter->second.union_(newOutputs);
- }
-
- DerivedPathsWithInfo res;
- for (auto & [drvPath, outputs] : byDrvPath)
- res.push_back({
- .path = DerivedPath::Built {
- .drvPath = drvPath,
- .outputs = outputs,
- },
- });
-
- return res;
- }
-};
-
-std::vector<std::string> InstallableFlake::getActualAttrPaths()
-{
- std::vector<std::string> res;
-
- for (auto & prefix : prefixes)
- res.push_back(prefix + *attrPaths.begin());
-
- for (auto & s : attrPaths)
- res.push_back(s);
-
- return res;
-}
-
-Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake)
-{
- auto vFlake = state.allocValue();
-
- callFlake(state, lockedFlake, *vFlake);
-
- auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs"));
- assert(aOutputs);
-
- state.forceValue(*aOutputs->value, [&]() { return aOutputs->value->determinePos(noPos); });
-
- return aOutputs->value;
-}
-
ref<eval_cache::EvalCache> openEvalCache(
EvalState & state,
std::shared_ptr<flake::LockedFlake> lockedFlake)
@@ -562,196 +422,11 @@ ref<eval_cache::EvalCache> openEvalCache(
});
}
-static std::string showAttrPaths(const std::vector<std::string> & paths)
-{
- std::string s;
- for (const auto & [n, i] : enumerate(paths)) {
- if (n > 0) s += n + 1 == paths.size() ? " or " : ", ";
- s += '\''; s += i; s += '\'';
- }
- return s;
-}
-
-InstallableFlake::InstallableFlake(
- SourceExprCommand * cmd,
- ref<EvalState> state,
- FlakeRef && flakeRef,
- std::string_view fragment,
- ExtendedOutputsSpec extendedOutputsSpec,
- Strings attrPaths,
- Strings prefixes,
- const flake::LockFlags & lockFlags)
- : InstallableValue(state),
- flakeRef(flakeRef),
- attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}),
- prefixes(fragment == "" ? Strings{} : prefixes),
- extendedOutputsSpec(std::move(extendedOutputsSpec)),
- lockFlags(lockFlags)
-{
- if (cmd && cmd->getAutoArgs(*state)->size())
- throw UsageError("'--arg' and '--argstr' are incompatible with flakes");
-}
-
-DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
-{
- Activity act(*logger, lvlTalkative, actUnknown, fmt("evaluating derivation '%s'", what()));
-
- auto attr = getCursor(*state);
-
- auto attrPath = attr->getAttrPathStr();
-
- if (!attr->isDerivation()) {
-
- // FIXME: use eval cache?
- auto v = attr->forceValue();
-
- if (v.type() == nPath) {
- PathSet context;
- auto storePath = state->copyPathToStore(context, Path(v.path));
- return {{
- .path = DerivedPath::Opaque {
- .path = std::move(storePath),
- }
- }};
- }
-
- else if (v.type() == nString) {
- PathSet context;
- auto s = state->forceString(v, context, noPos, fmt("while evaluating the flake output attribute '%s'", attrPath));
- auto storePath = state->store->maybeParseStorePath(s);
- if (storePath && context.count(std::string(s))) {
- return {{
- .path = DerivedPath::Opaque {
- .path = std::move(*storePath),
- }
- }};
- } else
- throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
- }
-
- else
- throw Error("flake output attribute '%s' is not a derivation or path", attrPath);
- }
-
- auto drvPath = attr->forceDerivation();
-
- std::optional<NixInt> priority;
-
- if (attr->maybeGetAttr(state->sOutputSpecified)) {
- } else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
- if (auto aPriority = aMeta->maybeGetAttr("priority"))
- priority = aPriority->getInt();
- }
-
- return {{
- .path = DerivedPath::Built {
- .drvPath = std::move(drvPath),
- .outputs = std::visit(overloaded {
- [&](const ExtendedOutputsSpec::Default & d) -> OutputsSpec {
- std::set<std::string> outputsToInstall;
- if (auto aOutputSpecified = attr->maybeGetAttr(state->sOutputSpecified)) {
- if (aOutputSpecified->getBool()) {
- if (auto aOutputName = attr->maybeGetAttr("outputName"))
- outputsToInstall = { aOutputName->getString() };
- }
- } else if (auto aMeta = attr->maybeGetAttr(state->sMeta)) {
- if (auto aOutputsToInstall = aMeta->maybeGetAttr("outputsToInstall"))
- for (auto & s : aOutputsToInstall->getListOfStrings())
- outputsToInstall.insert(s);
- }
-
- if (outputsToInstall.empty())
- outputsToInstall.insert("out");
-
- return OutputsSpec::Names { std::move(outputsToInstall) };
- },
- [&](const ExtendedOutputsSpec::Explicit & e) -> OutputsSpec {
- return e;
- },
- }, extendedOutputsSpec.raw()),
- },
- .info = {
- .priority = priority,
- .originalRef = flakeRef,
- .resolvedRef = getLockedFlake()->flake.lockedRef,
- .attrPath = attrPath,
- .extendedOutputsSpec = extendedOutputsSpec,
- }
- }};
-}
-
-std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
-{
- return {&getCursor(state)->forceValue(), noPos};
-}
-
-std::vector<ref<eval_cache::AttrCursor>>
-InstallableFlake::getCursors(EvalState & state)
-{
- auto evalCache = openEvalCache(state,
- std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
-
- auto root = evalCache->getRoot();
-
- std::vector<ref<eval_cache::AttrCursor>> res;
-
- Suggestions suggestions;
- auto attrPaths = getActualAttrPaths();
-
- for (auto & attrPath : attrPaths) {
- debug("trying flake output attribute '%s'", attrPath);
-
- auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
- if (attr) {
- res.push_back(ref(*attr));
- } else {
- suggestions += attr.getSuggestions();
- }
- }
-
- if (res.size() == 0)
- throw Error(
- suggestions,
- "flake '%s' does not provide attribute %s",
- flakeRef,
- showAttrPaths(attrPaths));
-
- return res;
-}
-
-std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
-{
- if (!_lockedFlake) {
- flake::LockFlags lockFlagsApplyConfig = lockFlags;
- lockFlagsApplyConfig.applyNixConfig = true;
- _lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlagsApplyConfig));
- }
- return _lockedFlake;
-}
-
-FlakeRef InstallableFlake::nixpkgsFlakeRef() const
-{
- auto lockedFlake = getLockedFlake();
-
- if (auto nixpkgsInput = lockedFlake->lockFile.findInput({"nixpkgs"})) {
- if (auto lockedNode = std::dynamic_pointer_cast<const flake::LockedNode>(nixpkgsInput)) {
- debug("using nixpkgs flake '%s'", lockedNode->lockedRef);
- return std::move(lockedNode->lockedRef);
- }
- }
-
- return Installable::nixpkgsFlakeRef();
-}
-
std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
ref<Store> store, std::vector<std::string> ss)
{
std::vector<std::shared_ptr<Installable>> result;
- if (readOnlyMode) {
- settings.readOnlyMode = true;
- }
-
if (file || expr) {
if (file && expr)
throw UsageError("'--file' and '--expr' are exclusive");
@@ -777,9 +452,8 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
result.push_back(
std::make_shared<InstallableAttrPath>(
- state, *this, vFile,
- prefix == "." ? "" : std::string { prefix },
- extendedOutputsSpec));
+ InstallableAttrPath::parse(
+ state, *this, vFile, prefix, extendedOutputsSpec)));
}
} else {
@@ -792,41 +466,10 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
auto prefix = std::move(prefix_);
auto extendedOutputsSpec = std::move(extendedOutputsSpec_);
- auto found = prefix.find('/');
- if (found != std::string::npos) {
+ if (prefix.find('/') != std::string::npos) {
try {
- auto derivedPath = std::visit(overloaded {
- // If the user did not use ^, we treat the output more liberally.
- [&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
- // First, we accept a symlink chain or an actual store path.
- auto storePath = store->followLinksToStorePath(prefix);
- // Second, we see if the store path ends in `.drv` to decide what sort
- // of derived path they want.
- //
- // This handling predates the `^` syntax. The `^*` in
- // `/nix/store/hash-foo.drv^*` unambiguously means "do the
- // `DerivedPath::Built` case", so plain `/nix/store/hash-foo.drv` could
- // also unambiguously mean "do the DerivedPath::Opaque` case".
- //
- // Issue #7261 tracks reconsidering this `.drv` dispatching.
- return storePath.isDerivation()
- ? (DerivedPath) DerivedPath::Built {
- .drvPath = std::move(storePath),
- .outputs = OutputsSpec::All {},
- }
- : (DerivedPath) DerivedPath::Opaque {
- .path = std::move(storePath),
- };
- },
- // If the user did use ^, we just do exactly what is written.
- [&](const ExtendedOutputsSpec::Explicit & outputSpec) -> DerivedPath {
- return DerivedPath::Built {
- .drvPath = store->parseStorePath(prefix),
- .outputs = outputSpec,
- };
- },
- }, extendedOutputsSpec.raw());
- result.push_back(std::make_shared<InstallableStorePath>(store, std::move(derivedPath)));
+ result.push_back(std::make_shared<InstallableDerivedPath>(
+ InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec)));
continue;
} catch (BadStorePath &) {
} catch (...) {
@@ -1062,8 +705,8 @@ void InstallablesCommand::prepare()
installables = load();
}
-Installables InstallablesCommand::load() {
- Installables installables;
+Installables InstallablesCommand::load()
+{
if (_installables.empty() && useDefaultInstallables())
// FIXME: commands like "nix profile install" should not have a
// default, probably.
@@ -1073,16 +716,13 @@ Installables InstallablesCommand::load() {
std::vector<std::string> InstallablesCommand::getFlakesForCompletion()
{
- if (_installables.empty()) {
- if (useDefaultInstallables())
- return {"."};
- return {};
- }
+ if (_installables.empty() && useDefaultInstallables())
+ return {"."};
return _installables;
}
-InstallableCommand::InstallableCommand(bool supportReadOnlyMode)
- : SourceExprCommand(supportReadOnlyMode)
+InstallableCommand::InstallableCommand()
+ : SourceExprCommand()
{
expectArgs({
.label = "installable",
diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh
index da6a3addd..be77fdc81 100644
--- a/src/libcmd/installables.hh
+++ b/src/libcmd/installables.hh
@@ -161,54 +161,4 @@ struct Installable
typedef std::vector<std::shared_ptr<Installable>> Installables;
-struct InstallableValue : Installable
-{
- ref<EvalState> state;
-
- InstallableValue(ref<EvalState> state) : state(state) {}
-};
-
-struct InstallableFlake : InstallableValue
-{
- FlakeRef flakeRef;
- Strings attrPaths;
- Strings prefixes;
- ExtendedOutputsSpec extendedOutputsSpec;
- const flake::LockFlags & lockFlags;
- mutable std::shared_ptr<flake::LockedFlake> _lockedFlake;
-
- InstallableFlake(
- SourceExprCommand * cmd,
- ref<EvalState> state,
- FlakeRef && flakeRef,
- std::string_view fragment,
- ExtendedOutputsSpec extendedOutputsSpec,
- Strings attrPaths,
- Strings prefixes,
- const flake::LockFlags & lockFlags);
-
- std::string what() const override { return flakeRef.to_string() + "#" + *attrPaths.begin(); }
-
- std::vector<std::string> getActualAttrPaths();
-
- Value * getFlakeOutputs(EvalState & state, const flake::LockedFlake & lockedFlake);
-
- DerivedPathsWithInfo toDerivedPaths() override;
-
- std::pair<Value *, PosIdx> toValue(EvalState & state) override;
-
- /* Get a cursor to every attrpath in getActualAttrPaths()
- that exists. However if none exists, throw an exception. */
- std::vector<ref<eval_cache::AttrCursor>>
- getCursors(EvalState & state) override;
-
- std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
-
- FlakeRef nixpkgsFlakeRef() const override;
-};
-
-ref<eval_cache::EvalCache> openEvalCache(
- EvalState & state,
- std::shared_ptr<flake::LockedFlake> lockedFlake);
-
}
diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk
index 152bc388d..541a7d2ba 100644
--- a/src/libcmd/local.mk
+++ b/src/libcmd/local.mk
@@ -6,7 +6,7 @@ libcmd_DIR := $(d)
libcmd_SOURCES := $(wildcard $(d)/*.cc)
-libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/nix
+libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers
libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
diff --git a/src/libcmd/nix-cmd.pc.in b/src/libcmd/nix-cmd.pc.in
index a21d93f1d..39575f222 100644
--- a/src/libcmd/nix-cmd.pc.in
+++ b/src/libcmd/nix-cmd.pc.in
@@ -6,4 +6,4 @@ Name: Nix
Description: Nix Package Manager
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lnixcmd
-Cflags: -I${includedir}/nix -std=c++20
+Cflags: -I${includedir}/nix -std=c++2a
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index 4158439b6..e3afb1531 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -19,6 +19,8 @@ extern "C" {
}
#endif
+#include "repl.hh"
+
#include "ansicolor.hh"
#include "shared.hh"
#include "eval.hh"
@@ -31,7 +33,9 @@ extern "C" {
#include "get-drvs.hh"
#include "derivations.hh"
#include "globals.hh"
-#include "command.hh"
+#include "flake/flake.hh"
+#include "flake/lockfile.hh"
+#include "editor-for.hh"
#include "finally.hh"
#include "markdown.hh"
#include "local-fs-store.hh"
@@ -45,18 +49,16 @@ extern "C" {
namespace nix {
struct NixRepl
+ : AbstractNixRepl
#if HAVE_BOEHMGC
- : gc
+ , gc
#endif
{
std::string curDir;
- ref<EvalState> state;
- Bindings * autoArgs;
size_t debugTraceIndex;
Strings loadedFiles;
- typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
std::function<AnnotatedValues()> getValues;
const static int envSize = 32768;
@@ -69,8 +71,11 @@ struct NixRepl
NixRepl(const Strings & searchPath, nix::ref<Store> store,ref<EvalState> state,
std::function<AnnotatedValues()> getValues);
- ~NixRepl();
- void mainLoop();
+ virtual ~NixRepl();
+
+ void mainLoop() override;
+ void initEnv() override;
+
StringSet completePrefix(const std::string & prefix);
bool getLine(std::string & input, const std::string & prompt);
StorePath getDerivationPath(Value & v);
@@ -78,7 +83,6 @@ struct NixRepl
void loadFile(const Path & path);
void loadFlake(const std::string & flakeRef);
- void initEnv();
void loadFiles();
void reloadFiles();
void addAttrsToScope(Value & attrs);
@@ -92,7 +96,6 @@ struct NixRepl
std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen);
};
-
std::string removeWhitespace(std::string s)
{
s = chomp(s);
@@ -104,7 +107,7 @@ std::string removeWhitespace(std::string s)
NixRepl::NixRepl(const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
std::function<NixRepl::AnnotatedValues()> getValues)
- : state(state)
+ : AbstractNixRepl(state)
, debugTraceIndex(0)
, getValues(getValues)
, staticEnv(new StaticEnv(false, state->staticBaseEnv.get()))
@@ -1029,8 +1032,22 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m
return str;
}
-void runRepl(
- ref<EvalState>evalState,
+
+std::unique_ptr<AbstractNixRepl> AbstractNixRepl::create(
+ const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
+ std::function<AnnotatedValues()> getValues)
+{
+ return std::make_unique<NixRepl>(
+ searchPath,
+ openStore(),
+ state,
+ getValues
+ );
+}
+
+
+void AbstractNixRepl::runSimple(
+ ref<EvalState> evalState,
const ValMap & extraEnv)
{
auto getValues = [&]()->NixRepl::AnnotatedValues{
@@ -1054,91 +1071,4 @@ void runRepl(
repl->mainLoop();
}
-struct CmdRepl : InstallablesCommand
-{
- CmdRepl() {
- evalSettings.pureEval = false;
- }
-
- void prepare() override
- {
- if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) {
- warn("future versions of Nix will require using `--file` to load a file");
- if (this->_installables.size() > 1)
- warn("more than one input file is not currently supported");
- auto filePath = this->_installables[0].data();
- file = std::optional(filePath);
- _installables.front() = _installables.back();
- _installables.pop_back();
- }
- installables = InstallablesCommand::load();
- }
-
- std::vector<std::string> files;
-
- Strings getDefaultFlakeAttrPaths() override
- {
- return {""};
- }
-
- bool useDefaultInstallables() override
- {
- return file.has_value() or expr.has_value();
- }
-
- bool forceImpureByDefault() override
- {
- return true;
- }
-
- std::string description() override
- {
- return "start an interactive environment for evaluating Nix expressions";
- }
-
- std::string doc() override
- {
- return
- #include "repl.md"
- ;
- }
-
- void run(ref<Store> store) override
- {
- auto state = getEvalState();
- auto getValues = [&]()->NixRepl::AnnotatedValues{
- auto installables = load();
- NixRepl::AnnotatedValues values;
- for (auto & installable: installables){
- auto what = installable->what();
- if (file){
- auto [val, pos] = installable->toValue(*state);
- auto what = installable->what();
- state->forceValue(*val, pos);
- auto autoArgs = getAutoArgs(*state);
- auto valPost = state->allocValue();
- state->autoCallFunction(*autoArgs, *val, *valPost);
- state->forceValue(*valPost, pos);
- values.push_back( {valPost, what });
- } else {
- auto [val, pos] = installable->toValue(*state);
- values.push_back( {val, what} );
- }
- }
- return values;
- };
- auto repl = std::make_unique<NixRepl>(
- searchPath,
- openStore(),
- state,
- getValues
- );
- repl->autoArgs = getAutoArgs(*repl->state);
- repl->initEnv();
- repl->mainLoop();
- }
-};
-
-static auto rCmdRepl = registerCommand<CmdRepl>("repl");
-
}
diff --git a/src/libcmd/repl.hh b/src/libcmd/repl.hh
new file mode 100644
index 000000000..dfccc93e7
--- /dev/null
+++ b/src/libcmd/repl.hh
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "eval.hh"
+
+#if HAVE_BOEHMGC
+#define GC_INCLUDE_NEW
+#include <gc/gc_cpp.h>
+#endif
+
+namespace nix {
+
+struct AbstractNixRepl
+{
+ ref<EvalState> state;
+ Bindings * autoArgs;
+
+ AbstractNixRepl(ref<EvalState> state)
+ : state(state)
+ { }
+
+ virtual ~AbstractNixRepl()
+ { }
+
+ typedef std::vector<std::pair<Value*,std::string>> AnnotatedValues;
+
+ static std::unique_ptr<AbstractNixRepl> create(
+ const Strings & searchPath, nix::ref<Store> store, ref<EvalState> state,
+ std::function<AnnotatedValues()> getValues);
+
+ static void runSimple(
+ ref<EvalState> evalState,
+ const ValMap & extraEnv);
+
+ virtual void initEnv() = 0;
+
+ virtual void mainLoop() = 0;
+};
+
+}