refact: ApplicationService ctor and some member functions

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe 2023-08-20 18:25:59 +08:00 committed by Comix
parent 0e7d84f61d
commit 920594d6e5
10 changed files with 229 additions and 204 deletions

View File

@ -6,6 +6,7 @@
#include <systemd/sd-bus.h>
#include <systemd/sd-journal.h>
#include <string_view>
#include <string>
#include <vector>
#include <deque>
#include <memory>
@ -73,6 +74,12 @@ ExitCode fromString(const char *str)
int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
{
int ret;
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
sd_journal_perror("open struct of ExecStart failed.");
return ret;
}
if (ret = sd_bus_message_append(msg, "s", "ExecStart"); ret < 0) {
sd_journal_perror("append ExecStart failed.");
return ret;
@ -138,6 +145,11 @@ int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
return ret;
}
if (ret = sd_bus_message_close_container(msg); ret < 0) {
sd_journal_perror("close struct of execStart failed.");
return ret;
}
return 0;
}
@ -146,18 +158,19 @@ int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_vie
int ret;
if (!props.empty()) {
for (auto [key, value] : props) {
// NOTE: append if necessary
// usage:
// sd_bus_message_append(msg,"s",key.data());
// sd_bus_message_open_container(msg,SD_BUS_TYPE_VARIANT,"[corresponding type]");
// append content....
// sd_bus_message_close_container(msg);
std::string keyStr{key};
std::string valueStr{value};
ret = sd_bus_message_append(msg, "(sv)", keyStr.data(), "s", valueStr.data());
if (ret < 0) {
return ret;
}
}
}
return 0;
}
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> cmdLines)
{
std::string serviceName{"internalError"};
std::map<std::string_view, std::string_view> props;
@ -176,7 +189,7 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
auto kvStr = str.substr(2);
if (!kvStr.empty()) [[likely]] {
auto it = kvStr.cbegin();
const auto *it = kvStr.cbegin();
if (it = std::find(it, kvStr.cend(), '='); it == kvStr.cend()) {
sd_journal_print(LOG_WARNING, "invalid k-v pair: %s", kvStr.data());
cmdLines.pop_front();
@ -248,11 +261,6 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
return serviceName;
}
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
sd_journal_perror("open struct failed.");
return serviceName;
}
if (ret = processKVPair(msg, props); ret < 0) { // process props
serviceName = "invalidInput";
return serviceName;
@ -263,10 +271,6 @@ std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
return serviceName;
}
if (ret = sd_bus_message_close_container(msg); ret < 0) {
sd_journal_perror("close struct failed.");
return serviceName;
}
if (ret = sd_bus_message_close_container(msg); ret < 0) {
sd_journal_perror("close array failed.");
return serviceName;

View File

@ -44,5 +44,5 @@ int main(int argc, char *argv[])
return false; // means to apply this function to the rest of the files
});
return app.exec();
return QCoreApplication::exec();
}

View File

