ProjectExplorer: Rework the build step run interface

Originally, the build manager used to run all build steps in a dedicated
thread. Communication between the step and the manager happened via a
QFutureInterface that was passed into the step's run() function.
Later, new steps were added that operated asynchronously, so the build
manager had to differentiate between the different kinds of steps for
starting and stopping.
These days, almost all build and deploy steps work asynchronously, which
made the QFuture-based interface look increasingly odd.
With this patch, all build steps are expected to work asynchronously, so
the build manager no longer needs to differentiate. Steps are started
and requested to stop via the run() and cancel() functions,
respectively, and emit the finished() signal when they are done. Build
step implementors no longer have to deal with a QFutureInterface. For
steps whose implementation is inherently synchronous, the BuildStep base
class offers a runInThread() function.

Change-Id: If905c68b234c5a669f6e19f43142eaa57d594803
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2019-01-25 14:26:34 +01:00
parent 536618b012
commit 966f4ea6a9
52 changed files with 355 additions and 399 deletions

View File

@@ -327,17 +327,18 @@ QString AndroidAvdManager::findAvd(const QString &avdName) const
return QString();
}
QString AndroidAvdManager::waitForAvd(const QString &avdName, const QFutureInterface<bool> &fi) const
QString AndroidAvdManager::waitForAvd(const QString &avdName,
const std::function<bool()> &cancelChecker) const
{
// we cannot use adb -e wait-for-device, since that doesn't work if a emulator is already running
// 60 rounds of 2s sleeping, two minutes for the avd to start
QString serialNumber;
for (int i = 0; i < 60; ++i) {
if (fi.isCanceled())
if (cancelChecker())
return QString();
serialNumber = findAvd(avdName);
if (!serialNumber.isEmpty())
return waitForBooted(serialNumber, fi) ? serialNumber : QString();
return waitForBooted(serialNumber, cancelChecker) ? serialNumber : QString();
QThread::sleep(2);
}
return QString();
@@ -358,11 +359,12 @@ bool AndroidAvdManager::isAvdBooted(const QString &device) const
return value == "stopped";
}
bool AndroidAvdManager::waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const
bool AndroidAvdManager::waitForBooted(const QString &serialNumber,
const std::function<bool()> &cancelChecker) const
{
// found a serial number, now wait until it's done booting...
for (int i = 0; i < 60; ++i) {
if (fi.isCanceled())
if (cancelChecker())
return false;
if (isAvdBooted(serialNumber)) {
return true;

View File

@@ -26,6 +26,7 @@
#include "androidconfigurations.h"
#include <functional>
#include <memory>
namespace Android {
@@ -51,11 +52,12 @@ public:
bool startAvdAsync(const QString &avdName) const;
QString findAvd(const QString &avdName) const;
QString waitForAvd(const QString &avdName,
const QFutureInterface<bool> &fi = QFutureInterface<bool>()) const;
const std::function<bool()> &cancelChecker = {}) const;
bool isAvdBooted(const QString &device) const;
private:
bool waitForBooted(const QString &serialNumber, const QFutureInterface<bool> &fi) const;
bool waitForBooted(const QString &serialNumber,
const std::function<bool()> &cancelChecker) const;
private:
const AndroidConfig &m_config;

View File

@@ -340,14 +340,14 @@ bool AndroidBuildApkStep::verifyCertificatePassword()
return success;
}
void AndroidBuildApkStep::run(QFutureInterface<bool> &fi)
void AndroidBuildApkStep::doRun()
{
if (m_skipBuilding) {
emit addOutput(tr("No application .pro file found, not building an APK."), BuildStep::OutputFormat::ErrorMessage);
reportRunResult(fi, true);
emit finished(true);
return;
}
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
void AndroidBuildApkStep::processStarted()

View File

@@ -86,7 +86,7 @@ private:
bool verifyKeystorePassword();
bool verifyCertificatePassword();
void run(QFutureInterface<bool> &fi) override;
void doRun() override;
bool m_signPackage = false;
bool m_verbose = false;

View File

@@ -298,7 +298,7 @@ bool AndroidDeployQtStep::init()
return true;
}
AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInterface<bool> &fi)
AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy()
{
QString args;
if (m_useAndroiddeployqt) {
@@ -386,7 +386,7 @@ AndroidDeployQtStep::DeployErrorCode AndroidDeployQtStep::runDeploy(QFutureInter
if (m_process->state() == QProcess::NotRunning)
break;
if (fi.isCanceled()) {
if (isCanceled()) {
m_process->kill();
m_process->waitForFinished();
}
@@ -472,25 +472,23 @@ void AndroidDeployQtStep::slotSetSerialNumber(const QString &serialNumber)
AndroidManager::setDeviceSerialNumber(target(), serialNumber);
}
void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
bool AndroidDeployQtStep::runImpl()
{
if (!m_avdName.isEmpty()) {
QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, fi);
QString serialNumber = AndroidAvdManager().waitForAvd(m_avdName, cancelChecker());
qCDebug(deployStepLog) << "Deploying to AVD:" << m_avdName << serialNumber;
if (serialNumber.isEmpty()) {
reportRunResult(fi, false);
return;
}
if (serialNumber.isEmpty())
return false;
m_serialNumber = serialNumber;
emit setSerialNumber(serialNumber);
}
DeployErrorCode returnValue = runDeploy(fi);
DeployErrorCode returnValue = runDeploy();
if (returnValue > DeployErrorCode::NoError && returnValue < DeployErrorCode::Failure) {
emit askForUninstall(returnValue);
if (m_askForUninstall) {
m_uninstallPreviousPackageRun = true;
returnValue = runDeploy(fi);
returnValue = runDeploy();
}
}
@@ -509,7 +507,7 @@ void AndroidDeployQtStep::run(QFutureInterface<bool> &fi)
}
}
reportRunResult(fi, returnValue == NoError);
return returnValue == NoError;
}
void AndroidDeployQtStep::gatherFilesToPull()
@@ -550,6 +548,11 @@ void AndroidDeployQtStep::gatherFilesToPull()
qCDebug(deployStepLog) << itr.key() << "to" << itr.value();
}
void AndroidDeployQtStep::doRun()
{
runInThread([this] { return runImpl(); });
}
void AndroidDeployQtStep::runCommand(const QString &program, const QStringList &arguments)
{
Utils::SynchronousProcess buildProc;

View File

@@ -84,12 +84,14 @@ private:
void runCommand(const QString &program, const QStringList &arguments);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
void doRun() override;
void gatherFilesToPull();
DeployErrorCode runDeploy(QFutureInterface<bool> &fi);
DeployErrorCode runDeploy();
void slotAskForUninstall(DeployErrorCode errorCode);
void slotSetSerialNumber(const QString &serialNumber);
bool runImpl();
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void processReadyReadStdOutput(DeployErrorCode &errorCode);

View File

@@ -95,7 +95,7 @@ bool AndroidPackageInstallationStep::init()
return AbstractProcessStep::init();
}
void AndroidPackageInstallationStep::run(QFutureInterface<bool> &fi)
void AndroidPackageInstallationStep::doRun()
{
QString error;
foreach (const QString &dir, m_androidDirsToClean) {
@@ -104,12 +104,12 @@ void AndroidPackageInstallationStep::run(QFutureInterface<bool> &fi)
emit addOutput(tr("Removing directory %1").arg(dir), OutputFormat::NormalMessage);
if (!FileUtils::removeRecursively(androidDir, &error)) {
emit addOutput(error, OutputFormat::Stderr);
reportRunResult(fi, false);
emit finished(false);
return;
}
}
}
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *AndroidPackageInstallationStep::createConfigWidget()

View File

@@ -40,13 +40,13 @@ class ANDROID_EXPORT AndroidPackageInstallationStep : public ProjectExplorer::Ab
public:
explicit AndroidPackageInstallationStep(ProjectExplorer::BuildStepList *bsl);
bool init() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void run(QFutureInterface<bool> &fi) override;
private:
bool init() override;
void doRun() override;
QStringList m_androidDirsToClean;
};

