Skip to content

Commit

Permalink
[dnf5 plugin] config-manager: Support "--add-or-replace" in "addrepo"
Browse files Browse the repository at this point in the history
What happens when the destination repository configuration file already
exists?
By default throw an error.

--overwrite  - Allow overwriting of existing repository configuration file

--add-or-replace - Allow adding or replacing a repository in the existing
                   configuration file
  • Loading branch information
jrohel committed Nov 2, 2023
1 parent e0e3734 commit 9d70e00
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 14 deletions.
41 changes: 32 additions & 9 deletions dnf5-plugins/config-manager_plugin/addrepo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,16 @@ void ConfigManagerAddRepoCommand::set_argument_parser() {
});
cmd.register_named_arg(set_opt);

auto add_or_replace = parser.add_new_named_arg("add-or-replace");
add_or_replace->set_long_name("add-or-replace");
add_or_replace->set_description("Allow adding or replacing a repository in the existing configuration file");
add_or_replace->set_has_value(false);
add_or_replace->set_parse_hook_func([this](cli::ArgumentParser::NamedArg *, const char *, const char *) {
file_policy = FilePolicy::ADD_OR_REPLACE;
return true;
});
cmd.register_named_arg(add_or_replace);

auto create_missing_dirs_opt = parser.add_new_named_arg("create-missing-dir");
create_missing_dirs_opt->set_long_name("create-missing-dir");
create_missing_dirs_opt->set_description("Allow creation of missing directories");
Expand All @@ -226,7 +236,7 @@ void ConfigManagerAddRepoCommand::set_argument_parser() {
overwrite_opt->set_description("Allow overwriting of existing repository configuration file");
overwrite_opt->set_has_value(false);
overwrite_opt->set_parse_hook_func([this](cli::ArgumentParser::NamedArg *, const char *, const char *) {
overwrite = true;
file_policy = FilePolicy::OVERWRITE;
return true;
});
cmd.register_named_arg(overwrite_opt);
Expand All @@ -245,6 +255,7 @@ void ConfigManagerAddRepoCommand::set_argument_parser() {
cmd.register_named_arg(save_filename_opt);

// Set conflicting arguments
add_or_replace->add_conflict_argument(*from_repofile_opt);
repo_id_opt->add_conflict_argument(*from_repofile_opt);
set_opt->add_conflict_argument(*from_repofile_opt);
}
Expand Down Expand Up @@ -287,7 +298,7 @@ void ConfigManagerAddRepoCommand::add_repos_from_repofile(
}
auto dest_path = dest_repo_dir / save_filename;

test_if_filepath_not_exist(dest_path);
test_if_filepath_not_exist(dest_path, false);

// Creates an open temporary file. It then closes it but does not remove it.
// In the following code, this temporary file is used to store the copied/downloaded configuration.
Expand Down Expand Up @@ -397,10 +408,19 @@ void ConfigManagerAddRepoCommand::create_repo(
}
auto dest_path = dest_repo_dir / save_filename;

test_if_filepath_not_exist(dest_path);
test_if_filepath_not_exist(dest_path, true);
test_if_ids_not_already_exist({repo_id}, dest_path);

ConfigParser parser;

if (file_policy == FilePolicy::ADD_OR_REPLACE && std::filesystem::exists(dest_path)) {
parser.read(dest_path);
if (parser.has_section(repo_id)) {
// If the repository with the id already exists, it will be removed.
parser.remove_section(repo_id);
}
}

parser.add_section(repo_id);

// Sets the default repository name. May be overwritten with "--set=name=<name>".
Expand All @@ -423,8 +443,9 @@ void ConfigManagerAddRepoCommand::create_repo(
}


void ConfigManagerAddRepoCommand::test_if_filepath_not_exist(const std::filesystem::path & path) const {
if (!overwrite && std::filesystem::exists(path)) {
void ConfigManagerAddRepoCommand::test_if_filepath_not_exist(
const std::filesystem::path & path, bool show_hint_add_or_replace) const {
if (file_policy == FilePolicy::ERROR && std::filesystem::exists(path)) {
ConfigParser parser;
parser.read(path);
std::string repo_ids;
Expand All @@ -437,11 +458,13 @@ void ConfigManagerAddRepoCommand::test_if_filepath_not_exist(const std::filesyst
}
repo_ids += repo_id;
}
throw ConfigManagerError(
BgettextMessage msg1 =
M_("File \"{}\" already exists and configures repositories with IDs \"{}\"."
" Add \"--add-or-replace\" or \"--overwrite\".");
BgettextMessage msg2 =
M_("File \"{}\" already exists and configures repositories with IDs \"{}\"."
" Add \"--overwrite\" to overwrite."),
path.string(),
repo_ids);
" Add \"--overwrite\" to overwrite.");
throw ConfigManagerError(show_hint_add_or_replace ? msg1 : msg2, path.string(), repo_ids);
}
}

Expand Down
17 changes: 12 additions & 5 deletions dnf5-plugins/config-manager_plugin/addrepo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ class ConfigManagerAddRepoCommand : public Command {
void configure() override;

private:
// Defines what happens when the destination repository configuration file already exists.
enum class FilePolicy {
ERROR, // Throw an error
OVERWRITE, // Allow overwriting of existing repository configuration file
ADD_OR_REPLACE // Allow adding or replacing a repository in the existing configuration file
};

struct SourceRepofile {
std::string location;
bool is_local_path;
Expand All @@ -60,7 +67,7 @@ class ConfigManagerAddRepoCommand : public Command {
/// Tests if the file does not exist.
/// @param path Path to check.
/// @throws ConfigManagerError Trown if `path` already exist and overwriting is not allowed.
void test_if_filepath_not_exist(const std::filesystem::path & path) const;
void test_if_filepath_not_exist(const std::filesystem::path & path, bool show_hint_add_or_replace) const;

/// Tests if the repositories IDs in the vector do not already exist in the configuration.
/// @param repo_ids List of repositories IDs to check.
Expand All @@ -72,10 +79,10 @@ class ConfigManagerAddRepoCommand : public Command {
libdnf5::ConfigMain tmp_config;
libdnf5::repo::ConfigRepo tmp_repo_conf{tmp_config, "temporary_to_check_repository_options"};

SourceRepofile source_repofile; // Location of source repository configuration file.
std::string repo_id; // The user-defined ID of the newly created repository.
bool create_missing_dirs{false}; // Allows to create missing directories.
bool overwrite{false}; // Allows to overwrite an existing configuration file.
SourceRepofile source_repofile; // Location of source repository configuration file.
std::string repo_id; // The user-defined ID of the newly created repository.
bool create_missing_dirs{false}; // Allows to create missing directories.
FilePolicy file_policy{FilePolicy::ERROR};
std::string save_filename; // User-defined name of newly saved configuration file.
std::map<std::string, std::string> repo_opts; // Options for the new repository.
};
Expand Down

0 comments on commit 9d70e00

Please sign in to comment.