aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcmd/command.cc17
-rw-r--r--src/libcmd/command.hh8
-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-flake.cc236
-rw-r--r--src/libcmd/installable-flake.hh50
-rw-r--r--src/libcmd/installable-value.hh14
-rw-r--r--src/libcmd/installables.cc304
-rw-r--r--src/libcmd/installables.hh50
-rw-r--r--src/libcmd/local.mk2
-rw-r--r--src/libcmd/repl.cc128
-rw-r--r--src/libcmd/repl.hh39
-rw-r--r--src/nix/bundle.cc1
-rw-r--r--src/nix/develop.cc1
-rw-r--r--src/nix/edit.cc1
-rw-r--r--src/nix/flake.cc1
-rw-r--r--src/nix/profile.cc1
-rw-r--r--src/nix/repl.cc95
20 files changed, 675 insertions, 469 deletions
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index 517cdf617..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,7 +122,7 @@ ref<EvalState> EvalCommand::getEvalState()
;
if (startReplOnEvalErrors) {
- evalState->debugRepl = &runRepl;
+ evalState->debugRepl = &AbstractNixRepl::runSimple;
};
}
return ref<EvalState>(evalState);
@@ -218,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 d16bdbc4b..1516daa00 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -231,10 +231,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;
@@ -284,8 +280,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-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 85edc28cf..cfc13a60f 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -1,6 +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"
@@ -390,111 +392,6 @@ static StorePath getDeriver(
return *derivers.begin();
}
-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)
@@ -524,187 +421,6 @@ 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)
{
@@ -739,9 +455,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 {
@@ -993,8 +708,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.
@@ -1004,11 +719,8 @@ Installables InstallablesCommand::load() {
std::vector<std::string> InstallablesCommand::getFlakesForCompletion()
{
- if (_installables.empty()) {
- if (useDefaultInstallables())
- return {"."};
- return {};
- }
+ if (_installables.empty() && useDefaultInstallables())
+ return {"."};
return _installables;
}
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/repl.cc b/src/libcmd/repl.cc
index 4158439b6..7c7d13659 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;
+};
+
+}
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index 6ae9460f6..dcf9a6f2d 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 16bbd8613..9d07a7a85 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -1,5 +1,6 @@
#include "eval.hh"
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
diff --git a/src/nix/edit.cc b/src/nix/edit.cc
index 76a134b1f..dfe75fbdf 100644
--- a/src/nix/edit.cc
+++ b/src/nix/edit.cc
@@ -3,6 +3,7 @@
#include "eval.hh"
#include "attr-path.hh"
#include "progress-bar.hh"
+#include "editor-for.hh"
#include <unistd.h>
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index c025bc7a6..053a9c9e1 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "eval.hh"
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 32364e720..208542a5c 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -1,4 +1,5 @@
#include "command.hh"
+#include "installable-flake.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
new file mode 100644
index 000000000..679bdea77
--- /dev/null
+++ b/src/nix/repl.cc
@@ -0,0 +1,95 @@
+#include "eval.hh"
+#include "globals.hh"
+#include "command.hh"
+#include "repl.hh"
+
+namespace nix {
+
+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 = [&]()->AbstractNixRepl::AnnotatedValues{
+ auto installables = load();
+ AbstractNixRepl::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 = AbstractNixRepl::create(
+ searchPath,
+ openStore(),
+ state,
+ getValues
+ );
+ repl->autoArgs = getAutoArgs(*repl->state);
+ repl->initEnv();
+ repl->mainLoop();
+ }
+};
+
+static auto rCmdRepl = registerCommand<CmdRepl>("repl");
+
+}