refact: DesktopFile's method and structure

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe 2023-08-21 16:02:26 +08:00 committed by Comix
parent 65b6c9eaf0
commit 06ee5e5899
10 changed files with 155 additions and 99 deletions

View File

@ -27,7 +27,7 @@ public:
u8"JobNew",
this,
SLOT(jobNewForward(QDBusObjectPath, QDBusObjectPath)))) {
qFatal() << "connect JobNew failed.";
qFatal("connect JobNew failed.");
}
if (!con.connect(JobManager.service(),
@ -36,7 +36,7 @@ public:
u8"JobRemoved",
this,
SLOT(jobRemovedForward(QDBusObjectPath, QString, QVariantList)))) {
qFatal() << "connect JobNew failed.";
qFatal("connect JobNew failed.");
}
connect(this, &Demo::applicationLaunched, [](QList<QString> apps) {

View File

@ -1,8 +1,9 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "applicationadaptor.h"
#include "dbus/applicationmanager1adaptor.h"
#include "applicationservice.h"
#include "dbus/AMobjectmanager1adaptor.h"
#include "systemdsignaldispatcher.h"
#include <QFile>
@ -10,17 +11,20 @@
ApplicationManager1Service::~ApplicationManager1Service() = default;
ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifier> ptr, QDBusConnection &connection)
ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifier> ptr, QDBusConnection &connection) noexcept
: m_identifier(std::move(ptr))
{
if (!connection.registerService(DDEApplicationManager1ServiceName)) {
qFatal() << connection.lastError();
qFatal("%s", connection.lastError().message().toLocal8Bit().data());
}
new ApplicationManager1Adaptor{this};
auto *tmp = new AMObjectManagerAdaptor{this};
if (auto *tmp = new (std::nothrow) ApplicationManager1Adaptor{this}; tmp == nullptr) {
qCritical() << "new Application Manager Adaptor failed.";
std::terminate();
}
if (tmp == nullptr) {
if (auto *tmp = new (std::nothrow) AMObjectManagerAdaptor{this}; tmp == nullptr) {
qCritical() << "new Object Manager of Application Manager Adaptor failed.";
std::terminate();
}
@ -29,7 +33,12 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
std::terminate();
}
m_jobManager.reset(new JobManager1Service(this));
m_jobManager.reset(new (std::nothrow) JobManager1Service(this));
if (!m_jobManager) {
qCritical() << "new JobManager failed.";
std::terminate();
}
auto &dispatcher = SystemdSignalDispatcher::instance();
@ -109,11 +118,8 @@ bool ApplicationManager1Service::addApplication(DesktopFile desktopFileSource) n
}
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();
}
qInfo() << "this application already exists."
<< "desktop source:" << application->desktopFileSource().sourcePath();
return false;
}
@ -209,16 +215,9 @@ void ApplicationManager1Service::updateApplication(const QSharedPointer<Applicat
return;
}
struct stat buf;
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;
}
auto mtime = getFileModifiedTime(desktopFile.sourceFileRef());
constexpr std::size_t secToNano = 1e9;
if (destApp->desktopFileSource().modified(buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec)) {
if (destApp->desktopFileSource().modified(mtime)) {
auto *newEntry = new (std::nothrow) DesktopEntry{};
if (newEntry == nullptr) {
qCritical() << "new DesktopEntry failed.";

View File

@ -13,15 +13,16 @@
#include <memory>
#include <QMap>
#include "dbus/jobmanager1service.h"
#include "dbus/APPobjectmanager1adaptor.h"
#include "dbus/applicationadaptor.h"
#include "desktopentry.h"
#include "identifier.h"
class ApplicationService;
class ApplicationManager1Service final : public QObject
{
Q_OBJECT
public:
explicit ApplicationManager1Service(std::unique_ptr<Identifier> ptr, QDBusConnection &connection);
explicit ApplicationManager1Service(std::unique_ptr<Identifier> ptr, QDBusConnection &connection) noexcept;
~ApplicationManager1Service() override;
ApplicationManager1Service(const ApplicationManager1Service &) = delete;
ApplicationManager1Service(ApplicationManager1Service &&) = delete;

View File

@ -3,6 +3,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
#include "dbus/applicationservice.h"
#include "APPobjectmanager1adaptor.h"
#include "applicationmanager1service.h"
#include "dbus/instanceadaptor.h"
#include "pwd.h"
@ -34,28 +35,24 @@ ApplicationService::~ApplicationService()
QSharedPointer<ApplicationService> ApplicationService::createApplicationService(DesktopFile source,
ApplicationManager1Service *parent) noexcept
{
QSharedPointer<ApplicationService> app{new (std::nothrow) ApplicationService{std::move(source), parent}};
if (!app) {
qCritical() << "new application service failed.";
return nullptr;
}
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;
}
auto appId = app->desktopFileSource().desktopId();
app.reset(new (std::nothrow) ApplicationService{std::move(source), parent});
sourceStream.setDevice(&sourceFile);
if (!appId.isEmpty()) {
objectPath = QString{DDEApplicationManager1ObjectPath} + "/" + escapeToObjectPath(appId);
} 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);
}
sourceStream.setDevice(app->desktopFileSource().sourceFile());
std::unique_ptr<DesktopEntry> entry{std::make_unique<DesktopEntry>()};
auto error = entry->parse(sourceStream);
@ -76,7 +73,11 @@ QSharedPointer<ApplicationService> ApplicationService::createApplicationService(
app->m_applicationPath = QDBusObjectPath{std::move(objectPath)};
// TODO: icon lookup
new (std::nothrow) APPObjectManagerAdaptor{app.data()};
if (auto *ptr = new (std::nothrow) APPObjectManagerAdaptor{app.data()}; ptr == nullptr) {
qCritical() << "new Object Manager of Application failed.";
return nullptr;
}
return app;
}
@ -252,10 +253,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
auto resourceFile = variantValue.toString();
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()));
}
commands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
if (resourceFile.isEmpty()) {
commands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
@ -303,7 +301,7 @@ QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringL
QStringList ApplicationService::actions() const noexcept
{
if (m_entry.isNull()) {
qWarning() << "desktop entry is empty, isPersistence:" << m_desktopSource.persistence();
qWarning() << "desktop entry is empty, source file:" << m_desktopSource.sourcePath();
return {};
}
@ -332,10 +330,7 @@ ObjectMap ApplicationService::GetManagedObjects() const
QString ApplicationService::id() const noexcept
{
if (m_desktopSource.persistence()) {
return m_desktopSource.desktopId();
}
return {};
return m_desktopSource.desktopId();
}
IconMap ApplicationService::icons() const

View File

@ -59,7 +59,7 @@ public:
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]] DesktopFile &desktopFileSource() noexcept { return m_desktopSource; }
[[nodiscard]] const QMap<QDBusObjectPath, QSharedPointer<InstanceService>> &applicationInstances() const noexcept
{
return m_Instances;

View File

@ -24,7 +24,11 @@ auto DesktopEntry::parserGroupHeader(const QString &str) noexcept
return it;
}
void functest(QMap<QString, QString> p) {}
QString DesktopFile::sourcePath() const noexcept
{
QFileInfo info(*m_fileSource);
return info.absoluteFilePath();
}
DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMap)::iterator &currentGroup) noexcept
{
@ -90,11 +94,14 @@ DesktopErrorCode DesktopEntry::parseEntry(const QString &str, decltype(m_entryMa
return DesktopErrorCode::NoError;
}
std::optional<DesktopFile> DesktopFile::createTemporaryDesktopFile(QString content) noexcept
std::optional<DesktopFile> DesktopFile::createTemporaryDesktopFile(std::unique_ptr<QFile> temporaryFile) 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())};
auto mtime = getFileModifiedTime(*temporaryFile);
if (mtime == 0) {
qWarning() << "create temporary file failed.";
return std::nullopt;
}
return DesktopFile{std::move(temporaryFile), "", mtime};
}
std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &desktopFile, DesktopErrorCode &err) noexcept
@ -134,17 +141,17 @@ std::optional<DesktopFile> DesktopFile::searchDesktopFileByPath(const QString &d
id = FileId.chopped(1); // remove extra "-""
}
struct stat buf;
if (auto ret = stat(path.toLatin1().data(), &buf); ret == -1) {
auto filePtr = std::make_unique<QFile>(std::move(path));
auto mtime = getFileModifiedTime(*filePtr);
if (mtime == 0) {
err = DesktopErrorCode::OpenFailed;
qWarning() << "get file" << path << "state failed:" << std::strerror(errno);
return std::nullopt;
}
err = DesktopErrorCode::NoError;
constexpr std::size_t secToNano = 1e9;
return DesktopFile{true, std::move(path), std::move(id), buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec};
return DesktopFile{std::move(filePtr), std::move(id), mtime};
}
std::optional<DesktopFile> DesktopFile::searchDesktopFileById(const QString &appId, DesktopErrorCode &err) noexcept
@ -178,21 +185,18 @@ bool DesktopFile::modified(std::size_t time) const noexcept
return time != m_mtime;
}
DesktopErrorCode DesktopEntry::parse(const DesktopFile &file) noexcept
DesktopErrorCode DesktopEntry::parse(DesktopFile &file) noexcept
{
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()));
DesktopFileGuard guard{file};
if (!guard.try_open()) {
qWarning() << file.sourcePath() << "can't open.";
return DesktopErrorCode::OpenFailed;
}
return parse(in);
QTextStream stream;
stream.setDevice(file.sourceFile());
return parse(stream);
}
DesktopErrorCode DesktopEntry::parse(QTextStream &stream) noexcept

