summaryrefslogtreecommitdiff
path: root/src/buildtool/storage/config.hpp
blob: d231f06a808efaf4f00a88d137b174df120db18b (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
// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef INCLUDED_SRC_BUILDTOOL_STORAGE_CONFIG_HPP
#define INCLUDED_SRC_BUILDTOOL_STORAGE_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 <fmt/core.h>
#include <nlohmann/json.hpp>

#include "src/buildtool/common/artifact_digest.hpp"
#include "src/buildtool/compatibility/compatibility.hpp"
#include "src/buildtool/execution_api/remote/config.hpp"
#include "src/buildtool/file_system/file_system_manager.hpp"
#include "src/buildtool/file_system/object_type.hpp"
#include "src/buildtool/logging/log_level.hpp"
#include "src/buildtool/logging/logger.hpp"
#include "src/utils/cpp/gsl.hpp"

#include <gsl/gsl>

/// \brief Global storage configuration.
class StorageConfig {
    struct ConfigData {
        // Build root directory. All the storage 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{kDefaultBuildRoot};

        // Number of total storage generations (default: two generations).
        std::size_t num_generations{2};
    };

  public:
    /// \brief Determine user home 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;
    }

    static inline auto const kDefaultBuildRoot =
        GetUserHome() / ".cache" / "just";

    [[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;
        return true;
    }

    /// \brief Specifies the number of storage generations.
    static auto SetNumGenerations(std::size_t num_generations) noexcept
        -> void {
        Data().num_generations = num_generations;
    }

    /// \brief Number of storage generations.
    [[nodiscard]] static auto NumGenerations() noexcept -> std::size_t {
        return Data().num_generations;
    }

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

    /// \brief Root directory of all storage generations.
    [[nodiscard]] static auto CacheRoot() noexcept -> std::filesystem::path {
        return BuildRoot() / "protocol-dependent";
    }

    /// \brief Directory for the git repository storing various roots
    [[nodiscard]] static auto GitRoot() noexcept -> std::filesystem::path {
        return BuildRoot() / "git";
    }

    /// \brief Root directory of specific storage generation for compatible and
    /// non-compatible protocol types.
    [[nodiscard]] static auto GenerationCacheRoot(std::size_t index) noexcept
        -> std::filesystem::path {
        ExpectsAudit(index < Data().num_generations);
        auto generation = std::string{"generation-"} + std::to_string(index);
        return CacheRoot() / generation;
    }

    /// \brief Storage directory of specific generation and protocol type.
    [[nodiscard]] static auto GenerationCacheDir(std::size_t index) noexcept
        -> std::filesystem::path {
        return UpdatePathForCompatibility(GenerationCacheRoot(index));
    }

    /// \brief String representation of the used execution backend.
    [[nodiscard]] static auto ExecutionBackendDescription() noexcept
        -> std::string {
        auto address = RemoteExecutionConfig::RemoteAddress();
        auto properties = RemoteExecutionConfig::PlatformProperties();
        try {
            // json::dump with json::error_handler_t::replace will not throw an
            // exception if invalid UTF-8 sequences are detected in the input.
            // Instead, it will replace them with the UTF-8 replacement
            // character, but still it needs to be inside a try-catch clause to
            // ensure the noexcept modifier of the enclosing function.
            return nlohmann::json{
                {"remote_address",
                 address ? nlohmann::json{fmt::format(
                               "{}:{}", address->host, address->port)}
                         : nlohmann::json{}},
                {"platform_properties", properties}}
                .dump(2, ' ', false, nlohmann::json::error_handler_t::replace);
        } catch (...) {
            return "";
        }
    }

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

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

#endif  // INCLUDED_SRC_BUILDTOOL_STORAGE_CONFIG_HPP