aboutsummaryrefslogtreecommitdiff
path: root/src/libcmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcmd')
-rw-r--r--src/libcmd/command-installable-value.cc11
-rw-r--r--src/libcmd/command-installable-value.hh13
-rw-r--r--src/libcmd/command.cc6
-rw-r--r--src/libcmd/command.hh61
-rw-r--r--src/libcmd/common-eval-args.cc8
-rw-r--r--src/libcmd/installable-attr-path.cc4
-rw-r--r--src/libcmd/installable-derived-path.cc38
-rw-r--r--src/libcmd/installable-flake.cc29
-rw-r--r--src/libcmd/installable-flake.hh30
-rw-r--r--src/libcmd/installable-value.cc44
-rw-r--r--src/libcmd/installable-value.hh93
-rw-r--r--src/libcmd/installables.cc122
-rw-r--r--src/libcmd/installables.hh172
13 files changed, 440 insertions, 191 deletions
diff --git a/src/libcmd/command-installable-value.cc b/src/libcmd/command-installable-value.cc
new file mode 100644
index 000000000..d7581534b
--- /dev/null
+++ b/src/libcmd/command-installable-value.cc
@@ -0,0 +1,11 @@
+#include "command-installable-value.hh"
+
+namespace nix {
+
+void InstallableValueCommand::run(ref<Store> store, ref<Installable> installable)
+{
+ auto installableValue = InstallableValue::require(installable);
+ run(store, installableValue);
+}
+
+}
diff --git a/src/libcmd/command-installable-value.hh b/src/libcmd/command-installable-value.hh
new file mode 100644
index 000000000..8e31a0b92
--- /dev/null
+++ b/src/libcmd/command-installable-value.hh
@@ -0,0 +1,13 @@
+#include "installable-value.hh"
+#include "command.hh"
+
+namespace nix {
+
+struct InstallableValueCommand : InstallableCommand
+{
+ virtual void run(ref<Store> store, ref<InstallableValue> installable) = 0;
+
+ void run(ref<Store> store, ref<Installable> installable) override;
+};
+
+}
diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc
index ab51c229d..bedf11e2c 100644
--- a/src/libcmd/command.cc
+++ b/src/libcmd/command.cc
@@ -165,7 +165,7 @@ BuiltPathsCommand::BuiltPathsCommand(bool recursive)
});
}
-void BuiltPathsCommand::run(ref<Store> store)
+void BuiltPathsCommand::run(ref<Store> store, Installables && installables)
{
BuiltPaths paths;
if (all) {
@@ -211,7 +211,7 @@ void StorePathsCommand::run(ref<Store> store, BuiltPaths && paths)
run(store, std::move(sorted));
}
-void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePaths)
+void StorePathCommand::run(ref<Store> store, StorePaths && storePaths)
{
if (storePaths.size() != 1)
throw UsageError("this command requires exactly one store path");
@@ -246,7 +246,7 @@ void MixProfile::updateProfile(const BuiltPaths & buildables)
{
if (!profile) return;
- std::vector<StorePath> result;
+ StorePaths result;
for (auto & buildable : buildables) {
std::visit(overloaded {
diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh
index b6d554aab..dbc155b79 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -1,6 +1,6 @@
#pragma once
-#include "installables.hh"
+#include "installable-value.hh"
#include "args.hh"
#include "common-eval-args.hh"
#include "path.hh"
@@ -18,17 +18,21 @@ class EvalState;
struct Pos;
class Store;
+static constexpr Command::Category catHelp = -1;
static constexpr Command::Category catSecondary = 100;
static constexpr Command::Category catUtility = 101;
static constexpr Command::Category catNixInstallation = 102;
-static constexpr auto installablesCategory = "Options that change the interpretation of installables";
+static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
struct NixMultiCommand : virtual MultiCommand, virtual Command
{
nlohmann::json toJSON() override;
};
+// For the overloaded run methods
+#pragma GCC diagnostic ignored "-Woverloaded-virtual"
+
/* A command that requires a Nix store. */
struct StoreCommand : virtual Command
{
@@ -97,10 +101,10 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions
SourceExprCommand();
- std::vector<std::shared_ptr<Installable>> parseInstallables(
+ Installables parseInstallables(
ref<Store> store, std::vector<std::string> ss);
- std::shared_ptr<Installable> parseInstallable(
+ ref<Installable> parseInstallable(
ref<Store> store, const std::string & installable);
virtual Strings getDefaultFlakeAttrPaths();
@@ -115,34 +119,43 @@ 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
+/* Like InstallablesCommand but the installables are not loaded */
+struct RawInstallablesCommand : virtual Args, SourceExprCommand
{
- std::vector<std::shared_ptr<Installable>> installables;
+ RawInstallablesCommand();
- InstallablesCommand();
+ virtual void run(ref<Store> store, std::vector<std::string> && rawInstallables) = 0;
+
+ void run(ref<Store> store) override;
- void prepare() override;
- Installables load();
+ // FIXME make const after CmdRepl's override is fixed up
+ virtual void applyDefaultInstallables(std::vector<std::string> & rawInstallables);
- virtual bool useDefaultInstallables() { return true; }
+ bool readFromStdIn = false;
std::vector<std::string> getFlakesForCompletion() override;
-protected:
+private:
- std::vector<std::string> _installables;
+ std::vector<std::string> rawInstallables;
+};
+/* A command that operates on a list of "installables", which can be
+ store paths, attribute paths, Nix expressions, etc. */
+struct InstallablesCommand : RawInstallablesCommand
+{
+ virtual void run(ref<Store> store, Installables && installables) = 0;
+
+ void run(ref<Store> store, std::vector<std::string> && rawInstallables) override;
};
/* A command that operates on exactly one "installable" */
struct InstallableCommand : virtual Args, SourceExprCommand
{
- std::shared_ptr<Installable> installable;
-
InstallableCommand();
- void prepare() override;
+ virtual void run(ref<Store> store, ref<Installable> installable) = 0;
+
+ void run(ref<Store> store) override;
std::vector<std::string> getFlakesForCompletion() override
{
@@ -177,22 +190,18 @@ public:
BuiltPathsCommand(bool recursive = false);
- using StoreCommand::run;
-
virtual void run(ref<Store> store, BuiltPaths && paths) = 0;
- void run(ref<Store> store) override;
+ void run(ref<Store> store, Installables && installables) override;
- bool useDefaultInstallables() override { return !all; }
+ void applyDefaultInstallables(std::vector<std::string> & rawInstallables) override;
};
struct StorePathsCommand : public BuiltPathsCommand
{
StorePathsCommand(bool recursive = false);
- using BuiltPathsCommand::run;
-
- virtual void run(ref<Store> store, std::vector<StorePath> && storePaths) = 0;
+ virtual void run(ref<Store> store, StorePaths && storePaths) = 0;
void run(ref<Store> store, BuiltPaths && paths) override;
};
@@ -200,11 +209,9 @@ struct StorePathsCommand : public BuiltPathsCommand
/* A command that operates on exactly one store path. */
struct StorePathCommand : public StorePathsCommand
{
- using StorePathsCommand::run;
-
virtual void run(ref<Store> store, const StorePath & storePath) = 0;
- void run(ref<Store> store, std::vector<StorePath> && storePaths) override;
+ void run(ref<Store> store, StorePaths && storePaths) override;
};
/* A helper class for registering commands globally. */
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 908127b4d..5b6477c82 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -136,7 +136,11 @@ MixEvalArgs::MixEvalArgs()
addFlag({
.longName = "eval-store",
- .description = "The Nix store to use for evaluations.",
+ .description =
+ R"(
+ The [URL of the Nix store](@docroot@/command-ref/new-cli/nix3-help-stores.md#store-url-format)
+ to use for evaluation, i.e. to store derivations (`.drv` files) and inputs referenced by them.
+ )",
.category = category,
.labels = {"store-url"},
.handler = {&evalStoreUrl},
@@ -166,7 +170,7 @@ Path lookupFileArg(EvalState & state, std::string_view s)
}
else if (hasPrefix(s, "flake:")) {
- settings.requireExperimentalFeature(Xp::Flakes);
+ experimentalFeatureSettings.require(Xp::Flakes);
auto flakeRef = parseFlakeRef(std::string(s.substr(6)), {}, true, false);
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
return state.store->toRealPath(storePath);
diff --git a/src/libcmd/installable-attr-path.cc b/src/libcmd/installable-attr-path.cc
index d9377f0d6..cf513126d 100644
--- a/src/libcmd/installable-attr-path.cc
+++ b/src/libcmd/installable-attr-path.cc
@@ -87,6 +87,10 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths()
.drvPath = drvPath,
.outputs = outputs,
},
+ .info = make_ref<ExtraPathInfoValue>(ExtraPathInfoValue::Value {
+ /* FIXME: reconsider backwards compatibility above
+ so we can fill in this info. */
+ }),
});
return res;
diff --git a/src/libcmd/installable-derived-path.cc b/src/libcmd/installable-derived-path.cc
index a9921b901..6ecf54b7c 100644
--- a/src/libcmd/installable-derived-path.cc
+++ b/src/libcmd/installable-derived-path.cc
@@ -10,7 +10,10 @@ std::string InstallableDerivedPath::what() const
DerivedPathsWithInfo InstallableDerivedPath::toDerivedPaths()
{
- return {{.path = derivedPath, .info = {} }};
+ return {{
+ .path = derivedPath,
+ .info = make_ref<ExtraPathInfo>(),
+ }};
}
std::optional<StorePath> InstallableDerivedPath::getStorePath()
@@ -31,27 +34,24 @@ InstallableDerivedPath InstallableDerivedPath::parse(
ExtendedOutputsSpec extendedOutputsSpec)
{
auto derivedPath = std::visit(overloaded {
- // If the user did not use ^, we treat the output more liberally.
+ // If the user did not use ^, we treat the output more
+ // liberally: we accept a symlink chain or an actual
+ // store path.
[&](const ExtendedOutputsSpec::Default &) -> DerivedPath {
- // First, we accept a symlink chain or an actual store path.
auto storePath = store->followLinksToStorePath(prefix);
- // Second, we see if the store path ends in `.drv` to decide what sort
- // of derived path they want.
- //
- // This handling predates the `^` syntax. The `^*` in
- // `/nix/store/hash-foo.drv^*` unambiguously means "do the
- // `DerivedPath::Built` case", so plain `/nix/store/hash-foo.drv` could
- // also unambiguously mean "do the DerivedPath::Opaque` case".
- //
- // Issue #7261 tracks reconsidering this `.drv` dispatching.
- return storePath.isDerivation()
- ? (DerivedPath) DerivedPath::Built {
- .drvPath = std::move(storePath),
- .outputs = OutputsSpec::All {},
- }
- : (DerivedPath) DerivedPath::Opaque {
- .path = std::move(storePath),
+ // Remove this prior to stabilizing the new CLI.
+ if (storePath.isDerivation()) {
+ auto oldDerivedPath = DerivedPath::Built {
+ .drvPath = storePath,
+ .outputs = OutputsSpec::All { },
};
+ warn(
+ "The interpretation of store paths arguments ending in `.drv` recently changed. If this command is now failing try again with '%s'",
+ oldDerivedPath.to_string(*store));
+ };
+ return DerivedPath::Opaque {
+ .path = std::move(storePath),
+ };
},
// If the user did use ^, we just do exactly what is written.
[&](const ExtendedOutputsSpec::Explicit & outputSpec) -> DerivedPath {
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 60a97deaf..a3352af76 100644
--- a/src/libcmd/installable-flake.cc
+++ b/src/libcmd/installable-flake.cc
@@ -101,7 +101,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
return {{
.path = DerivedPath::Opaque {
.path = std::move(storePath),
- }
+ },
+ .info = make_ref<ExtraPathInfo>(),
}};
}
@@ -113,7 +114,8 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
return {{
.path = DerivedPath::Opaque {
.path = std::move(*storePath),
- }
+ },
+ .info = make_ref<ExtraPathInfo>(),
}};
} else
throw Error("flake output attribute '%s' evaluates to the string '%s' which is not a store path", attrPath, s);
@@ -160,13 +162,16 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths()
},
}, extendedOutputsSpec.raw()),
},
- .info = {
- .priority = priority,
- .originalRef = flakeRef,
- .resolvedRef = getLockedFlake()->flake.lockedRef,
- .attrPath = attrPath,
- .extendedOutputsSpec = extendedOutputsSpec,
- }
+ .info = make_ref<ExtraPathInfoFlake>(
+ ExtraPathInfoValue::Value {
+ .priority = priority,
+ .attrPath = attrPath,
+ .extendedOutputsSpec = extendedOutputsSpec,
+ },
+ ExtraPathInfoFlake::Flake {
+ .originalRef = flakeRef,
+ .resolvedRef = getLockedFlake()->flake.lockedRef,
+ }),
}};
}
@@ -178,8 +183,7 @@ std::pair<Value *, PosIdx> InstallableFlake::toValue(EvalState & state)
std::vector<ref<eval_cache::AttrCursor>>
InstallableFlake::getCursors(EvalState & state)
{
- auto evalCache = openEvalCache(state,
- std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)));
+ auto evalCache = openEvalCache(state, getLockedFlake());
auto root = evalCache->getRoot();
@@ -213,6 +217,7 @@ std::shared_ptr<flake::LockedFlake> InstallableFlake::getLockedFlake() const
{
if (!_lockedFlake) {
flake::LockFlags lockFlagsApplyConfig = lockFlags;
+ // FIXME why this side effect?
lockFlagsApplyConfig.applyNixConfig = true;
_lockedFlake = std::make_shared<flake::LockedFlake>(lockFlake(*state, flakeRef, lockFlagsApplyConfig));
}
@@ -230,7 +235,7 @@ FlakeRef InstallableFlake::nixpkgsFlakeRef() const
}
}
- return Installable::nixpkgsFlakeRef();
+ return InstallableValue::nixpkgsFlakeRef();
}
}
diff --git a/src/libcmd/installable-flake.hh b/src/libcmd/installable-flake.hh
index c75765086..313d2d7a3 100644
--- a/src/libcmd/installable-flake.hh
+++ b/src/libcmd/installable-flake.hh
@@ -4,6 +4,30 @@
namespace nix {
+/**
+ * Extra info about a \ref DerivedPath "derived path" that ultimately
+ * come from a Flake.
+ *
+ * Invariant: every ExtraPathInfo gotten from an InstallableFlake should
+ * be possible to downcast to an ExtraPathInfoFlake.
+ */
+struct ExtraPathInfoFlake : ExtraPathInfoValue
+{
+ /**
+ * Extra struct to get around C++ designated initializer limitations
+ */
+ struct Flake {
+ FlakeRef originalRef;
+ FlakeRef resolvedRef;
+ };
+
+ Flake flake;
+
+ ExtraPathInfoFlake(Value && v, Flake && f)
+ : ExtraPathInfoValue(std::move(v)), flake(f)
+ { }
+};
+
struct InstallableFlake : InstallableValue
{
FlakeRef flakeRef;
@@ -33,8 +57,10 @@ struct InstallableFlake : InstallableValue
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. */
+ /**
+ * 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;
diff --git a/src/libcmd/installable-value.cc b/src/libcmd/installable-value.cc
new file mode 100644
index 000000000..30f80edb2
--- /dev/null
+++ b/src/libcmd/installable-value.cc
@@ -0,0 +1,44 @@
+#include "installable-value.hh"
+#include "eval-cache.hh"
+
+namespace nix {
+
+std::vector<ref<eval_cache::AttrCursor>>
+InstallableValue::getCursors(EvalState & state)
+{
+ auto evalCache =
+ std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state,
+ [&]() { return toValue(state).first; });
+ return {evalCache->getRoot()};
+}
+
+ref<eval_cache::AttrCursor>
+InstallableValue::getCursor(EvalState & state)
+{
+ /* Although getCursors should return at least one element, in case it doesn't,
+ bound check to avoid an undefined behavior for vector[0] */
+ return getCursors(state).at(0);
+}
+
+static UsageError nonValueInstallable(Installable & installable)
+{
+ return UsageError("installable '%s' does not correspond to a Nix language value", installable.what());
+}
+
+InstallableValue & InstallableValue::require(Installable & installable)
+{
+ auto * castedInstallable = dynamic_cast<InstallableValue *>(&installable);
+ if (!castedInstallable)
+ throw nonValueInstallable(installable);
+ return *castedInstallable;
+}
+
+ref<InstallableValue> InstallableValue::require(ref<Installable> installable)
+{
+ auto castedInstallable = installable.dynamic_pointer_cast<InstallableValue>();
+ if (!castedInstallable)
+ throw nonValueInstallable(*installable);
+ return ref { castedInstallable };
+}
+
+}
diff --git a/src/libcmd/installable-value.hh b/src/libcmd/installable-value.hh
index c6cdc4797..9e076cb10 100644
--- a/src/libcmd/installable-value.hh
+++ b/src/libcmd/installable-value.hh
@@ -1,14 +1,107 @@
#pragma once
#include "installables.hh"
+#include "flake/flake.hh"
namespace nix {
+struct DrvInfo;
+struct SourceExprCommand;
+
+namespace eval_cache { class EvalCache; class AttrCursor; }
+
+struct App
+{
+ std::vector<DerivedPath> context;
+ Path program;
+ // FIXME: add args, sandbox settings, metadata, ...
+};
+
+struct UnresolvedApp
+{
+ App unresolved;
+ App resolve(ref<Store> evalStore, ref<Store> store);
+};
+
+/**
+ * Extra info about a \ref DerivedPath "derived path" that ultimately
+ * come from a Nix language value.
+ *
+ * Invariant: every ExtraPathInfo gotten from an InstallableValue should
+ * be possible to downcast to an ExtraPathInfoValue.
+ */
+struct ExtraPathInfoValue : ExtraPathInfo
+{
+ /**
+ * Extra struct to get around C++ designated initializer limitations
+ */
+ struct Value {
+ /**
+ * An optional priority for use with "build envs". See Package
+ */
+ std::optional<NixInt> priority;
+
+ /**
+ * The attribute path associated with this value. The idea is
+ * that an installable referring to a value typically refers to
+ * a larger value, from which we project a smaller value out
+ * with this.
+ */
+ std::string attrPath;
+
+ /**
+ * \todo merge with DerivedPath's 'outputs' field?
+ */
+ ExtendedOutputsSpec extendedOutputsSpec;
+ };
+
+ Value value;
+
+ ExtraPathInfoValue(Value && v)
+ : value(v)
+ { }
+
+ virtual ~ExtraPathInfoValue() = default;
+};
+
+/**
+ * An Installable which corresponds a Nix langauge value, in addition to
+ * a collection of \ref DerivedPath "derived paths".
+ */
struct InstallableValue : Installable
{
ref<EvalState> state;
InstallableValue(ref<EvalState> state) : state(state) {}
+
+ virtual ~InstallableValue() { }
+
+ virtual std::pair<Value *, PosIdx> toValue(EvalState & state) = 0;
+
+ /**
+ * Get a cursor to each value this Installable could refer to.
+ * However if none exists, throw exception instead of returning
+ * empty vector.
+ */
+ virtual std::vector<ref<eval_cache::AttrCursor>>
+ getCursors(EvalState & state);
+
+ /**
+ * Get the first and most preferred cursor this Installable could
+ * refer to, or throw an exception if none exists.
+ */
+ virtual ref<eval_cache::AttrCursor>
+ getCursor(EvalState & state);
+
+ UnresolvedApp toApp(EvalState & state);
+
+ virtual FlakeRef nixpkgsFlakeRef() const
+ {
+ return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
+ }
+
+ static InstallableValue & require(Installable & installable);
+ static ref<InstallableValue> require(ref<Installable> installable);
};
}
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc
index 00c6f9516..67549b280 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -153,7 +153,7 @@ SourceExprCommand::SourceExprCommand()
.longName = "file",
.shortName = 'f',
.description =
- "Interpret installables as attribute paths relative to the Nix expression stored in *file*. "
+ "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#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,
@@ -164,7 +164,7 @@ SourceExprCommand::SourceExprCommand()
addFlag({
.longName = "expr",
- .description = "Interpret installables as attribute paths relative to the Nix expression *expr*.",
+ .description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.",
.category = installablesCategory,
.labels = {"expr"},
.handler = {&expr}
@@ -332,7 +332,7 @@ void completeFlakeRefWithFragment(
void completeFlakeRef(ref<Store> store, std::string_view prefix)
{
- if (!settings.isExperimentalFeatureEnabled(Xp::Flakes))
+ if (!experimentalFeatureSettings.isEnabled(Xp::Flakes))
return;
if (prefix == "")
@@ -364,23 +364,6 @@ DerivedPathWithInfo Installable::toDerivedPath()
return std::move(buildables[0]);
}
-std::vector<ref<eval_cache::AttrCursor>>
-Installable::getCursors(EvalState & state)
-{
- auto evalCache =
- std::make_shared<nix::eval_cache::EvalCache>(std::nullopt, state,
- [&]() { return toValue(state).first; });
- return {evalCache->getRoot()};
-}
-
-ref<eval_cache::AttrCursor>
-Installable::getCursor(EvalState & state)
-{
- /* Although getCursors should return at least one element, in case it doesn't,
- bound check to avoid an undefined behavior for vector[0] */
- return getCursors(state).at(0);
-}
-
static StorePath getDeriver(
ref<Store> store,
const Installable & i,
@@ -422,10 +405,10 @@ ref<eval_cache::EvalCache> openEvalCache(
});
}
-std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
+Installables SourceExprCommand::parseInstallables(
ref<Store> store, std::vector<std::string> ss)
{
- std::vector<std::shared_ptr<Installable>> result;
+ Installables result;
if (file || expr) {
if (file && expr)
@@ -451,7 +434,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
for (auto & s : ss) {
auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s);
result.push_back(
- std::make_shared<InstallableAttrPath>(
+ make_ref<InstallableAttrPath>(
InstallableAttrPath::parse(
state, *this, vFile, prefix, extendedOutputsSpec)));
}
@@ -468,7 +451,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
if (prefix.find('/') != std::string::npos) {
try {
- result.push_back(std::make_shared<InstallableDerivedPath>(
+ result.push_back(make_ref<InstallableDerivedPath>(
InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec)));
continue;
} catch (BadStorePath &) {
@@ -480,7 +463,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
try {
auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath("."));
- result.push_back(std::make_shared<InstallableFlake>(
+ result.push_back(make_ref<InstallableFlake>(
this,
getEvalState(),
std::move(flakeRef),
@@ -501,7 +484,7 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables(
return result;
}
-std::shared_ptr<Installable> SourceExprCommand::parseInstallable(
+ref<Installable> SourceExprCommand::parseInstallable(
ref<Store> store, const std::string & installable)
{
auto installables = parseInstallables(store, {installable});
@@ -513,7 +496,7 @@ std::vector<BuiltPathWithResult> Installable::build(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
- const std::vector<std::shared_ptr<Installable>> & installables,
+ const Installables & installables,
BuildMode bMode)
{
std::vector<BuiltPathWithResult> res;
@@ -522,11 +505,11 @@ std::vector<BuiltPathWithResult> Installable::build(
return res;
}
-std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Installable::build2(
+std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build2(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
- const std::vector<std::shared_ptr<Installable>> & installables,
+ const Installables & installables,
BuildMode bMode)
{
if (mode == Realise::Nothing)
@@ -534,8 +517,8 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
struct Aux
{
- ExtraPathInfo info;
- std::shared_ptr<Installable> installable;
+ ref<ExtraPathInfo> info;
+ ref<Installable> installable;
};
std::vector<DerivedPath> pathsToBuild;
@@ -548,7 +531,7 @@ std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> Instal
}
}
- std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> res;
+ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> res;
switch (mode) {
@@ -620,7 +603,7 @@ BuiltPaths Installable::toBuiltPaths(
ref<Store> store,
Realise mode,
OperateOn operateOn,
- const std::vector<std::shared_ptr<Installable>> & installables)
+ const Installables & installables)
{
if (operateOn == OperateOn::Output) {
BuiltPaths res;
@@ -642,7 +625,7 @@ StorePathSet Installable::toStorePaths(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
- const std::vector<std::shared_ptr<Installable>> & installables)
+ const Installables & installables)
{
StorePathSet outPaths;
for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) {
@@ -656,7 +639,7 @@ StorePath Installable::toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode, OperateOn operateOn,
- std::shared_ptr<Installable> installable)
+ ref<Installable> installable)
{
auto paths = toStorePaths(evalStore, store, mode, operateOn, {installable});
@@ -668,7 +651,7 @@ StorePath Installable::toStorePath(
StorePathSet Installable::toDerivations(
ref<Store> store,
- const std::vector<std::shared_ptr<Installable>> & installables,
+ const Installables & installables,
bool useDeriver)
{
StorePathSet drvPaths;
@@ -677,9 +660,12 @@ StorePathSet Installable::toDerivations(
for (const auto & b : i->toDerivedPaths())
std::visit(overloaded {
[&](const DerivedPath::Opaque & bo) {
- if (!useDeriver)
- throw Error("argument '%s' did not evaluate to a derivation", i->what());
- drvPaths.insert(getDeriver(store, *i, bo.path));
+ drvPaths.insert(
+ bo.path.isDerivation()
+ ? bo.path
+ : useDeriver
+ ? getDeriver(store, *i, bo.path)
+ : throw Error("argument '%s' did not evaluate to a derivation", i->what()));
},
[&](const DerivedPath::Built & bfd) {
drvPaths.insert(bfd.drvPath);
@@ -689,36 +675,55 @@ StorePathSet Installable::toDerivations(
return drvPaths;
}
-InstallablesCommand::InstallablesCommand()
+RawInstallablesCommand::RawInstallablesCommand()
{
+ addFlag({
+ .longName = "stdin",
+ .description = "Read installables from the standard input.",
+ .handler = {&readFromStdIn, true}
+ });
+
expectArgs({
.label = "installables",
- .handler = {&_installables},
+ .handler = {&rawInstallables},
.completer = {[&](size_t, std::string_view prefix) {
completeInstallable(prefix);
}}
});
}
-void InstallablesCommand::prepare()
+void RawInstallablesCommand::applyDefaultInstallables(std::vector<std::string> & rawInstallables)
{
- installables = load();
+ if (rawInstallables.empty()) {
+ // FIXME: commands like "nix profile install" should not have a
+ // default, probably.
+ rawInstallables.push_back(".");
+ }
}
-Installables InstallablesCommand::load()
+void RawInstallablesCommand::run(ref<Store> store)
{
- if (_installables.empty() && useDefaultInstallables())
- // FIXME: commands like "nix profile install" should not have a
- // default, probably.
- _installables.push_back(".");
- return parseInstallables(getStore(), _installables);
+ if (readFromStdIn && !isatty(STDIN_FILENO)) {
+ std::string word;
+ while (std::cin >> word) {
+ rawInstallables.emplace_back(std::move(word));
+ }
+ }
+
+ applyDefaultInstallables(rawInstallables);
+ run(store, std::move(rawInstallables));
}
-std::vector<std::string> InstallablesCommand::getFlakesForCompletion()
+std::vector<std::string> RawInstallablesCommand::getFlakesForCompletion()
{
- if (_installables.empty() && useDefaultInstallables())
- return {"."};
- return _installables;
+ applyDefaultInstallables(rawInstallables);
+ return rawInstallables;
+}
+
+void InstallablesCommand::run(ref<Store> store, std::vector<std::string> && rawInstallables)
+{
+ auto installables = parseInstallables(store, rawInstallables);
+ run(store, std::move(installables));
}
InstallableCommand::InstallableCommand()
@@ -734,9 +739,16 @@ InstallableCommand::InstallableCommand()
});
}
-void InstallableCommand::prepare()
+void InstallableCommand::run(ref<Store> store)
+{
+ auto installable = parseInstallable(store, _installable);
+ run(store, std::move(installable));
+}
+
+void BuiltPathsCommand::applyDefaultInstallables(std::vector<std::string> & rawInstallables)
{
- installable = parseInstallable(getStore(), _installable);
+ if (rawInstallables.empty() && !all)
+ rawInstallables.push_back(".");
}
}
diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh
index be77fdc81..b6efc0f17 100644
--- a/src/libcmd/installables.hh
+++ b/src/libcmd/installables.hh
@@ -4,9 +4,7 @@
#include "path.hh"
#include "outputs-spec.hh"
#include "derived-path.hh"
-#include "eval.hh"
#include "store-api.hh"
-#include "flake/flake.hh"
#include "build-result.hh"
#include <optional>
@@ -14,122 +12,156 @@
namespace nix {
struct DrvInfo;
-struct SourceExprCommand;
-
-namespace eval_cache { class EvalCache; class AttrCursor; }
-
-struct App
-{
- std::vector<DerivedPath> context;
- Path program;
- // FIXME: add args, sandbox settings, metadata, ...
-};
-
-struct UnresolvedApp
-{
- App unresolved;
- App resolve(ref<Store> evalStore, ref<Store> store);
-};
enum class Realise {
- /* Build the derivation. Postcondition: the
- derivation outputs exist. */
+ /**
+ * Build the derivation.
+ *
+ * Postcondition: the derivation outputs exist.
+ */
Outputs,
- /* Don't build the derivation. Postcondition: the store derivation
- exists. */
+ /**
+ * Don't build the derivation.
+ *
+ * Postcondition: the store derivation exists.
+ */
Derivation,
- /* Evaluate in dry-run mode. Postcondition: nothing. */
- // FIXME: currently unused, but could be revived if we can
- // evaluate derivations in-memory.
+ /**
+ * Evaluate in dry-run mode.
+ *
+ * Postcondition: nothing.
+ *
+ * \todo currently unused, but could be revived if we can evaluate
+ * derivations in-memory.
+ */
Nothing
};
-/* How to handle derivations in commands that operate on store paths. */
+/**
+ * How to handle derivations in commands that operate on store paths.
+ */
enum class OperateOn {
- /* Operate on the output path. */
+ /**
+ * Operate on the output path.
+ */
Output,
- /* Operate on the .drv path. */
+ /**
+ * Operate on the .drv path.
+ */
Derivation
};
+/**
+ * Extra info about a DerivedPath
+ *
+ * Yes, this is empty, but that is intended. It will be sub-classed by
+ * the subclasses of Installable to allow those to provide more info.
+ * Certain commands will make use of this info.
+ */
struct ExtraPathInfo
{
- std::optional<NixInt> priority;
- std::optional<FlakeRef> originalRef;
- std::optional<FlakeRef> resolvedRef;
- std::optional<std::string> attrPath;
- // FIXME: merge with DerivedPath's 'outputs' field?
- std::optional<ExtendedOutputsSpec> extendedOutputsSpec;
+ virtual ~ExtraPathInfo() = default;
};
-/* A derived path with any additional info that commands might
- need from the derivation. */
+/**
+ * A DerivedPath with \ref ExtraPathInfo "any additional info" that
+ * commands might need from the derivation.
+ */
struct DerivedPathWithInfo
{
DerivedPath path;
- ExtraPathInfo info;
+ ref<ExtraPathInfo> info;
};
+/**
+ * Like DerivedPathWithInfo but extending BuiltPath with \ref
+ * ExtraPathInfo "extra info" and also possibly the \ref BuildResult
+ * "result of building".
+ */
struct BuiltPathWithResult
{
BuiltPath path;
- ExtraPathInfo info;
+ ref<ExtraPathInfo> info;
std::optional<BuildResult> result;
};
+/**
+ * Shorthand, for less typing and helping us keep the choice of
+ * collection in sync.
+ */
typedef std::vector<DerivedPathWithInfo> DerivedPathsWithInfo;
+struct Installable;
+
+/**
+ * Shorthand, for less typing and helping us keep the choice of
+ * collection in sync.
+ */
+typedef std::vector<ref<Installable>> Installables;
+
+/**
+ * Installables are the main positional arguments for the Nix
+ * Command-line.
+ *
+ * This base class is very flexible, and just assumes and the
+ * Installable refers to a collection of \ref DerivedPath "derived paths" with
+ * \ref ExtraPathInfo "extra info".
+ */
struct Installable
{
virtual ~Installable() { }
+ /**
+ * What Installable is this?
+ *
+ * Prints back valid CLI syntax that would result in this same
+ * installable. It doesn't need to be exactly what the user wrote,
+ * just something that means the same thing.
+ */
virtual std::string what() const = 0;
+ /**
+ * Get the collection of \ref DerivedPathWithInfo "derived paths
+ * with info" that this \ref Installable instalallable denotes.
+ *
+ * This is the main method of this class
+ */
virtual DerivedPathsWithInfo toDerivedPaths() = 0;
+ /**
+ * A convenience wrapper of the above for when we expect an
+ * installable to produce a single \ref DerivedPath "derived path"
+ * only.
+ *
+ * If no or multiple \ref DerivedPath "derived paths" are produced,
+ * and error is raised.
+ */
DerivedPathWithInfo toDerivedPath();
- UnresolvedApp toApp(EvalState & state);
-
- virtual std::pair<Value *, PosIdx> toValue(EvalState & state)
- {
- throw Error("argument '%s' cannot be evaluated", what());
- }
-
- /* Return a value only if this installable is a store path or a
- symlink to it. */
+ /**
+ * Return a value only if this installable is a store path or a
+ * symlink to it.
+ *
+ * \todo should we move this to InstallableDerivedPath? It is only
+ * supposed to work there anyways. Can always downcast.
+ */
virtual std::optional<StorePath> getStorePath()
{
return {};
}
- /* Get a cursor to each value this Installable could refer to. However
- if none exists, throw exception instead of returning empty vector. */
- virtual std::vector<ref<eval_cache::AttrCursor>>
- getCursors(EvalState & state);
-
- /* Get the first and most preferred cursor this Installable could refer
- to, or throw an exception if none exists. */
- virtual ref<eval_cache::AttrCursor>
- getCursor(EvalState & state);
-
- virtual FlakeRef nixpkgsFlakeRef() const
- {
- return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
- }
-
static std::vector<BuiltPathWithResult> build(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
- const std::vector<std::shared_ptr<Installable>> & installables,
+ const Installables & installables,
BuildMode bMode = bmNormal);
- static std::vector<std::pair<std::shared_ptr<Installable>, BuiltPathWithResult>> build2(
+ static std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> build2(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
- const std::vector<std::shared_ptr<Installable>> & installables,
+ const Installables & installables,
BuildMode bMode = bmNormal);
static std::set<StorePath> toStorePaths(
@@ -137,18 +169,18 @@ struct Installable
ref<Store> store,
Realise mode,
OperateOn operateOn,
- const std::vector<std::shared_ptr<Installable>> & installables);
+ const Installables & installables);
static StorePath toStorePath(
ref<Store> evalStore,
ref<Store> store,
Realise mode,
OperateOn operateOn,
- std::shared_ptr<Installable> installable);
+ ref<Installable> installable);
static std::set<StorePath> toDerivations(
ref<Store> store,
- const std::vector<std::shared_ptr<Installable>> & installables,
+ const Installables & installables,
bool useDeriver = false);
static BuiltPaths toBuiltPaths(
@@ -156,9 +188,7 @@ struct Installable
ref<Store> store,
Realise mode,
OperateOn operateOn,
- const std::vector<std::shared_ptr<Installable>> & installables);
+ const Installables & installables);
};
-typedef std::vector<std::shared_ptr<Installable>> Installables;
-
}