@ -53,10 +53,9 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
return;
}
const auto &appRef = *appIt;
const auto &applicationPath = appRef->m_applicationPath.path();
const auto &applicationPath = (*appIt)->applicationPath().path();
if (!appRef->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) [[likely]] {
if (!(*appIt)->addOneInstance(instanceId, applicationPath, systemdUnitPath.path())) [[likely]] {
qCritical() << "add Instance failed:" << applicationPath << unitName << systemdUnitPath.path();
}
@ -83,16 +82,15 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
return;
}
const auto &appRef = *appIt;
const auto &appIns = (*appIt)->applicationInstances();
auto instanceIt = std::find_if(appRef->m_Instances.cbegin(),
appRef->m_Instances.cend(),
[&systemdUnitPath](const QSharedPointer<InstanceService> &value) {
auto instanceIt = std::find_if(
appIns.cbegin(), appIns.cend(), [&systemdUnitPath](const QSharedPointer<InstanceService> &value) {
return value->systemdUnitPath() == systemdUnitPath;
});
if (instanceIt != appRef->m_Instances.cend()) [[likely]] {
appRef->removeOneInstance(instanceIt.key());
if (instanceIt != appIns.cend()) [[likely]] {
(*appIt)->removeOneInstance(instanceIt.key());
}
});
}
@ -102,7 +100,41 @@ QList<QDBusObjectPath> ApplicationManager1Service::list() const
return m_applicationList.keys();
}
void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application)
bool ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) noexcept
{
QSharedPointer<ApplicationService> application =
ApplicationService::createApplicationService(std::move(desktopFileSource), this);
if (!application) {
return false;
}
if (m_applicationList.constFind(application->applicationPath()) != m_applicationList.cend()) {
auto info = qInfo();
info << "this application already exists.";
if (application->desktopFileSource().persistence()) {
info << "desktop source:" << application->desktopFileSource().fileSource();
}
return false;
}
auto *ptr = application.data();
if (auto *adaptor = new (std::nothrow) ApplicationAdaptor{ptr}; adaptor == nullptr) {
qCritical() << "new ApplicationAdaptor failed.";
return false;
}
if (!registerObjectToDBus(
ptr, application->applicationPath().path(), getDBusInterface(QMetaType::fromType<ApplicationAdaptor>()))) {
return false;
}
m_applicationList.insert(application->applicationPath(), application);
emit InterfacesAdded(application->applicationPath(), getInterfacesListFromObject(ptr));
return true;
}
void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &application) noexcept
{
if (auto it = m_applicationList.find(application); it != m_applicationList.cend()) {
emit InterfacesRemoved(application, getInterfacesListFromObject(it->data()));
@ -111,7 +143,7 @@ void ApplicationManager1Service::removeOneApplication(const QDBusObjectPath &app
}
}
void ApplicationManager1Service::removeAllApplication()
void ApplicationManager1Service::removeAllApplication() noexcept
{
for (const auto &app : m_applicationList.keys()) {
removeOneApplication(app);
@ -173,8 +205,12 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
void ApplicationManager1Service::updateApplication(const QSharedPointer<ApplicationService> &destApp,
const DesktopFile &desktopFile) noexcept
{
if (auto app = m_applicationList.find(destApp->applicationPath()); app == m_applicationList.cend()) {
return;
}
struct stat buf;
const auto *filePath = desktopFile.filePath().toLocal8Bit().data();
const auto *filePath = desktopFile.fileSource().toLocal8Bit().data();
if (auto ret = stat(filePath, &buf); ret == -1) {
qWarning() << "get file" << filePath << "state failed:" << std::strerror(errno);
return;
@ -182,14 +218,19 @@ void ApplicationManager1Service::updateApplication(const QSharedPointer<Applicat
constexpr std::size_t secToNano = 1e9;
if (destApp->m_desktopSource.m_file.modified(buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec)) {
auto newEntry = new DesktopEntry{};
auto err = newEntry->parse(destApp->m_desktopSource.m_file);
if (destApp->desktopFileSource().modified(buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec)) {
auto *newEntry = new (std::nothrow) DesktopEntry{};
if (newEntry == nullptr) {
qCritical() << "new DesktopEntry failed.";
return;
}
auto err = newEntry->parse(destApp->desktopFileSource());
if (err != DesktopErrorCode::NoError and err != DesktopErrorCode::EntryKeyInvalid) {
qWarning() << "update desktop file failed:" << err << ", content wouldn't change.";
return;
}
destApp->m_entry.reset(newEntry);
destApp->resetEntry(newEntry);
}
}

View File

@ -31,39 +31,11 @@ public:
Q_PROPERTY(QList<QDBusObjectPath> List READ list)
[[nodiscard]] QList<QDBusObjectPath> list() const;
template <typename T>
bool addApplication(T &&desktopFileSource)
{
QSharedPointer<ApplicationService> application = makeApplication(std::forward<T>(desktopFileSource), this);
if (!application) {
return false;
}
bool addApplication(DesktopFile desktopFileSource) noexcept;
void removeOneApplication(const QDBusObjectPath &application) noexcept;
void removeAllApplication() noexcept;
if (m_applicationList.constFind(application->m_applicationPath) != m_applicationList.cend()) {
auto info = qInfo();
info << "this application already exists.";
if (application->m_isPersistence) {
info << "desktop source:" << application->m_desktopSource.m_file.filePath();
}
return false;
}
auto *ptr = application.data();
new ApplicationAdaptor{ptr};
if (!registerObjectToDBus(
ptr, application->m_applicationPath.path(), getDBusInterface(QMetaType::fromType<ApplicationAdaptor>()))) {
return false;
}
m_applicationList.insert(application->m_applicationPath, application);
emit InterfacesAdded(application->m_applicationPath, getInterfacesListFromObject(ptr));
return true;
}
void removeOneApplication(const QDBusObjectPath &application);
void removeAllApplication();
void updateApplication(const QSharedPointer<ApplicationService> &deskApp, const DesktopFile &desktopFile) noexcept;
void updateApplication(const QSharedPointer<ApplicationService> &destApp, const DesktopFile &desktopFile) noexcept;
JobManager1Service &jobManager() noexcept { return *m_jobManager; }
@ -82,59 +54,4 @@ private:
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
};
template <typename T>
QSharedPointer<ApplicationService> makeApplication(T &&source,
ApplicationManager1Service *parent) // NOTE: maybe we should refactor
{
static_assert(std::is_same_v<T, DesktopFile> or std::is_same_v<T, QString>, "param type must be QString or DesktopFile.");
QString objectPath;
QTextStream sourceStream;
QFile sourceFile;
QSharedPointer<ApplicationService> app{nullptr};
if constexpr (std::is_same_v<T, DesktopFile>) {
DesktopFile in{std::forward<T>(source)};
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(in.desktopId());
sourceFile.setFileName(in.filePath());
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
qCritical() << "desktop file can't open:" << in.filePath() << sourceFile.errorString();
return nullptr;
}
app.reset(new ApplicationService{std::move(in)});
sourceStream.setDevice(&sourceFile);
} else if (std::is_same_v<T, QString>) {
QString in{std::forward<T>(source)};
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128);
app.reset(new ApplicationService{std::move(in)});
sourceStream.setString(&in, QTextStream::ReadOnly | QTextStream::Text);
}
std::unique_ptr<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
auto error = entry->parse(sourceStream);
if (error != DesktopErrorCode::NoError) {
if (error != DesktopErrorCode::EntryKeyInvalid) {
return nullptr;
}
}
if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) {
bool ok{false};
if (auto hidden = val.value().toBoolean(ok); ok and hidden) {
return nullptr;
}
}
app->m_parent = parent;
app->m_entry.reset(entry.release());
app->m_applicationPath = QDBusObjectPath{std::move(objectPath)};
// TODO: icon lookup
new APPObjectManagerAdaptor{app.data()};
return app;
}
#endif

View File

@ -13,10 +13,16 @@
#include <QRegularExpression>
#include <QProcess>
#include <algorithm>
#include <new>
ApplicationService::ApplicationService(DesktopFile source, ApplicationManager1Service *parent)
: QObject(parent)
, m_desktopSource(std::move(source))
{
}
ApplicationService::~ApplicationService()
{
m_desktopSource.destruct(m_isPersistence);
for (auto &instance : m_Instances.values()) {
instance->m_Application = QDBusObjectPath{"/"};
auto *ptr = instance.get();
@ -25,6 +31,55 @@ ApplicationService::~ApplicationService()
}
}
QSharedPointer<ApplicationService> ApplicationService::createApplicationService(DesktopFile source,
ApplicationManager1Service *parent) noexcept
{
QString objectPath;
QTextStream sourceStream;
QFile sourceFile;
QString tempSource;
QSharedPointer<ApplicationService> app{nullptr};
if (source.persistence()) {
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(source.desktopId());
sourceFile.setFileName(source.fileSource());
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
qCritical() << "desktop file can't open:" << source.fileSource() << sourceFile.errorString();
return nullptr;
}
app.reset(new (std::nothrow) ApplicationService{std::move(source), parent});
sourceStream.setDevice(&sourceFile);
} else {
tempSource = source.fileSource();
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + QUuid::createUuid().toString(QUuid::Id128);
app.reset(new (std::nothrow) ApplicationService{std::move(source), parent});
sourceStream.setString(&tempSource, QTextStream::ReadOnly | QTextStream::Text);
}
std::unique_ptr<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
auto error = entry->parse(sourceStream);
if (error != DesktopErrorCode::NoError) {
if (error != DesktopErrorCode::EntryKeyInvalid) {
return nullptr;
}
}
if (auto val = entry->value(DesktopFileEntryKey, "Hidden"); val.has_value()) {
bool ok{false};
if (auto hidden = val.value().toBoolean(ok); ok and hidden) {
return nullptr;
}
}
app->m_entry.reset(entry.release());
app->m_applicationPath = QDBusObjectPath{std::move(objectPath)};
// TODO: icon lookup
new (std::nothrow) APPObjectManagerAdaptor{app.data()};
return app;
}
QString ApplicationService::GetActionName(const QString &identifier, const QStringList &env) const
{
const auto &supportedActions = actions();
@ -129,7 +184,7 @@ QString ApplicationService::GetIconName(const QString &action) const
return ok ? name : "";
}
QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, QVariantMap options)
QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options)
{
QString execStr;
bool ok;
@ -189,7 +244,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
cmds.prepend("--");
auto &jobManager = m_parent->jobManager();
auto &jobManager = static_cast<ApplicationManager1Service *>(parent())->jobManager();
return jobManager.addJob(
m_applicationPath.path(),
@ -198,6 +253,10 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
if (m_desktopSource.persistence()) {
commands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.fileSource()));
}
if (resourceFile.isEmpty()) {
commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
@ -211,7 +270,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
return objectPath;
}
int location{0};
qsizetype location{0};
location = commands.indexOf(R"(%f)");
if (location != -1) { // due to std::move, there only remove once
commands.remove(location);
@ -225,16 +284,15 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
}
}
// resourceFile must be available in the following contexts
auto tmp = commands;
tmp.insert(location, resourceFile);
tmp.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
// NOTE: resourceFile must be available in the following contexts
commands.insert(location, resourceFile);
commands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
QProcess process;
process.start(getApplicationLauncherBinary(), tmp);
process.start(getApplicationLauncherBinary(), commands);
process.waitForFinished();
auto exitCode = process.exitCode();
if (exitCode != 0) {
qWarning() << "Launch Application Failed:" << binary << tmp;
qWarning() << "Launch Application Failed:" << binary << commands;
return QString{""};
}
return objectPath;
@ -245,7 +303,7 @@ QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, Q
QStringList ApplicationService::actions() const noexcept
{
if (m_entry.isNull()) {
qWarning() << "desktop entry is empty, isPersistence:" << m_isPersistence;
qWarning() << "desktop entry is empty, isPersistence:" << m_desktopSource.persistence();
return {};
}
@ -274,8 +332,8 @@ ObjectMap ApplicationService::GetManagedObjects() const
QString ApplicationService::id() const noexcept
{
if (m_isPersistence) {
return m_desktopSource.m_file.desktopId();
if (m_desktopSource.persistence()) {
return m_desktopSource.desktopId();
}
return {};
}
@ -310,8 +368,8 @@ QList<QDBusObjectPath> ApplicationService::instances() const noexcept
bool ApplicationService::addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath)
{
auto service = new InstanceService{instanceId, application, systemdUnitPath};
auto adaptor = new InstanceAdaptor(service);
auto *service = new InstanceService{instanceId, application, systemdUnitPath};
auto *adaptor = new InstanceAdaptor(service);
QString objectPath{m_applicationPath.path() + "/" + instanceId};
if (registerObjectToDBus(service, objectPath, getDBusInterface(QMetaType::fromType<InstanceAdaptor>()))) {
@ -327,7 +385,7 @@ bool ApplicationService::addOneInstance(const QString &instanceId, const QString
return false;
}
void ApplicationService::removeOneInstance(const QDBusObjectPath &instance)
void ApplicationService::removeOneInstance(const QDBusObjectPath &instance) noexcept
{
if (auto it = m_Instances.find(instance); it != m_Instances.cend()) {
emit InterfacesRemoved(instance, getInterfacesListFromObject(it->data()));
@ -336,7 +394,7 @@ void ApplicationService::removeOneInstance(const QDBusObjectPath &instance)
}
}
void ApplicationService::removeAllInstance()
void ApplicationService::removeAllInstance() noexcept
{
for (const auto &instance : m_Instances.keys()) {
removeOneInstance(instance);
@ -353,9 +411,14 @@ QDBusObjectPath ApplicationService::findInstance(const QString &instanceId) cons
return {};
}
void ApplicationService::resetEntry(DesktopEntry *newEntry) noexcept
{
m_entry.reset(newEntry);
}
QString ApplicationService::userNameLookup(uid_t uid)
{
auto pws = getpwuid(uid);
auto *pws = getpwuid(uid);
return pws->pw_name;
}

View File

@ -15,6 +15,7 @@
#include <QTextStream>
#include <QFile>
#include <memory>
#include <utility>
#include "dbus/instanceservice.h"
#include "global.h"
#include "desktopentry.h"
@ -54,13 +55,20 @@ public:
void setLauncher(const QString &launcher) noexcept { m_launcher = launcher; }
bool addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath);
void recoverInstances(const QList<QDBusObjectPath>) noexcept;
void removeOneInstance(const QDBusObjectPath &instance);
void removeAllInstance();
void recoverInstances(const QList<QDBusObjectPath> &instanceList) noexcept;
void removeOneInstance(const QDBusObjectPath &instance) noexcept;
void removeAllInstance() noexcept;
[[nodiscard]] const QDBusObjectPath &applicationPath() const noexcept { return m_applicationPath; }
[[nodiscard]] const DesktopFile &desktopFileSource() const noexcept { return m_desktopSource; }
[[nodiscard]] const QMap<QDBusObjectPath, QSharedPointer<InstanceService>> &applicationInstances() const noexcept
{
return m_Instances;
}
void resetEntry(DesktopEntry *newEntry) noexcept;
public Q_SLOTS:
[[nodiscard]] QString GetActionName(const QString &identifier, const QStringList &env) const;
QDBusObjectPath Launch(QString action, QStringList fields, QVariantMap options);
QDBusObjectPath Launch(const QString &action, const QStringList &fields, const QVariantMap &options);
[[nodiscard]] QString GetIconName(const QString &action) const;
[[nodiscard]] QString GetDisplayName(const QStringList &env) const;
[[nodiscard]] ObjectMap GetManagedObjects() const;
@ -71,51 +79,17 @@ Q_SIGNALS:
private:
friend class ApplicationManager1Service;
template <typename T>
friend QSharedPointer<ApplicationService> makeApplication(T &&source, ApplicationManager1Service *parent);
template <typename T>
explicit ApplicationService(T &&source)
: m_isPersistence(static_cast<bool>(std::is_same_v<T, DesktopFile>))
, m_desktopSource(std::forward<T>(source))
{
}
explicit ApplicationService(DesktopFile source, ApplicationManager1Service *parent);
static QSharedPointer<ApplicationService> createApplicationService(DesktopFile source,
ApplicationManager1Service *parent) noexcept;
bool m_AutoStart{false};
bool m_isPersistence;
ApplicationManager1Service *m_parent{nullptr};
QDBusObjectPath m_applicationPath;
QString m_launcher{getApplicationLauncherBinary()};
union DesktopSource
{
template <typename T, std::enable_if_t<std::is_same_v<T, DesktopFile>, bool> = true>
DesktopSource(T &&source)
: m_file(std::forward<T>(source))
{
}
template <typename T, std::enable_if_t<std::is_same_v<T, QString>, bool> = true>
DesktopSource(T &&source)
: m_temp(std::forward<T>(source))
{
}
void destruct(bool isPersistence)
{
if (isPersistence) {
m_file.~DesktopFile();
} else {
m_temp.~QString();
}
}
~DesktopSource(){};
QString m_temp;
DesktopFile m_file;
} m_desktopSource;
DesktopFile m_desktopSource;
QSharedPointer<DesktopEntry> m_entry{nullptr};
QSharedPointer<DesktopIcons> m_Icons{nullptr};
QMap<QDBusObjectPath, QSharedPointer<InstanceService>> m_Instances;
QString userNameLookup(uid_t uid);
static QString userNameLookup(uid_t uid);
[[nodiscard]] LaunchTask unescapeExec(const QString &str, const QStringList &fields);
};

View File

@ -12,6 +12,7 @@
#include <QStringView>
#include <QVariant>
#include <iostream>
#include <chrono>
auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
{
@ -23,6 +24,8 @@ auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
return it;
}
void functest(QMap<QString, QString> p) {}
DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMap)::iterator &currentGroup) noexcept
{
if (str.startsWith("#")) {
@ -87,6 +90,13 @@ DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMa
return DesktopErrorCode::NoError;
}
std::optional<DesktopFile> DesktopFile::createTemporaryDesktopFile(QString content) noexcept
{
auto now = std::chrono::high_resolution_clock::now().time_since_epoch();
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(now);
return DesktopFile{false, std::move(content), "", static_cast<size_t>(nano.count())};
}
std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept
{
constexpr decltype(auto) desktopSuffix = ".desktop";
@ -132,9 +142,9 @@ std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &d
}
err = DesktopErrorCode::NoError;
constexpr std::size_t nanoToSec = 1e9;
constexpr std::size_t secToNano = 1e9;
return DesktopFile{std::move(path), std::move(id), buf.st_mtim.tv_sec * nanoToSec + buf.st_mtim.tv_nsec};
return DesktopFile{true, std::move(path), std::move(id), buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec};
}
std::optional<DesktopFile> DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept
@ -168,15 +178,20 @@ bool DesktopFile::modified(std::size_t time) const noexcept
return time != m_mtime;
}
DesktopErrorCode DesktopEntry::parse(const DesktopFile &appId) noexcept
DesktopErrorCode DesktopEntry::parse(const DesktopFile &file) noexcept
{
auto file = QFile(appId.filePath());
if (!file.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
qWarning() << appId.filePath() << "can't open.";
QTextStream in;
if (file.persistence()) {
auto sourceFile = QFile(file.fileSource());
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
qWarning() << file.fileSource() << "can't open.";
return DesktopErrorCode::OpenFailed;
}
in.setDevice(&sourceFile);
} else {
in.setString(const_cast<QString *>(&file.fileSource()));
}
QTextStream in{&file};
return parse(in);
}

