Skip to content

Commit

Permalink
Move value-only methods to InstallableValue
Browse files Browse the repository at this point in the history
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 NixOS/rfcs#134.
  • Loading branch information
Ericson2314 committed Mar 15, 2023
1 parent eb56cb7 commit 1c6a631
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 71 deletions.
11 changes: 11 additions & 0 deletions src/libcmd/command-installable-value.cc
Original file line number Diff line number Diff line change
@@ -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 changes: 13 additions & 0 deletions src/libcmd/command-installable-value.hh
Original file line number Diff line number Diff line change
@@ -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 changes: 44 additions & 0 deletions src/libcmd/installable-value.cc
Original file line number Diff line number Diff line change
@@ -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 };
}

}
30 changes: 30 additions & 0 deletions src/libcmd/installable-value.hh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,41 @@

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
{
ref<EvalState> 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);
};

}
17 changes: 0 additions & 17 deletions src/libcmd/installables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
30 changes: 0 additions & 30 deletions src/libcmd/installables.hh
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,6 @@ 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. */
Expand Down Expand Up @@ -92,30 +79,13 @@ struct Installable

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. */
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"}});
Expand Down
3 changes: 2 additions & 1 deletion src/nix/app.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "installables.hh"
#include "installable-derived-path.hh"
#include "installable-value.hh"
#include "store-api.hh"
#include "eval-inline.hh"
#include "eval-cache.hh"
Expand Down Expand Up @@ -40,7 +41,7 @@ std::string resolveString(
return rewriteStrings(toResolve, rewrites);
}

UnresolvedApp Installable::toApp(EvalState & state)
UnresolvedApp InstallableValue::toApp(EvalState & state)
{
auto cursor = getCursor(state);
auto attrPath = cursor->getAttrPath();
Expand Down
6 changes: 3 additions & 3 deletions src/nix/bundle.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "command.hh"
#include "installable-flake.hh"
#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
Expand All @@ -8,7 +8,7 @@

using namespace nix;

struct CmdBundle : InstallableCommand
struct CmdBundle : InstallableValueCommand
{
std::string bundler = "github:NixOS/bundlers";
std::optional<Path> outLink;
Expand Down Expand Up @@ -70,7 +70,7 @@ struct CmdBundle : InstallableCommand
return res;
}

void run(ref<Store> store, ref<Installable> installable) override
void run(ref<Store> store, ref<InstallableValue> installable) override
{
auto evalState = getEvalState();

Expand Down
6 changes: 3 additions & 3 deletions src/nix/edit.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "command.hh"
#include "command-installable-value.hh"
#include "shared.hh"
#include "eval.hh"
#include "attr-path.hh"
Expand All @@ -9,7 +9,7 @@

using namespace nix;

struct CmdEdit : InstallableCommand
struct CmdEdit : InstallableValueCommand
{
std::string description() override
{
Expand All @@ -25,7 +25,7 @@ struct CmdEdit : InstallableCommand

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();

Expand Down
8 changes: 4 additions & 4 deletions src/nix/eval.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "command.hh"
#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
Expand All @@ -11,13 +11,13 @@

using namespace nix;

struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption
struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption
{
bool raw = false;
std::optional<std::string> apply;
std::optional<Path> writeTo;

CmdEval() : InstallableCommand()
CmdEval() : InstallableValueCommand()
{
addFlag({
.longName = "raw",
Expand Down Expand Up @@ -54,7 +54,7 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption

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)
throw UsageError("--raw and --json are mutually exclusive");
Expand Down
6 changes: 4 additions & 2 deletions src/nix/fmt.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "command.hh"
#include "installable-value.hh"
#include "run.hh"

using namespace nix;
Expand Down Expand Up @@ -31,8 +32,9 @@ struct CmdFmt : SourceExprCommand {
auto evalState = getEvalState();
auto evalStore = getEvalStore();

auto installable = parseInstallable(store, ".");
auto app = installable->toApp(*evalState).resolve(evalStore, store);
auto installable_ = parseInstallable(store, ".");
auto & installable = InstallableValue::require(*installable_);
auto app = installable.toApp(*evalState).resolve(evalStore, store);

Strings programArgs{app.program};

Expand Down
12 changes: 7 additions & 5 deletions src/nix/repl.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "eval.hh"
#include "globals.hh"
#include "command.hh"
#include "installable-value.hh"
#include "repl.hh"

namespace nix {
Expand Down Expand Up @@ -57,19 +58,20 @@ struct CmdRepl : RawInstallablesCommand
auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{
auto installables = parseInstallables(store, rawInstallables);
AbstractNixRepl::AnnotatedValues values;
for (auto & installable: installables){
auto what = installable->what();
for (auto & installable_: installables){
auto & installable = InstallableValue::require(*installable_);
auto what = installable.what();
if (file){
auto [val, pos] = installable->toValue(*state);
auto what = installable->what();
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);
auto [val, pos] = installable.toValue(*state);
values.push_back( {val, what} );
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/nix/run.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "run.hh"
#include "command.hh"
#include "command-installable-value.hh"
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
Expand Down Expand Up @@ -137,7 +137,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment

static auto rCmdShell = registerCommand<CmdShell>("shell");

struct CmdRun : InstallableCommand
struct CmdRun : InstallableValueCommand
{
using InstallableCommand::run;

Expand Down Expand Up @@ -183,7 +183,7 @@ struct CmdRun : InstallableCommand
return res;
}

void run(ref<Store> store, ref<Installable> installable) override
void run(ref<Store> store, ref<InstallableValue> installable) override
{
auto state = getEvalState();

Expand Down
6 changes: 3 additions & 3 deletions src/nix/search.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "command.hh"
#include "command-installable-value.hh"
#include "globals.hh"
#include "eval.hh"
#include "eval-inline.hh"
Expand All @@ -22,7 +22,7 @@ std::string wrap(std::string prefix, std::string s)
return concatStrings(prefix, s, ANSI_NORMAL);
}

struct CmdSearch : InstallableCommand, MixJSON
struct CmdSearch : InstallableValueCommand, MixJSON
{
std::vector<std::string> res;
std::vector<std::string> excludeRes;
Expand Down Expand Up @@ -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;
evalSettings.enableImportFromDerivation.setDefault(false);
Expand Down

0 comments on commit 1c6a631

Please sign in to comment.