fix: processing all input files lazily

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe 2025-01-13 16:53:08 +08:00 committed by Wang Zichong
parent 3345c0c023
commit 1c4ae3f700
2 changed files with 68 additions and 101 deletions

View File

@ -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_front("-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;
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath())); if (value.isNull()) {
if (rawResources.isEmpty()) { newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
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) { return QDBusError::Failed;
fieldIndex = fieldLocation;
location = it;
break;
} }
fieldLocation = it->indexOf(R"(%F)"); auto tmp = task.command;
if (fieldLocation != -1) { if (task.fieldLocation == -1) {
fieldIndex = fieldLocation; tmp.insert(task.argNum + 1, rawRes);
location = it; } else {
break; auto arg = tmp.at(task.argNum);
arg.insert(task.fieldLocation, rawRes);
tmp[task.argNum] = arg;
} }
newCommands.append(std::move(tmp));
} }
newCommands.push_front(QString{"--SourcePath=%1"}.arg(m_desktopSource.sourcePath()));
if (location == newCommands.end()) {
qCritical() << R"(internal logic error, can't find %f or %F in exec command, abort.)";
return QDBusError::Failed;
}
const auto &rawResource = rawResources.split(' ', Qt::SkipEmptyParts);
QStringList resources;
std::transform(rawResource.cbegin(), rawResource.cend(), std::back_inserter(resources), [](const QString &res) {
auto url = QUrl::fromUserInput(res);
if (url.isValid()) {
if (url.isLocalFile()) {
return url.toLocalFile();
}
// 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;
});
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{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;
task.Resources.emplace_back(fields.join(' ')); if (fields.empty()) {
fields.clear(); qDebug() << QString{"fields is empty, %%1 will be ignored."}.arg(c);
newArg.append(R"(%F)"); break;
}
if (c == 'F') {
task.Resources.emplace_back(fields.join(' '));
} else {
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;

View File

@ -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)