lix/src/libcmd/installable-value.hh
John Ericson d2162e7acd Make more string values work as installables
As discussed in #7417, it would be good to make more string values work
as installables. That is to say, if an installable refers to a value,
and the value is a string, it used to not work at all, since #7484, it
works somewhat, and this PR make it work some more.

The new cases that are added for `BuiltPath` contexts:

- Fixed input- or content-addressed derivation:

  ```
  nix-repl> hello.out.outPath
  "/nix/store/jppfl2bp1zhx8sgs2mgifmsx6dv16mv2-hello-2.12"

  nix-repl> :p builtins.getContext hello.out.outPath
  { "/nix/store/c7jrxqjhdda93lhbkanqfs07x2bzazbm-hello-2.12.drv" = { outputs = [ "out" ]; }; }

  The string matches the specified single output of that derivation, so
  it should also be valid.

- Floating content-addressed derivation:

  ```
  nix-repl> (hello.overrideAttrs (_: { __contentAddressed = true; })).out.outPath
  "/1a08j26xqc0zm8agps8anxpjji410yvsx4pcgyn4bfan1ddkx2g0"

  nix-repl> :p builtins.getContext (hello.overrideAttrs (_: { __contentAddressed = true; })).out.outPath
  { "/nix/store/qc645pyf9wl37c6qvqzaqkwsm1gp48al-hello-2.12.drv" = { outputs = [ "out" ]; }; }
  ```

  The string is not a path but a placeholder, however it also matches
  the context, and because it is a CA derivation we have no better
  option. This should also be valid.

We may also want to think about richer attrset based values (also
discussed in that issue and #6507), but this change "completes" our
string-based building blocks, from which the others can be desugared
into or at least described/document/taught in terms of.

Progress towards #7417

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
2023-05-15 09:03:38 -04:00

122 lines
3.2 KiB
C++

#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);
static InstallableValue & require(Installable & installable);
static ref<InstallableValue> require(ref<Installable> installable);
protected:
/**
* Handles either a plain path, or a string with a single string
* context elem in the right format. The latter case is handled by
* `EvalState::coerceToDerivedPath()`; see it for details.
*
* @param v Value that is hopefully a string or path per the above.
*
* @param pos Position of value to aid with diagnostics.
*
* @param errorCtx Arbitrary message for use in potential error message when something is wrong with `v`.
*
* @result A derived path (with empty info, for now) if the value
* matched the above criteria.
*/
std::optional<DerivedPathWithInfo> trySinglePathToDerivedPaths(Value & v, const PosIdx pos, std::string_view errorCtx);
};
}