1010#include < ranges>
1111#include < sstream>
1212#include < stdexcept>
13+ #include < unordered_map>
1314#include < utility>
1415
1516#include < boost/algorithm/string.hpp>
@@ -71,9 +72,9 @@ class RPMRepository final : public IRepository {
7172public:
7273 RPMRepository () = default ;
7374 ~RPMRepository () override = default ;
74- RPMRepository (const RPMRepository&) = delete ;
75+ RPMRepository (const RPMRepository&) = default ;
7576 RPMRepository (RPMRepository&&) = default ;
76- RPMRepository& operator =(const RPMRepository&) = delete ;
77+ RPMRepository& operator =(const RPMRepository&) = default ;
7778 RPMRepository& operator =(RPMRepository&&) = default ;
7879
7980 [[nodiscard]] std::string id () const override { return m_id; };
@@ -130,19 +131,88 @@ class RPMRepositoryParser final {
130131static_assert (IsParser<RPMRepositoryParser, std::filesystem::path,
131132 std::vector<RPMRepository>>);
132133
134+
133135class RPMRepositoryFile final {
136+ static constexpr auto m_parser = RPMRepositoryParser();
137+ std::filesystem::path m_path;
138+ std::unordered_map<std::string, RPMRepository> m_repos;
139+ public:
140+ RPMRepositoryFile (auto path, auto repos)
141+ : m_path(std::move(path))
142+ , m_repos(std::move(repos))
143+ {
144+ }
145+
146+ const auto & repos () const
147+ {
148+ return m_repos;
149+ }
150+
151+ auto & repo (const std::string& name) const
152+ {
153+ return repos ().at (name);
154+ }
155+
156+ auto reposList () const
157+ {
158+ return repos ()
159+ | std::views::transform ([](const auto & pair)
160+ { return pair.second ; })
161+ | std::ranges::to<std::vector>();
162+ }
163+
164+ void save () const
165+ {
166+ m_parser.unparse (reposList (), m_path);
167+ }
168+ };
169+
170+ class RPMRepoManager final {
171+ static constexpr auto m_parser = RPMRepositoryParser();
172+ static constexpr auto m_basedir = " /etc/yum.repos.d/" ;
173+ std::unordered_map<std::string, std::shared_ptr<RPMRepositoryFile>> m_filesIdx;
174+
175+ void addRepoFile (auto && repofile)
176+ {
177+ for (auto & [repo, _] : repofile.repos ()) {
178+ m_filesIdx.insert ({repo, std::make_shared<RPMRepositoryFile>(repofile)});
179+ }
180+ }
181+
182+ static auto vecToMap (std::vector<RPMRepository>&& repos)
183+ {
184+ std::unordered_map<std::string, RPMRepository> output;
185+ for (auto && repo : std::move (repos))
186+ {
187+ output.insert ({repo.id (), std::move (repo)});
188+ }
189+ return output;
190+ }
191+
134192public:
135- ~RPMRepositoryFile () = default ;
136- RPMRepositoryFile () = default ;
137- RPMRepositoryFile (const RPMRepositoryFile&) = delete ;
138- RPMRepositoryFile& operator =(const RPMRepositoryFile&) = delete ;
139- RPMRepositoryFile (RPMRepositoryFile&&) = delete ;
140- RPMRepositoryFile& operator =(RPMRepositoryFile&&) = delete ;
141- void save ();
142- void load ();
193+
194+ void install (const std::filesystem::path& source)
195+ {
196+ const auto & dest = m_basedir / source.filename ();
197+ if (m_filesIdx.contains (dest)) {
198+ LOG_WARN (" Repository already installed {}, skipping" , dest.string ());
199+ return ;
200+ }
201+ cloyster::copyFile (source, dest);
202+ std::vector<RPMRepository> repos;
203+ m_parser.parse (dest, repos);
204+ auto && reposMap = vecToMap (std::move (repos));
205+ auto && repofile = RPMRepositoryFile (dest, reposMap);
206+ addRepoFile (repofile);
207+ }
208+
209+ void enable (const auto & repo, bool value)
210+ {
211+ auto & repofile = m_filesIdx.at (repo);
212+ repofile.repo (repo).enable (value);
213+ repofile.save ();
214+ }
143215};
144- static_assert (cloyster::concepts::IsSaveable<RPMRepositoryFile>);
145- static_assert (cloyster::concepts::NotCopiableNotMoveable<RPMRepositoryFile>);
146216
147217}; // namespace cloyster::services::repos {
148218
@@ -164,7 +234,6 @@ constexpr std::string_view CLOYSTER_REPO_EL10 = {
164234#include " cloysterhpc/repos/el10/cloyster.repo"
165235};
166236
167- // @TODO Make this a RPMRepositoryFile method
168237void installFile (const std::filesystem::path& path, std::istream& data)
169238{
170239 if (cloyster::dryRun) {
@@ -181,7 +250,7 @@ void installFile(const std::filesystem::path& path, std::istream& data)
181250 fil << data.rdbuf ();
182251}
183252
184- constexpr auto getDefaultPath (const auto & osinfo)
253+ constexpr auto getCloysterRepoPath (const auto & osinfo)
185254{
186255 switch (osinfo.getPlatform ()) {
187256 case OS::Platform::el8:
@@ -276,7 +345,7 @@ namespace cloyster::services::repos {
276345
277346auto RepoManager::loadDefaults ()
278347{
279- const auto & path = getDefaultPath (m_os);
348+ const auto & path = getCloysterRepoPath (m_os);
280349 std::istringstream stream;
281350 switch (m_os.getPlatform ()) {
282351 case OS::Platform::el8:
@@ -517,7 +586,6 @@ void RepoManager::install(const std::vector<std::filesystem::path>& paths)
517586 }
518587}
519588
520- // / Private API
521589
522590std::vector<std::shared_ptr<const IRepository>> RepoManager::listRepos () const
523591{
0 commit comments