View File

@@ -86,7 +86,7 @@ bool AutogenStep::init()
return AbstractProcessStep::init();
}
void AutogenStep::run(QFutureInterface<bool> &fi)
void AutogenStep::doRun()
{
BuildConfiguration *bc = buildConfiguration();
@@ -104,12 +104,12 @@ void AutogenStep::run(QFutureInterface<bool> &fi)
if (!m_runAutogen) {
emit addOutput(tr("Configuration unchanged, skipping autogen step."), BuildStep::OutputFormat::NormalMessage);
reportRunResult(fi, true);
emit finished(true);
return;
}
m_runAutogen = false;
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *AutogenStep::createConfigWidget()

View File

@@ -66,11 +66,12 @@ class AutogenStep : public ProjectExplorer::AbstractProcessStep
public:
explicit AutogenStep(ProjectExplorer::BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
private:
bool init() override;
void doRun() override;
ProjectExplorer::BaseStringAspect *m_additionalArgumentsAspect = nullptr;
bool m_runAutogen = false;
};

View File

@@ -84,7 +84,7 @@ bool AutoreconfStep::init()
return AbstractProcessStep::init();
}
void AutoreconfStep::run(QFutureInterface<bool> &fi)
void AutoreconfStep::doRun()
{
BuildConfiguration *bc = buildConfiguration();
@@ -96,12 +96,12 @@ void AutoreconfStep::run(QFutureInterface<bool> &fi)
if (!m_runAutoreconf) {
emit addOutput(tr("Configuration unchanged, skipping autoreconf step."), BuildStep::OutputFormat::NormalMessage);
reportRunResult(fi, true);
emit finished(true);
return;
}
m_runAutoreconf = false;
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *AutoreconfStep::createConfigWidget()

View File

@@ -67,7 +67,7 @@ public:
explicit AutoreconfStep(ProjectExplorer::BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
private:

View File

@@ -105,7 +105,7 @@ bool ConfigureStep::init()
return AbstractProcessStep::init();
}
void ConfigureStep::run(QFutureInterface<bool>& fi)
void ConfigureStep::doRun()
{
BuildConfiguration *bc = buildConfiguration();
@@ -121,12 +121,12 @@ void ConfigureStep::run(QFutureInterface<bool>& fi)
if (!m_runConfigure) {
emit addOutput(tr("Configuration unchanged, skipping configure step."), BuildStep::OutputFormat::NormalMessage);
reportRunResult(fi, true);
emit finished(true);
return;
}
m_runConfigure = false;
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *ConfigureStep::createConfigWidget()

View File

@@ -67,14 +67,15 @@ class ConfigureStep : public ProjectExplorer::AbstractProcessStep
public:
explicit ConfigureStep(ProjectExplorer::BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void setAdditionalArguments(const QString &list);
void notifyBuildDirectoryChanged();
private:
bool init() override;
void doRun() override;
void updateDetails();
ProjectExplorer::BaseStringAspect *m_additionalArgumentsAspect = nullptr;

View File

@@ -66,12 +66,11 @@ BareMetalGdbCommandsDeployStep::BareMetalGdbCommandsDeployStep(BuildStepList *bs
: BuildStep(bsl, stepId())
{
setDefaultDisplayName(displayName());
setRunInGuiThread(true);
}
void BareMetalGdbCommandsDeployStep::run(QFutureInterface<bool> &fi)
void BareMetalGdbCommandsDeployStep::doRun()
{
reportRunResult(fi, true);
emit finished(true);
}
bool BareMetalGdbCommandsDeployStep::fromMap(const QVariantMap &map)

View File

@@ -40,9 +40,6 @@ class BareMetalGdbCommandsDeployStep : public ProjectExplorer::BuildStep
public:
explicit BareMetalGdbCommandsDeployStep(ProjectExplorer::BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
@@ -55,6 +52,9 @@ public:
QString gdbCommands() const;
private:
bool init() override;
void doRun() override;
QString m_gdbCommands;
};

View File

@@ -233,46 +233,47 @@ bool CMakeBuildStep::init()
return AbstractProcessStep::init();
}
void CMakeBuildStep::run(QFutureInterface<bool> &fi)
void CMakeBuildStep::doRun()
{
// Make sure CMake state was written to disk before trying to build:
CMakeBuildConfiguration *bc = cmakeBuildConfiguration();
QTC_ASSERT(bc, return);
bool mustDelay = false;
m_waiting = false;
auto p = static_cast<CMakeProject *>(bc->project());
if (p->persistCMakeState()) {
emit addOutput(tr("Persisting CMake state..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true;
m_waiting = true;
} else if (p->mustUpdateCMakeStateBeforeBuild()) {
emit addOutput(tr("Running CMake in preparation to build..."), BuildStep::OutputFormat::NormalMessage);
mustDelay = true;
} else {
mustDelay = false;
m_waiting = true;
}
if (mustDelay) {
if (m_waiting) {
m_runTrigger = connect(project(), &Project::parsingFinished,
this, [this, &fi](bool success) { handleProjectWasParsed(fi, success); });
this, [this](bool success) { handleProjectWasParsed(success); });
} else {
runImpl(fi);
runImpl();
}
}
void CMakeBuildStep::runImpl(QFutureInterface<bool> &fi)
void CMakeBuildStep::runImpl()
{
// Do the actual build:
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
void CMakeBuildStep::handleProjectWasParsed(QFutureInterface<bool> &fi, bool success)
void CMakeBuildStep::handleProjectWasParsed(bool success)
{
m_waiting = false;
disconnect(m_runTrigger);
if (success) {
runImpl(fi);
if (isCanceled()) {
emit finished(false);
} else if (success) {
runImpl();
} else {
AbstractProcessStep::stdError(tr("Project did not parse successfully, cannot build."));
reportRunResult(fi, false);
emit finished(false);
}
}
@@ -288,7 +289,7 @@ void CMakeBuildStep::stdOutput(const QString &line)
bool ok = false;
int percent = m_percentProgress.cap(1).toInt(&ok);
if (ok)
futureInterface()->setProgressValue(percent);
emit progress(percent, QString());
return;
} else if (m_ninjaProgress.indexIn(line) != -1) {
AbstractProcessStep::stdOutput(line);
@@ -299,7 +300,7 @@ void CMakeBuildStep::stdOutput(const QString &line)
int all = m_ninjaProgress.cap(2).toInt(&ok);
if (ok && all != 0) {
const int percent = static_cast<int>(100.0 * done/all);
futureInterface()->setProgressValue(percent);
emit progress(percent, QString());
}
}
return;
@@ -551,12 +552,11 @@ CMakeBuildStepFactory::CMakeBuildStepFactory()
void CMakeBuildStep::processStarted()
{
m_useNinja = false;
futureInterface()->setProgressRange(0, 100);
AbstractProcessStep::processStarted();
}
void CMakeBuildStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
AbstractProcessStep::processFinished(exitCode, status);
futureInterface()->setProgressValue(100);
emit progress(100, QString());
}

View File

@@ -56,11 +56,6 @@ public:
CMakeBuildConfiguration *cmakeBuildConfiguration() const;
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
QString buildTarget() const;
bool buildsBuildTarget(const QString &target) const;
void setBuildTarget(const QString &target);
@@ -98,8 +93,12 @@ protected:
private:
void ctor(ProjectExplorer::BuildStepList *bsl);
void runImpl(QFutureInterface<bool> &fi);
void handleProjectWasParsed(QFutureInterface<bool> &fi, bool success);
bool init() override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void runImpl();
void handleProjectWasParsed(bool success);
void handleBuildTargetChanges(bool success);
CMakeRunConfiguration *targetsActiveRunConfiguration() const;
@@ -112,6 +111,7 @@ private:
QString m_buildTarget;
QString m_toolArguments;
bool m_useNinja = false;
bool m_waiting = false;
};
class CMakeBuildStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget

View File

@@ -169,9 +169,9 @@ QString IosBuildStep::buildCommand() const
return QString("xcodebuild"); // add path?
}
void IosBuildStep::run(QFutureInterface<bool> &fi)
void IosBuildStep::doRun()
{
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *IosBuildStep::createConfigWidget()

View File

@@ -48,9 +48,6 @@ class IosBuildStep : public ProjectExplorer::AbstractProcessStep
public:
explicit IosBuildStep(ProjectExplorer::BuildStepList *parent);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void setBaseArguments(const QStringList &args);
void setExtraArguments(const QStringList &extraArgs);
@@ -60,6 +57,8 @@ public:
QString buildCommand() const;
private:
bool init() override;
void doRun() override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;

View File

@@ -58,7 +58,6 @@ IosDeployStep::IosDeployStep(BuildStepList *parent)
: BuildStep(parent, stepId())
{
setImmutable(true);
setRunInGuiThread(true);
updateDisplayNames();
connect(DeviceManager::instance(), &DeviceManager::updated,
this, &IosDeployStep::updateDisplayNames);
@@ -101,22 +100,19 @@ bool IosDeployStep::init()
return true;
}
void IosDeployStep::run(QFutureInterface<bool> &fi)
void IosDeployStep::doRun()
{
m_futureInterface = fi;
QTC_CHECK(m_transferStatus == NoTransfer);
if (device().isNull()) {
TaskHub::addTask(Task::Error, tr("Deployment failed. No iOS device found."),
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
reportRunResult(m_futureInterface, !iossimulator().isNull());
emit finished(!iossimulator().isNull());
cleanup();
return;
}
m_toolHandler = new IosToolHandler(m_deviceType, this);
m_transferStatus = TransferInProgress;
m_futureInterface.setProgressRange(0, 200);
m_futureInterface.setProgressValueAndText(0, QLatin1String("Transferring application"));
m_futureInterface.reportStarted();
emit progress(0, tr("Transferring application"));
connect(m_toolHandler, &IosToolHandler::isTransferringApp,
this, &IosDeployStep::handleIsTransferringApp);
connect(m_toolHandler, &IosToolHandler::didTransferApp,
@@ -129,7 +125,7 @@ void IosDeployStep::run(QFutureInterface<bool> &fi)
m_toolHandler->requestTransferApp(appBundle(), m_deviceType.identifier);
}
void IosDeployStep::cancel()
void IosDeployStep::doCancel()
{
if (m_toolHandler)
m_toolHandler->stop();
@@ -150,8 +146,7 @@ void IosDeployStep::handleIsTransferringApp(IosToolHandler *handler, const QStri
{
Q_UNUSED(handler); Q_UNUSED(bundlePath); Q_UNUSED(deviceId);
QTC_CHECK(m_transferStatus == TransferInProgress);
m_futureInterface.setProgressRange(0, maxProgress);
m_futureInterface.setProgressValueAndText(progress, info);
emit this->progress(progress * 100 / maxProgress, info);
}
void IosDeployStep::handleDidTransferApp(IosToolHandler *handler, const QString &bundlePath,
@@ -168,7 +163,7 @@ void IosDeployStep::handleDidTransferApp(IosToolHandler *handler, const QString
tr("Deployment failed. The settings in the Devices window of Xcode might be incorrect."),
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
}
reportRunResult(m_futureInterface, status == IosToolHandler::Success);
emit finished(status == IosToolHandler::Success);
}
void IosDeployStep::handleFinished(IosToolHandler *handler)
@@ -178,7 +173,7 @@ void IosDeployStep::handleFinished(IosToolHandler *handler)
m_transferStatus = TransferFailed;
TaskHub::addTask(Task::Error, tr("Deployment failed."),
ProjectExplorer::Constants::TASK_CATEGORY_DEPLOYMENT);
reportRunResult(m_futureInterface, false);
emit finished(false);
break;
case NoTransfer:
case TransferOk:

View File

@@ -32,7 +32,6 @@
#include <projectexplorer/buildstep.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <QFutureInterface>
#include <QProcess>
namespace Ios {
@@ -54,14 +53,13 @@ public:
explicit IosDeployStep(ProjectExplorer::BuildStepList *bc);
static Core::Id stepId();
void cleanup();
private:
void doRun() override;
void doCancel() override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
void run(QFutureInterface<bool> &fi) override;
void cleanup();
void cancel() override;
private:
void handleIsTransferringApp(Ios::IosToolHandler *handler, const QString &bundlePath,
const QString &deviceId, int progress, int maxProgress,
const QString &info);
@@ -85,7 +83,6 @@ private:
TransferStatus m_transferStatus = NoTransfer;
IosToolHandler *m_toolHandler = nullptr;
QFutureInterface<bool> m_futureInterface;
ProjectExplorer::IDevice::ConstPtr m_device;
QString m_bundlePath;
IosDeviceType m_deviceType;

View File

@@ -187,9 +187,9 @@ bool IosDsymBuildStep::isDefault() const
return arguments() == defaultArguments() && command() == defaultCommand();
}
void IosDsymBuildStep::run(QFutureInterface<bool> &fi)
void IosDsymBuildStep::doRun()
{
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *IosDsymBuildStep::createConfigWidget()

View File

@@ -42,9 +42,6 @@ class IosDsymBuildStep : public ProjectExplorer::AbstractProcessStep
public:
IosDsymBuildStep(ProjectExplorer::BuildStepList *parent);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void setArguments(const QStringList &args);
QStringList arguments() const;
@@ -54,10 +51,12 @@ public:
void setCommand(const QString &command);
bool isDefault() const;
QVariantMap toMap() const override;
private:
bool init() override;
void doRun() override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &map) override;
QStringList defaultCleanCmdList() const;
QStringList defaultCmdList() const;

View File

@@ -61,28 +61,33 @@ bool NimCompilerCleanStep::init()
return result;
}
void NimCompilerCleanStep::run(QFutureInterface<bool> &fi)
void NimCompilerCleanStep::doRun()
{
if (!m_buildDir.exists()) {
emit addOutput(tr("Build directory \"%1\" does not exist.").arg(m_buildDir.toUserOutput()), BuildStep::OutputFormat::ErrorMessage);
reportRunResult(fi, false);
emit finished(false);
return;
}
if (!removeCacheDirectory()) {
emit addOutput(tr("Failed to delete the cache directory."), BuildStep::OutputFormat::ErrorMessage);
reportRunResult(fi, false);
emit finished(false);
return;
}
if (!removeOutFilePath()) {
emit addOutput(tr("Failed to delete the out file."), BuildStep::OutputFormat::ErrorMessage);
reportRunResult(fi, false);
emit finished(false);
return;
}
emit addOutput(tr("Clean step completed successfully."), BuildStep::OutputFormat::NormalMessage);
reportRunResult(fi, true);
emit finished(true);
}
void NimCompilerCleanStep::doCancel()
{
// Can be left empty. The run() function hardly does anything.
}
bool NimCompilerCleanStep::removeCacheDirectory()

View File

@@ -39,10 +39,12 @@ public:
NimCompilerCleanStep(ProjectExplorer::BuildStepList *parentList);
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool init() override;
void run(QFutureInterface<bool> &fi) override;
private:
bool init() override;
void doRun() override;
void doCancel() override;
bool removeCacheDirectory();
bool removeOutFilePath();

View File

@@ -104,7 +104,6 @@ public:
Private(AbstractProcessStep *q) : q(q) {}
AbstractProcessStep *q;
QFutureInterface<bool> *m_futureInterface = nullptr;
std::unique_ptr<Utils::QtcProcess> m_process;
std::unique_ptr<IOutputParser> m_outputParserChain;
ProcessParameters m_param;
@@ -125,7 +124,6 @@ AbstractProcessStep::AbstractProcessStep(BuildStepList *bsl, Core::Id id) :
BuildStep(bsl, id),
d(new Private(this))
{
setRunInGuiThread(true);
}
AbstractProcessStep::~AbstractProcessStep()
@@ -209,7 +207,7 @@ bool AbstractProcessStep::init()
YourBuildStep::run().
*/
void AbstractProcessStep::run(QFutureInterface<bool> &fi)
void AbstractProcessStep::doRun()
{
QDir wd(d->m_param.effectiveWorkingDirectory());
if (!wd.exists()) {
@@ -217,7 +215,7 @@ void AbstractProcessStep::run(QFutureInterface<bool> &fi)
emit addOutput(tr("Could not create directory \"%1\"")
.arg(QDir::toNativeSeparators(wd.absolutePath())),
BuildStep::OutputFormat::ErrorMessage);
reportRunResult(fi, false);
finish(false);
return;
}
}
@@ -225,12 +223,10 @@ void AbstractProcessStep::run(QFutureInterface<bool> &fi)
QString effectiveCommand = d->m_param.effectiveCommand();
if (!QFileInfo::exists(effectiveCommand)) {
processStartupFailed();
reportRunResult(fi, false);
finish(false);
return;
}
d->m_futureInterface = &fi;
d->m_process.reset(new Utils::QtcProcess());
d->m_process->setUseCtrlCStub(Utils::HostOsInfo::isWindowsHost());
d->m_process->setWorkingDirectory(wd.absolutePath());
@@ -249,13 +245,13 @@ void AbstractProcessStep::run(QFutureInterface<bool> &fi)
processStartupFailed();
d->m_process.reset();
d->m_outputParserChain.reset();
reportRunResult(fi, false);
finish(false);
return;
}
processStarted();
}
void AbstractProcessStep::cancel()
void AbstractProcessStep::doCancel()
{
Core::Reaper::reap(d->m_process.release());
}
@@ -275,7 +271,7 @@ void AbstractProcessStep::cleanUp(QProcess *process)
d->m_process.reset();
// Report result
reportRunResult(*d->m_futureInterface, returnValue);
finish(returnValue);
}
/*!
@@ -420,9 +416,9 @@ void AbstractProcessStep::stdError(const QString &line)
emit addOutput(line, BuildStep::OutputFormat::Stderr, BuildStep::DontAppendNewline);
}
QFutureInterface<bool> *AbstractProcessStep::futureInterface() const
void AbstractProcessStep::finish(bool success)
{
return d->m_futureInterface;
emit finished(success);
}
void AbstractProcessStep::taskAdded(const Task &task, int linkedOutputLines, int skipLines)

View File

@@ -41,10 +41,6 @@ class PROJECTEXPLORER_EXPORT AbstractProcessStep : public BuildStep
Q_OBJECT
public:
bool init() override;
void run(QFutureInterface<bool> &) override;
void cancel() override;
ProcessParameters *processParameters();
bool ignoreReturnValue();
@@ -59,6 +55,8 @@ public:
protected:
AbstractProcessStep(BuildStepList *bsl, Core::Id id);
~AbstractProcessStep() override;
bool init() override;
void doRun() override;
virtual void processStarted();
virtual void processFinished(int exitCode, QProcess::ExitStatus status);
@@ -67,9 +65,11 @@ protected:
virtual void stdOutput(const QString &line);
virtual void stdError(const QString &line);
QFutureInterface<bool> *futureInterface() const;
void doCancel() override;
private:
virtual void finish(bool success);
void processReadyReadStdOutput();
void processReadyReadStdError();
void slotProcessFinished(int, QProcess::ExitStatus);

View File

@@ -79,9 +79,8 @@ public:
// is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling
bool m_skipDisabled = false;
bool m_canceling = false;
QFutureWatcher<bool> m_watcher;
QFutureInterface<bool> m_futureInterfaceForAysnc;
BuildStep *m_currentBuildStep;
bool m_lastStepSucceeded = true;
BuildStep *m_currentBuildStep = nullptr;
QString m_currentConfiguration;
// used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
QHash<Project *, int> m_activeBuildSteps;
@@ -107,16 +106,6 @@ BuildManager::BuildManager(QObject *parent, QAction *cancelBuildAction)
m_instance = this;
d = new BuildManagerPrivate;
connect(&d->m_watcher, &QFutureWatcherBase::finished,
this, &BuildManager::nextBuildQueue, Qt::QueuedConnection);
connect(&d->m_watcher, &QFutureWatcherBase::progressValueChanged,
this, &BuildManager::progressChanged);
connect(&d->m_watcher, &QFutureWatcherBase::progressTextChanged,
this, &BuildManager::progressTextChanged);
connect(&d->m_watcher, &QFutureWatcherBase::progressRangeChanged,
this, &BuildManager::progressChanged);
connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject,
this, &BuildManager::aboutToRemoveProject);
@@ -203,14 +192,9 @@ void BuildManager::cancel()
if (d->m_canceling)
return;
d->m_canceling = true;
d->m_watcher.cancel();
if (d->m_currentBuildStep->runInGuiThread()) {
d->m_currentBuildStep->cancel();
while (d->m_canceling)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} else {
d->m_watcher.waitForFinished();
}
d->m_currentBuildStep->cancel();
while (d->m_canceling)
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // TODO: Is this really necessary?
}
}
@@ -352,8 +336,6 @@ void BuildManager::addToOutputWindow(const QString &string, BuildStep::OutputFor
void BuildManager::nextBuildQueue()
{
d->m_futureInterfaceForAysnc = QFutureInterface<bool>();
d->m_outputWindow->flush();
if (d->m_canceling) {
d->m_canceling = false;
@@ -375,7 +357,7 @@ void BuildManager::nextBuildQueue()
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress));
decrementActiveBuildSteps(d->m_currentBuildStep);
const bool success = d->m_skipDisabled || d->m_watcher.result();
const bool success = d->m_skipDisabled || d->m_lastStepSucceeded;
if (success) {
nextStep();
} else {
@@ -397,28 +379,10 @@ void BuildManager::nextBuildQueue()
}
}
void BuildManager::progressChanged()
void BuildManager::progressChanged(int percent, const QString &text)
{
if (!d->m_progressFutureInterface)
return;
int range = d->m_watcher.progressMaximum() - d->m_watcher.progressMinimum();
if (range != 0) {
int percent = (d->m_watcher.progressValue() - d->m_watcher.progressMinimum()) * 100 / range;
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress * 100 + percent, msgProgress(d->m_progress, d->m_maxProgress)
+ QLatin1Char('\n') + d->m_watcher.progressText());
}
}
void BuildManager::progressTextChanged()
{
if (!d->m_progressFutureInterface)
return;
int range = d->m_watcher.progressMaximum() - d->m_watcher.progressMinimum();
int percent = 0;
if (range != 0)
percent = (d->m_watcher.progressValue() - d->m_watcher.progressMinimum()) * 100 / range;
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100 + percent, msgProgress(d->m_progress, d->m_maxProgress) +
QLatin1Char('\n') + d->m_watcher.progressText());
if (d->m_progressFutureInterface)
d->m_progressFutureInterface->setProgressValueAndText(percent, text);
}
void BuildManager::nextStep()
@@ -445,12 +409,16 @@ void BuildManager::nextStep()
return;
}
if (d->m_currentBuildStep->runInGuiThread()) {
d->m_watcher.setFuture(d->m_futureInterfaceForAysnc.future());
d->m_currentBuildStep->run(d->m_futureInterfaceForAysnc);
} else {
d->m_watcher.setFuture(Utils::runAsync(&BuildStep::run, d->m_currentBuildStep));
}
static const auto finishedHandler = [](bool success) {
d->m_lastStepSucceeded = success;
disconnect(d->m_currentBuildStep, nullptr, instance(), nullptr);
BuildManager::nextBuildQueue();
};
connect(d->m_currentBuildStep, &BuildStep::finished, instance(), finishedHandler,
Qt::QueuedConnection);
connect(d->m_currentBuildStep, &BuildStep::progress,
instance(), &BuildManager::progressChanged);
d->m_currentBuildStep->run();
} else {
d->m_running = false;
d->m_previousBuildStepProject = nullptr;

View File

@@ -85,8 +85,7 @@ private:
BuildStep::OutputNewlineSetting newlineSettings = BuildStep::DoAppendNewline);
static void nextBuildQueue();
static void progressChanged();
static void progressTextChanged();
static void progressChanged(int percent, const QString &text);
static void emitCancelMessage();
static void showBuildResults();
static void updateTaskCount();

View File

@@ -34,8 +34,11 @@
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <QFormLayout>
#include <QFutureWatcher>
#include <QPointer>
/*!
\class ProjectExplorer::BuildStep
@@ -127,6 +130,18 @@ BuildStep::BuildStep(BuildStepList *bsl, Core::Id id) :
expander->registerSubProvider([this] { return projectConfiguration()->macroExpander(); });
}
void BuildStep::run()
{
m_cancelFlag = false;
doRun();
}
void BuildStep::cancel()
{
m_cancelFlag = true;
doCancel();
}
BuildStepConfigWidget *BuildStep::createConfigWidget()
{
auto widget = new BuildStepConfigWidget(this);
@@ -218,25 +233,32 @@ void BuildStep::setWidgetExpandedByDefault(bool widgetExpandedByDefault)
immutable steps are run. The default implementation returns \c false.
*/
bool BuildStep::runInGuiThread() const
void BuildStep::runInThread(const std::function<bool()> &syncImpl)
{
return m_runInGuiThread;
m_runInGuiThread = false;
m_cancelFlag = false;
auto * const watcher = new QFutureWatcher<bool>(this);
connect(watcher, &QFutureWatcher<bool>::finished, this, [this, watcher] {
emit finished(watcher->result());
watcher->deleteLater();
});
watcher->setFuture(Utils::runAsync(syncImpl));
}
void BuildStep::setRunInGuiThread(bool runInGuiThread)
std::function<bool ()> BuildStep::cancelChecker() const
{
m_runInGuiThread = runInGuiThread;
return [step = QPointer<const BuildStep>(this)] { return step && step->isCanceled(); };
}
/*!
This function needs to be reimplemented only for build steps that return
\c false from runInGuiThread().
\sa runInGuiThread()
*/
void BuildStep::cancel()
bool BuildStep::isCanceled() const
{
// Do nothing
return m_cancelFlag;
}
void BuildStep::doCancel()
{
QTC_ASSERT(!m_runInGuiThread, qWarning() << "Build step" << displayName()
<< "neeeds to implement the doCancel() function");
}
void BuildStep::setEnabled(bool b)

View File

@@ -33,6 +33,9 @@
#include <QFutureInterface>
#include <QWidget>
#include <functional>
#include <memory>
namespace ProjectExplorer {
class BuildConfiguration;
@@ -54,11 +57,10 @@ protected:
public:
virtual bool init() = 0;
virtual void run(QFutureInterface<bool> &fi) = 0;
void run();
void cancel();
virtual BuildStepConfigWidget *createConfigWidget();
virtual void cancel();
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
@@ -88,9 +90,6 @@ public:
bool isImmutable() const { return m_immutable; }
void setImmutable(bool immutable) { m_immutable = immutable; }
bool runInGuiThread() const;
void setRunInGuiThread(bool runInGuiThread);
signals:
/// Adds a \p task to the Issues pane.
/// Do note that for linking compile output with tasks, you should first emit the task
@@ -104,11 +103,24 @@ signals:
void enabledChanged();
void progress(int percentage, const QString &message);
void finished(bool result);
protected:
void runInThread(const std::function<bool()> &syncImpl);
std::function<bool()> cancelChecker() const;
bool isCanceled() const;
private:
virtual void doRun() = 0;
virtual void doCancel();
std::atomic_bool m_cancelFlag;
bool m_enabled = true;
bool m_immutable = false;
bool m_widgetExpandedByDefault = true;
bool m_runInGuiThread = false;
bool m_runInGuiThread = true;
};
class PROJECTEXPLORER_EXPORT BuildStepInfo

View File

@@ -77,9 +77,9 @@ bool DeviceCheckBuildStep::init()
return true;
}
void DeviceCheckBuildStep::run(QFutureInterface<bool> &fi)
void DeviceCheckBuildStep::doRun()
{
reportRunResult(fi, true);
emit finished(true);
}
Core::Id DeviceCheckBuildStep::stepId()

View File

@@ -39,7 +39,7 @@ public:
explicit DeviceCheckBuildStep(BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
void doRun() override;
static Core::Id stepId();
static QString displayName();

View File

@@ -71,9 +71,9 @@ bool ProcessStep::init()
return AbstractProcessStep::init();
}
void ProcessStep::run(QFutureInterface<bool> & fi)
void ProcessStep::doRun()
{
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
BuildStepConfigWidget *ProcessStep::createConfigWidget()

View File

@@ -45,9 +45,6 @@ class ProcessStep : public AbstractProcessStep
public:
explicit ProcessStep(BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &) override;
BuildStepConfigWidget *createConfigWidget() override;
QString command() const;
@@ -58,9 +55,10 @@ public:
void setArguments(const QString &arguments);
void setWorkingDirectory(const QString &workingDirectory);
QVariantMap toMap() const override;
private:
bool init() override;
void doRun() override;
QVariantMap toMap() const override;
bool fromMap(const QVariantMap &map) override;
QString m_command;

View File

@@ -127,14 +127,13 @@ QbsBuildStep::QbsBuildStep(ProjectExplorer::BuildStepList *bsl) :
{
setDisplayName(tr("Qbs Build"));
setQbsConfiguration(QVariantMap());
setRunInGuiThread(true);
// setQbsConfiguration(other->qbsConfiguration(PreserveVariables));
}
QbsBuildStep::~QbsBuildStep()
{
cancel();
doCancel();
if (m_job) {
m_job->deleteLater();
m_job = nullptr;
@@ -171,10 +170,8 @@ bool QbsBuildStep::init()
return true;
}
void QbsBuildStep::run(QFutureInterface<bool> &fi)
void QbsBuildStep::doRun()
{
m_fi = &fi;
// We need a pre-build parsing step in order not to lose project file changes done
// right before building (but before the delay has elapsed).
parseProject();
@@ -185,7 +182,7 @@ ProjectExplorer::BuildStepConfigWidget *QbsBuildStep::createConfigWidget()
return new QbsBuildStepConfigWidget(this);
}
void QbsBuildStep::cancel()
void QbsBuildStep::doCancel()
{
if (m_parsingProject)
qbsProject()->cancelParsing();
@@ -354,17 +351,14 @@ void QbsBuildStep::reparsingDone(bool success)
void QbsBuildStep::handleTaskStarted(const QString &desciption, int max)
{
Q_UNUSED(desciption);
QTC_ASSERT(m_fi, return);
m_progressBase = m_fi->progressValue();
m_fi->setProgressRange(0, m_progressBase + max);
m_currentTask = desciption;
m_maxProgress = max;
}
void QbsBuildStep::handleProgress(int value)
{
QTC_ASSERT(m_fi, return);
m_fi->setProgressValue(m_progressBase + value);
if (m_maxProgress > 0)
emit progress(value * 100 / m_maxProgress, m_currentTask);
}
void QbsBuildStep::handleCommandDescriptionReport(const QString &highlight, const QString &message)
@@ -489,11 +483,11 @@ void QbsBuildStep::build()
m_job = qbsProject()->build(options, m_products, error);
if (!m_job) {
emit addOutput(error, OutputFormat::ErrorMessage);
reportRunResult(*m_fi, false);
emit finished(false);
return;
}
m_progressBase = 0;
m_maxProgress = 0;
connect(m_job, &qbs::AbstractJob::finished, this, &QbsBuildStep::buildingDone);
connect(m_job, &qbs::AbstractJob::taskStarted,
@@ -509,9 +503,7 @@ void QbsBuildStep::build()
void QbsBuildStep::finish()
{
QTC_ASSERT(m_fi, return);
reportRunResult(*m_fi, m_lastWasSuccess);
m_fi = nullptr; // do not delete, it is not ours
emit finished(m_lastWasSuccess);
if (m_job) {
m_job->deleteLater();
m_job = nullptr;

View File

@@ -58,13 +58,6 @@ public:
explicit QbsBuildStep(ProjectExplorer::BuildStepList *bsl);
~QbsBuildStep() override;
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void cancel() override;
QVariantMap qbsConfiguration(VariableHandling variableHandling) const;
void setQbsConfiguration(const QVariantMap &config);
@@ -91,6 +84,10 @@ signals:
void qbsBuildOptionsChanged();
private:
bool init() override;
void doRun() override;
void doCancel() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
@@ -129,9 +126,9 @@ private:
QStringList m_activeFileTags;
QStringList m_products;
QFutureInterface<bool> *m_fi;
qbs::BuildJob *m_job = nullptr;
int m_progressBase;
QString m_currentTask;
int m_maxProgress;
bool m_lastWasSuccess;
ProjectExplorer::IOutputParser *m_parser = nullptr;
bool m_parsingProject = false;

View File

@@ -49,7 +49,6 @@ QbsCleanStep::QbsCleanStep(ProjectExplorer::BuildStepList *bsl) :
ProjectExplorer::BuildStep(bsl, Constants::QBS_CLEANSTEP_ID)
{
setDisplayName(tr("Qbs Clean"));
setRunInGuiThread(true);
m_dryRunAspect = addAspect<BaseBoolAspect>();
m_dryRunAspect->setSettingsKey("Qbs.DryRun");
@@ -75,7 +74,7 @@ QbsCleanStep::QbsCleanStep(ProjectExplorer::BuildStepList *bsl) :
QbsCleanStep::~QbsCleanStep()
{
cancel();
doCancel();
if (m_job) {
m_job->deleteLater();
m_job = nullptr;
@@ -96,10 +95,8 @@ bool QbsCleanStep::init()
return true;
}
void QbsCleanStep::run(QFutureInterface<bool> &fi)
void QbsCleanStep::doRun()
{
m_fi = &fi;
auto pro = static_cast<QbsProject *>(project());
qbs::CleanOptions options;
options.setDryRun(m_dryRunAspect->value());
@@ -109,11 +106,11 @@ void QbsCleanStep::run(QFutureInterface<bool> &fi)
m_job = pro->clean(options, m_products, error);
if (!m_job) {
emit addOutput(error, OutputFormat::ErrorMessage);
reportRunResult(*m_fi, false);
emit finished(false);
return;
}
m_progressBase = 0;
m_maxProgress = 0;
connect(m_job, &qbs::AbstractJob::finished, this, &QbsCleanStep::cleaningDone);
connect(m_job, &qbs::AbstractJob::taskStarted,
@@ -131,7 +128,7 @@ ProjectExplorer::BuildStepConfigWidget *QbsCleanStep::createConfigWidget()
return w;
}
void QbsCleanStep::cancel()
void QbsCleanStep::doCancel()
{
if (m_job)
m_job->cancel();
@@ -145,9 +142,7 @@ void QbsCleanStep::cleaningDone(bool success)
item.codeLocation().filePath(), item.codeLocation().line());
}
QTC_ASSERT(m_fi, return);
reportRunResult(*m_fi, success);
m_fi = nullptr; // do not delete, it is not ours
emit finished(success);
m_job->deleteLater();
m_job = nullptr;
}
@@ -155,15 +150,13 @@ void QbsCleanStep::cleaningDone(bool success)
void QbsCleanStep::handleTaskStarted(const QString &desciption, int max)
{
Q_UNUSED(desciption);
QTC_ASSERT(m_fi, return);
m_progressBase = m_fi->progressValue();
m_fi->setProgressRange(0, m_progressBase + max);
m_maxProgress = max;
}
void QbsCleanStep::handleProgress(int value)
{
QTC_ASSERT(m_fi, return);
m_fi->setProgressValue(m_progressBase + value);
if (m_maxProgress > 0)
emit progress(value * 100 / m_maxProgress, m_description);
}
void QbsCleanStep::updateState()

View File

@@ -44,13 +44,6 @@ public:
explicit QbsCleanStep(ProjectExplorer::BuildStepList *bsl);
~QbsCleanStep() override;
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void cancel() override;
bool dryRun() const { return m_dryRunAspect->value(); }
bool keepGoing() const { return m_keepGoingAspect->value(); }
@@ -58,6 +51,11 @@ signals:
void stateChanged();
private:
bool init() override;
void doRun() override;
void doCancel() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void cleaningDone(bool success);
void handleTaskStarted(const QString &desciption, int max);
void handleProgress(int value);
@@ -72,9 +70,9 @@ private:
QStringList m_products;
QFutureInterface<bool> *m_fi = nullptr;
qbs::CleanJob *m_job = nullptr;
int m_progressBase;
QString m_description;
int m_maxProgress;
bool m_showCompilerOutput = true;
ProjectExplorer::IOutputParser *m_parser = nullptr;
};

View File

@@ -61,7 +61,6 @@ QbsInstallStep::QbsInstallStep(ProjectExplorer::BuildStepList *bsl) :
ProjectExplorer::BuildStep(bsl, Constants::QBS_INSTALLSTEP_ID)
{
setDisplayName(tr("Qbs Install"));
setRunInGuiThread(true);
const QbsBuildConfiguration * const bc = buildConfig();
connect(bc, &QbsBuildConfiguration::qbsConfigurationChanged,
@@ -74,7 +73,7 @@ QbsInstallStep::QbsInstallStep(ProjectExplorer::BuildStepList *bsl) :
QbsInstallStep::~QbsInstallStep()
{
cancel();
doCancel();
if (m_job)
m_job->deleteLater();
m_job = nullptr;
@@ -86,19 +85,17 @@ bool QbsInstallStep::init()
return true;
}
void QbsInstallStep::run(QFutureInterface<bool> &fi)
void QbsInstallStep::doRun()
{
m_fi = &fi;
auto pro = static_cast<QbsProject *>(project());
m_job = pro->install(m_qbsInstallOptions);
if (!m_job) {
reportRunResult(*m_fi, false);
emit finished(false);
return;
}
m_progressBase = 0;
m_maxProgress = 0;
connect(m_job, &qbs::AbstractJob::finished, this, &QbsInstallStep::installDone);
connect(m_job, &qbs::AbstractJob::taskStarted,
@@ -112,7 +109,7 @@ ProjectExplorer::BuildStepConfigWidget *QbsInstallStep::createConfigWidget()
return new QbsInstallStepConfigWidget(this);
}
void QbsInstallStep::cancel()
void QbsInstallStep::doCancel()
{
if (m_job)
m_job->cancel();
@@ -180,25 +177,21 @@ void QbsInstallStep::installDone(bool success)
item.codeLocation().filePath(), item.codeLocation().line());
}
QTC_ASSERT(m_fi, return);
reportRunResult(*m_fi, success);
m_fi = nullptr; // do not delete, it is not ours
emit finished(success);
m_job->deleteLater();
m_job = nullptr;
}
void QbsInstallStep::handleTaskStarted(const QString &desciption, int max)
{
Q_UNUSED(desciption);
QTC_ASSERT(m_fi, return);
m_progressBase = m_fi->progressValue();
m_fi->setProgressRange(0, m_progressBase + max);
m_description = desciption;
m_maxProgress = max;
}
void QbsInstallStep::handleProgress(int value)
{
QTC_ASSERT(m_fi, return);
m_fi->setProgressValue(m_progressBase + value);
if (m_maxProgress > 0)
emit progress(value * 100 / m_maxProgress, m_description);
}
void QbsInstallStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type,

View File

@@ -45,16 +45,6 @@ public:
explicit QbsInstallStep(ProjectExplorer::BuildStepList *bsl);
~QbsInstallStep() override;
bool init() override;
void run(QFutureInterface<bool> &fi) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void cancel() override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
qbs::InstallOptions installOptions() const;
QString installRoot() const;
bool removeFirst() const;
@@ -65,6 +55,13 @@ signals:
void changed();
private:
bool init() override;
void doRun() override;
void doCancel() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
const QbsBuildConfiguration *buildConfig() const;
void installDone(bool success);
void handleTaskStarted(const QString &desciption, int max);
@@ -80,9 +77,9 @@ private:
qbs::InstallOptions m_qbsInstallOptions;
QFutureInterface<bool> *m_fi = nullptr;
qbs::InstallJob *m_job = nullptr;
int m_progressBase;
QString m_description;
int m_maxProgress;
bool m_showCompilerOutput = true;
ProjectExplorer::IOutputParser *m_parser = nullptr;

View File

@@ -172,10 +172,10 @@ bool QmakeMakeStep::init()
return AbstractProcessStep::init();
}
void QmakeMakeStep::run(QFutureInterface<bool> & fi)
void QmakeMakeStep::doRun()
{
if (m_scriptTarget) {
reportRunResult(fi, true);
emit finished(true);
return;
}
@@ -183,11 +183,11 @@ void QmakeMakeStep::run(QFutureInterface<bool> & fi)
if (!ignoreReturnValue())
emit addOutput(tr("Cannot find Makefile. Check your build settings."), BuildStep::OutputFormat::NormalMessage);
const bool success = ignoreReturnValue();
reportRunResult(fi, success);
emit finished(success);
return;
}
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
///

View File

@@ -55,7 +55,7 @@ public:
QmakeBuildConfiguration *qmakeBuildConfiguration() const;
bool init() override;
void run(QFutureInterface<bool> &) override;
void doRun() override;
private:
bool m_scriptTarget = false;

View File

@@ -77,13 +77,6 @@ QMakeStep::QMakeStep(BuildStepList *bsl) : AbstractProcessStep(bsl, QMAKE_BS_ID)
{
//: QMakeStep default display name
setDefaultDisplayName(tr("qmake"));
connect(&m_inputWatcher, &QFutureWatcher<bool>::canceled,
this, [this]() {
if (m_commandFuture)
m_commandFuture->cancel();
});
connect(&m_commandWatcher, &QFutureWatcher<bool>::finished, this, &QMakeStep::runNextCommand);
}
QmakeBuildConfiguration *QMakeStep::qmakeBuildConfiguration() const
@@ -172,9 +165,6 @@ QMakeStepConfig QMakeStep::deducedArguments() const
bool QMakeStep::init()
{
if (m_commandFuture)
return false;
QmakeBuildConfiguration *qmakeBc = qmakeBuildConfiguration();
const BaseQtVersion *qtVersion = QtKitInformation::qtVersion(target()->kit());
@@ -262,21 +252,16 @@ bool QMakeStep::init()
return AbstractProcessStep::init();
}
void QMakeStep::run(QFutureInterface<bool> &fi)
void QMakeStep::doRun()
{
m_inputFuture = fi;
m_inputWatcher.setFuture(m_inputFuture.future());
fi.setProgressRange(0, static_cast<int>(State::POST_PROCESS));
fi.setProgressValue(0);
if (m_scriptTemplate) {
reportRunResult(fi, true);
emit finished(true);
return;
}
if (!m_needToRunQMake) {
emit addOutput(tr("Configuration unchanged, skipping qmake step."), BuildStep::OutputFormat::NormalMessage);
reportRunResult(fi, true);
emit finished(true);
return;
}
@@ -312,6 +297,17 @@ bool QMakeStep::processSucceeded(int exitCode, QProcess::ExitStatus status)
return result;
}
void QMakeStep::doCancel()
{
AbstractProcessStep::doCancel();
}
void QMakeStep::finish(bool success)
{
m_wasSuccess = success;
runNextCommand();
}
void QMakeStep::startOneCommand(const QString &command, const QString &args)
{
ProcessParameters *pp = processParameters();
@@ -319,31 +315,19 @@ void QMakeStep::startOneCommand(const QString &command, const QString &args)
pp->setArguments(args);
pp->resolveAll();
QTC_ASSERT(!m_commandFuture || m_commandFuture->future().isFinished(), return);
m_commandFuture.reset(new QFutureInterface<bool>);
m_commandWatcher.setFuture(m_commandFuture->future());
AbstractProcessStep::run(*m_commandFuture);
AbstractProcessStep::doRun();
}
void QMakeStep::runNextCommand()
{
bool wasSuccess = true;
if (m_commandFuture) {
if (m_commandFuture->isCanceled())
wasSuccess = false;
else if (m_commandFuture->isFinished())
wasSuccess = m_commandFuture->future().result();
else
wasSuccess = false; // should not happen
}
if (isCanceled())
m_wasSuccess = false;
m_commandFuture.reset();
if (!wasSuccess)
if (!m_wasSuccess)
m_nextState = State::POST_PROCESS;
m_inputFuture.setProgressValue(static_cast<int>(m_nextState));
emit progress(static_cast<int>(m_nextState) * 100 / static_cast<int>(State::POST_PROCESS),
QString());
switch (m_nextState) {
case State::IDLE:
@@ -364,8 +348,7 @@ void QMakeStep::runNextCommand()
return;
case State::POST_PROCESS:
m_nextState = State::IDLE;
reportRunResult(m_inputFuture, wasSuccess);
m_inputFuture = QFutureInterface<bool>();
emit finished(m_wasSuccess);
return;
}
}

View File

@@ -29,7 +29,6 @@
#include <projectexplorer/abstractprocessstep.h>
#include <QStringList>
#include <QFutureWatcher>
#include <memory>
@@ -116,7 +115,7 @@ public:
QmakeBuildConfiguration *qmakeBuildConfiguration() const;
bool init() override;
void run(QFutureInterface<bool> &) override;
void doRun() override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
void setForced(bool b);
@@ -165,6 +164,9 @@ protected:
bool processSucceeded(int exitCode, QProcess::ExitStatus status) override;
private:
void doCancel() override;
void finish(bool success) override;
void startOneCommand(const QString &command, const QString &args);
void runNextCommand();
@@ -176,13 +178,9 @@ private:
// Extra arguments for qmake.
QStringList m_extraArgs;
QFutureInterface<bool> m_inputFuture;
QFutureWatcher<bool> m_inputWatcher;
std::unique_ptr<QFutureInterface<bool>> m_commandFuture;
QFutureWatcher<bool> m_commandWatcher;
// last values
enum class State { IDLE = 0, RUN_QMAKE, RUN_MAKE_QMAKE_ALL, POST_PROCESS };
bool m_wasSuccess = true;
State m_nextState = State::IDLE;
bool m_forced = false;
bool m_needToRunQMake = false; // set in init(), read in run()

View File

@@ -40,7 +40,6 @@ class AbstractRemoteLinuxDeployStepPrivate
{
public:
bool hasError;
QFutureInterface<bool> future;
};
} // namespace Internal
@@ -48,7 +47,6 @@ public:
AbstractRemoteLinuxDeployStep::AbstractRemoteLinuxDeployStep(BuildStepList *bsl, Core::Id id)
: BuildStep(bsl, id), d(new Internal::AbstractRemoteLinuxDeployStepPrivate)
{
setRunInGuiThread(true);
}
AbstractRemoteLinuxDeployStep::~AbstractRemoteLinuxDeployStep()
@@ -79,7 +77,7 @@ bool AbstractRemoteLinuxDeployStep::init()
return canDeploy;
}
void AbstractRemoteLinuxDeployStep::run(QFutureInterface<bool> &fi)
void AbstractRemoteLinuxDeployStep::doRun()
{
connect(deployService(), &AbstractRemoteLinuxDeployService::errorMessage,
this, &AbstractRemoteLinuxDeployStep::handleErrorMessage);
@@ -95,11 +93,10 @@ void AbstractRemoteLinuxDeployStep::run(QFutureInterface<bool> &fi)
this, &AbstractRemoteLinuxDeployStep::handleFinished);
d->hasError = false;
d->future = fi;
deployService()->start();
}
void AbstractRemoteLinuxDeployStep::cancel()
void AbstractRemoteLinuxDeployStep::doCancel()
{
if (d->hasError)
return;
@@ -139,7 +136,7 @@ void AbstractRemoteLinuxDeployStep::handleFinished()
else
emit addOutput(tr("Deploy step finished."), OutputFormat::NormalMessage);
disconnect(deployService(), nullptr, this, nullptr);
reportRunResult(d->future, !d->hasError);
emit finished(!d->hasError);
}
void AbstractRemoteLinuxDeployStep::handleStdOutData(const QString &data)

View File

@@ -42,15 +42,15 @@ class REMOTELINUX_EXPORT AbstractRemoteLinuxDeployStep : public ProjectExplorer:
public:
~AbstractRemoteLinuxDeployStep() override;
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
bool init() override;
void run(QFutureInterface<bool> &fi) override;
void cancel() override;
virtual AbstractRemoteLinuxDeployService *deployService() const = 0;
protected:
bool fromMap(const QVariantMap &map) override;
QVariantMap toMap() const override;
bool init() override;
void doRun() override;
void doCancel() override;
explicit AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, Core::Id id);
virtual bool initInternal(QString *error = nullptr) = 0;

View File

@@ -94,32 +94,9 @@ bool TarPackageCreationStep::init()
return true;
}
void TarPackageCreationStep::run(QFutureInterface<bool> &fi)
void TarPackageCreationStep::doRun()
{
setPackagingStarted();
const QList<DeployableFile> &files = target()->deploymentData().allFiles();
if (m_incrementalDeploymentAspect->value()) {
m_files.clear();
for (const DeployableFile &file : files)
addNeededDeploymentFiles(file, target()->kit());
} else {
m_files = files;
}
const bool success = doPackage(fi);
setPackagingFinished(success);
if (success)
emit addOutput(tr("Packaging finished successfully."), OutputFormat::NormalMessage);
else
emit addOutput(tr("Packaging failed."), OutputFormat::ErrorMessage);
connect(BuildManager::instance(), &BuildManager::buildQueueFinished,
this, &TarPackageCreationStep::deployFinished);
reportRunResult(fi, success);
runInThread([this] { return runImpl(); });
}
void TarPackageCreationStep::addNeededDeploymentFiles(
@@ -151,7 +128,7 @@ void TarPackageCreationStep::addNeededDeploymentFiles(
}
}
bool TarPackageCreationStep::doPackage(QFutureInterface<bool> &fi)
bool TarPackageCreationStep::doPackage()
{
emit addOutput(tr("Creating tarball..."), OutputFormat::NormalMessage);
if (!m_packagingNeeded) {
@@ -176,7 +153,7 @@ bool TarPackageCreationStep::doPackage(QFutureInterface<bool> &fi)
}
QFileInfo fileInfo = d.localFilePath().toFileInfo();
if (!appendFile(tarFile, fileInfo, d.remoteDirectory() + QLatin1Char('/')
+ fileInfo.fileName(), fi)) {
+ fileInfo.fileName())) {
return false;
}
}
@@ -192,7 +169,7 @@ bool TarPackageCreationStep::doPackage(QFutureInterface<bool> &fi)
}
bool TarPackageCreationStep::appendFile(QFile &tarFile, const QFileInfo &fileInfo,
const QString &remoteFilePath, const QFutureInterface<bool> &fi)
const QString &remoteFilePath)
{
if (!writeHeader(tarFile, fileInfo, remoteFilePath))
return false;
@@ -202,7 +179,7 @@ bool TarPackageCreationStep::appendFile(QFile &tarFile, const QFileInfo &fileInf
dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)) {
const QString thisLocalFilePath = dir.path() + QLatin1Char('/') + fileName;
const QString thisRemoteFilePath = remoteFilePath + QLatin1Char('/') + fileName;
if (!appendFile(tarFile, QFileInfo(thisLocalFilePath), thisRemoteFilePath, fi))
if (!appendFile(tarFile, QFileInfo(thisLocalFilePath), thisRemoteFilePath))
return false;
}
return true;
@@ -231,7 +208,7 @@ bool TarPackageCreationStep::appendFile(QFile &tarFile, const QFileInfo &fileInf
while (!file.atEnd() && file.error() == QFile::NoError && tarFile.error() == QFile::NoError) {
const QByteArray data = file.read(chunkSize);
tarFile.write(data);
if (fi.isCanceled())
if (isCanceled())
return false;
}
if (file.error() != QFile::NoError) {
@@ -339,6 +316,34 @@ QString TarPackageCreationStep::packageFileName() const
return project()->displayName() + QLatin1String(".tar");
}
bool TarPackageCreationStep::runImpl()
{
setPackagingStarted();
const QList<DeployableFile> &files = target()->deploymentData().allFiles();
if (m_incrementalDeploymentAspect->value()) {
m_files.clear();
for (const DeployableFile &file : files)
addNeededDeploymentFiles(file, target()->kit());
} else {
m_files = files;
}
const bool success = doPackage();
setPackagingFinished(success);
if (success)
emit addOutput(tr("Packaging finished successfully."), OutputFormat::NormalMessage);
else
emit addOutput(tr("Packaging failed."), OutputFormat::ErrorMessage);
connect(BuildManager::instance(), &BuildManager::buildQueueFinished,
this, &TarPackageCreationStep::deployFinished);
return success;
}
BuildStepConfigWidget *TarPackageCreationStep::createConfigWidget()
{
auto widget = BuildStep::createConfigWidget();

View File

@@ -48,9 +48,6 @@ public:
static Core::Id stepId();
static QString displayName();
bool init() override;
void run(QFutureInterface<bool> &fi) override;
void setIgnoreMissingFiles(bool ignoreMissingFiles);
bool ignoreMissingFiles() const;
@@ -58,6 +55,9 @@ public:
bool isIncrementalDeployment() const;
private:
bool init() override;
void doRun() override;
void deployFinished(bool success);
void addNeededDeploymentFiles(const ProjectExplorer::DeployableFile &deployable,
@@ -69,9 +69,10 @@ private:
QString packageFileName() const override;
bool doPackage(QFutureInterface<bool> &fi);
bool runImpl();
bool doPackage();
bool appendFile(QFile &tarFile, const QFileInfo &fileInfo,
const QString &remoteFilePath, const QFutureInterface<bool> &fi);
const QString &remoteFilePath);
bool writeHeader(QFile &tarFile, const QFileInfo &fileInfo,
const QString &remoteFilePath);

View File

@@ -114,7 +114,7 @@ bool WinRtPackageDeploymentStep::init()
return AbstractProcessStep::init();
}
void WinRtPackageDeploymentStep::run(QFutureInterface<bool> &fi)
void WinRtPackageDeploymentStep::doRun()
{
const QtSupport::BaseQtVersion *qt = QtSupport::QtKitInformation::qtVersion(target()->kit());
if (!qt)
@@ -143,7 +143,7 @@ void WinRtPackageDeploymentStep::run(QFutureInterface<bool> &fi)
}
}
AbstractProcessStep::run(fi);
AbstractProcessStep::doRun();
}
bool WinRtPackageDeploymentStep::processSucceeded(int exitCode, QProcess::ExitStatus status)

View File

@@ -38,18 +38,18 @@ class WinRtPackageDeploymentStep : public ProjectExplorer::AbstractProcessStep
public:
explicit WinRtPackageDeploymentStep(ProjectExplorer::BuildStepList *bsl);
bool init() override;
void run(QFutureInterface<bool> &fi) override;
bool processSucceeded(int exitCode, QProcess::ExitStatus status) override;
void stdOutput(const QString &line) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
QString defaultWinDeployQtArguments() const;
void raiseError(const QString &errorMessage);
void raiseWarning(const QString &warningMessage);
private:
bool init() override;
void doRun() override;
bool processSucceeded(int exitCode, QProcess::ExitStatus status) override;
void stdOutput(const QString &line) override;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget() override;
bool parseIconsAndExecutableFromManifest(QString manifestFileName, QStringList *items, QString *executable);
ProjectExplorer::BaseStringAspect *m_argsAspect = nullptr;