Skip to content

Commit

Permalink
feat: support rewrite some apps config files
Browse files Browse the repository at this point in the history
Rewrite *.desktop/*.service/*.conf.

Log:
  • Loading branch information
kamiyadm authored and ComixHe committed Dec 19, 2024
1 parent fb3eaeb commit 158a785
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 11 deletions.
205 changes: 194 additions & 11 deletions libs/linglong/src/linglong/repo/ostree_repo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "linglong/utils/finally/finally.h"

Check warning on line 21 in libs/linglong/src/linglong/repo/ostree_repo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/finally/finally.h" not found.
#include "linglong/utils/packageinfo_handler.h"

Check warning on line 22 in libs/linglong/src/linglong/repo/ostree_repo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/packageinfo_handler.h" not found.
#include "linglong/utils/transaction.h"

Check warning on line 23 in libs/linglong/src/linglong/repo/ostree_repo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/transaction.h" not found.
#include "linglong/utils/gkeyfile_wrapper.h"

Check warning on line 24 in libs/linglong/src/linglong/repo/ostree_repo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/gkeyfile_wrapper.h" not found.

#include <gio/gio.h>

Check warning on line 26 in libs/linglong/src/linglong/repo/ostree_repo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <gio/gio.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <glib.h>

Check warning on line 27 in libs/linglong/src/linglong/repo/ostree_repo.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <glib.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
Expand Down Expand Up @@ -1606,17 +1607,10 @@ utils::error::Result<void> OSTreeRepo::exportEntries(
qCritical() << "Invalid symlink: " << info.filePath();
continue;
}
// In KDE environment, every desktop should own the executable permission
// We just set the file permission to 0755 here.
if (info.suffix() == "desktop") {
if (!QFile::setPermissions(info.absoluteFilePath(),
QFileDevice::ReadOwner | QFileDevice::WriteOwner
| QFileDevice::ExeOwner | QFileDevice::ReadGroup
| QFileDevice::ExeGroup | QFileDevice::ReadOther
| QFileDevice::ExeOther)) {
qCritical() << "Failed to chmod" << info.absoluteFilePath();
Q_ASSERT(false);
}

auto ret = IniLikeFileRewrite(info, QString::fromStdString(item.info.id));
if (!ret) {
qCritical() << ret.error().message();
}

const auto parentDirForLinkPath =
Expand Down Expand Up @@ -2198,6 +2192,195 @@ OSTreeRepo::listLocalBy(const linglong::repo::repoCacheQuery &query) const noexc
return this->cache->queryLayerItem(query);
}

utils::error::Result<void> desktopFileRewrite(const QString &filePath, const QString &id)
{
LINGLONG_TRACE("rewrite desktop file " + filePath);

auto file = utils::GKeyFileWrapper::New(filePath);
if (!file) {
return LINGLONG_ERR(file);
}

const auto groups = file->getGroups();
// set Exec
for (const auto &group : groups) {
auto hasExecRet = file->hasKey("Exec", group);
if (!hasExecRet) {
return LINGLONG_ERR(hasExecRet);
}
const auto &hasExec = *hasExecRet;
if (!hasExec) {
qWarning() << "No Exec Section in" << group << ", set a default value";
auto defaultExec = QString("%1 run %2").arg(LINGLONG_CLIENT_PATH, id);
return LINGLONG_OK;
}

auto originExec = file->getValue<QString>("Exec", group);
if (!originExec) {
return LINGLONG_ERR(originExec);
}

auto newExec = QString("%1 run %2 -- %3").arg(LINGLONG_CLIENT_PATH, id, *originExec);
file->setValue("Exec", newExec, group);
}

file->setValue<QString>("TryExec", LINGLONG_CLIENT_PATH, utils::GKeyFileWrapper::DesktopEntry);
file->setValue<QString>("X-linglong", id, utils::GKeyFileWrapper::DesktopEntry);

// save file
auto ret = file->saveToFile(filePath);
if(!ret) {
return LINGLONG_ERR(ret);
}

return LINGLONG_OK;
}

utils::error::Result<void> dbusServiceRewrite(const QString &filePath, const QString &id)
{
LINGLONG_TRACE("rewrite dbus service file " + filePath);

auto file = utils::GKeyFileWrapper::New(filePath);
if (!file) {
return LINGLONG_ERR(file);
}

auto hasExecRet = file->hasKey("Exec", utils::GKeyFileWrapper::DBusService);
if (!hasExecRet) {
return LINGLONG_ERR(hasExecRet);
}
const auto &hasExec = *hasExecRet;
if (!hasExec) {
qWarning() << "DBus service" << filePath << "has no Exec Section.";
return LINGLONG_OK;
}

auto originExec = file->getValue<QString>("Exec", utils::GKeyFileWrapper::DBusService);
if (!originExec) {
return LINGLONG_ERR(originExec);
}

auto newExec = QString("%1 run %2 -- %3").arg(LINGLONG_CLIENT_PATH, id, *originExec);
file->setValue<QString>("Exec", newExec, utils::GKeyFileWrapper::DBusService);

auto ret = file->saveToFile(filePath);
if (!ret) {
return LINGLONG_ERR(ret);
}

return LINGLONG_OK;
}

utils::error::Result<void> systemdServiceRewrite(const QString &filePath, const QString &id)
{
LINGLONG_TRACE("rewrite systemd user service " + filePath);

// Related doc: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
// NOTE: The key is allowed to be repeated in the service group
QStringList execKeys{ "ExecStart", "ExecStartPost", "ExecCondition",
"ExecStop", "ExecStopPost", "ExecReload" };
auto file = utils::GKeyFileWrapper::New(filePath);
if (!file) {
return LINGLONG_ERR(file);
}

auto keys = file->getkeys(utils::GKeyFileWrapper::SystemdService);
if(!keys) {
return LINGLONG_ERR(keys);
}
for(const auto &key : *keys) {
if(!execKeys.contains(key)) {
continue;
}

auto originExec = file->getValue<QString>(key, utils::GKeyFileWrapper::SystemdService);
if (!originExec) {
return LINGLONG_ERR(originExec);
}

auto newExec = QString("%1 run %2 -- %3").arg(LINGLONG_CLIENT_PATH, id, *originExec);
file->setValue<QString>(key, newExec, utils::GKeyFileWrapper::SystemdService);
}

auto ret = file->saveToFile(filePath);
if (!ret) {
return LINGLONG_ERR(ret);
}

return LINGLONG_OK;
}

utils::error::Result<void> contextMenuRewrite(const QString &filePath, const QString &id)
{
LINGLONG_TRACE("rewrite context menu" + filePath);

auto file = utils::GKeyFileWrapper::New(filePath);
if (!file) {
return LINGLONG_ERR(file);
}

auto groups = file->getGroups();
// set Exec
for (const auto &group : groups) {
auto hasExecRet = file->hasKey("Exec", group);
if (!hasExecRet) {
return LINGLONG_ERR(hasExecRet);
}
const auto &hasExec = *hasExecRet;
// first group has no Exec, just skip it
if (!hasExec) {
continue;
}

auto originExec = file->getValue<QString>("Exec", group);
if (!originExec) {
return LINGLONG_ERR(originExec);
}
auto newExec = QString("%1 run %2 -- %3").arg(LINGLONG_CLIENT_PATH, id, *originExec);
file->setValue<QString>("Exec", newExec, group);
}

auto ret = file->saveToFile(filePath);
if (!ret) {
return LINGLONG_ERR(ret);
}

return LINGLONG_OK;
}

utils::error::Result<void> OSTreeRepo::IniLikeFileRewrite(const QFileInfo &info,
const QString &id) noexcept
{
LINGLONG_TRACE("ini-like file rewrite");

if (info.path().contains("share/applications") && info.suffix() == "desktop") {
auto ret = desktopFileRewrite(info.absoluteFilePath(), id);
if (!ret) {
return LINGLONG_ERR(ret);
}
// In KDE environment, every desktop should own the executable permission
// We just set the file permission to 0755 here.
if (!QFile::setPermissions(info.absoluteFilePath(),
QFileDevice::ReadOwner | QFileDevice::WriteOwner
| QFileDevice::ExeOwner | QFileDevice::ReadGroup
| QFileDevice::ExeGroup | QFileDevice::ReadOther
| QFileDevice::ExeOther)) {
qCritical() << "Failed to chmod" << info.absoluteFilePath();
Q_ASSERT(false);
}

} else if (info.path().contains("share/dbus-1") && info.suffix() == "service") {
return dbusServiceRewrite(info.absoluteFilePath(), id);
} else if (info.path().contains("share/systemd/user") && info.suffix() == "service") {
return systemdServiceRewrite(info.absoluteFilePath(), id);
} else if (info.path().contains("share/applications/context-menus")
&& info.suffix() == "conf") {
return contextMenuRewrite(info.absoluteFilePath(), id);
}

return LINGLONG_OK;
}

OSTreeRepo::~OSTreeRepo() = default;

} // namespace linglong::repo
2 changes: 2 additions & 0 deletions libs/linglong/src/linglong/repo/ostree_repo.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ class OSTreeRepo : public QObject
bool fallbackLayerDir = true) const noexcept;
utils::error::Result<void> exportEntries(
const QDir &entriesDir, const api::types::v1::RepositoryCacheLayersItem &item) noexcept;
utils::error::Result<void> IniLikeFileRewrite(const QFileInfo &info,
const QString &id) noexcept;
};

} // namespace linglong::repo
2 changes: 2 additions & 0 deletions libs/utils/src/linglong/utils/configure.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#define LINGLONG_DEFAULT_OCI_RUNTIME "@LINGLONG_DEFAULT_OCI_RUNTIME@"
#define LINGLONG_UAB_DATA_LOCATION "@CMAKE_INSTALL_FULL_LIBDIR@/linglong/builder/uab"
#define LINGLONG_BUILDER_HELPER LINGLONG_LIBEXEC_DIR "/builder/helper"
#define LINGLONG_CLIENT_NAME "@LINGLONG_CLI_BIN@"
#define LINGLONG_CLIENT_PATH "@CMAKE_INSTALL_FULL_BINDIR@/@LINGLONG_CLI_BIN@"

// The package's locale domain.
#define PACKAGE_LOCALE_DOMAIN "@GETTEXT_DOMAIN_NAME@"
Expand Down

0 comments on commit 158a785

Please sign in to comment.