summaryrefslogtreecommitdiff
path: root/src/buildtool/execution_api/local/config.hpp
blob: 5ce8b9efd3413ac5f29afed3b4856a5f661cf991 (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
#ifndef INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_CONFIG_HPP
#define INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_CONFIG_HPP

#ifdef __unix__
#include <pwd.h>
#include <sys/types.h>
#include <unistd.h>
#else
#error "Non-unix is not supported yet"
#endif

#include <filesystem>
#include <functional>
#include <string>
#include <vector>

#include "src/buildtool/compatibility/compatibility.hpp"
#include "src/buildtool/file_system/file_system_manager.hpp"
#include "src/buildtool/logging/logger.hpp"

/// \brief Store global build system configuration.
class LocalExecutionConfig {
    struct ConfigData {

        // Build root directory. All the cache dirs are subdirs of build_root.
        // By default, build_root is set to $HOME/.cache/just.
        // If the user uses --local-build-root PATH,
        // then build_root will be set to PATH.
        std::filesystem::path build_root{};

        // cache_root points to one of the following
        // build_root/protocol-dependent/{git-sha1,compatible-sha256}
        // git-sha1 is the current default. If the user passes the flag
        // --compatible, then the subfolder compatible_sha256 is used
        std::filesystem::path cache_root{};

        // Launcher to be prepended to action's command before executed.
        // Default: ["env", "--"]
        std::vector<std::string> launcher{"env", "--"};

        // Persistent build directory option
        bool keep_build_dir{false};
    };

    // different folder for different caching protocol
    [[nodiscard]] static auto UpdatePathForCompatibility(
        std::filesystem::path const& dir) -> std::filesystem::path {
        return dir / (Compatibility::IsCompatible() ? "compatible-sha256"
                                                    : "git-sha1");
    }

  public:
    [[nodiscard]] static auto SetBuildRoot(
        std::filesystem::path const& dir) noexcept -> bool {
        if (FileSystemManager::IsRelativePath(dir)) {
            Logger::Log(LogLevel::Error,
                        "Build root must be absolute path but got '{}'.",
                        dir.string());
            return false;
        }
        Data().build_root = dir;
        Data().cache_root = "";  // in case we re-set build_root, we are sure
                                 // that the cache path is recomputed as well
        return true;
    }

    [[nodiscard]] static auto SetLauncher(
        std::vector<std::string> const& launcher) noexcept -> bool {
        try {
            Data().launcher = launcher;
        } catch (std::exception const& e) {
            Logger::Log(LogLevel::Error,
                        "when setting the local launcher\n{}",
                        e.what());
            return false;
        }
        return true;
    }

    [[nodiscard]] static auto SetKeepBuildDir(bool is_persistent) noexcept
        -> bool {
        Data().keep_build_dir = is_persistent;
        return true;
    }

    /// \brief User directory.
    [[nodiscard]] static auto GetUserDir() noexcept -> std::filesystem::path {
        return GetUserHome() / ".cache" / "just";
    }

    /// \brief Build directory, defaults to user directory if not set
    [[nodiscard]] static auto BuildRoot() noexcept -> std::filesystem::path {
        auto& build_root = Data().build_root;
        if (build_root.empty()) {
            build_root = GetUserDir();
        }
        return build_root;
    }

    [[nodiscard]] static auto CacheRoot() noexcept -> std::filesystem::path {
        auto& cache_root = Data().cache_root;
        if (cache_root.empty()) {
            cache_root =
                UpdatePathForCompatibility(BuildRoot() / "protocol-dependent");
        }
        return cache_root;
    }

    // CAS directory based on the type of the file.
    // Specialized just for regular File or Exectuable
    template <ObjectType kType,
              typename = std::enable_if<kType == ObjectType::File or
                                        kType == ObjectType::Executable>>
    [[nodiscard]] static inline auto CASDir() noexcept
        -> std::filesystem::path {
        static const std::string kSuffix = std::string{"cas"} + ToChar(kType);
        return CacheRoot() / kSuffix;
    }

    /// \brief Action cache directory
    [[nodiscard]] static auto ActionCacheDir() noexcept
        -> std::filesystem::path {
        return CacheRoot() / "ac";
    }

    /// \brief Target cache directory
    [[nodiscard]] static auto TargetCacheDir() noexcept
        -> std::filesystem::path {
        return CacheRoot() / "tc";
    }

    [[nodiscard]] static auto GetLauncher() noexcept
        -> std::vector<std::string> {
        return Data().launcher;
    }

    [[nodiscard]] static auto KeepBuildDir() noexcept -> bool {
        return Data().keep_build_dir;
    }

  private:
    [[nodiscard]] static auto Data() noexcept -> ConfigData& {
        static ConfigData instance{};
        return instance;
    }

    /// \brief Determine user root directory
    [[nodiscard]] static auto GetUserHome() noexcept -> std::filesystem::path {
        char const* root{nullptr};

#ifdef __unix__
        root = std::getenv("HOME");
        if (root == nullptr) {
            root = getpwuid(getuid())->pw_dir;
        }
#endif

        if (root == nullptr) {
            Logger::Log(LogLevel::Error,
                        "Cannot determine user home directory.");
            std::exit(EXIT_FAILURE);
        }

        return root;
    }
};

#endif  // INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_CONFIG_HPP