View File

@ -2,13 +2,16 @@
//
// SPDX-License-Identifier: LGPL-3.0-or-later
#ifndef DESKTOPENTRY_H
#define DESKTOPENTRY_H
#include <QString>
#include <QMap>
#include <QDebug>
#include <QLocale>
#include <QTextStream>
#include <optional>
#include <sys/stat.h>
#include <QFile>
constexpr static auto defaultKeyStr = "default";
@ -22,38 +25,68 @@ enum class DesktopErrorCode {
EntryKeyInvalid
};
struct DesktopFileGuard;
struct DesktopFile
{
DesktopFile(const DesktopFile &) = default;
friend struct DesktopFileGuard;
DesktopFile(const DesktopFile &) = delete;
DesktopFile(DesktopFile &&) = default;
DesktopFile &operator=(const DesktopFile &) = default;
DesktopFile &operator=(const DesktopFile &) = delete;
DesktopFile &operator=(DesktopFile &&) = default;
~DesktopFile() = default;
[[nodiscard]] const QString &fileSource() const noexcept { return m_fileSource; }
[[nodiscard]] QString sourcePath() const noexcept;
// WARNING: This raw pointer's ownership belong to DesktopFile, DO NOT MODIFY!
[[nodiscard]] QFile *sourceFile() const noexcept { return &sourceFileRef(); };
[[nodiscard]] QFile &sourceFileRef() 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;
static std::optional<DesktopFile> createTemporaryDesktopFile(QString content) noexcept;
static std::optional<DesktopFile> createTemporaryDesktopFile(std::unique_ptr<QFile> temporaryFile) noexcept;
private:
DesktopFile(bool persistence, QString &&source, QString &&fileId, std::size_t mtime)
: m_isPersistence(persistence)
, m_mtime(mtime)
DesktopFile(std::unique_ptr<QFile> source, QString fileId, std::size_t mtime)
: m_mtime(mtime)
, m_fileSource(std::move(source))
, m_desktopId(std::move(fileId))
{
}
bool m_isPersistence;
std::size_t m_mtime;
QString m_fileSource{""};
std::unique_ptr<QFile> m_fileSource{nullptr};
QString m_desktopId{""};
};
struct DesktopFileGuard
{
DesktopFileGuard(const DesktopFileGuard &) = delete;
DesktopFileGuard(DesktopFileGuard &&other) noexcept
: fileRef(other.fileRef)
{
}
DesktopFileGuard &operator=(const DesktopFileGuard &) = delete;
DesktopFileGuard &operator=(DesktopFileGuard &&) = delete;
explicit DesktopFileGuard(DesktopFile &file)
: fileRef(file)
{
}
bool try_open() { return fileRef.m_fileSource->open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text); }
~DesktopFileGuard()
{
if (fileRef.m_fileSource->isOpen()) {
fileRef.m_fileSource->close();
}
}
private:
DesktopFile &fileRef;
};
class DesktopEntry
{
public:
@ -86,7 +119,7 @@ public:
DesktopEntry &operator=(DesktopEntry &&) = default;
~DesktopEntry() = default;
[[nodiscard]] DesktopErrorCode parse(const DesktopFile &file) noexcept;
[[nodiscard]] DesktopErrorCode parse(DesktopFile &file) noexcept;
[[nodiscard]] DesktopErrorCode parse(QTextStream &stream) noexcept;
[[nodiscard]] std::optional<QMap<QString, Value>> group(const QString &key) const noexcept;
[[nodiscard]] std::optional<Value> value(const QString &key, const QString &valueKey) const noexcept;
@ -100,3 +133,5 @@ private:
QDebug operator<<(QDebug debug, const DesktopEntry::Value &v);
QDebug operator<<(QDebug debug, const DesktopErrorCode &v);
#endif

View File

@ -19,6 +19,7 @@
#include <QDBusObjectPath>
#include <unistd.h>
#include <QUuid>
#include <sys/stat.h>
#include "constant.h"
#include "config.h"
@ -103,7 +104,7 @@ public:
}
if (!m_initFlag) {
qFatal() << "invoke init at first.";
qFatal("invoke init at first.");
}
switch (m_serverType) {
@ -113,17 +114,17 @@ public:
m_serverConnection.emplace(QDBusConnection::connectToBus(static_cast<QDBusConnection::BusType>(m_serverType),
ApplicationManagerServerDBusName));
if (!m_serverConnection->isConnected()) {
qFatal() << m_serverConnection->lastError();
qFatal("%s", m_serverConnection->lastError().message().toLocal8Bit().data());
}
return m_serverConnection.value();
}
case DBusType::Custom: {
if (m_serverBusAddress.isEmpty()) {
qFatal() << "connect to custom dbus must init this object by custom dbus address";
qFatal("connect to custom dbus must init this object by custom dbus address");
}
m_serverConnection.emplace(QDBusConnection::connectToBus(m_serverBusAddress, ApplicationManagerServerDBusName));
if (!m_serverConnection->isConnected()) {
qFatal() << m_serverConnection->lastError();
qFatal("%s", m_serverConnection->lastError().message().toLocal8Bit().data());
}
return m_serverConnection.value();
}
@ -140,7 +141,7 @@ public:
QDBusConnection &globalDestBus()
{
if (!m_destConnection) {
qFatal() << "please set which bus should application manager to use to invoke other D-Bus service's method.";
qFatal("please set which bus should application manager to use to invoke other D-Bus service's method.");
}
return m_destConnection.value();
}
@ -157,18 +158,18 @@ public:
m_destConnection.emplace(
QDBusConnection::connectToBus(QDBusConnection::BusType::SessionBus, ApplicationManagerDestDBusName));
if (!m_destConnection->isConnected()) {
qFatal() << m_destConnection->lastError();
qFatal("%s", m_destConnection->lastError().message().toLocal8Bit().data());
}
return;
}
if (m_destBusAddress.isEmpty()) {
qFatal() << "connect to custom dbus must init this object by custom dbus address";
qFatal("connect to custom dbus must init this object by custom dbus address");
}
m_destConnection.emplace(QDBusConnection::connectToBus(m_destBusAddress, ApplicationManagerDestDBusName));
if (!m_destConnection->isConnected()) {
qFatal() << m_destConnection->lastError();
qFatal("%s", m_destConnection->lastError().message().toLocal8Bit().data());
}
}
@ -374,4 +375,25 @@ ObjectMap dumpDBusObject(const QMap<QDBusObjectPath, QSharedPointer<T>> &map)
return objs;
}
inline std::size_t getFileModifiedTime(QFile &file)
{
struct stat buf;
QFileInfo info{file};
if (!file.isOpen()) {
if (auto ret = file.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text); !ret) {
qWarning() << "open file" << info.absoluteFilePath() << "failed.";
return 0;
}
}
if (auto ret = stat(info.absoluteFilePath().toLocal8Bit().data(), &buf); ret == -1) {
qWarning() << "get file" << info.absoluteFilePath() << "state failed:" << std::strerror(errno);
return 0;
}
constexpr std::size_t secToNano = 1e9;
return buf.st_mtim.tv_sec * secToNano + buf.st_mtim.tv_nsec;
}
#endif

View File

@ -32,8 +32,8 @@ public:
bus.setDestBus();
m_am = new ApplicationManager1Service{std::make_unique<CGroupsIdentifier>(), bus.globalServerBus()};
DesktopFile file{true, "/usr/share/applications/test-Application.desktop", "test-Application", 0};
auto ptr = std::make_unique<QFile>(QString{"/usr/share/applications/test-Application.desktop"});
DesktopFile file{std::move(ptr), "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{"/"});

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->fileSource().toStdString(), path.toStdString());
EXPECT_EQ(exampleFile->sourcePath(), path);
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->fileSource()};
QFile in{exampleFile->sourcePath()};
ASSERT_TRUE(in.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text));
QTextStream fs{&in};
auto err = entry.parse(fs);