View File

@ -30,33 +30,44 @@ struct DesktopFile
DesktopFile &operator=(DesktopFile &&) = default;
~DesktopFile() = default;
[[nodiscard]] const QString &filePath() const { return m_filePath; }
[[nodiscard]] const QString &desktopId() const { return m_desktopId; }
[[nodiscard]] const QString &fileSource() const noexcept { return m_fileSource; }
[[nodiscard]] const QString &desktopId() const noexcept { return m_desktopId; }
[[nodiscard]] bool persistence() const noexcept { return m_isPersistence; }
[[nodiscard]] bool modified(std::size_t time) const noexcept;
static std::optional<DesktopFile> searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept;
static std::optional<DesktopFile> searchDesktopFileByPath(const QString &desktopFilePath, DesktopErrorCode &err) noexcept;
[[nodiscard]] bool modified(std::size_t time) const noexcept;
static std::optional<DesktopFile> createTemporaryDesktopFile(QString content) noexcept;
private:
DesktopFile(QString &&path, QString &&fileId, std::size_t mtime)
: m_mtime(mtime)
, m_filePath(std::move(path))
DesktopFile(bool persistence, QString &&source, QString &&fileId, std::size_t mtime)
: m_isPersistence(persistence)
, m_mtime(mtime)
, m_fileSource(std::move(source))
, m_desktopId(std::move(fileId))
{
}
bool m_isPersistence;
std::size_t m_mtime;
QString m_filePath{""};
QString m_fileSource{""};
QString m_desktopId{""};
};
class DesktopEntry
{
public:
class Value : public QMap<QString, QString>
class Value final : private QMap<QString, QString>
{
public:
using QMap<QString, QString>::QMap;
using QMap<QString, QString>::find;
using QMap<QString, QString>::insert;
using QMap<QString, QString>::cbegin;
using QMap<QString, QString>::cend;
using QMap<QString, QString>::begin;
using QMap<QString, QString>::end;
QString toString(bool &ok) const noexcept;
bool toBoolean(bool &ok) const noexcept;
QString toIconString(bool &ok) const noexcept;

View File

@ -33,8 +33,8 @@ public:
m_am = new ApplicationManager1Service{std::make_unique<CGroupsIdentifier>(), bus.globalServerBus()};
DesktopFile file{"/usr/share/applications/test-Application.desktop", "test-Application", 0};
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file));
DesktopFile file{true, "/usr/share/applications/test-Application.desktop", "test-Application", 0};
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file), nullptr);
QSharedPointer<InstanceService> instance =
QSharedPointer<InstanceService>::create(InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"});
app->m_Instances.insert(InstancePath, instance);

View File

@ -45,7 +45,7 @@ TEST_F(TestDesktopEntry, desktopFile)
auto curDir = QDir::current();
QString path{curDir.absolutePath() + QDir::separator() + "data" + QDir::separator() + "applications" + QDir::separator() +
"deepin-editor.desktop"};
EXPECT_EQ(exampleFile->filePath().toStdString(), path.toStdString());
EXPECT_EQ(exampleFile->fileSource().toStdString(), path.toStdString());
EXPECT_EQ(exampleFile->desktopId().toStdString(), "deepin-editor");
}
@ -54,7 +54,7 @@ TEST_F(TestDesktopEntry, prase)
const auto &exampleFile = file();
ASSERT_FALSE(exampleFile.isNull());
DesktopEntry entry;
QFile in{exampleFile->filePath()};
QFile in{exampleFile->fileSource()};
ASSERT_TRUE(in.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text));
QTextStream fs{&in};
auto err = entry.parse(fs);