Skip to content

Commit

Permalink
feat: add new class GKeyFileWrapper
Browse files Browse the repository at this point in the history
Wrap GKeyFile from glib which used for parsing ini-like config file.

Log:
  • Loading branch information
kamiyadm authored and ComixHe committed Dec 19, 2024
1 parent bbd5df5 commit fb3eaeb
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 0 deletions.
2 changes: 2 additions & 0 deletions libs/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ pfl_add_library(
src/linglong/utils/xdg/desktop_entry.cpp
src/linglong/utils/xdg/desktop_entry.h
src/linglong/utils/xdg/directory.h
src/linglong/utils/gkeyfile_wrapper.cpp
src/linglong/utils/gkeyfile_wrapper.h
COMPILE_FEATURES
PUBLIC
cxx_std_17
Expand Down
16 changes: 16 additions & 0 deletions libs/utils/src/linglong/utils/gkeyfile_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

#include "linglong/utils/gkeyfile_wrapper.h"

namespace linglong::utils {

const GKeyFileWrapper::GroupName GKeyFileWrapper::DesktopEntry = "Desktop Entry";
const GKeyFileWrapper::GroupName GKeyFileWrapper::DBusService = "D-BUS Service";
const GKeyFileWrapper::GroupName GKeyFileWrapper::SystemdService = "Service";
const GKeyFileWrapper::GroupName GKeyFileWrapper::ContextMenu = "Menu Entry";

} // namespace linglong::utils
179 changes: 179 additions & 0 deletions libs/utils/src/linglong/utils/gkeyfile_wrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd.
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/

#pragma once

#include "linglong/utils/error/error.h"

#include <glib.h>
#include <tl/expected.hpp>

#include <QFile>
#include <QString>


namespace linglong::utils {

class GKeyFileWrapper final
{
// constructors
public:
GKeyFileWrapper(GKeyFileWrapper &&) = default;
GKeyFileWrapper(const GKeyFileWrapper &) = delete;
auto operator=(GKeyFileWrapper &&) -> GKeyFileWrapper & = default;
auto operator=(const GKeyFileWrapper &) -> GKeyFileWrapper & = delete;
~GKeyFileWrapper() = default;

static auto New(const QString &filePath) -> error::Result<GKeyFileWrapper>
{
LINGLONG_TRACE(QString("create GKeyFileWrapper for %1").arg(filePath));

auto desktopEntryFile = QFile(filePath);
if (!desktopEntryFile.exists()) {
return LINGLONG_ERR("no such file");
}

g_autoptr(GError) gErr = nullptr;
GKeyFileWrapper entry;
g_key_file_load_from_file(entry.gKeyFile.get(),
filePath.toLocal8Bit().constData(),
G_KEY_FILE_KEEP_TRANSLATIONS,
&gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_load_from_file", gErr);
}

return entry;
}

private:
GKeyFileWrapper()
: gKeyFile(std::unique_ptr<GKeyFile, decltype(&g_key_file_free)>(g_key_file_new(),
g_key_file_free)){};

// types
public:
using GroupName = QString;

public:
static const GroupName DesktopEntry;
static const GroupName DBusService;
static const GroupName SystemdService;
static const GroupName ContextMenu;

// data members
private:
std::unique_ptr<GKeyFile, decltype(&g_key_file_free)> gKeyFile;

// methods
public:
template<typename Value>
void setValue(const QString &key, const Value &value, const GroupName &group);

template<typename Value>
auto getValue(const QString &key, const GroupName &group) const -> error::Result<Value>;

auto getGroups() -> QStringList
{
gsize length = 0;
g_auto(GStrv) groups = g_key_file_get_groups(this->gKeyFile.get(), &length);

QStringList result;
for (gsize i = 0; i < length; i++) {
auto group = groups[i]; // NOLINT
result << group;
}

return result;
}

auto getkeys(const QString &group) -> error::Result<QStringList>
{
LINGLONG_TRACE("get keys from " + group);

g_autoptr(GError) gErr = nullptr;
gsize length;
g_auto(GStrv) keys = g_key_file_get_keys(this->gKeyFile.get(),
group.toLocal8Bit().constData(),
&length,
&gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_get_keys", gErr);
}

QStringList result;
for (gsize i = 0; i < length; i++) {
auto key = keys[i]; // NOLINT
result << key;
}

return result;
}

auto saveToFile(const QString &filepath) -> error::Result<void>
{
LINGLONG_TRACE(QString("save to %1").arg(filepath));

g_autoptr(GError) gErr = nullptr;

g_key_file_save_to_file(this->gKeyFile.get(), filepath.toLocal8Bit().constData(), &gErr);
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_save_to_file", gErr);
}

return LINGLONG_OK;
}

auto hasKey(const QString &key, const GroupName &group) -> error::Result<bool>
{
LINGLONG_TRACE(QString("check %1 is in %2 or not").arg(key).arg(group));

g_autoptr(GError) gErr = nullptr;
if (!g_key_file_has_key(this->gKeyFile.get(),
group.toLocal8Bit().constData(),
key.toLocal8Bit().constData(),
&gErr)) {
if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_has_key", gErr);
}
return false;
}
return true;
}
};

template<>
inline void GKeyFileWrapper::setValue(const QString &key,
const QString &value,
const GroupName &group)
{
g_key_file_set_string(this->gKeyFile.get(),
group.toLocal8Bit().constData(),
key.toLocal8Bit().constData(),
value.toLocal8Bit().constData());
}

template<>
[[nodiscard]] inline auto GKeyFileWrapper::getValue(
const QString &key, const GroupName &group) const -> error::Result<QString>
{
LINGLONG_TRACE(QString("get %1 from %2").arg(key, group));

g_autoptr(GError) gErr = nullptr;

g_autofree gchar *value = g_key_file_get_string(this->gKeyFile.get(),
group.toLocal8Bit().constData(),
key.toLocal8Bit().constData(),
&gErr);

if (gErr != nullptr) {
return LINGLONG_ERR("g_key_file_get_string", gErr);
}

return value;
}

} // namespace linglong::utils

0 comments on commit fb3eaeb

Please sign in to comment.