diff --git a/include/cloysterhpc/file.h b/include/cloysterhpc/file.h new file mode 100644 index 00000000..5109a008 --- /dev/null +++ b/include/cloysterhpc/file.h @@ -0,0 +1,32 @@ +/* + * Copyright 2025 Arthur Mendes + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CLOYSTERHPC_FILE_H_ +#define CLOYSTERHPC_FILE_H_ + +#include + +/** + * Generic file class + * + * This class should only read and write, + */ +class GenericFile { +protected: + std::filesystem::path m_path; + +public: + explicit GenericFile(const std::filesystem::path& path) + : m_path(path) + { + } + + virtual void read() { } + virtual void write() { } + + virtual ~GenericFile() = default; +}; + +#endif diff --git a/include/cloysterhpc/functions.h b/include/cloysterhpc/functions.h index 0f20cd33..4f8b209b 100644 --- a/include/cloysterhpc/functions.h +++ b/include/cloysterhpc/functions.h @@ -4,12 +4,14 @@ #include #include #include +#include #include #include #include #include #include +#include namespace cloyster { // Globals @@ -164,6 +166,9 @@ std::string findAndReplace(const std::string_view& source, */ void copyFile(std::filesystem::path source, std::filesystem::path destination); +std::optional readKeyfileString(Glib::RefPtr file, + const std::string_view group, const std::string_view key); + } /* namespace cloyster */ #endif // CLOYSTERHPC_FUNCTIONS_H_ diff --git a/include/cloysterhpc/services/repo.h b/include/cloysterhpc/services/repo.h index 84a8d699..18268a99 100644 --- a/include/cloysterhpc/services/repo.h +++ b/include/cloysterhpc/services/repo.h @@ -12,6 +12,9 @@ #include #include +#include +#include + /** * @brief This class represents an EL .repo file as it's found in * /etc/yum.repos.d/ @@ -47,4 +50,12 @@ class repo { static void load_repository(std::filesystem::path path); }; +class repository_exception : public std::runtime_error { +public: + explicit repository_exception(const std::string& msg) + : std::runtime_error(msg) + { + } +}; + #endif // CLOYSTERHPC_REPO_H_ diff --git a/include/cloysterhpc/services/repofile.h b/include/cloysterhpc/services/repofile.h new file mode 100644 index 00000000..238d85d0 --- /dev/null +++ b/include/cloysterhpc/services/repofile.h @@ -0,0 +1,64 @@ +/* + * Copyright 2025 Arthur Mendes + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef CLOYSTERHPC_REPOFILE_H_ +#define CLOYSTERHPC_REPOFILE_H_ + +#include + +#include +#include + +#include +#include + +struct ELCloneRepo { + std::string group; + std::string name; + std::optional base_url; + std::optional metalink; + bool enabled; + bool gpgcheck; + std::string gpgkey; + + // (P/ todos os repositórios) + // std::string release; +}; + +/** + * Repository file class + * + * This class should parse the repository data + */ +class ELRepoFile : GenericFile { +private: + Glib::RefPtr m_file; + + std::vector parseData(); + void unparseData(const std::vector& data); + + std::vector m_repositories; + +public: + explicit ELRepoFile(const std::filesystem::path& path) + : GenericFile(path) + { + } + + virtual void read() override; + virtual void write() override; + + void parse(); + void parse(const std::stringstream& ss); + void unparse(); + void unparse(std::stringstream& ss); + + [[nodiscard]] std::vector& getRepositories(); + [[nodiscard]] const std::vector& getRepositoriesConst() const; + + ~ELRepoFile() override = default; +}; + +#endif diff --git a/src/functions.cpp b/src/functions.cpp index 178091f7..c70c5024 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -351,4 +351,12 @@ void copyFile(std::filesystem::path source, std::filesystem::path destination) } } +std::optional readKeyfileString(Glib::RefPtr file, + const std::string_view group, const std::string_view key) +{ + return file->has_key(group.data(), key.data()) + ? std::make_optional(file->get_string(group.data(), key.data())) + : std::nullopt; +} + } // namespace cloyster diff --git a/src/services/repo.cpp b/src/services/repo.cpp index b79a000d..9e5889c7 100644 --- a/src/services/repo.cpp +++ b/src/services/repo.cpp @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include diff --git a/src/services/repofile.cpp b/src/services/repofile.cpp new file mode 100644 index 00000000..a208511c --- /dev/null +++ b/src/services/repofile.cpp @@ -0,0 +1,104 @@ +#include +#include + +void ELRepoFile::read() +{ + try { + m_file = Glib::KeyFile::create(); + m_file->load_from_file(m_path.string()); + } catch (Glib::FileError& e) { + throw repository_exception( + std::format("Could not load repository file {} ({})", + m_path.string(), e.what())); + } +} + +void ELRepoFile::write() { m_file->save_to_file(m_path.string()); } + +void ELRepoFile::parse() +{ + read(); + + m_repositories = parseData(); +} + +void ELRepoFile::parse(const std::stringstream& ss) +{ + m_file = Glib::KeyFile::create(); + m_file->load_from_data(ss.str().c_str()); + m_repositories = parseData(); +} + +std::vector ELRepoFile::parseData() +{ + auto reponames = m_file->get_groups(); + + std::vector repositories; + + for (const auto& repogroup : reponames) { + auto name = m_file->get_string(repogroup, "name"); + + if (name.empty()) { + throw repository_exception(std::format( + "Could not load repo name from repo '{}' at m_file {}", + repogroup.raw(), m_path.string())); + } + + auto metalink = cloyster::readKeyfileString( + m_file, std::string_view { repogroup.c_str() }, "metalink"); + auto baseurl = cloyster::readKeyfileString( + m_file, std::string_view { repogroup.c_str() }, "baseurl"); + + auto enabled = m_file->get_boolean(repogroup, "enabled"); + auto gpgcheck = m_file->get_boolean(repogroup, "gpgcheck"); + auto gpgkey = m_file->get_string(repogroup, "gpgkey"); + + ELCloneRepo repo; + repo.group = repogroup.raw(); + repo.name = name.raw(); + repo.metalink + = metalink.transform([](const auto& v) { return v.raw(); }); + repo.base_url + = baseurl.transform([](const auto& v) { return v.raw(); }); + repo.enabled = enabled; + repo.gpgcheck = gpgcheck; + repo.gpgkey = gpgkey; + repositories.push_back(std::move(repo)); + } + + return repositories; +} + +void ELRepoFile::unparseData(const std::vector& repositories) +{ + for (const auto& repo : repositories) { + m_file->set_string(repo.group, "name", repo.name); + m_file->set_boolean(repo.group, "enabled", repo.enabled); + m_file->set_boolean(repo.group, "gpgcheck", repo.gpgcheck); + m_file->set_string(repo.group, "gpgkey", repo.gpgkey); + } +} + +void ELRepoFile::unparse() +{ + unparseData(m_repositories); + write(); +} + +void ELRepoFile::unparse(std::stringstream& ss) +{ + unparseData(m_repositories); + ss.seekp(0); + ss << m_file->to_data(); +} + +[[nodiscard]] std::vector& ELRepoFile::getRepositories() +{ + return m_repositories; +} + +[[nodiscard]] const std::vector& +ELRepoFile::getRepositoriesConst() const +{ + return m_repositories; +}