Move more command line parsing into a module
Some checks failed
Test / build (push) Failing after 13s

This commit is contained in:
2026-01-25 11:33:55 +01:00
parent c9a3ebd623
commit da02080fc1
3 changed files with 105 additions and 28 deletions

View File

@@ -30,6 +30,25 @@ namespace katja
const std::vector<std::string> arguments; const std::vector<std::string> arguments;
}; };
export struct search_command
{
const std::string needle;
};
export struct updates_command
{
};
export struct help_command
{
};
export using subcommand = std::variant<
search_command,
updates_command,
help_command
>;
export class invalid_command_error : public std::runtime_error export class invalid_command_error : public std::runtime_error
{ {
const std::string command; const std::string command;
@@ -40,13 +59,26 @@ namespace katja
{ {
} }
invalid_command_error(const std::string& invalid_command) explicit invalid_command_error(const std::string& invalid_command)
: command{ invalid_command }, : command{ invalid_command },
std::runtime_error("Unknown command given on the command line.") std::runtime_error("Unknown command given on the command line.")
{ {
} }
}; };
export class command_line_error : public std::runtime_error
{
boost::program_options::options_description description;
public:
command_line_error(const std::string& message,
boost::program_options::options_description&& description)
: description(std::move(description)),
std::runtime_error(message)
{
}
};
export command_line parse_command_line(int argc, const char **argv) export command_line parse_command_line(int argc, const char **argv)
{ {
if (argc == 1) if (argc == 1)
@@ -70,4 +102,42 @@ namespace katja
} }
throw invalid_command_error(argv[1]); throw invalid_command_error(argv[1]);
} }
search_command parse_search_command(const std::vector<std::string>& arguments)
{
boost::program_options::options_description search_description("Search packages");
search_description
.add_options()("name", "Find packages by name");
boost::program_options::positional_options_description positional_arguments;
positional_arguments.add("name", 1);
boost::program_options::variables_map option_map;
auto command_parser = boost::program_options::command_line_parser(arguments)
.options(search_description).positional(positional_arguments);
boost::program_options::store(command_parser.run(), option_map);
boost::program_options::notify(option_map);
if (!option_map.count("name"))
{
throw command_line_error("Search string wasn't specified.",
std::move(search_description));
}
return search_command{ option_map["name"].as<std::string>() };
}
export subcommand parse_subcommand(const command_line& subcommand_line)
{
switch (subcommand_line.type)
{
case command::updates:
return updates_command();
case command::search:
return parse_search_command(subcommand_line.arguments);
case command::help:
return help_command();
default:
std::unreachable();
}
}
} }

View File

@@ -26,7 +26,13 @@ export namespace katja
class configuration class configuration
{ {
public: public:
using repositories_t = std::forward_list<std::pair<std::string, repository_configuration>>; using value_type = std::pair<std::string, repository_configuration>;
using reference_type = value_type&;
using const_reference_type = const value_type&;
using repositories_t = std::forward_list<value_type>;
using size_type = repositories_t::size_type;
using difference_type = repositories_t::difference_type;
private: private:
repositories_t repositories; repositories_t repositories;
@@ -47,6 +53,16 @@ export namespace katja
return this->repositories.end(); return this->repositories.end();
} }
repositories_t::const_iterator begin() const
{
return this->repositories.begin();
}
repositories_t::const_iterator end() const
{
return this->repositories.end();
}
repositories_t::const_iterator cbegin() repositories_t::const_iterator cbegin()
{ {
return this->repositories.cbegin(); return this->repositories.cbegin();

View File

@@ -6,6 +6,7 @@
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <iostream> #include <iostream>
#include <variant>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@@ -36,14 +37,13 @@ static void search_names(std::shared_ptr<katja::repository> repository, const st
} }
} }
int main(int argc, const char **argv) static void handle_subcommand(const katja::configuration& configuration,
const katja::subcommand& command)
{ {
katja::configuration configuration = katja::read_configuration("katja.toml"); if (std::holds_alternative<katja::updates_command>(command))
{
katja::package_database installed_database = katja::read_installed_database(); katja::package_database installed_database = katja::read_installed_database();
katja::command_line command_line = katja::parse_command_line(argc, argv);
if (command_line.type == katja::command::updates)
{
for (const auto& [repository_name, repository_configuration] : configuration) for (const auto& [repository_name, repository_configuration] : configuration)
{ {
std::filesystem::path slackbuild_repository{ repository_configuration.path }; std::filesystem::path slackbuild_repository{ repository_configuration.path };
@@ -52,34 +52,25 @@ int main(int argc, const char **argv)
get_updates(repository, std::move(installed_database)); get_updates(repository, std::move(installed_database));
} }
} }
else if (command_line.type == katja::command::search) else if (std::holds_alternative<katja::search_command>(command))
{ {
boost::program_options::options_description search_description("Search packages");
search_description
.add_options()("name", "Find packages by name");
boost::program_options::positional_options_description positional_arguments;
positional_arguments.add("name", 1);
boost::program_options::variables_map option_map;
auto command_parser = boost::program_options::command_line_parser(command_line.arguments)
.options(search_description).positional(positional_arguments);
boost::program_options::store(command_parser.run(), option_map);
boost::program_options::notify(option_map);
if (!option_map.count("name"))
{
std::cerr << search_description;
return EXIT_FAILURE;
}
for (const auto& [repository_name, repository_configuration] : configuration) for (const auto& [repository_name, repository_configuration] : configuration)
{ {
std::filesystem::path slackbuild_repository{ repository_configuration.path }; std::filesystem::path slackbuild_repository{ repository_configuration.path };
auto repository = std::make_shared<katja::sbo_repository>(slackbuild_repository); auto repository = std::make_shared<katja::sbo_repository>(slackbuild_repository);
search_names(repository, option_map["name"].as<std::string>()); search_names(repository, std::get<katja::search_command>(command).needle);
} }
} }
}
int main(int argc, const char **argv)
{
katja::configuration configuration = katja::read_configuration("katja.toml");
katja::command_line command_line = katja::parse_command_line(argc, argv);
katja::subcommand subcommand = katja::parse_subcommand(command_line);
handle_subcommand(configuration, subcommand);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }