forked from lix-project/lix
Move value-only methods to InstallableValue
These methods would previously fail on the other `Installable`s, so moving them to this class is more correct as to where they actually work. Additionally, a `InstallableValueCommand` is created to make it easier (or rather no worse than before) to write commands that just work on `InstallableValue`s. Besides being a cleanup to avoid failing default methods, this gets us closer to https://github.com/NixOS/rfcs/pull/134.
This commit is contained in:
parent
acd707acca
commit
c998e0172f
11
src/libcmd/command-installable-value.cc
Normal file
11
src/libcmd/command-installable-value.cc
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
13
src/libcmd/command-installable-value.hh
Normal file
13
src/libcmd/command-installable-value.hh
Normal file
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
44
src/libcmd/installable-value.cc
Normal file
44
src/libcmd/installable-value.cc
Normal file
|
@ -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 };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,11 +4,41 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
struct InstallableValue : Installable
|
struct InstallableValue : Installable
|
||||||
{
|
{
|
||||||
ref<EvalState> state;
|
ref<EvalState> state;
|
||||||
|
|
||||||
InstallableValue(ref<EvalState> state) : state(state) {}
|
InstallableValue(ref<EvalState> state) : state(state) {}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
static InstallableValue & require(Installable & installable);
|
||||||
|
static ref<InstallableValue> require(ref<Installable> installable);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -364,23 +364,6 @@ DerivedPathWithInfo Installable::toDerivedPath()
|
||||||
return std::move(buildables[0]);
|
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(
|
static StorePath getDeriver(
|
||||||
ref<Store> store,
|
ref<Store> store,
|
||||||
const Installable & i,
|
const Installable & i,
|
||||||
|
|
|
@ -18,19 +18,6 @@ struct SourceExprCommand;
|
||||||
|
|
||||||
namespace eval_cache { class EvalCache; class AttrCursor; }
|
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 {
|
enum class Realise {
|
||||||
/* Build the derivation. Postcondition: the
|
/* Build the derivation. Postcondition: the
|
||||||
derivation outputs exist. */
|
derivation outputs exist. */
|
||||||
|
@ -92,13 +79,6 @@ struct Installable
|
||||||
|
|
||||||
DerivedPathWithInfo toDerivedPath();
|
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
|
/* Return a value only if this installable is a store path or a
|
||||||
symlink to it. */
|
symlink to it. */
|
||||||
virtual std::optional<StorePath> getStorePath()
|
virtual std::optional<StorePath> getStorePath()
|
||||||
|
@ -106,16 +86,6 @@ struct Installable
|
||||||
return {};
|
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
|
virtual FlakeRef nixpkgsFlakeRef() const
|
||||||
{
|
{
|
||||||
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
|
return FlakeRef::fromAttrs({{"type","indirect"}, {"id", "nixpkgs"}});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "installables.hh"
|
#include "installables.hh"
|
||||||
#include "installable-derived-path.hh"
|
#include "installable-derived-path.hh"
|
||||||
|
#include "installable-value.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
#include "eval-cache.hh"
|
#include "eval-cache.hh"
|
||||||
|
@ -40,7 +41,7 @@ std::string resolveString(
|
||||||
return rewriteStrings(toResolve, rewrites);
|
return rewriteStrings(toResolve, rewrites);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnresolvedApp Installable::toApp(EvalState & state)
|
UnresolvedApp InstallableValue::toApp(EvalState & state)
|
||||||
{
|
{
|
||||||
auto cursor = getCursor(state);
|
auto cursor = getCursor(state);
|
||||||
auto attrPath = cursor->getAttrPath();
|
auto attrPath = cursor->getAttrPath();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "command.hh"
|
|
||||||
#include "installable-flake.hh"
|
#include "installable-flake.hh"
|
||||||
|
#include "command-installable-value.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
struct CmdBundle : InstallableCommand
|
struct CmdBundle : InstallableValueCommand
|
||||||
{
|
{
|
||||||
std::string bundler = "github:NixOS/bundlers";
|
std::string bundler = "github:NixOS/bundlers";
|
||||||
std::optional<Path> outLink;
|
std::optional<Path> outLink;
|
||||||
|
@ -70,7 +70,7 @@ struct CmdBundle : InstallableCommand
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ref<Store> store, ref<Installable> installable) override
|
void run(ref<Store> store, ref<InstallableValue> installable) override
|
||||||
{
|
{
|
||||||
auto evalState = getEvalState();
|
auto evalState = getEvalState();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "command.hh"
|
#include "command-installable-value.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
struct CmdEdit : InstallableCommand
|
struct CmdEdit : InstallableValueCommand
|
||||||
{
|
{
|
||||||
std::string description() override
|
std::string description() override
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ struct CmdEdit : InstallableCommand
|
||||||
|
|
||||||
Category category() override { return catSecondary; }
|
Category category() override { return catSecondary; }
|
||||||
|
|
||||||
void run(ref<Store> store, ref<Installable> installable) override
|
void run(ref<Store> store, ref<InstallableValue> installable) override
|
||||||
{
|
{
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "command.hh"
|
#include "command-installable-value.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
@ -11,13 +11,13 @@
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
|
struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
|
||||||
{
|
{
|
||||||
bool raw = false;
|
bool raw = false;
|
||||||
std::optional<std::string> apply;
|
std::optional<std::string> apply;
|
||||||
std::optional<Path> writeTo;
|
std::optional<Path> writeTo;
|
||||||
|
|
||||||
CmdEval() : InstallableCommand()
|
CmdEval() : InstallableValueCommand()
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
.longName = "raw",
|
.longName = "raw",
|
||||||
|
@ -54,7 +54,7 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
|
||||||
|
|
||||||
Category category() override { return catSecondary; }
|
Category category() override { return catSecondary; }
|
||||||
|
|
||||||
void run(ref<Store> store, ref<Installable> installable) override
|
void run(ref<Store> store, ref<InstallableValue> installable) override
|
||||||
{
|
{
|
||||||
if (raw && json)
|
if (raw && json)
|
||||||
throw UsageError("--raw and --json are mutually exclusive");
|
throw UsageError("--raw and --json are mutually exclusive");
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "installable-value.hh"
|
||||||
#include "run.hh"
|
#include "run.hh"
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
@ -31,8 +32,9 @@ struct CmdFmt : SourceExprCommand {
|
||||||
auto evalState = getEvalState();
|
auto evalState = getEvalState();
|
||||||
auto evalStore = getEvalStore();
|
auto evalStore = getEvalStore();
|
||||||
|
|
||||||
auto installable = parseInstallable(store, ".");
|
auto installable_ = parseInstallable(store, ".");
|
||||||
auto app = installable->toApp(*evalState).resolve(evalStore, store);
|
auto & installable = InstallableValue::require(*installable_);
|
||||||
|
auto app = installable.toApp(*evalState).resolve(evalStore, store);
|
||||||
|
|
||||||
Strings programArgs{app.program};
|
Strings programArgs{app.program};
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "command.hh"
|
#include "command.hh"
|
||||||
|
#include "installable-value.hh"
|
||||||
#include "repl.hh"
|
#include "repl.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -57,11 +58,12 @@ struct CmdRepl : RawInstallablesCommand
|
||||||
auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
|
auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
|
||||||
auto installables = parseInstallables(store, rawInstallables);
|
auto installables = parseInstallables(store, rawInstallables);
|
||||||
AbstractNixRepl::AnnotatedValues values;
|
AbstractNixRepl::AnnotatedValues values;
|
||||||
for (auto & installable: installables){
|
for (auto & installable_: installables){
|
||||||
auto what = installable->what();
|
auto & installable = InstallableValue::require(*installable_);
|
||||||
|
auto what = installable.what();
|
||||||
if (file){
|
if (file){
|
||||||
auto [val, pos] = installable->toValue(*state);
|
auto [val, pos] = installable.toValue(*state);
|
||||||
auto what = installable->what();
|
auto what = installable.what();
|
||||||
state->forceValue(*val, pos);
|
state->forceValue(*val, pos);
|
||||||
auto autoArgs = getAutoArgs(*state);
|
auto autoArgs = getAutoArgs(*state);
|
||||||
auto valPost = state->allocValue();
|
auto valPost = state->allocValue();
|
||||||
|
@ -69,7 +71,7 @@ struct CmdRepl : RawInstallablesCommand
|
||||||
state->forceValue(*valPost, pos);
|
state->forceValue(*valPost, pos);
|
||||||
values.push_back( {valPost, what });
|
values.push_back( {valPost, what });
|
||||||
} else {
|
} else {
|
||||||
auto [val, pos] = installable->toValue(*state);
|
auto [val, pos] = installable.toValue(*state);
|
||||||
values.push_back( {val, what} );
|
values.push_back( {val, what} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "run.hh"
|
#include "run.hh"
|
||||||
#include "command.hh"
|
#include "command-installable-value.hh"
|
||||||
#include "common-args.hh"
|
#include "common-args.hh"
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
@ -137,7 +137,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment
|
||||||
|
|
||||||
static auto rCmdShell = registerCommand<CmdShell>("shell");
|
static auto rCmdShell = registerCommand<CmdShell>("shell");
|
||||||
|
|
||||||
struct CmdRun : InstallableCommand
|
struct CmdRun : InstallableValueCommand
|
||||||
{
|
{
|
||||||
using InstallableCommand::run;
|
using InstallableCommand::run;
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ struct CmdRun : InstallableCommand
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ref<Store> store, ref<Installable> installable) override
|
void run(ref<Store> store, ref<InstallableValue> installable) override
|
||||||
{
|
{
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "command.hh"
|
#include "command-installable-value.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "eval.hh"
|
#include "eval.hh"
|
||||||
#include "eval-inline.hh"
|
#include "eval-inline.hh"
|
||||||
|
@ -22,7 +22,7 @@ std::string wrap(std::string prefix, std::string s)
|
||||||
return concatStrings(prefix, s, ANSI_NORMAL);
|
return concatStrings(prefix, s, ANSI_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmdSearch : InstallableCommand, MixJSON
|
struct CmdSearch : InstallableValueCommand, MixJSON
|
||||||
{
|
{
|
||||||
std::vector<std::string> res;
|
std::vector<std::string> res;
|
||||||
std::vector<std::string> excludeRes;
|
std::vector<std::string> excludeRes;
|
||||||
|
@ -61,7 +61,7 @@ struct CmdSearch : InstallableCommand, MixJSON
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(ref<Store> store, ref<Installable> installable) override
|
void run(ref<Store> store, ref<InstallableValue> installable) override
|
||||||
{
|
{
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
evalSettings.enableImportFromDerivation.setDefault(false);
|
evalSettings.enableImportFromDerivation.setDefault(false);
|
||||||
|
|
Loading…
Reference in a new issue