1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#pragma once
///@file

#include "lix/libutil/config.hh"
#include "lix/libstore/path.hh"
#include "lix/libstore/outputs-spec.hh"
#include "lix/libutil/comparator.hh"
#include "lix/libutil/json-fwd.hh"
#include "lix/libutil/ref.hh"
#include "lix/libutil/result.hh"

#include <kj/async.h>
#include <variant>

namespace nix {

class Store;

/**
 * An opaque derived path.
 *
 * Opaque derived paths are just store paths, and fully evaluated. They
 * cannot be simplified further. Since they are opaque, they cannot be
 * built, but they can fetched.
 */
struct DerivedPathOpaque {
    StorePath path;

    std::string to_string(const Store & store) const;
    static DerivedPathOpaque parse(const Store & store, std::string_view);
    kj::Promise<Result<JSON>> toJSON(const Store & store) const;

    GENERATE_CMP(DerivedPathOpaque, me->path);
};

struct SingleDerivedPath;

/**
 * A single derived path that is built from a derivation
 *
 * Built derived paths are pair of a derivation and an output name. They are
 * evaluated by building the derivation, and then taking the resulting output
 * path of the given output name.
 */
struct SingleDerivedPathBuilt {
    DerivedPathOpaque drvPath;
    OutputName output;

    DECLARE_CMP(SingleDerivedPathBuilt);
};

namespace derived_path::detail {
using SingleDerivedPathRaw = std::variant<
    DerivedPathOpaque,
    SingleDerivedPathBuilt
>;
}

/**
 * A "derived path" is a very simple sort of expression (not a Nix
 * language expression! But an expression in a the general sense) that
 * evaluates to (concrete) store path. It is either:
 *
 * - opaque, in which case it is just a concrete store path with
 *   possibly no known derivation
 *
 * - built, in which case it is a pair of a derivation path and an
 *   output name.
 */
struct SingleDerivedPath : derived_path::detail::SingleDerivedPathRaw {
    using Raw = derived_path::detail::SingleDerivedPathRaw;
    using Raw::Raw;

    using Opaque = DerivedPathOpaque;
    using Built = SingleDerivedPathBuilt;

    inline const Raw & raw() const {
        return static_cast<const Raw &>(*this);
    }
};

static inline DerivedPathOpaque makeConstantStorePath(StorePath drvPath)
{
    return SingleDerivedPath::Opaque { std::move(drvPath) };
}

/**
 * A set of derived paths that are built from a derivation
 *
 * Built derived paths are pair of a derivation and some output names.
 * They are evaluated by building the derivation, and then replacing the
 * output names with the resulting outputs.
 *
 * Note that does mean a derived store paths evaluates to multiple
 * opaque paths, which is sort of icky as expressions are supposed to
 * evaluate to single values. Perhaps this should have just a single
 * output name.
 */
struct DerivedPathBuilt {
    DerivedPathOpaque drvPath;
    OutputsSpec outputs;

    /**
     * Uses `^` as the separator
     */
    std::string to_string(const Store & store) const;
    /**
     * Uses `!` as the separator
     */
    std::string to_string_legacy(const Store & store) const;
    /**
     * The caller splits on the separator, so it works for both variants.
     */
    static DerivedPathBuilt parse(const Store & store, DerivedPathOpaque, std::string_view);
    kj::Promise<Result<JSON>> toJSON(Store & store) const;

    DECLARE_CMP(DerivedPathBuilt);
};

namespace derived_path::detail {
using DerivedPathRaw = std::variant<
    DerivedPathOpaque,
    DerivedPathBuilt
>;
}

/**
 * A "derived path" is a very simple sort of expression that evaluates
 * to one or more (concrete) store paths. It is either:
 *
 * - opaque, in which case it is just a single concrete store path with
 *   possibly no known derivation
 *
 * - built, in which case it is a pair of a derivation path and some
 *   output names.
 */
struct DerivedPath : derived_path::detail::DerivedPathRaw {
    using Raw = derived_path::detail::DerivedPathRaw;
    using Raw::Raw;

    using Opaque = DerivedPathOpaque;
    using Built = DerivedPathBuilt;

    inline const Raw & raw() const {
        return static_cast<const Raw &>(*this);
    }

    /**
     * Get the store path this is ultimately derived from (by realising
     * and projecting outputs).
     *
     * Note that this is *not* a property of the store object being
     * referred to, but just of this path --- how we happened to be
     * referring to that store object. In other words, this means this
     * function breaks "referential transparency". It should therefore
     * be used only with great care.
     */
    const StorePath & getBaseStorePath() const;

    /**
     * Uses `^` as the separator
     */
    std::string to_string(const Store & store) const;
    /**
     * Uses `!` as the separator
     */
    std::string to_string_legacy(const Store & store) const;
    /**
     * Uses `!` as the separator
     */
    static DerivedPath parseLegacy(const Store & store, std::string_view);

    /**
     * Convert a `SingleDerivedPath` to a `DerivedPath`.
     */
    static DerivedPath fromSingle(const SingleDerivedPath &);
};

typedef std::vector<DerivedPath> DerivedPaths;

}