Compare commits
5 Commits
0695c9784c
...
8ca6a6d5a8
Author | SHA1 | Date | |
---|---|---|---|
8ca6a6d5a8 | |||
|
74d95e8240 | ||
|
1c4ae3f700 | ||
3345c0c023 | |||
|
0b0c75849c |
15
debian/changelog
vendored
15
debian/changelog
vendored
@ -1,3 +1,18 @@
|
|||||||
|
dde-application-manager (1.2.16.2) unstable; urgency=medium
|
||||||
|
|
||||||
|
* release 1.2.16.2
|
||||||
|
* fix: processing all input files lazily
|
||||||
|
* fix: correct the ordering of application args
|
||||||
|
|
||||||
|
-- Gary Wang <wangzichong@deepin.org> Thu, 10 Apr 2025 13:34:00 +0800
|
||||||
|
|
||||||
|
dde-application-manager (1.2.16.1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* release 1.2.16.1
|
||||||
|
* fix unable to process Exec keys with %% escaping
|
||||||
|
|
||||||
|
-- Gary Wang <wangzichong@deepin.org> Wed, 09 Apr 2025 18:26:00 +0800
|
||||||
|
|
||||||
dde-application-manager (1.2.16) unstable; urgency=medium
|
dde-application-manager (1.2.16) unstable; urgency=medium
|
||||||
|
|
||||||
* release 1.2.16
|
* release 1.2.16
|
||||||
|
@ -286,8 +286,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [bin, execCmds, res] = std::move(task);
|
if (task.LaunchBin.isEmpty()) {
|
||||||
if (bin.isEmpty()) {
|
|
||||||
qCritical() << "error command is detected, abort.";
|
qCritical() << "error command is detected, abort.";
|
||||||
safe_sendErrorReply(QDBusError::Failed);
|
safe_sendErrorReply(QDBusError::Failed);
|
||||||
return {};
|
return {};
|
||||||
@ -295,25 +294,24 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
|
|
||||||
if (terminal()) {
|
if (terminal()) {
|
||||||
// don't change this sequence
|
// don't change this sequence
|
||||||
execCmds.push_front("-e"); // run all original execution commands in deepin-terminal
|
cmds.push_back("deepin-terminal");
|
||||||
execCmds.push_front("--keep-open"); // keep terminal open, prevent exit immediately
|
cmds.push_back("--keep-open"); // keep terminal open, prevent exit immediately
|
||||||
execCmds.push_front("deepin-terminal");
|
cmds.push_back("-e"); // run all original execution commands in deepin-terminal
|
||||||
}
|
}
|
||||||
cmds.append(std::move(execCmds));
|
|
||||||
|
|
||||||
auto &jobManager = parent()->jobManager();
|
auto &jobManager = parent()->jobManager();
|
||||||
return jobManager.addJob(
|
return jobManager.addJob(
|
||||||
m_applicationPath.path(),
|
m_applicationPath.path(),
|
||||||
[this, binary = std::move(bin), commands = std::move(cmds)](const QVariant &value) -> QVariant {
|
[this, task, cmds = std::move(cmds)](const QVariant &value) -> QVariant { // do not change it to mutable lambda
|
||||||
auto rawResources = value.toString();
|
|
||||||
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
|
auto instanceRandomUUID = QUuid::createUuid().toString(QUuid::Id128);
|
||||||
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
|
auto objectPath = m_applicationPath.path() + "/" + instanceRandomUUID;
|
||||||
auto newCommands = commands;
|
auto newCommands = cmds;
|
||||||
|
|
||||||
|
if (value.isNull()) {
|
||||||
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
||||||
if (rawResources.isEmpty()) {
|
|
||||||
newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
|
newCommands.push_front(QString{R"(--unitName=app-DDE-%1@%2.service)"}.arg(
|
||||||
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
|
escapeApplicationId(this->id()), instanceRandomUUID)); // launcher should use this instanceId
|
||||||
|
newCommands.append(task.command);
|
||||||
|
|
||||||
QProcess process;
|
QProcess process;
|
||||||
qDebug() << "launcher :" << m_launcher << "run with commands:" << newCommands;
|
qDebug() << "launcher :" << m_launcher << "run with commands:" << newCommands;
|
||||||
@ -327,51 +325,25 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
return objectPath;
|
return objectPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto location = newCommands.end();
|
auto rawRes = value.toString();
|
||||||
qsizetype fieldIndex{-1};
|
if (task.argNum != -1) {
|
||||||
for (auto it = newCommands.begin(); it != newCommands.end(); ++it) {
|
if (task.argNum >= newCommands.size()) {
|
||||||
auto fieldLocation = it->indexOf(R"(%f)");
|
qCritical() << "task.argNum >= task.command.size()";
|
||||||
if (fieldLocation != -1) {
|
|
||||||
fieldIndex = fieldLocation;
|
|
||||||
location = it;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldLocation = it->indexOf(R"(%F)");
|
|
||||||
if (fieldLocation != -1) {
|
|
||||||
fieldIndex = fieldLocation;
|
|
||||||
location = it;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (location == newCommands.end()) {
|
|
||||||
qCritical() << R"(internal logic error, can't find %f or %F in exec command, abort.)";
|
|
||||||
return QDBusError::Failed;
|
return QDBusError::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &rawResource = rawResources.split(' ', Qt::SkipEmptyParts);
|
auto tmp = task.command;
|
||||||
QStringList resources;
|
if (task.fieldLocation == -1) {
|
||||||
std::transform(rawResource.cbegin(), rawResource.cend(), std::back_inserter(resources), [](const QString &res) {
|
tmp.insert(task.argNum + 1, rawRes);
|
||||||
auto url = QUrl::fromUserInput(res);
|
} else {
|
||||||
if (url.isValid()) {
|
auto arg = tmp.at(task.argNum);
|
||||||
if (url.isLocalFile()) {
|
arg.insert(task.fieldLocation, rawRes);
|
||||||
return url.toLocalFile();
|
tmp[task.argNum] = arg;
|
||||||
}
|
}
|
||||||
// for now, we only support local file, maybe we will support remote file in the future.
|
|
||||||
// TODO: return processRemoteFile(url);
|
|
||||||
} // if url is invalid, passing to launcher directly
|
|
||||||
|
|
||||||
return res;
|
newCommands.append(std::move(tmp));
|
||||||
});
|
|
||||||
auto tmpRes = resources.join(' ');
|
|
||||||
|
|
||||||
location->replace(fieldIndex, tmpRes.size(), tmpRes);
|
|
||||||
auto newCmd = location->split(' ', Qt::SkipEmptyParts);
|
|
||||||
location = newCommands.erase(location);
|
|
||||||
for (auto &c : newCmd) {
|
|
||||||
location = newCommands.insert(location, std::move(c));
|
|
||||||
}
|
}
|
||||||
|
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
|
||||||
newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
newCommands.push_front(QString{R"(--unitName=DDE-%1@%2.service)"}.arg(this->id(), instanceRandomUUID));
|
||||||
|
|
||||||
QProcess process;
|
QProcess process;
|
||||||
@ -386,7 +358,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
|
|
||||||
return objectPath;
|
return objectPath;
|
||||||
},
|
},
|
||||||
std::move(res));
|
std::move(task.Resources));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ApplicationService::SendToDesktop() const noexcept
|
bool ApplicationService::SendToDesktop() const noexcept
|
||||||
@ -1023,17 +995,17 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, QStringList fiel
|
|||||||
const QChar percentage{'%'};
|
const QChar percentage{'%'};
|
||||||
bool exclusiveField{false};
|
bool exclusiveField{false};
|
||||||
|
|
||||||
for (const auto &arg : *args) {
|
for (auto arg = args->begin(); arg != args->end(); ++arg) {
|
||||||
QString newArg;
|
QString newArg;
|
||||||
|
|
||||||
for (const auto *it = arg.cbegin(); it != arg.cend();) {
|
for (const auto *it = arg->cbegin(); it != arg->cend();) {
|
||||||
if (*it != percentage) {
|
if (*it != percentage) {
|
||||||
newArg.append(*(it++));
|
newArg.append(*(it++));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto *code = it + 1;
|
const auto *code = it + 1;
|
||||||
if (code == arg.cend()) {
|
if (code == arg->cend()) {
|
||||||
qWarning() << R"(content of exec is invalid, a unterminated % is detected.)";
|
qWarning() << R"(content of exec is invalid, a unterminated % is detected.)";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -1044,66 +1016,57 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, QStringList fiel
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (code->toLatin1()) {
|
switch (auto c = code->toLatin1(); c) {
|
||||||
case 'f': { // Defer to async job
|
case 'f':
|
||||||
if (exclusiveField) {
|
[[fallthrough]];
|
||||||
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
exclusiveField = true;
|
|
||||||
|
|
||||||
if (fields.empty()) {
|
|
||||||
qDebug() << R"(fields is empty, %f will be ignored.)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fields.size() > 1) {
|
|
||||||
qDebug() << R"(fields count is greater than one, %f will only take first element.)";
|
|
||||||
}
|
|
||||||
|
|
||||||
task.Resources.emplace_back(fields.takeFirst());
|
|
||||||
newArg.append(R"(%f)");
|
|
||||||
} break;
|
|
||||||
case 'u': {
|
|
||||||
if (exclusiveField) {
|
|
||||||
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
exclusiveField = true;
|
|
||||||
|
|
||||||
if (fields.empty()) {
|
|
||||||
qDebug() << "fields is empty, %u will be ignored.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fields.size() > 1) {
|
|
||||||
qDebug() << R"(fields count is greater than one, %u will only take first element.)";
|
|
||||||
}
|
|
||||||
|
|
||||||
newArg.append(processUrl(fields.takeFirst()));
|
|
||||||
} break;
|
|
||||||
case 'F': { // Defer to async job
|
case 'F': { // Defer to async job
|
||||||
if (exclusiveField) {
|
if (exclusiveField) {
|
||||||
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
qDebug() << QString{"exclusive field is detected again, %%1 will be ignored."}.arg(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exclusiveField = true;
|
exclusiveField = true;
|
||||||
|
|
||||||
|
if (fields.empty()) {
|
||||||
|
qDebug() << QString{"fields is empty, %%1 will be ignored."}.arg(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'F') {
|
||||||
task.Resources.emplace_back(fields.join(' '));
|
task.Resources.emplace_back(fields.join(' '));
|
||||||
fields.clear();
|
} else {
|
||||||
newArg.append(R"(%F)");
|
std::for_each(
|
||||||
|
fields.begin(), fields.end(), [&task](QString &str) { task.Resources.emplace_back(std::move(str)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
task.argNum = std::distance(args->begin(), arg) - 1;
|
||||||
|
task.fieldLocation = std::distance(arg->cbegin(), it) - 1;
|
||||||
} break;
|
} break;
|
||||||
|
case 'u':
|
||||||
case 'U': {
|
case 'U': {
|
||||||
if (exclusiveField) {
|
if (exclusiveField) {
|
||||||
qDebug() << R"(exclusive field is detected again, %f will be ignored.)";
|
qDebug() << QString{"exclusive field is detected again, %%1 will be ignored."}.arg(c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
exclusiveField = true;
|
exclusiveField = true;
|
||||||
|
|
||||||
|
if (fields.empty()) {
|
||||||
|
qDebug() << QString{"fields is empty, %%1 will be ignored."}.arg(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QStringList urls;
|
QStringList urls;
|
||||||
std::transform(fields.cbegin(), fields.cend(), std::back_inserter(urls), processUrl);
|
std::transform(fields.cbegin(), fields.cend(), std::back_inserter(urls), processUrl);
|
||||||
fields.clear();
|
fields.clear();
|
||||||
newArg.append(urls.join(' ')); // split at the end of loop
|
|
||||||
|
if (c == 'U') {
|
||||||
|
task.Resources.emplace_back(urls.join(' '));
|
||||||
|
} else {
|
||||||
|
std::for_each(
|
||||||
|
urls.begin(), urls.end(), [&task](QString &url) { task.Resources.emplace_back(std::move(url)); });
|
||||||
|
}
|
||||||
|
|
||||||
|
task.argNum = std::distance(args->begin(), arg) - 1;
|
||||||
|
task.fieldLocation = std::distance(arg->cbegin(), it) - 1;
|
||||||
} break;
|
} break;
|
||||||
case 'i': {
|
case 'i': {
|
||||||
auto val = m_entry->value(DesktopFileEntryKey, "Icon");
|
auto val = m_entry->value(DesktopFileEntryKey, "Icon");
|
||||||
@ -1169,7 +1132,7 @@ LaunchTask ApplicationService::unescapeExec(const QString &str, QStringList fiel
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (task.Resources.isEmpty()) {
|
if (task.Resources.isEmpty()) {
|
||||||
task.Resources.emplace_back(QString{""}); // mapReduce should run once at least
|
task.Resources.emplace_back(QVariant{}); // mapReduce should run once at least
|
||||||
}
|
}
|
||||||
|
|
||||||
qInfo() << "after unescape exec:" << task.LaunchBin << task.command << task.Resources;
|
qInfo() << "after unescape exec:" << task.LaunchBin << task.command << task.Resources;
|
||||||
|
@ -135,9 +135,9 @@ public:
|
|||||||
const QLocale &locale = getUserLocale()) const noexcept;
|
const QLocale &locale = getUserLocale()) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]] LaunchTask unescapeExec(const QString &str, QStringList fields) noexcept;
|
[[nodiscard]] LaunchTask unescapeExec(const QString &str, QStringList fields) noexcept;
|
||||||
void autoRemoveFromDesktop() const noexcept;
|
|
||||||
void unescapeEens(QVariantMap&) noexcept;
|
|
||||||
[[nodiscard]] static std::optional<QStringList> unescapeExecArgs(const QString &str) noexcept;
|
[[nodiscard]] static std::optional<QStringList> unescapeExecArgs(const QString &str) noexcept;
|
||||||
|
void unescapeEens(QVariantMap&) noexcept;
|
||||||
|
void autoRemoveFromDesktop() const noexcept;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
// NOTE: 'realExec' only for internal implementation
|
// NOTE: 'realExec' only for internal implementation
|
||||||
|
@ -29,9 +29,13 @@ struct LaunchTask
|
|||||||
LaunchTask &operator=(const LaunchTask &) = default;
|
LaunchTask &operator=(const LaunchTask &) = default;
|
||||||
LaunchTask &operator=(LaunchTask &&) = default;
|
LaunchTask &operator=(LaunchTask &&) = default;
|
||||||
explicit operator bool() const { return !LaunchBin.isEmpty() and !command.isEmpty(); }
|
explicit operator bool() const { return !LaunchBin.isEmpty() and !command.isEmpty(); }
|
||||||
|
|
||||||
QString LaunchBin;
|
QString LaunchBin;
|
||||||
QStringList command;
|
QStringList command;
|
||||||
QVariantList Resources;
|
QVariantList Resources;
|
||||||
|
bool singleInstance{false};
|
||||||
|
int argNum{-1};
|
||||||
|
int fieldLocation{-1};
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(LaunchTask)
|
Q_DECLARE_METATYPE(LaunchTask)
|
||||||
|
Loading…
Reference in New Issue
Block a user