aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/derived-path.hh
blob: c96e0df67cb1e1f836e94142dfae6fd058047459 (plain)
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#pragma once
///@file

#include "config.hh"
#include "path.hh"
#include "outputs-spec.hh"
#include "comparator.hh"

#include <variant>

#include <nlohmann/json_fwd.hpp>

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);
    nlohmann::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 {
    ref<SingleDerivedPath> drvPath;
    OutputName output;

    /**
     * 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;
    /**
     * The caller splits on the separator, so it works for both variants.
     *
     * @param xpSettings Stop-gap to avoid globals during unit tests.
     */
    static SingleDerivedPathBuilt parse(
        const Store & store, ref<SingleDerivedPath> drvPath,
        OutputNameView outputs,
        const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
    nlohmann::json toJSON(Store & store) const;

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

    /**
     * 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
     *
     * @param xpSettings Stop-gap to avoid globals during unit tests.
     */
    static SingleDerivedPath parse(
        const Store & store,
        std::string_view,
        const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
    /**
     * Uses `!` as the separator
     *
     * @param xpSettings Stop-gap to avoid globals during unit tests.
     */
    static SingleDerivedPath parseLegacy(
        const Store & store,
        std::string_view,
        const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
    nlohmann::json toJSON(Store & store) const;
};

static inline ref<SingleDerivedPath> makeConstantStorePathRef(StorePath drvPath)
{
    return make_ref<SingleDerivedPath>(SingleDerivedPath::Opaque { 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 {
    ref<SingleDerivedPath> drvPath;
    OutputsSpec outputs;

    /**
     * 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;
    /**
     * The caller splits on the separator, so it works for both variants.
     *
     * @param xpSettings Stop-gap to avoid globals during unit tests.
     */
    static DerivedPathBuilt parse(
        const Store & store, ref<SingleDerivedPath>,
        std::string_view,
        const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
    nlohmann::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
     *
     * @param xpSettings Stop-gap to avoid globals during unit tests.
     */
    static DerivedPath parse(
        const Store & store,
        std::string_view,
        const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
    /**
     * Uses `!` as the separator
     *
     * @param xpSettings Stop-gap to avoid globals during unit tests.
     */
    static DerivedPath parseLegacy(
        const Store & store,
        std::string_view,
        const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);

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

    nlohmann::json toJSON(Store & store) const;
};

typedef std::vector<DerivedPath> DerivedPaths;

/**
 * Used by various parser functions to require experimental features as
 * needed.
 *
 * Somewhat unfortunate this cannot just be an implementation detail for
 * this module.
 *
 * @param xpSettings Stop-gap to avoid globals during unit tests.
 */
void drvRequireExperiment(
    const SingleDerivedPath & drv,
    const ExperimentalFeatureSettings & xpSettings = experimentalFeatureSettings);
}