QmlDesigner: Prepare split of puppet creator

We can move the environment building outside of the puppet start. The
puppet building is now broken and if we add it again it should be too
done outside of process start.

Change-Id: I33ea01428cf509c26409147d2784d0327478c3ed
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2022-09-27 15:28:12 +02:00
parent f195c3a065
commit bb71aa6d43
7 changed files with 509 additions and 0 deletions

View File

@@ -38,6 +38,7 @@ add_qtc_plugin(QmlDesigner
dynamiclicensecheck.h dynamiclicensecheck.h
generateresource.cpp generateresource.h generateresource.cpp generateresource.h
openuiqmlfiledialog.cpp openuiqmlfiledialog.h openuiqmlfiledialog.ui openuiqmlfiledialog.cpp openuiqmlfiledialog.h openuiqmlfiledialog.ui
puppetenvironmentbuilder.cpp puppetenvironmentbuilder.h
qmldesignerconstants.h qmldesignerconstants.h
qmldesignericons.h qmldesignericons.h
qmldesignerplugin.cpp qmldesignerplugin.h qmldesignerplugin.cpp qmldesignerplugin.h

View File

@@ -0,0 +1,21 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include <QProcessEnvironment>
#include <QString>
namespace QmlDesigner {
class PuppetStartData
{
public:
QString puppetPath;
QString workingDirectoryPath;
QString forwardOutput;
QString freeTypeOption;
QString debugPuppet;
QProcessEnvironment environment;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,96 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "puppetstarter.h"
#include <QCoreApplication>
#include <QMessageBox>
#include <QProcess>
namespace QmlDesigner {
PuppetStarter::PuppetStarter(ProjectExplorer::Target *target, const Model *model)
: m_target(target)
, m_availablePuppetType(FallbackPuppet)
, m_model(model)
{
}
QProcessUniquePointer PuppetStarter::createPuppetProcess(
const PuppetStartData &data,
const QString &puppetMode,
const QString &socketToken,
std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const
{
return puppetProcess(data.puppetPath,
data.workingDirectoryPath,
data.forwardOutput,
data.freeTypeOption,
data.debugPuppet,
data.environment,
puppetMode,
socketToken,
processOutputCallback,
processFinishCallback,
customOptions);
}
QProcessUniquePointer PuppetStarter::puppetProcess(
const QString &puppetPath,
const QString &workingDirectory,
const QString &forwardOutput,
const QString &freeTypeOption,
const QString &debugPuppet,
const QProcessEnvironment &processEnvironment,
const QString &puppetMode,
const QString &socketToken,
std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const
{
QProcessUniquePointer puppetProcess{new QProcess};
puppetProcess->setObjectName(puppetMode);
puppetProcess->setProcessEnvironment(processEnvironment);
QObject::connect(QCoreApplication::instance(),
&QCoreApplication::aboutToQuit,
puppetProcess.get(),
&QProcess::kill);
QObject::connect(puppetProcess.get(),
static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
processFinishCallback);
if (forwardOutput == puppetMode || forwardOutput == "all") {
puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(puppetProcess.get(), &QProcess::readyRead, processOutputCallback);
}
puppetProcess->setWorkingDirectory(workingDirectory);
QStringList processArguments;
if (puppetMode == "custom")
processArguments = customOptions;
else
processArguments = {socketToken, puppetMode};
processArguments.push_back("-graphicssystem raster");
processArguments.push_back(freeTypeOption);
puppetProcess->start(puppetPath, processArguments);
if (debugPuppet == puppetMode || debugPuppet == "all") {
QMessageBox::information(
nullptr,
QCoreApplication::translate("PuppetStarter", "Puppet is starting..."),
QCoreApplication::translate(
"PuppetStarter",
"You can now attach your debugger to the %1 puppet with process id: %2.")
.arg(puppetMode, QString::number(puppetProcess->processId())));
}
return puppetProcess;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,93 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include "qprocessuniqueptr.h"
#include <puppetstartdata.h>
#include <utils/id.h>
#include <QString>
#include <QProcessEnvironment>
#include <designersettings.h>
namespace ProjectExplorer {
class Target;
} // namespace ProjectExplorer
namespace QmlDesigner {
class PuppetBuildProgressDialog;
class Model;
class PuppetStarter
{
public:
enum PuppetType { FallbackPuppet, UserSpacePuppet, BinPathPuppet };
PuppetStarter(ProjectExplorer::Target *target, const Model *model);
void createQml2PuppetExecutableIfMissing();
QProcessUniquePointer createPuppetProcess(
const PuppetStartData &data,
const QString &puppetMode,
const QString &socketToken,
std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions = {}) const;
void setQrcMappingString(const QString qrcMapping);
static QString defaultPuppetToplevelBuildDirectory();
static QString defaultPuppetFallbackDirectory();
static QString qmlPuppetFallbackDirectory(const DesignerSettings &settings);
protected:
bool startBuildProcess(const QString &buildDirectoryPath,
const QString &command,
const QStringList &processArguments = QStringList(),
PuppetBuildProgressDialog *progressDialog = nullptr) const;
static QString puppetSourceDirectoryPath();
static QString qml2PuppetProjectFile();
bool checkPuppetIsReady(const QString &puppetPath) const;
bool qtIsSupported() const;
QProcessUniquePointer puppetProcess(const QString &puppetPath,
const QString &workingDirectory,
const QString &forwardOutput,
const QString &freeTypeOption,
const QString &debugPuppet,
const QProcessEnvironment &processEnvironment,
const QString &puppetMode,
const QString &socketToken,
std::function<void()> processOutputCallback,
std::function<void(int, QProcess::ExitStatus)> processFinishCallback,
const QStringList &customOptions) const;
QProcessEnvironment processEnvironment() const;
QString buildCommand() const;
QString qmakeCommand() const;
QByteArray qtHash() const;
QDateTime qtLastModified() const;
QDateTime puppetSourceLastModified() const;
bool useOnlyFallbackPuppet() const;
QString getStyleConfigFileName() const;
bool usesVirtualKeyboard() const;
private:
mutable QString m_compileLog;
ProjectExplorer::Target *m_target = nullptr;
PuppetType m_availablePuppetType;
static QHash<Utils::Id, PuppetType> m_qml2PuppetForKitPuppetHash;
const Model *m_model = nullptr;
QString m_qrcMapping;
};
} // namespace QmlDesigner

View File

@@ -0,0 +1,241 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "puppetenvironmentbuilder.h"
#include "designersettings.h"
#include "qmldesignerplugin.h"
#include <model.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/target.h>
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <qmlprojectmanager/qmlmultilanguageaspect.h>
#include <qmlprojectmanager/qmlproject.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversions.h>
#include <QLibraryInfo>
namespace QmlDesigner {
namespace {
Q_LOGGING_CATEGORY(puppetEnvirmentBuild, "qtc.puppet.environmentBuild", QtWarningMsg)
void filterOutQtBaseImportPath(QStringList *stringList)
{
Utils::erase(*stringList, [](const QString &string) {
QDir dir(string);
return dir.dirName() == "qml"
&& !dir.entryInfoList(QStringList("QtTest"), QDir::Dirs).isEmpty();
});
}
Utils::FilePath pathForBinPuppet(ProjectExplorer::Target *target)
{
if (!target || !target->kit())
return {};
QtSupport::QtVersion *currentQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (currentQtVersion)
return currentQtVersion->binPath().pathAppended("qml2puppet").withExecutableSuffix();
return {};
}
} // namespace
QProcessEnvironment PuppetEnvironmentBuilder::processEnvironment() const
{
qCInfo(puppetEnvirmentBuild) << Q_FUNC_INFO;
m_availablePuppetType = determinePuppetType();
m_environment = Utils::Environment::systemEnvironment();
addKit();
addRendering();
addControls();
addPixelRatio();
addVirtualKeyboard();
addForceQApplication();
addImportPaths();
addCustomFileSelectors();
qCInfo(puppetEnvirmentBuild) << "Puppet environment:" << m_environment.toStringList();
return m_environment.toProcessEnvironment();
}
bool PuppetEnvironmentBuilder::usesVirtualKeyboard() const
{
if (m_target) {
auto *qmlbuild = qobject_cast<QmlProjectManager::QmlBuildSystem *>(m_target->buildSystem());
const Utils::EnvironmentItem virtualKeyboard("QT_IM_MODULE", "qtvirtualkeyboard");
return qmlbuild && qmlbuild->environment().indexOf(virtualKeyboard);
}
return false;
}
QString PuppetEnvironmentBuilder::getStyleConfigFileName() const
{
if (m_target) {
for (const Utils::FilePath &fileName :
m_target->project()->files(ProjectExplorer::Project::SourceFiles)) {
if (fileName.fileName() == "qtquickcontrols2.conf")
return fileName.toString();
}
}
return {};
}
void PuppetEnvironmentBuilder::addKit() const
{
if (m_target) {
if (m_availablePuppetType == PuppetType::Kit) {
m_target->kit()->addToBuildEnvironment(m_environment);
const QtSupport::QtVersion *qt = QtSupport::QtKitAspect::qtVersion(m_target->kit());
if (qt) { // Kits without a Qt version should not have a puppet!
// Update PATH to include QT_HOST_BINS
m_environment.prependOrSetPath(qt->hostBinPath());
}
}
}
}
void PuppetEnvironmentBuilder::addRendering() const
{
m_environment.set("QML_BAD_GUI_RENDER_LOOP", "true");
m_environment.set("QML_PUPPET_MODE", "true");
m_environment.set("QML_DISABLE_DISK_CACHE", "true");
m_environment.set("QMLPUPPET_RENDER_EFFECTS", "true");
if (!m_environment.hasKey("QT_SCREEN_SCALE_FACTORS") && !m_environment.hasKey("QT_SCALE_FACTOR"))
m_environment.set("QT_AUTO_SCREEN_SCALE_FACTOR", "1");
const bool smoothRendering = m_designerSettings.value(DesignerSettingsKey::SMOOTH_RENDERING).toBool();
if (smoothRendering)
m_environment.set("QMLPUPPET_SMOOTH_RENDERING", "true");
}
void PuppetEnvironmentBuilder::addControls() const
{
const QString controlsStyle = m_designerSettings.value(DesignerSettingsKey::CONTROLS_STYLE).toString();
if (!controlsStyle.isEmpty()) {
m_environment.set("QT_QUICK_CONTROLS_STYLE", controlsStyle);
m_environment.set("QT_LABS_CONTROLS_STYLE", controlsStyle);
}
const QString styleConfigFileName = getStyleConfigFileName();
if (!styleConfigFileName.isEmpty())
m_environment.appendOrSet("QT_QUICK_CONTROLS_CONF", styleConfigFileName);
}
void PuppetEnvironmentBuilder::addPixelRatio() const
{
m_environment.set("FORMEDITOR_DEVICE_PIXEL_RATIO",
QString::number(QmlDesignerPlugin::formEditorDevicePixelRatio()));
}
void PuppetEnvironmentBuilder::addVirtualKeyboard() const
{
if (usesVirtualKeyboard()) {
m_environment.set("QT_IM_MODULE", "qtvirtualkeyboard");
m_environment.set("QT_VIRTUALKEYBOARD_DESKTOP_DISABLE", "1");
}
}
void PuppetEnvironmentBuilder::addQuick3D() const
{
// set env var if QtQuick3D import exists
QmlDesigner::Import import = QmlDesigner::Import::createLibraryImport("QtQuick3D", "1.0");
if (m_model.hasImport(import, true, true))
m_environment.set("QMLDESIGNER_QUICK3D_MODE", "true");
import = QmlDesigner::Import::createLibraryImport("QtQuick3D.Particles3D", "1.0");
if (m_model.hasImport(import, true, true))
m_environment.set("QMLDESIGNER_QUICK3D_PARTICLES3D_MODE", "true");
bool particlemode = m_designerSettings.value("particleMode").toBool();
if (!particlemode)
m_environment.set("QT_QUICK3D_DISABLE_PARTICLE_SYSTEMS", "1");
else
m_environment.set("QT_QUICK3D_EDITOR_PARTICLE_SYSTEMS", "1");
}
void PuppetEnvironmentBuilder::addForceQApplication() const
{
auto import = QmlDesigner::Import::createLibraryImport("QtCharts", "2.0");
if (m_model.hasImport(import, true, true)) {
m_environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true");
} else if (m_target) {
auto bs = qobject_cast<QmlProjectManager::QmlBuildSystem *>(m_target->buildSystem());
if (bs && bs->widgetApp())
m_environment.set("QMLDESIGNER_FORCE_QAPPLICATION", "true");
}
}
void PuppetEnvironmentBuilder::addMultiLanguageDatatbase() const
{
if (m_target) {
if (auto multiLanguageAspect = QmlProjectManager::QmlMultiLanguageAspect::current(m_target)) {
if (!multiLanguageAspect->databaseFilePath().isEmpty())
m_environment.set("QT_MULTILANGUAGE_DATABASE",
multiLanguageAspect->databaseFilePath().toString());
}
}
}
void PuppetEnvironmentBuilder::addImportPaths() const
{
QStringList importPaths = m_model.importPaths();
if (m_availablePuppetType == PuppetType::Fallback)
filterOutQtBaseImportPath(&importPaths);
if (m_target) {
QStringList designerImports = m_target->additionalData("QmlDesignerImportPath").toStringList();
importPaths.append(designerImports);
}
if (m_availablePuppetType == PuppetType::Fallback)
importPaths.prepend(QLibraryInfo::location(QLibraryInfo::Qml2ImportsPath));
constexpr auto pathSep = Utils::HostOsInfo::pathListSeparator();
m_environment.appendOrSet("QML2_IMPORT_PATH", importPaths.join(pathSep), pathSep);
qCInfo(puppetEnvirmentBuild) << "Puppet import paths:" << importPaths;
}
void PuppetEnvironmentBuilder::addCustomFileSelectors() const
{
QStringList customFileSelectors;
if (m_target)
customFileSelectors = m_target->additionalData("CustomFileSelectorsData").toStringList();
customFileSelectors.append("DesignMode");
constexpr auto pathSep = Utils::HostOsInfo::pathListSeparator();
if (!customFileSelectors.isEmpty())
m_environment.appendOrSet("QML_FILE_SELECTORS", customFileSelectors.join(","), pathSep);
qCInfo(puppetEnvirmentBuild) << "Puppet selectors:" << customFileSelectors;
}
PuppetType PuppetEnvironmentBuilder::determinePuppetType() const
{
if (m_target && m_target->kit() && m_target->kit()->isValid()) {
if (pathForBinPuppet(m_target).isExecutableFile())
return PuppetType::Kit;
}
return PuppetType::Fallback;
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
#include <utils/environment.h>
#include <QProcessEnvironment>
namespace ProjectExplorer {
class Target;
}
namespace QmlDesigner {
enum class PuppetType { Fallback, UserSpace, Kit };
class PuppetEnvironmentBuilder
{
public:
PuppetEnvironmentBuilder(ProjectExplorer::Target *target,
const class DesignerSettings &designerSettings,
const class Model &model)
: m_target(target)
, m_designerSettings(designerSettings)
, m_model(model)
{}
QProcessEnvironment processEnvironment() const;
private:
PuppetType determinePuppetType() const;
bool usesVirtualKeyboard() const;
QString getStyleConfigFileName() const;
void addKit() const;
void addRendering() const;
void addControls() const;
void addPixelRatio() const;
void addVirtualKeyboard() const;
void addQuick3D() const;
void addForceQApplication() const;
void addMultiLanguageDatatbase() const;
void addImportPaths() const;
void addCustomFileSelectors() const;
private:
ProjectExplorer::Target *m_target = nullptr;
const DesignerSettings &m_designerSettings;
const Model &m_model;
mutable PuppetType m_availablePuppetType = {};
mutable Utils::Environment m_environment;
};
} // namespace QmlDesigner

View File

@@ -225,6 +225,9 @@ function(extend_with_qmldesigner_core target_name)
instances/puppetbuildprogressdialog.h instances/puppetbuildprogressdialog.h
instances/puppetcreator.cpp instances/puppetcreator.cpp
instances/puppetcreator.h instances/puppetcreator.h
instances/puppetstarter.cpp
instances/puppetstarter.h
instances/puppetstartdata.h
instances/puppetdialog.cpp instances/puppetdialog.cpp
instances/puppetdialog.h instances/puppetdialog.h
instances/qprocessuniqueptr.h instances/qprocessuniqueptr.h