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.hh23
-rw-r--r--src/libcmd/command.hh4
-rw-r--r--src/libcmd/common-eval-args.cc8
-rw-r--r--src/libcmd/common-eval-args.hh1
-rw-r--r--src/libcmd/editor-for.hh1
-rw-r--r--src/libcmd/installable-attr-path.cc4
-rw-r--r--src/libcmd/installable-attr-path.hh3
-rw-r--r--src/libcmd/installable-derived-path.cc5
-rw-r--r--src/libcmd/installable-derived-path.hh1
-rw-r--r--src/libcmd/installable-flake.cc26
-rw-r--r--src/libcmd/installable-flake.hh31
-rw-r--r--src/libcmd/installable-value.cc44
-rw-r--r--src/libcmd/installable-value.hh94
-rw-r--r--src/libcmd/installables.cc21
-rw-r--r--src/libcmd/installables.hh154
-rw-r--r--src/libcmd/legacy.hh1
-rw-r--r--src/libcmd/markdown.hh3
-rw-r--r--src/libcmd/repl.hh1
19 files changed, 339 insertions, 97 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..7880d4119
--- /dev/null
+++ b/src/libcmd/command-installable-value.hh
@@ -0,0 +1,23 @@
+#pragma once
+///@file
+
+#include "installable-value.hh"
+#include "command.hh"
+
+namespace nix {
+
+/**
+ * An InstallableCommand where the single positional argument must be an
+ * InstallableValue in particular.
+ */
+struct InstallableValueCommand : InstallableCommand
+{
+ /**
+ * Entry point to this command
+ */
+ 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.hh b/src/libcmd/command.hh
index 874ca3249..96236b987 100644
--- a/src/libcmd/command.hh
+++ b/src/libcmd/command.hh
@@ -1,6 +1,7 @@
#pragma once
+///@file
-#include "installables.hh"
+#include "installable-value.hh"
#include "args.hh"
#include "common-eval-args.hh"
#include "path.hh"
@@ -18,6 +19,7 @@ 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;
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/common-eval-args.hh b/src/libcmd/common-eval-args.hh
index 1ec800613..b69db11dd 100644
--- a/src/libcmd/common-eval-args.hh
+++ b/src/libcmd/common-eval-args.hh
@@ -1,4 +1,5 @@
#pragma once
+///@file
#include "args.hh"
diff --git a/src/libcmd/editor-for.hh b/src/libcmd/editor-for.hh
index 8fbd08792..f752bd849 100644
--- a/src/libcmd/editor-for.hh
+++ b/src/libcmd/editor-for.hh
@@ -1,4 +1,5 @@
#pragma once
+///@file
#include "types.hh"
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-attr-path.hh b/src/libcmd/installable-attr-path.hh
index c06132ec8..e9f0c33da 100644
--- a/src/libcmd/installable-attr-path.hh
+++ b/src/libcmd/installable-attr-path.hh
@@ -1,3 +1,6 @@
+#pragma once
+///@file
+
#include "globals.hh"
#include "installable-value.hh"
#include "outputs-spec.hh"
diff --git a/src/libcmd/installable-derived-path.cc b/src/libcmd/installable-derived-path.cc
index 729dc7d31..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()
diff --git a/src/libcmd/installable-derived-path.hh b/src/libcmd/installable-derived-path.hh
index 042878b91..e0b4f18b3 100644
--- a/src/libcmd/installable-derived-path.hh
+++ b/src/libcmd/installable-derived-path.hh
@@ -1,4 +1,5 @@
#pragma once
+///@file
#include "installables.hh"
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc
index 7b0cc376d..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,
+ }),
}};
}
@@ -212,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));
}
@@ -229,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..afe64d977 100644
--- a/src/libcmd/installable-flake.hh
+++ b/src/libcmd/installable-flake.hh
@@ -1,9 +1,34 @@
#pragma once
+///@file
#include "installable-value.hh"
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 +58,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..bfb3bfeed 100644
--- a/src/libcmd/installable-value.hh
+++ b/src/libcmd/installable-value.hh
@@ -1,14 +1,108 @@
#pragma once
+///@file
#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 5cbf26b88..67549b280 100644
--- a/src/libcmd/installables.cc
+++ b/src/libcmd/installables.cc
@@ -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,
@@ -534,7 +517,7 @@ std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> Installable::build
struct Aux
{
- ExtraPathInfo info;
+ ref<ExtraPathInfo> info;
ref<Installable> installable;
};
diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh
index 6c2922d89..42d6c7c7c 100644
--- a/src/libcmd/installables.hh
+++ b/src/libcmd/installables.hh
@@ -1,12 +1,11 @@
#pragma once
+///@file
#include "util.hh"
#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,113 +13,144 @@
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,
diff --git a/src/libcmd/legacy.hh b/src/libcmd/legacy.hh
index f503b0da3..357500a4d 100644
--- a/src/libcmd/legacy.hh
+++ b/src/libcmd/legacy.hh
@@ -1,4 +1,5 @@
#pragma once
+///@file
#include <functional>
#include <map>
diff --git a/src/libcmd/markdown.hh b/src/libcmd/markdown.hh
index 78320fcf5..a04d32a4f 100644
--- a/src/libcmd/markdown.hh
+++ b/src/libcmd/markdown.hh
@@ -1,3 +1,6 @@
+#pragma once
+///@file
+
#include "types.hh"
namespace nix {
diff --git a/src/libcmd/repl.hh b/src/libcmd/repl.hh
index dfccc93e7..731c8e6db 100644
--- a/src/libcmd/repl.hh
+++ b/src/libcmd/repl.hh
@@ -1,4 +1,5 @@
#pragma once
+///@file
#include "eval.hh"