QbsBuildStep: Employ task tree for running

Task-number: QTCREATORBUG-29168
Change-Id: I508b7951f53f25f7cfd3e7f7e80086281cc7168e
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Jarek Kobus
2023-07-15 08:28:14 +02:00
parent 8423d2b5e5
commit e87a131c37
4 changed files with 107 additions and 230 deletions

View File

@@ -138,10 +138,6 @@ QbsBuildConfiguration::QbsBuildConfiguration(Target *target, Utils::Id id)
QbsBuildConfiguration::~QbsBuildConfiguration()
{
for (BuildStep * const bs : buildSteps()->steps()) {
if (const auto qbs = qobject_cast<QbsBuildStep *>(bs))
qbs->dropSession();
}
delete m_buildSystem;
}

View File

@@ -7,35 +7,29 @@
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"
#include "qbsprojectmanagertr.h"
#include "qbsrequest.h"
#include "qbssession.h"
#include "qbssettings.h"
#include <coreplugin/icore.h>
#include <projectexplorer/buildsteplist.h>
#include <projectexplorer/kit.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorertr.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtkitinformation.h>
#include <qtsupport/qtversionmanager.h>
#include <utils/algorithm.h>
#include <utils/aspects.h>
#include <utils/guard.h>
#include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/outputformatter.h>
#include <utils/pathchooser.h>
#include <utils/process.h>
#include <utils/qtcassert.h>
#include <utils/variablechooser.h>
#include <QCheckBox>
#include <QJsonArray>
#include <QJsonObject>
#include <QLabel>
#include <QThread>
// --------------------------------------------------------------------
@@ -51,10 +45,43 @@ const char QBS_CLEAN_INSTALL_ROOT[] = "Qbs.CleanInstallRoot";
using namespace ProjectExplorer;
using namespace QtSupport;
using namespace Tasking;
using namespace Utils;
namespace QbsProjectManager {
namespace Internal {
namespace QbsProjectManager::Internal {
class QbsParserTaskAdapter : public TaskAdapter<QPointer<QbsBuildSystem>>
{
public:
~QbsParserTaskAdapter()
{
QbsBuildSystem *buildSystem = *task();
if (buildSystem && m_isRunning)
buildSystem->cancelParsing();
}
void start() final
{
QbsBuildSystem *buildSystem = *task();
if (!buildSystem) {
emit done(false);
return;
}
m_isRunning = true;
connect(buildSystem->target(), &Target::parsingFinished, this, [this](bool success) {
m_isRunning = false;
emit done(success);
});
buildSystem->parseCurrentBuildConfiguration();
}
private:
bool m_isRunning = false;
};
} // namespace QbsProjectManager::Internal
TASKING_DECLARE_TASK(QbsParserTask, QbsProjectManager::Internal::QbsParserTaskAdapter);
namespace QbsProjectManager::Internal {
ArchitecturesAspect::ArchitecturesAspect(AspectContainer *container)
: MultiSelectionAspect(container)
@@ -244,16 +271,9 @@ QbsBuildStep::QbsBuildStep(BuildStepList *bsl, Id id) :
setConfiguredArchitectures(selectedAbis.selectedArchitectures()); });
}
QbsBuildStep::~QbsBuildStep()
{
doCancel();
if (m_session)
m_session->disconnect(this);
}
bool QbsBuildStep::init()
{
if (m_session)
if (!BuildStep::init())
return false;
auto bc = static_cast<QbsBuildConfiguration *>(buildConfiguration());
@@ -274,27 +294,11 @@ void QbsBuildStep::setupOutputFormatter(OutputFormatter *formatter)
BuildStep::setupOutputFormatter(formatter);
}
void QbsBuildStep::doRun()
{
// 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).
m_parsingAfterBuild = false;
parseProject();
}
QWidget *QbsBuildStep::createConfigWidget()
{
return new QbsBuildStepConfigWidget(this);
}
void QbsBuildStep::doCancel()
{
if (m_parsingProject)
qbsBuildSystem()->cancelParsing();
else if (m_session)
m_session->cancelCurrentJob();
}
QVariantMap QbsBuildStep::qbsConfiguration(VariableHandling variableHandling) const
{
QVariantMap config = m_qbsConfiguration;
@@ -386,91 +390,6 @@ void QbsBuildStep::toMap(QVariantMap &map) const
map.insert(QBS_CONFIG, m_qbsConfiguration);
}
void QbsBuildStep::buildingDone(const ErrorInfo &error)
{
m_session->disconnect(this);
m_session = nullptr;
m_lastWasSuccess = !error.hasError();
for (const ErrorInfoItem &item : std::as_const(error.items)) {
createTaskAndOutput(
ProjectExplorer::Task::Error,
item.description,
item.filePath.toString(),
item.line);
}
// Building can uncover additional target artifacts.
qbsBuildSystem()->updateAfterBuild();
// The reparsing, if it is necessary, has to be done before finished() is emitted, as
// otherwise a potential additional build step could conflict with the parsing step.
if (qbsBuildSystem()->parsingScheduled()) {
m_parsingAfterBuild = true;
parseProject();
} else {
finish();
}
}
void QbsBuildStep::reparsingDone(bool success)
{
disconnect(target(), &Target::parsingFinished, this, &QbsBuildStep::reparsingDone);
m_parsingProject = false;
if (m_parsingAfterBuild) {
finish();
} else if (!success) {
m_lastWasSuccess = false;
finish();
} else {
build();
}
}
void QbsBuildStep::handleTaskStarted(const QString &desciption, int max)
{
m_currentTask = desciption;
m_maxProgress = max;
}
void QbsBuildStep::handleProgress(int value)
{
if (m_maxProgress > 0)
emit progress(value * 100 / m_maxProgress, m_currentTask);
}
void QbsBuildStep::handleCommandDescription(const QString &message)
{
emit addOutput(message, OutputFormat::Stdout);
}
void QbsBuildStep::handleProcessResult(
const FilePath &executable,
const QStringList &arguments,
const FilePath &workingDir,
const QStringList &stdOut,
const QStringList &stdErr,
bool success)
{
Q_UNUSED(workingDir);
const bool hasOutput = !stdOut.isEmpty() || !stdErr.isEmpty();
if (success && !hasOutput)
return;
emit addOutput(executable.toUserOutput() + ' ' + ProcessArgs::joinArgs(arguments),
OutputFormat::Stdout);
for (const QString &line : stdErr)
emit addOutput(line, OutputFormat::Stderr);
for (const QString &line : stdOut)
emit addOutput(line, OutputFormat::Stdout);
}
void QbsBuildStep::createTaskAndOutput(ProjectExplorer::Task::TaskType type, const QString &message,
const QString &file, int line)
{
emit addOutput(message, OutputFormat::Stdout);
emit addTask(CompileTask(type, message, FilePath::fromString(file), line), 1);
}
QString QbsBuildStep::buildVariant() const
{
return qbsConfiguration(PreserveVariables).value(Constants::QBS_CONFIG_VARIANT_KEY).toString();
@@ -496,59 +415,70 @@ QString QbsBuildStep::profile() const
return qbsConfiguration(PreserveVariables).value(Constants::QBS_CONFIG_PROFILE_KEY).toString();
}
void QbsBuildStep::parseProject()
GroupItem QbsBuildStep::runRecipe()
{
m_parsingProject = true;
connect(target(), &Target::parsingFinished, this, &QbsBuildStep::reparsingDone);
qbsBuildSystem()->parseCurrentBuildConfiguration();
}
void QbsBuildStep::build()
{
m_session = qbsBuildSystem()->session();
if (!m_session) {
emit addOutput(QbsProjectManager::Tr::tr("No qbs session exists for this target."),
const auto onPreParserSetup = [this](QPointer<QbsBuildSystem> &buildSystem) {
buildSystem = qbsBuildSystem();
};
const auto onBuildSetup = [this](QbsRequest &request) {
QbsSession *session = static_cast<QbsBuildSystem*>(buildSystem())->session();
if (!session) {
emit addOutput(Tr::tr("No qbs session exists for this target."),
OutputFormat::ErrorMessage);
emit finished(false);
return;
return SetupResult::StopWithError;
}
QJsonObject request;
request.insert("type", "build-project");
request.insert("max-job-count", maxJobs());
request.insert("keep-going", keepGoing());
request.insert("command-echo-mode", showCommandLines() ? "command-line" : "summary");
request.insert("install", install());
QbsSession::insertRequestedModuleProperties(request);
request.insert("clean-install-root", cleanInstallRoot());
QJsonObject requestData;
requestData.insert("type", "build-project");
requestData.insert("max-job-count", maxJobs());
requestData.insert("keep-going", keepGoing());
requestData.insert("command-echo-mode", showCommandLines() ? "command-line" : "summary");
requestData.insert("install", install());
QbsSession::insertRequestedModuleProperties(requestData);
requestData.insert("clean-install-root", cleanInstallRoot());
if (!m_products.isEmpty())
request.insert("products", QJsonArray::fromStringList(m_products));
requestData.insert("products", QJsonArray::fromStringList(m_products));
if (!m_changedFiles.isEmpty()) {
const auto changedFilesArray = QJsonArray::fromStringList(m_changedFiles);
request.insert("changed-files", changedFilesArray);
request.insert("files-to-consider", changedFilesArray);
requestData.insert("changed-files", changedFilesArray);
requestData.insert("files-to-consider", changedFilesArray);
}
if (!m_activeFileTags.isEmpty())
request.insert("active-file-tags", QJsonArray::fromStringList(m_activeFileTags));
request.insert("data-mode", "only-if-changed");
requestData.insert("active-file-tags", QJsonArray::fromStringList(m_activeFileTags));
requestData.insert("data-mode", "only-if-changed");
m_session->sendRequest(request);
m_maxProgress = 0;
connect(m_session, &QbsSession::projectBuilt, this, &QbsBuildStep::buildingDone);
connect(m_session, &QbsSession::taskStarted, this, &QbsBuildStep::handleTaskStarted);
connect(m_session, &QbsSession::taskProgress, this, &QbsBuildStep::handleProgress);
connect(m_session, &QbsSession::commandDescription,
this, &QbsBuildStep::handleCommandDescription);
connect(m_session, &QbsSession::processResult, this, &QbsBuildStep::handleProcessResult);
connect(m_session, &QbsSession::errorOccurred, this, [this] {
buildingDone(ErrorInfo(QbsProjectManager::Tr::tr("Build canceled: Qbs session failed.")));
request.setSession(session);
request.setRequestData(requestData);
connect(&request, &QbsRequest::progressChanged, this, &BuildStep::progress);
connect(&request, &QbsRequest::outputAdded, this,
[this](const QString &output, OutputFormat format) {
emit addOutput(output, format);
});
}
connect(&request, &QbsRequest::taskAdded, this, [this](const Task &task) {
emit addTask(task, 1);
});
return SetupResult::Continue;
};
const auto onPostParserSetup = [this](QPointer<QbsBuildSystem> &buildSystem) {
buildSystem = qbsBuildSystem();
return buildSystem->parsingScheduled() ? SetupResult::Continue : SetupResult::StopWithDone;
};
void QbsBuildStep::finish()
{
m_session = nullptr;
emit finished(m_lastWasSuccess);
const Group root {
// 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).
QbsParserTask(onPreParserSetup),
Group {
continueOnError,
QbsRequestTask(onBuildSetup),
// Building can uncover additional target artifacts.
Sync([this] { qbsBuildSystem()->updateAfterBuild(); }),
// The reparsing, if it is necessary, has to be done before done() is emitted, as
// otherwise a potential additional build step could conflict with the parsing step.
QbsParserTask(onPostParserSetup)
}
};
return root;
}
void QbsBuildStep::updateState()
@@ -589,16 +519,6 @@ QbsBuildStepData QbsBuildStep::stepData() const
return data;
}
void QbsBuildStep::dropSession()
{
if (m_session) {
doCancel();
m_session->disconnect(this);
m_session = nullptr;
}
}
// --------------------------------------------------------------------
// QbsBuildStepConfigWidget:
// --------------------------------------------------------------------
@@ -857,7 +777,6 @@ QbsBuildStepFactory::QbsBuildStepFactory()
setSupportedProjectType(Constants::PROJECT_ID);
}
} // namespace Internal
} // namespace QbsProjectManager
} // namespace QbsProjectManager::Internal
#include "qbsbuildstep.moc"

