diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2022-06-07 16:27:28 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2022-06-10 09:31:03 +0000 |
commit | 36dbc62a1d67f02241e5c5860af083d7f4a0d7b5 (patch) | |
tree | 64b194bf30e65514ee37d67a0a094bbd30ebf540 | |
parent | d8c605179ad4934c5f9a2060dd398a13821336c4 (diff) |
QmlDesigner: Queue puppet processes during import
On some systems launcing multiple simultaneous import processes causes
imports to fail. Fixed by only launching single process at a time
and queuing the rest.
Fixes: QDS-7107
Change-Id: I330c5920dcbd74d3b4f2e7f40899795a4fbaf3ac
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
3 files changed, 103 insertions, 90 deletions
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp index 2dd653273c..76deb3a3b3 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/iconrenderer/iconrenderer.cpp @@ -198,8 +198,7 @@ void IconRenderer::finishCreateIcon() render(saveFile); - // Allow little time for file operations to finish - QTimer::singleShot(1000, qGuiApp, &QGuiApplication::quit); + QTimer::singleShot(0, qGuiApp, &QGuiApplication::quit); } void IconRenderer::render(const QString &fileName) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp index e3aae0cb7d..8e8087dd21 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp @@ -37,6 +37,7 @@ #include <utils/algorithm.h> #include <utils/runextensions.h> +#include <utils/qtcassert.h> #include <QApplication> #include <QDir> @@ -90,21 +91,16 @@ void ItemLibraryAssetImporter::importQuick3D(const QStringList &inputFiles, if (!isCancelled()) { const auto parseData = m_parseData; - for (const auto &pd : parseData) { - if (!startImportProcess(pd)) { - addError(tr("Failed to start import 3D asset process."), - pd.sourceInfo.absoluteFilePath()); - m_parseData.remove(pd.importId); - } - } + for (const auto &pd : parseData) + m_puppetQueue.append(pd.importId); + startNextImportProcess(); } if (!isCancelled()) { // Wait for puppet processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { postImport(); } else { - m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Importing 3D assets."); addInfo(progressTitle); notifyProgress(0, progressTitle); @@ -142,21 +138,14 @@ void ItemLibraryAssetImporter::addInfo(const QString &infoMsg, const QString &sr emit infoReported(infoMsg, srcPath); } -void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, - int importId) +void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { Q_UNUSED(exitCode) - ++m_qmlImportFinishedCount; - - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); + m_puppetProcess.reset(); - if (m_parseData.contains(importId)) { - const ParseData &pd = m_parseData[importId]; + if (m_parseData.contains(m_currentImportId)) { + const ParseData &pd = m_parseData[m_currentImportId]; QString errStr; if (exitStatus == QProcess::ExitStatus::CrashExit) { errStr = tr("Import process crashed."); @@ -179,15 +168,19 @@ void ItemLibraryAssetImporter::importProcessFinished(int exitCode, QProcess::Exi addError(tr("Asset import process failed: \"%1\".") .arg(pd.sourceInfo.absoluteFilePath())); addError(errStr); - m_parseData.remove(importId); + m_parseData.remove(m_currentImportId); } } - if (m_qmlImportFinishedCount == m_qmlPuppetCount) { + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextImportProcess(); + + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::postImport); } else { - notifyProgress(int(100. * (double(m_qmlImportFinishedCount) / double(m_qmlPuppetCount)))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -196,17 +189,17 @@ void ItemLibraryAssetImporter::iconProcessFinished(int exitCode, QProcess::ExitS Q_UNUSED(exitCode) Q_UNUSED(exitStatus) - m_qmlPuppetProcesses.erase( - std::remove_if(m_qmlPuppetProcesses.begin(), m_qmlPuppetProcesses.end(), - [&](const auto &entry) { - return !entry || entry->state() == QProcess::NotRunning; - })); + m_puppetProcess.reset(); + + int finishedCount = m_parseData.size() - m_puppetQueue.size(); + if (!m_puppetQueue.isEmpty()) + startNextIconProcess(); - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { notifyProgress(100); QTimer::singleShot(0, this, &ItemLibraryAssetImporter::finalizeQuick3DImport); } else { - notifyProgress(int(100. * (1. - (double(m_qmlPuppetProcesses.size()) / double(m_qmlPuppetCount))))); + notifyProgress(int(100. * (double(finishedCount) / double(m_parseData.size())))); } } @@ -225,11 +218,11 @@ void ItemLibraryAssetImporter::reset() m_tempDir = new QTemporaryDir; m_importFiles.clear(); m_overwrittenImports.clear(); - m_qmlPuppetProcesses.clear(); - m_qmlPuppetCount = 0; - m_qmlImportFinishedCount = 0; + m_puppetProcess.reset(); m_parseData.clear(); m_requiredImports.clear(); + m_currentImportId = 0; + m_puppetQueue.clear(); } void ItemLibraryAssetImporter::parseFiles(const QStringList &filePaths, @@ -351,7 +344,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa return true; } -void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) +void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd) { QDir outDir = pd.outDir; if (pd.originalAssetName != pd.assetName) { @@ -452,8 +445,10 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(const ParseData &pd) "QtQuick3D", impVersionStr)); } } - if (impVersionMajor > 0 && impVersionMajor < 6 - && startIconProcess(24, iconFileName, qmlIt.filePath())) { + if (impVersionMajor > 0 && impVersionMajor < 6) { + pd.iconFile = iconFileName; + pd.iconSource = qmlIt.filePath(); + m_puppetQueue.append(pd.importId); // Since icon is generated by external process, the file won't be // ready for asset gathering below, so assume its generation succeeds // and add it now. @@ -589,84 +584,101 @@ ItemLibraryAssetImporter::OverwriteResult ItemLibraryAssetImporter::confirmAsset return OverwriteResult::Skip; } -bool ItemLibraryAssetImporter::startImportProcess(const ParseData &pd) +void ItemLibraryAssetImporter::startNextImportProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - QJsonDocument optDoc(pd.options); - - puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() - << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); - - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - importProcessFinished(exitCode, exitStatus, pd.importId); - }, - puppetArgs); - - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + QJsonDocument optDoc(pd.options); + + puppetArgs << "--import3dAsset" << pd.sourceInfo.absoluteFilePath() + << pd.outDir.absolutePath() << QString::fromUtf8(optDoc.toJson()); + + m_currentImportId = pd.importId; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + importProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start import 3D asset process."), + pd.sourceInfo.absoluteFilePath()); + m_parseData.remove(pd.importId); + m_puppetProcess.reset(); + } } } - return false; } -bool ItemLibraryAssetImporter::startIconProcess(int size, const QString &iconFile, - const QString &iconSource) +void ItemLibraryAssetImporter::startNextIconProcess() { + if (m_puppetQueue.isEmpty()) + return; + auto doc = QmlDesignerPlugin::instance()->currentDesignDocument(); Model *model = doc ? doc->currentModel() : nullptr; if (model) { PuppetCreator puppetCreator(doc->currentTarget(), model); puppetCreator.createQml2PuppetExecutableIfMissing(); - QStringList puppetArgs; - puppetArgs << "--rendericon" << QString::number(size) << iconFile << iconSource; - QProcessUniquePointer process = puppetCreator.createPuppetProcess( - "custom", - {}, - [&] {}, - [&](int exitCode, QProcess::ExitStatus exitStatus) { - iconProcessFinished(exitCode, exitStatus); - }, - puppetArgs); - - if (process->waitForStarted(5000)) { - m_qmlPuppetProcesses.push_back(std::move(process)); - return true; - } else { - process.reset(); + + bool done = false; + while (!m_puppetQueue.isEmpty() && !done) { + const ParseData pd = m_parseData.value(m_puppetQueue.takeLast()); + QStringList puppetArgs; + puppetArgs << "--rendericon" << QString::number(24) << pd.iconFile << pd.iconSource; + m_puppetProcess = puppetCreator.createPuppetProcess( + "custom", + {}, + [&] {}, + [&](int exitCode, QProcess::ExitStatus exitStatus) { + iconProcessFinished(exitCode, exitStatus); + }, + puppetArgs); + + if (m_puppetProcess->waitForStarted(10000)) { + done = true; + } else { + addError(tr("Failed to start icon generation process."), + pd.sourceInfo.absoluteFilePath()); + m_puppetProcess.reset(); + } } } - return false; } void ItemLibraryAssetImporter::postImport() { - Q_ASSERT(m_qmlPuppetProcesses.empty()); + QTC_ASSERT(m_puppetQueue.isEmpty() && !m_puppetProcess, return); if (!isCancelled()) { - for (const auto &pd : qAsConst(m_parseData)) + for (auto &pd : m_parseData) postParseQuick3DAsset(pd); + startNextIconProcess(); } if (!isCancelled()) { // Wait for icon generation processes to finish - if (m_qmlPuppetProcesses.empty()) { + if (m_puppetQueue.isEmpty() && !m_puppetProcess) { finalizeQuick3DImport(); } else { - m_qmlPuppetCount = static_cast<int>(m_qmlPuppetProcesses.size()); const QString progressTitle = tr("Generating icons."); addInfo(progressTitle); notifyProgress(0, progressTitle); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h index 83be9af5f4..1f0009eaab 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h @@ -74,7 +74,7 @@ signals: void importFinished(); private slots: - void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, int importId); + void importProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); void iconProcessFinished(int exitCode, QProcess::ExitStatus exitStatus); private: @@ -87,6 +87,8 @@ private: QString assetName; QString originalAssetName; int importId; + QString iconFile; + QString iconSource; }; void notifyFinished(); @@ -96,7 +98,7 @@ private: const QSet<QString> &preselectedFilesForOverwrite); bool preParseQuick3DAsset(const QString &file, ParseData &pd, const QSet<QString> &preselectedFilesForOverwrite); - void postParseQuick3DAsset(const ParseData &pd); + void postParseQuick3DAsset(ParseData &pd); void copyImportedFiles(); void notifyProgress(int value, const QString &text); @@ -110,8 +112,8 @@ private: }; OverwriteResult confirmAssetOverwrite(const QString &assetName); - bool startImportProcess(const ParseData &pd); - bool startIconProcess(int size, const QString &iconFile, const QString &iconSource); + void startNextImportProcess(); + void startNextIconProcess(); void postImport(); void finalizeQuick3DImport(); QString sourceSceneTargetFilePath(const ParseData &pd); @@ -122,12 +124,12 @@ private: bool m_cancelled = false; QString m_importPath; QTemporaryDir *m_tempDir = nullptr; - std::vector<QProcessUniquePointer> m_qmlPuppetProcesses; - int m_qmlPuppetCount = 0; - int m_qmlImportFinishedCount = 0; + QProcessUniquePointer m_puppetProcess; int m_importIdCounter = 0; + int m_currentImportId = 0; QHash<int, ParseData> m_parseData; QString m_progressTitle; QList<Import> m_requiredImports; + QList<int> m_puppetQueue; }; } // QmlDesigner |