-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Repository class refactoring #95
base: master
Are you sure you want to change the base?
Conversation
src/services/repo.cpp
Outdated
return file; | ||
} catch (Glib::FileError& e) { | ||
throw repository_exception( | ||
std::format("Could not load repository file {} ({})", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt::format
.
src/services/repo.cpp
Outdated
|
||
void ELRepoFile::read() | ||
{ | ||
printf("reading\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No...
src/services/repo.cpp
Outdated
for (const auto& r : m_repositories) { | ||
std::print("repo found '{}'\n", r.group); | ||
std::print("\tname: '{}'\n", r.name); | ||
std::print("\tbaseurl: '{}'\n", r.baseURL.value_or("null")); | ||
std::print("\tmetalink: '{}'\n", r.metalink.value_or("null")); | ||
std::print("\tenabled: {}\n", r.enabled); | ||
std::print("\tgpg: (check: {}, key: {})\n", r.gpgcheck, r.gpgkey); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this debug? If yes add #ifndef NDEBUG
. Also we are using fmt::format
instead and use the LOG_DEBUG
directive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was glibmm test code I forgot to remove.
src/services/repo.cpp
Outdated
m_repositories.push_back(std::move(repo)); | ||
} | ||
|
||
for (const auto& r : m_repositories) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would avoid using only r
as variable name. Usually we use it for well defined counters, like: i
, j
and k
. Or for iterators, like it
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is only code for toying with glibmm
In real life, this would not be like this
(This comment applies to every printf/fmt::format comment above)
include/cloysterhpc/services/repo.h
Outdated
/** | ||
* Repository file class | ||
*/ | ||
template <class Repo> class RepoFile { | ||
protected: | ||
std::filesystem::path m_path; | ||
std::vector<Repo> m_repositories; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are mixing up "repository" and File
class
- Remove the
Repo
type parameter - Rename
RepoFile
toFile
- Remove
m_repositories
member
This class only wraps file I/O, it must not know anything about repositories
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like this?
class File {
protected:
std::filesystem::path m_path;
public:
RepoFile(const std::filesystem::path& path)
: m_path(path)
{}
virtual void read() {}
virtual void write() {}
};
(Me including the repositories list there was a mistake... I already removed it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partially, there will be an entity named something like "File" on the namespace "cloysterhpc" that will handle basic file operations. Open, close, write, read, chmod. There's a lot of that on glib and we may use them:
https://gnome.pages.gitlab.gnome.org/glibmm/classGio_1_1File.html
https://gnome.pages.gitlab.gnome.org/glibmm/group__FileUtils.html
https://gnome.pages.gitlab.gnome.org/glibmm/group__UriUtils.html
I do believe that GIO
will solve almost everything.
include/cloysterhpc/services/repo.h
Outdated
class ELRepoFile : public RepoFile<ELRepo> { | ||
private: | ||
Glib::RefPtr<Glib::KeyFile> loadFile(); | ||
|
||
public: | ||
ELRepoFile(const std::filesystem::path& path) | ||
: RepoFile(path) | ||
{ | ||
} | ||
|
||
void read() override; | ||
void write() override; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can have an abstract RepoFile
which extends the File
, adds the m_repositories
generic member, and with parse
unparse
methods, read
is super read
followed by parse
and write
is unparse
followed by super write
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::filesystem::path
is convertible to std::string
or const char*
. We must use it. It's the right API.
However the file
class that be dependent on std::filesystem::path
and not the derived one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to be clear
parse
loads data from the file into them_repositories
memberunparse
loads them_repositories
member into the file
Also, @arthurmco, add overloads to parse
and unparse
which I/O into istringstream
ostringstream
instead of directly into the file so we can test without touching the disks. I don't know if this is possible because I don't know the interface of glibmm
if it can load/unload keyfiles from strings, can it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is possible; glibmm can load keyhole data from a string.
class repository_exception : public std::runtime_error { | ||
public: | ||
explicit repository_exception(const std::string& msg) | ||
: std::runtime_error(msg) | ||
{ | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@viniciusferrao opinions on this? if we'll not be handling exceptions is there any point in creating our own exceptions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is just a WIP. But not sure. But it is a good practice to specialize the throw: https://isocpp.org/wiki/faq/exceptions#what-to-throw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a WIP
src/services/repo.cpp
Outdated
auto metalink = (file->has_key(repogroup, "metalink")) | ||
? std::make_optional(file->get_string(repogroup, "metalink")) | ||
: std::nullopt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optionals are really cool. Add a free function for reading an optional from keyfiles
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm an idiot. I have too much difficulty reading ternary operators. That's a technical debt in my mind.
The std::nullopt
should be inside a std::make_optional
? I don't know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is okay, you can read this like this if (file->has_key(repogroup, "metalink")) { metalink = std::make_optional(file->get_string(repogroup, "metalink")) } else { metalink = std::nullopt; }
. metalink
is an optional set to the metalink
property if it exists in the file, or set to nullopt
if not. This is pretty general, we'll want to use std::optional
to represent optional values in the conf file, so I'm suggesting that we create a function for that
inline std::optional<std::string> get_optional_string(
const KeyFile& fil,
const std::string& group,
const std::string& key)
{
if (fil->has_key(group, key)) {
return fil->get_string(group, key);
}
return std::nullopt;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The optional is got with the .value()
accessor, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but glib keyfile is not using optional here, I guess the interface is older than std::optional
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but glib keyfile is not using optional here, I guess the interface is older than std::optional
Yes it is. But we are talking about the same issue? That our API shuould provide access with std::optional
and inside the class we encapsulate that? If that's the case yes I do agree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying for us to extend glibmm file interface and add this as a member function?
src/services/repo.cpp
Outdated
std::vector<ELRepo> ELRepoFile::parse(const std::stringstream& ss) | ||
{ | ||
m_file = Glib::KeyFile::create(); | ||
m_file->load_from_data(ss.str().c_str()); | ||
return this->parseData(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, now
- Add
m_repositories
member as a vector of ELRepo with a getter - The getter should load the data into the member if the member is empty and return at the end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside of ELRepo?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inside ELRepoFile
include/cloysterhpc/services/repo.h
Outdated
struct ELRepo { | ||
std::string group; | ||
std::string name; | ||
std::optional<std::string> baseURL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
base_url
include/cloysterhpc/services/repo.h
Outdated
void unparse( const std::vector<ELRepo>& repositories ); | ||
void unparse( const std::vector<ELRepo>& repositories, std::stringstream& ss ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void unparse( const std::vector<ELRepo>& repositories ); | |
void unparse( const std::vector<ELRepo>& repositories, std::stringstream& ss ); | |
void unparse(const std::vector<ELRepo>& repositories); | |
void unparse(const std::vector<ELRepo>& repositories, std::stringstream& ss); |
src/services/repo.cpp
Outdated
auto get_optional_string | ||
= [this](auto group, auto key) -> std::optional<Glib::ustring> { | ||
return m_file->has_key(group, key) | ||
? std::make_optional(m_file->get_string(group, key)) | ||
: std::nullopt; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why this captures this
, anyway, move it to functions.cpp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API looks good, there are a few points
- Make sure to remove the prints
- Rename the ELReo to ELCloneRepo
- Remove the PR from draft
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another issue that I've observed. The virtual classes should be on its own files. This needs to be fixed.
src/services/repo.cpp
Outdated
|
||
std::vector<ELRepo> ELRepoFile::parse() | ||
{ | ||
this->read(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need "this"?
src/services/repo.cpp
Outdated
|
||
if (name.empty()) { | ||
throw repository_exception(std::format( | ||
"Could not load repo name from repo '{}' at file {}", | ||
"Could not load repo name from repo '{}' at m_file {}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more than a DEBUG message for the developer than to the user. For the user it should be something more friendly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you suggest?
include/cloysterhpc/functions.h
Outdated
@@ -164,6 +166,9 @@ std::string findAndReplace(const std::string_view& source, | |||
*/ | |||
void copyFile(std::filesystem::path source, std::filesystem::path destination); | |||
|
|||
std::optional<Glib::ustring> readKeyfileString(Glib::RefPtr<Glib::KeyFile> file, | |||
const std::string_view& group, const std::string_view& key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std:string_view
is already a pointer to a string. It should not be passed as const ref.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't know that. I thought it was pointer+length. It will be fixed
include/cloysterhpc/services/repo.h
Outdated
/** | ||
* Repository file class | ||
* | ||
* This class should parse the repository data | ||
*/ | ||
class ELRepoFile : GenericFile { | ||
private: | ||
private: | ||
Glib::RefPtr<Glib::KeyFile> m_file; | ||
|
||
std::vector<ELRepo> parseData(); | ||
void unparseData(const std::vector<ELRepo>&); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing the variable name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable name is not needed in the declaration and the context is obvious, but I will fixed because of conventions
src/functions.cpp
Outdated
@@ -351,4 +351,12 @@ void copyFile(std::filesystem::path source, std::filesystem::path destination) | |||
} | |||
} | |||
|
|||
std::optional<Glib::ustring> readKeyfileString(Glib::RefPtr<Glib::KeyFile> file, | |||
const std::string_view& group, const std::string_view& key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to be const ref.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See this comment
Quality Gate passedIssues Measures |
Refactor the repository class based on @dhilst 's modeling