From 158a785bd6c4526ed54e279e9865c9ab7eeb59a1 Mon Sep 17 00:00:00 2001 From: kamiyadm Date: Tue, 17 Dec 2024 18:31:07 +0800 Subject: [PATCH] feat: support rewrite some apps config files Rewrite *.desktop/*.service/*.conf. Log: --- .../src/linglong/repo/ostree_repo.cpp | 205 +++++++++++++++++- libs/linglong/src/linglong/repo/ostree_repo.h | 2 + libs/utils/src/linglong/utils/configure.h.in | 2 + 3 files changed, 198 insertions(+), 11 deletions(-) diff --git a/libs/linglong/src/linglong/repo/ostree_repo.cpp b/libs/linglong/src/linglong/repo/ostree_repo.cpp index 59743a3bc..1ebdbb641 100644 --- a/libs/linglong/src/linglong/repo/ostree_repo.cpp +++ b/libs/linglong/src/linglong/repo/ostree_repo.cpp @@ -21,6 +21,7 @@ #include "linglong/utils/finally/finally.h" #include "linglong/utils/packageinfo_handler.h" #include "linglong/utils/transaction.h" +#include "linglong/utils/gkeyfile_wrapper.h" #include #include @@ -1606,17 +1607,10 @@ utils::error::Result 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 = @@ -2198,6 +2192,195 @@ OSTreeRepo::listLocalBy(const linglong::repo::repoCacheQuery &query) const noexc return this->cache->queryLayerItem(query); } +utils::error::Result 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("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("TryExec", LINGLONG_CLIENT_PATH, utils::GKeyFileWrapper::DesktopEntry); + file->setValue("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 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("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("Exec", newExec, utils::GKeyFileWrapper::DBusService); + + auto ret = file->saveToFile(filePath); + if (!ret) { + return LINGLONG_ERR(ret); + } + + return LINGLONG_OK; +} + +utils::error::Result 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(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(key, newExec, utils::GKeyFileWrapper::SystemdService); + } + + auto ret = file->saveToFile(filePath); + if (!ret) { + return LINGLONG_ERR(ret); + } + + return LINGLONG_OK; +} + +utils::error::Result 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("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); + } + + auto ret = file->saveToFile(filePath); + if (!ret) { + return LINGLONG_ERR(ret); + } + + return LINGLONG_OK; +} + +utils::error::Result 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 diff --git a/libs/linglong/src/linglong/repo/ostree_repo.h b/libs/linglong/src/linglong/repo/ostree_repo.h index e0ab0caf2..ce3cab55a 100644 --- a/libs/linglong/src/linglong/repo/ostree_repo.h +++ b/libs/linglong/src/linglong/repo/ostree_repo.h @@ -156,6 +156,8 @@ class OSTreeRepo : public QObject bool fallbackLayerDir = true) const noexcept; utils::error::Result exportEntries( const QDir &entriesDir, const api::types::v1::RepositoryCacheLayersItem &item) noexcept; + utils::error::Result IniLikeFileRewrite(const QFileInfo &info, + const QString &id) noexcept; }; } // namespace linglong::repo diff --git a/libs/utils/src/linglong/utils/configure.h.in b/libs/utils/src/linglong/utils/configure.h.in index ea8806970..50a7508b9 100644 --- a/libs/utils/src/linglong/utils/configure.h.in +++ b/libs/utils/src/linglong/utils/configure.h.in @@ -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@"