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
#pragma once
///@file

#include <optional>

#include "lix/libutil/types.hh"
#include "lix/libutil/comparator.hh"

namespace nix {

/**
 * A "search path" is a list of ways look for something, used with
 * `builtins.findFile` and `< >` lookup expressions.
 */
struct SearchPath
{
    /**
     * A single element of a `SearchPath`.
     *
     * Each element is tried in succession when looking up a path. The first
     * element to completely match wins.
     */
    struct Elem;

    /**
     * The first part of a `SearchPath::Elem` pair.
     *
     * Called a "prefix" because it takes the form of a prefix of a file
     * path (first `n` path components). When looking up a path, to use
     * a `SearchPath::Elem`, its `Prefix` must match the path.
     */
    struct Prefix;

    /**
     * The second part of a `SearchPath::Elem` pair.
     *
     * It is either a path or a URL (with certain restrictions / extra
     * structure).
     *
     * If the prefix of the path we are looking up matches, we then
     * check if the rest of the path points to something that exists
     * within the directory denoted by this. If so, the
     * `SearchPath::Elem` as a whole matches, and that *something* being
     * pointed to by the rest of the path we are looking up is the
     * result.
     */
    struct Path;

    /**
     * The list of search path elements. Each one is checked for a path
     * when looking up. (The actual lookup entry point is in `EvalState`
     * not in this class.)
     */
    std::list<SearchPath::Elem> elements;

    /**
     * Parse a string into a `SearchPath`
     */
    static SearchPath parse(const Strings & rawElems);
};

struct SearchPath::Prefix
{
    /**
     * Underlying string
     *
     * @todo Should we normalize this when constructing a `SearchPath::Prefix`?
     */
    std::string s;

    GENERATE_CMP(SearchPath::Prefix, me->s);

    /**
     * If the path possibly matches this search path element, return the
     * suffix that we should look for inside the resolved value of the
     * element
     * Note the double optionality in the name. While we might have a matching prefix, the suffix may not exist.
     */
    std::optional<std::string_view> suffixIfPotentialMatch(std::string_view path) const;
};

struct SearchPath::Path
{
    /**
     * The location of a search path item, as a path or URL.
     *
     * @todo Maybe change this to `std::variant<SourcePath, URL>`.
     */
    std::string s;

    GENERATE_CMP(SearchPath::Path, me->s);
};

struct SearchPath::Elem
{

    Prefix prefix;
    Path path;

    GENERATE_CMP(SearchPath::Elem, me->prefix, me->path);

    /**
     * Parse a string into a `SearchPath::Elem`
     */
    static SearchPath::Elem parse(std::string_view rawElem);
};

}