refact: ApplicationService ctor and some member functions
Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
		@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 ¤tGroup) 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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user