View File

@@ -3,19 +3,13 @@
#pragma once
#include "qbsbuildconfiguration.h"
#include <projectexplorer/buildstep.h>
#include <projectexplorer/task.h>
namespace QbsProjectManager {
namespace Internal {
class ErrorInfo;
class QbsProject;
class QbsSession;
namespace QbsProjectManager::Internal {
class QbsBuildStepConfigWidget;
class QbsBuildStepData;
class QbsBuildSystem;
class ArchitecturesAspect : public Utils::MultiSelectionAspect
{
@@ -50,7 +44,6 @@ public:
};
QbsBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
~QbsBuildStep() override;
QVariantMap qbsConfiguration(VariableHandling variableHandling) const;
void setQbsConfiguration(const QVariantMap &config);
@@ -70,11 +63,6 @@ public:
Utils::BoolAspect forceProbes{this};
Utils::StringAspect commandLine{this};
QbsBuildSystem *qbsBuildSystem() const;
QbsBuildStepData stepData() const;
void dropSession();
signals:
void qbsConfigurationChanged();
void qbsBuildOptionsChanged();
@@ -82,36 +70,17 @@ signals:
private:
bool init() override;
void setupOutputFormatter(Utils::OutputFormatter *formatter) override;
void doRun() override;
void doCancel() override;
Tasking::GroupItem runRecipe() final;
QWidget *createConfigWidget() override;
void fromMap(const QVariantMap &map) override;
void toMap(QVariantMap &map) const override;
void buildingDone(const ErrorInfo &error);
void reparsingDone(bool success);
void handleTaskStarted(const QString &desciption, int max);
void handleProgress(int value);
void handleCommandDescription(const QString &message);
void handleProcessResult(
const Utils::FilePath &executable,
const QStringList &arguments,
const Utils::FilePath &workingDir,
const QStringList &stdOut,
const QStringList &stdErr,
bool success);
void createTaskAndOutput(ProjectExplorer::Task::TaskType type,
const QString &message, const QString &file, int line);
QbsBuildSystem *qbsBuildSystem() const;
QbsBuildStepData stepData() const;
void setBuildVariant(const QString &variant);
void setConfiguredArchitectures(const QStringList &architectures);
QString profile() const;
void parseProject();
void build();
void finish();
void updateState();
QStringList configuredArchitectures() const;
@@ -122,14 +91,6 @@ private:
QStringList m_activeFileTags;
QStringList m_products;
QbsSession *m_session = nullptr;
QString m_currentTask;
int m_maxProgress;
bool m_lastWasSuccess;
bool m_parsingProject = false;
bool m_parsingAfterBuild = false;
friend class QbsBuildStepConfigWidget;
};
@@ -139,5 +100,4 @@ public:
QbsBuildStepFactory();
};
} // namespace Internal
} // namespace QbsProjectManager
} // namespace QbsProjectManager::Internal

View File

@@ -3,7 +3,9 @@
#include "qbsinstallstep.h"
#include "qbsbuildconfiguration.h"
#include "qbsbuildstep.h"
#include "qbsproject.h"
#include "qbsprojectmanagerconstants.h"
#include "qbsprojectmanagertr.h"
#include "qbsrequest.h"