aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/value/context.cc
blob: 22361d8fa24fb2ffa28e2655e4bd54b7b80ec5ef (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
#include "value/context.hh"

#include <optional>

namespace nix {

NixStringContextElem NixStringContextElem::parse(
    std::string_view s0,
    const ExperimentalFeatureSettings & xpSettings)
{
    std::string_view s = s0;

    std::function<SingleDerivedPath()> parseRest;
    parseRest = [&]() -> SingleDerivedPath {
        // Case on whether there is a '!'
        size_t index = s.find("!");
        if (index == std::string_view::npos) {
            return SingleDerivedPath::Opaque {
                .path = StorePath { s },
            };
        } else {
            std::string output { s.substr(0, index) };
            // Advance string to parse after the '!'
            s = s.substr(index + 1);
            auto drv = make_ref<SingleDerivedPath>(parseRest());
            drvRequireExperiment(*drv, xpSettings);
            return SingleDerivedPath::Built {
                .drvPath = std::move(drv),
                .output = std::move(output),
            };
        }
    };

    if (s.size() == 0) {
        throw BadNixStringContextElem(s0,
            "String context element should never be an empty string");
    }

    switch (s.at(0)) {
    case '!': {
        // Advance string to parse after the '!'
        s = s.substr(1);

        // Find *second* '!'
        if (s.find("!") == std::string_view::npos) {
            throw BadNixStringContextElem(s0,
                "String content element beginning with '!' should have a second '!'");
        }

        return std::visit(
            [&](auto x) -> NixStringContextElem { return std::move(x); },
            parseRest());
    }
    case '=': {
        return NixStringContextElem::DrvDeep {
            .drvPath = StorePath { s.substr(1) },
        };
    }
    default: {
        // Ensure no '!'
        if (s.find("!") != std::string_view::npos) {
            throw BadNixStringContextElem(s0,
                "String content element not beginning with '!' should not have a second '!'");
        }
        return std::visit(
            [&](auto x) -> NixStringContextElem { return std::move(x); },
            parseRest());
    }
    }
}

std::string NixStringContextElem::to_string() const
{
    std::string res;

    std::function<void(const SingleDerivedPath &)> toStringRest;
    toStringRest = [&](auto & p) {
        std::visit(overloaded {
            [&](const SingleDerivedPath::Opaque & o) {
                res += o.path.to_string();
            },
            [&](const SingleDerivedPath::Built & o) {
                res += o.output;
                res += '!';
                toStringRest(*o.drvPath);
            },
        }, p.raw());
    };

    std::visit(overloaded {
        [&](const NixStringContextElem::Built & b) {
            res += '!';
            toStringRest(b);
        },
        [&](const NixStringContextElem::Opaque & o) {
            toStringRest(o);
        },
        [&](const NixStringContextElem::DrvDeep & d) {
            res += '=';
            res += d.drvPath.to_string();
        },
    }, raw);

    return res;
}

}