diff options
-rw-r--r-- | share/man/just-mr.1.md | 6 | ||||
-rw-r--r-- | share/man/just-mrrc.5.md | 8 | ||||
-rw-r--r-- | src/other_tools/just_mr/cli.hpp | 11 | ||||
-rw-r--r-- | src/other_tools/just_mr/launch.cpp | 3 | ||||
-rw-r--r-- | src/other_tools/just_mr/main.cpp | 18 | ||||
-rw-r--r-- | src/other_tools/just_mr/setup_utils.cpp | 67 | ||||
-rw-r--r-- | src/other_tools/just_mr/setup_utils.hpp | 3 |
7 files changed, 107 insertions, 9 deletions
diff --git a/share/man/just-mr.1.md b/share/man/just-mr.1.md index e05828c6..12bd71a5 100644 --- a/share/man/just-mr.1.md +++ b/share/man/just-mr.1.md @@ -53,6 +53,12 @@ order: The default configuration lookup order can be adjusted in the just-mrrc file. See **`just-mrrc`**(5) for more details. +**`--absent`** *`PATH`* +Path to a file specifying which repositories are to be considered +absent, overriding the values set by the *`"pragma"`* entries in the +multi-repository configuration. The file has to contain a JSON array +of those repository names to be considered absent. + **`-D`**, **`--defines`** *`JSON`* Defines, via an in-line JSON object, an overlay configuration for **`just`**(1); if used as a launcher for a subcommand known to support diff --git a/share/man/just-mrrc.5.md b/share/man/just-mrrc.5.md index 5a7d0b82..b0a434e3 100644 --- a/share/man/just-mrrc.5.md +++ b/share/man/just-mrrc.5.md @@ -51,6 +51,10 @@ The just-mrrc is given by a JSON object. detail). The lookup is performed in the same order the location objects appear in the list. + - The value for the key *`"absent"`*, if provided, is a JSON list + of location objects to search for a file specifying the list of + absent repositories. + - The value for the key *`"local build root"`* is a single location object, specifying the path to use as the local build root. For more details, see **`just-mr`**(1). @@ -124,6 +128,10 @@ An example just-mrrc file could look like the following: , {"root": "home", "path": ".just-repos.json"} , {"root": "system", "path": "etc/just-repos.json"} ] +, "absent": + [ {"root": "workspace", "path": "etc/absent.json"} + , {"root": "home", "path": ".just-absent"} + ] , "local build root": {"root": "home", "path": ".cache/just"} , "checkout locations": {"root": "home", "path": ".just-local.json"} , "local launcher": ["env", "--"] diff --git a/src/other_tools/just_mr/cli.hpp b/src/other_tools/just_mr/cli.hpp index 328ab666..4c0c6e34 100644 --- a/src/other_tools/just_mr/cli.hpp +++ b/src/other_tools/just_mr/cli.hpp @@ -33,6 +33,7 @@ /// \brief Arguments common to all just-mr subcommands struct MultiRepoCommonArguments { std::optional<std::filesystem::path> repository_config{std::nullopt}; + std::optional<std::filesystem::path> absent_repository_file{std::nullopt}; std::optional<std::filesystem::path> checkout_locations_file{std::nullopt}; std::vector<std::string> explicit_distdirs{}; JustMR::PathsPtr just_mr_paths = std::make_shared<JustMR::Paths>(); @@ -98,6 +99,16 @@ static inline void SetupMultiRepoCommonArguments( "Repository-description file to use.") ->type_name("FILE"); app->add_option_function<std::string>( + "--absent", + [clargs](auto const& file_raw) { + clargs->absent_repository_file = + std::filesystem::weakly_canonical( + std::filesystem::absolute(file_raw)); + }, + "File specifying the repositories to consider absent (overrides the " + "pragma in the config file).") + ->type_name("FILE"); + app->add_option_function<std::string>( "--local-build-root", [clargs](auto const& local_build_root_raw) { clargs->just_mr_paths->root = std::filesystem::weakly_canonical( diff --git a/src/other_tools/just_mr/launch.cpp b/src/other_tools/just_mr/launch.cpp index 26b87059..4e9403a8 100644 --- a/src/other_tools/just_mr/launch.cpp +++ b/src/other_tools/just_mr/launch.cpp @@ -60,7 +60,8 @@ auto CallJust(std::optional<std::filesystem::path> const& config_file, if (not lock) { return kExitGenericFailure; } - auto config = JustMR::Utils::ReadConfiguration(config_file); + auto config = JustMR::Utils::ReadConfiguration( + config_file, common_args.absent_repository_file); use_config = true; mr_config_path = MultiRepoSetup(config, diff --git a/src/other_tools/just_mr/main.cpp b/src/other_tools/just_mr/main.cpp index 85105e50..1e8905d6 100644 --- a/src/other_tools/just_mr/main.cpp +++ b/src/other_tools/just_mr/main.cpp @@ -590,6 +590,21 @@ void SetupLogging(MultiRepoLogArguments const& clargs) { } } } + // read path to absent repository specification if not already provided by + // the user + if (not clargs->common.absent_repository_file) { + auto absent_order = rc_config["absent"]; + if (absent_order.IsNotNull() and absent_order->IsList()) { + for (auto const& entry : absent_order->List()) { + auto path = ReadLocation( + entry, clargs->common.just_mr_paths->workspace_root); + if (path and FileSystemManager::IsFile(path->first)) { + clargs->common.absent_repository_file = path->first; + break; + } + } + } + } // read config lookup order auto config_lookup_order = rc_config["config lookup order"]; if (config_lookup_order.IsNotNull()) { @@ -744,7 +759,8 @@ auto main(int argc, char* argv[]) -> int { } // The remaining options all need the config file - auto config = JustMR::Utils::ReadConfiguration(config_file); + auto config = JustMR::Utils::ReadConfiguration( + config_file, arguments.common.absent_repository_file); // Run subcommand `setup` or `setup-env` if (arguments.cmd == SubCommand::kSetup or diff --git a/src/other_tools/just_mr/setup_utils.cpp b/src/other_tools/just_mr/setup_utils.cpp index b325a71d..332503ea 100644 --- a/src/other_tools/just_mr/setup_utils.cpp +++ b/src/other_tools/just_mr/setup_utils.cpp @@ -148,7 +148,8 @@ void DefaultReachableRepositories( } auto ReadConfiguration( - std::optional<std::filesystem::path> const& config_file_opt) noexcept + std::optional<std::filesystem::path> const& config_file_opt, + std::optional<std::filesystem::path> const& absent_file_opt) noexcept -> std::shared_ptr<Configuration> { if (not config_file_opt) { Logger::Log(LogLevel::Error, "Cannot find repository configuration."); @@ -156,7 +157,7 @@ auto ReadConfiguration( } auto const& config_file = *config_file_opt; - std::shared_ptr<Configuration> config{nullptr}; + auto config = nlohmann::json::object(); if (not FileSystemManager::IsFile(config_file)) { Logger::Log(LogLevel::Error, "Cannot read config file {}.", @@ -165,14 +166,13 @@ auto ReadConfiguration( } try { std::ifstream fs(config_file); - auto map = Expression::FromJson(nlohmann::json::parse(fs)); - if (not map->IsMap()) { + config = nlohmann::json::parse(fs); + if (not config.is_object()) { Logger::Log(LogLevel::Error, "Config file {} does not contain a JSON object.", config_file.string()); std::exit(kExitConfigError); } - config = std::make_shared<Configuration>(map); } catch (std::exception const& e) { Logger::Log(LogLevel::Error, "Parsing config file {} failed with error:\n{}", @@ -180,7 +180,62 @@ auto ReadConfiguration( e.what()); std::exit(kExitConfigError); } - return config; + + if (absent_file_opt) { + if (not FileSystemManager::IsFile(*absent_file_opt)) { + Logger::Log(LogLevel::Error, + "Not file specifying the absent repositories: {}", + absent_file_opt->string()); + std::exit(kExitConfigError); + } + try { + std::ifstream fs(*absent_file_opt); + auto absent = nlohmann::json::parse(fs); + if (not absent.is_array()) { + Logger::Log(LogLevel::Error, + "Expected {} to contain a list of repository " + "names, but found {}", + absent_file_opt->string(), + absent.dump()); + std::exit(kExitConfigError); + } + std::unordered_set<std::string> absent_set{}; + for (auto const& repo : absent) { + if (not repo.is_string()) { + Logger::Log(LogLevel::Error, + "Repositories names have to be strings, but " + "found entry {} in {}", + repo.dump(), + absent_file_opt->string()); + std::exit(kExitConfigError); + } + absent_set.insert(repo); + } + auto new_repos = nlohmann::json::object(); + auto repos = config.value("repositories", nlohmann::json::object()); + for (auto const& [key, val] : repos.items()) { + new_repos[key] = val; + auto ws = val.value("repository", nlohmann::json::object()); + auto pragma = ws.value("pragma", nlohmann::json::object()); + pragma["absent"] = absent_set.contains(key); + ws["pragma"] = pragma; + new_repos[key]["repository"] = ws; + } + config["repositories"] = new_repos; + } catch (std::exception const& e) { + Logger::Log(LogLevel::Error, + "Parsing absent-repos file {} failed with error:\n{}", + absent_file_opt->string(), + e.what()); + std::exit(kExitConfigError); + } + } + + try { + return std::make_shared<Configuration>(Expression::FromJson(config)); + } catch (...) { + return nullptr; + } } auto SetupRemoteApi(std::optional<std::string> const& remote_exec_addr, diff --git a/src/other_tools/just_mr/setup_utils.hpp b/src/other_tools/just_mr/setup_utils.hpp index 3294a7e5..9530cc95 100644 --- a/src/other_tools/just_mr/setup_utils.hpp +++ b/src/other_tools/just_mr/setup_utils.hpp @@ -55,7 +55,8 @@ void DefaultReachableRepositories( /// \brief Read in a just-mr configuration file. [[nodiscard]] auto ReadConfiguration( - std::optional<std::filesystem::path> const& config_file_opt) noexcept + std::optional<std::filesystem::path> const& config_file_opt, + std::optional<std::filesystem::path> const& absent_file_opt) noexcept -> std::shared_ptr<Configuration>; /// \brief Setup of a remote API based on just-mr arguments. |