summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2023-04-01 14:16:44 +0200
committerEugen Wissner <belka@caraus.de>2023-04-01 14:17:08 +0200
commitf46a16b4a0d50b6512df2b312f7f800a9a963ca2 (patch)
tree8b385dc31c90065ba8e5a970dec9c931d68b7f43 /src
parent0385dbbe53cbeb89b541fa6ae659540a261bc69b (diff)
downloadslackbuilder-f46a16b4a0d50b6512df2b312f7f800a9a963ca2.tar.gz
Add an utility to list all installed packages
Diffstat (limited to 'src')
-rw-r--r--src/command.cpp74
-rw-r--r--src/command.h48
-rw-r--r--src/main.cpp22
-rw-r--r--src/package.cpp76
-rw-r--r--src/package.h27
5 files changed, 247 insertions, 0 deletions
diff --git a/src/command.cpp b/src/command.cpp
new file mode 100644
index 0000000..4066c23
--- /dev/null
+++ b/src/command.cpp
@@ -0,0 +1,74 @@
+#include "command.h"
+#include <cassert>
+
+namespace katja
+{
+ void list::execute() const
+ {
+ for (const auto& package : katja::read_package_database())
+ {
+ std::cout << package.second.name()
+ << " " << package.second.version()
+ << " (" << package.second.tag() << ")"
+ << std::endl;
+ }
+ }
+
+ void help::execute() const
+ {
+ std::cout << "Usage:\n"
+ "\tkatja {info|help} [OPTIONS]\n\n";
+ }
+
+ command_exception::command_exception(const command_exception_t exception_type,
+ std::vector<std::string> failed_arguments) noexcept
+ : m_exception_type(exception_type), m_failed_arguments(failed_arguments)
+ {
+ }
+
+ const char *command_exception::what() const noexcept
+ {
+ switch (m_exception_type)
+ {
+ case command_exception_t::no_command:
+ return "No command specified.";
+ case command_exception_t::too_many_arguments:
+ return "Too many arguments given.";
+ case command_exception_t::unknown_command:
+ return "Unknown command.";
+ }
+ assert(false);
+ }
+
+ const std::vector<std::string>& command_exception::failed_arguments() const noexcept
+ {
+ return m_failed_arguments;
+ }
+
+ std::unique_ptr<command> parse_command_line(int argc, char **argv)
+ {
+ if (argc > 2)
+ {
+ std::vector<std::string> failed_arguments;
+
+ for (std::size_t i = 2; i < argc; ++i)
+ {
+ failed_arguments.push_back(argv[i]);
+ }
+ throw command_exception(command_exception_t::unknown_command);
+ }
+ else if (argc < 2)
+ {
+ throw command_exception(command_exception_t::no_command);
+ }
+ if (strcmp(argv[1], "list") == 0)
+ {
+ return std::make_unique<list>();
+ }
+ else if (strcmp(argv[1], "help") == 0)
+ {
+ return std::make_unique<help>();
+ }
+ throw command_exception(command_exception_t::unknown_command, { argv[1] });
+ }
+}
diff --git a/src/command.h b/src/command.h
new file mode 100644
index 0000000..8d0679d
--- /dev/null
+++ b/src/command.h
@@ -0,0 +1,48 @@
+#include <iostream>
+#include <cstring>
+#include <memory>
+#include <vector>
+#include "package.h"
+
+namespace katja
+{
+ class command
+ {
+ public:
+ virtual void execute() const = 0;
+ };
+
+ class list final : public command
+ {
+ public:
+ void execute() const override;
+ };
+
+ class help final : public command
+ {
+ public:
+ void execute() const override;
+ };
+
+ enum class command_exception_t
+ {
+ no_command,
+ too_many_arguments,
+ unknown_command,
+ };
+
+ class command_exception final : public std::exception
+ {
+ command_exception_t m_exception_type;
+ std::vector<std::string> m_failed_arguments;
+
+ public:
+ explicit command_exception(const command_exception_t exception_type,
+ std::vector<std::string> failed_arguments = {}) noexcept;
+
+ const char *what() const noexcept override;
+ const std::vector<std::string>& failed_arguments() const noexcept;
+ };
+
+ std::unique_ptr<command> parse_command_line(int argc, char **argv);
+}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..ef8dfcd
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,22 @@
+#include "command.h"
+
+int main(int argc, char **argv)
+{
+ std::unique_ptr<katja::command> command;
+
+ try
+ {
+ command = katja::parse_command_line(argc, argv);
+ }
+ catch (katja::command_exception& e)
+ {
+ std::cout << e.what() << std::endl << std::endl;
+
+ katja::help().execute();
+
+ return EXIT_FAILURE;
+ }
+ command->execute();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/package.cpp b/src/package.cpp
new file mode 100644
index 0000000..0734a5e
--- /dev/null
+++ b/src/package.cpp
@@ -0,0 +1,76 @@
+#include "package.h"
+#include <filesystem>
+
+namespace katja
+{
+ package::package(const std::string& name, const std::string& version,
+ const std::string& architecture, const std::string& tag)
+ : m_name(name), m_version(version), m_architecture(architecture), m_tag(tag)
+ {
+ }
+
+ const std::string& package::name() const noexcept
+ {
+ return m_name;
+ }
+
+ const std::string& package::version() const noexcept
+ {
+ return m_version;
+ }
+
+ const std::string& package::architecture() const noexcept
+ {
+ return m_architecture;
+ }
+
+ const std::string& package::tag() const noexcept
+ {
+ return m_tag;
+ }
+
+ std::optional<package> package::parse(const std::string& full_name) noexcept
+ {
+ std::size_t tag_separator = full_name.find_last_of('-');
+
+ if (tag_separator == std::string::npos || tag_separator == 0)
+ {
+ return std::nullopt;
+ }
+ std::size_t architecture_separator = full_name.find_last_of('-', tag_separator - 1);
+
+ if (architecture_separator == std::string::npos || architecture_separator == 0)
+ {
+ return std::nullopt;
+ }
+ std::size_t version_separator = full_name.find_last_of('-', architecture_separator - 1);
+
+ if (version_separator == std::string::npos || version_separator == 0)
+ {
+ return std::nullopt;
+ }
+ package parsed_package{
+ full_name.substr(0, version_separator),
+ full_name.substr(version_separator + 1, architecture_separator - version_separator - 1),
+ full_name.substr(architecture_separator + 1, tag_separator - architecture_separator - 1),
+ full_name.substr(tag_separator + 1)
+ };
+ return std::make_optional(parsed_package);
+ }
+
+ std::unordered_map<std::string, package> read_package_database()
+ {
+ std::unordered_map<std::string, package> packages;
+
+ for (const auto& entry : std::filesystem::directory_iterator("/var/lib/pkgtools/packages"))
+ {
+ std::optional<package> maybe_package = package::parse(entry.path().filename());
+
+ if (maybe_package.has_value())
+ {
+ packages.insert_or_assign(maybe_package.value().name(), maybe_package.value());
+ }
+ }
+ return packages;
+ }
+}
diff --git a/src/package.h b/src/package.h
new file mode 100644
index 0000000..5ffd060
--- /dev/null
+++ b/src/package.h
@@ -0,0 +1,27 @@
+#include <string>
+#include <optional>
+#include <unordered_map>
+
+namespace katja
+{
+ class package
+ {
+ std::string m_name;
+ std::string m_version;
+ std::string m_architecture;
+ std::string m_tag;
+
+ public:
+ explicit package(const std::string& name, const std::string& version,
+ const std::string& architecture, const std::string& tag);
+
+ const std::string& name() const noexcept;
+ const std::string& version() const noexcept;
+ const std::string& architecture() const noexcept;
+ const std::string& tag() const noexcept;
+
+ static std::optional<package> parse(const std::string& full_name) noexcept;
+ };
+
+ std::unordered_map<std::string, package> read_package_database();
+}