forked from qt-creator/qt-creator
BuildManager: Employ task tree for running
Task-number: QTCREATORBUG-29168 Change-Id: Ibdc1882f3a019855bc06e7a7e49e2ae6e3bf17f1 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -260,31 +260,23 @@ public:
|
|||||||
Internal::CompileOutputWindow *m_outputWindow = nullptr;
|
Internal::CompileOutputWindow *m_outputWindow = nullptr;
|
||||||
Internal::TaskWindow *m_taskWindow = nullptr;
|
Internal::TaskWindow *m_taskWindow = nullptr;
|
||||||
|
|
||||||
QMetaObject::Connection m_scheduledBuild;
|
QList<BuildItem> m_pendingQueue;
|
||||||
QList<BuildItem> m_buildQueue;
|
QList<BuildItem> m_buildQueue;
|
||||||
int m_progress = 0;
|
int m_progress = 0;
|
||||||
int m_maxProgress = 0;
|
int m_maxProgress = 0;
|
||||||
bool m_poppedUpTaskWindow = false;
|
bool m_poppedUpTaskWindow = false;
|
||||||
bool m_running = false;
|
|
||||||
bool m_isDeploying = false;
|
bool m_isDeploying = false;
|
||||||
// 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;
|
|
||||||
bool m_lastStepSucceeded = true;
|
|
||||||
bool m_allStepsSucceeded = true;
|
|
||||||
BuildStep *m_currentBuildStep = nullptr;
|
|
||||||
QString m_currentConfiguration;
|
|
||||||
// used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
|
// used to decide if we are building a project to decide when to emit buildStateChanged(Project *)
|
||||||
QHash<Project *, int> m_activeBuildSteps;
|
QHash<Project *, int> m_activeBuildSteps;
|
||||||
QHash<Target *, int> m_activeBuildStepsPerTarget;
|
QHash<Target *, int> m_activeBuildStepsPerTarget;
|
||||||
QHash<ProjectConfiguration *, int> m_activeBuildStepsPerProjectConfiguration;
|
QHash<ProjectConfiguration *, int> m_activeBuildStepsPerProjectConfiguration;
|
||||||
Project *m_previousBuildStepProject = nullptr;
|
|
||||||
|
|
||||||
// Progress reporting to the progress manager
|
// Progress reporting to the progress manager
|
||||||
QFutureInterface<void> *m_progressFutureInterface = nullptr;
|
QFutureInterface<void> *m_progressFutureInterface = nullptr;
|
||||||
QFutureWatcher<void> m_progressWatcher;
|
QFutureWatcher<void> m_progressWatcher;
|
||||||
QPointer<FutureProgress> m_futureProgress;
|
QPointer<FutureProgress> m_futureProgress;
|
||||||
|
|
||||||
|
std::unique_ptr<TaskTree> m_taskTree;
|
||||||
QElapsedTimer m_elapsed;
|
QElapsedTimer m_elapsed;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -475,7 +467,7 @@ void BuildManager::aboutToRemoveProject(Project *p)
|
|||||||
bool BuildManager::isBuilding()
|
bool BuildManager::isBuilding()
|
||||||
{
|
{
|
||||||
// we are building even if we are not running yet
|
// we are building even if we are not running yet
|
||||||
return !d->m_buildQueue.isEmpty() || d->m_running;
|
return !d->m_pendingQueue.isEmpty() || !d->m_buildQueue.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BuildManager::isDeploying()
|
bool BuildManager::isDeploying()
|
||||||
@@ -506,20 +498,51 @@ QString BuildManager::displayNameForStepId(Id stepId)
|
|||||||
return Tr::tr("Build");
|
return Tr::tr("Build");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildManager::cleanupBuild()
|
||||||
|
{
|
||||||
|
const QList<BuildItem> buildQueue = d->m_buildQueue;
|
||||||
|
d->m_buildQueue.clear();
|
||||||
|
for (const BuildItem &item : buildQueue) {
|
||||||
|
decrementActiveBuildSteps(item.buildStep);
|
||||||
|
disconnect(item.buildStep, nullptr, m_instance, nullptr);
|
||||||
|
}
|
||||||
|
if (d->m_progressFutureInterface) {
|
||||||
|
d->m_progressFutureInterface->reportFinished();
|
||||||
|
d->m_progressWatcher.setFuture(QFuture<void>());
|
||||||
|
delete d->m_progressFutureInterface;
|
||||||
|
d->m_progressFutureInterface = nullptr;
|
||||||
|
}
|
||||||
|
d->m_progress = 0;
|
||||||
|
d->m_maxProgress = 0;
|
||||||
|
d->m_futureProgress = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void BuildManager::cancel()
|
void BuildManager::cancel()
|
||||||
{
|
{
|
||||||
if (d->m_scheduledBuild) {
|
if (!d->m_taskTree)
|
||||||
disconnect(d->m_scheduledBuild);
|
|
||||||
d->m_scheduledBuild = {};
|
|
||||||
clearBuildQueue();
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
d->m_taskTree.reset();
|
||||||
|
|
||||||
|
const QList<BuildItem> pendingQueue = d->m_pendingQueue;
|
||||||
|
d->m_pendingQueue.clear();
|
||||||
|
for (const BuildItem &item : pendingQueue) {
|
||||||
|
decrementActiveBuildSteps(item.buildStep);
|
||||||
|
disconnect(item.buildStep, nullptr, m_instance, nullptr);
|
||||||
}
|
}
|
||||||
if (d->m_running) {
|
|
||||||
if (d->m_canceling)
|
d->m_poppedUpTaskWindow = false;
|
||||||
return;
|
d->m_isDeploying = false;
|
||||||
d->m_canceling = true;
|
|
||||||
d->m_currentBuildStep->cancel();
|
if (d->m_progressFutureInterface) {
|
||||||
|
d->m_progressFutureInterface->setProgressValueAndText(100 * d->m_progress,
|
||||||
|
Tr::tr("Build/Deployment canceled"));
|
||||||
|
d->m_progressFutureInterface->reportCanceled();
|
||||||
}
|
}
|
||||||
|
cleanupBuild();
|
||||||
|
|
||||||
|
addToOutputWindow(Tr::tr("Canceled build/deployment."), BuildStep::OutputFormat::ErrorMessage);
|
||||||
|
emit m_instance->buildQueueFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildManager::updateTaskCount()
|
void BuildManager::updateTaskCount()
|
||||||
@@ -541,39 +564,6 @@ void BuildManager::finish()
|
|||||||
QApplication::alert(ICore::dialogParent(), 3000);
|
QApplication::alert(ICore::dialogParent(), 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildManager::emitCancelMessage()
|
|
||||||
{
|
|
||||||
addToOutputWindow(Tr::tr("Canceled build/deployment."), BuildStep::OutputFormat::ErrorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildManager::clearBuildQueue()
|
|
||||||
{
|
|
||||||
for (const BuildItem &item : std::as_const(d->m_buildQueue)) {
|
|
||||||
decrementActiveBuildSteps(item.buildStep);
|
|
||||||
disconnectOutput(item.buildStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
d->m_buildQueue.clear();
|
|
||||||
d->m_running = false;
|
|
||||||
d->m_poppedUpTaskWindow = false;
|
|
||||||
d->m_isDeploying = false;
|
|
||||||
d->m_previousBuildStepProject = nullptr;
|
|
||||||
d->m_currentBuildStep = nullptr;
|
|
||||||
|
|
||||||
if (d->m_progressFutureInterface) {
|
|
||||||
d->m_progressFutureInterface->reportCanceled();
|
|
||||||
d->m_progressFutureInterface->reportFinished();
|
|
||||||
d->m_progressWatcher.setFuture(QFuture<void>());
|
|
||||||
delete d->m_progressFutureInterface;
|
|
||||||
d->m_progressFutureInterface = nullptr;
|
|
||||||
}
|
|
||||||
d->m_futureProgress = nullptr;
|
|
||||||
d->m_maxProgress = 0;
|
|
||||||
|
|
||||||
emit m_instance->buildQueueFinished(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void BuildManager::toggleOutputWindow()
|
void BuildManager::toggleOutputWindow()
|
||||||
{
|
{
|
||||||
d->m_outputWindow->toggle(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
|
d->m_outputWindow->toggle(IOutputPane::ModeSwitch | IOutputPane::WithFocus);
|
||||||
@@ -600,58 +590,137 @@ bool BuildManager::tasksAvailable()
|
|||||||
|
|
||||||
void BuildManager::startBuildQueue()
|
void BuildManager::startBuildQueue()
|
||||||
{
|
{
|
||||||
if (d->m_buildQueue.isEmpty()) {
|
if (compileOutputSettings().popUp())
|
||||||
emit m_instance->buildQueueFinished(true);
|
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay if any of the involved build systems are currently parsing.
|
const auto onAwaiterSetup = [](QSet<BuildSystem *> &buildSystems) {
|
||||||
const auto buildSystems = transform<QSet<BuildSystem *>>(d->m_buildQueue,
|
// Delay if any of the involved build systems are currently parsing.
|
||||||
[](const BuildItem &item) { return item.buildStep->buildSystem(); });
|
buildSystems = transform<QSet<BuildSystem *>>(
|
||||||
for (const BuildSystem * const bs : buildSystems) {
|
d->m_buildQueue, [](const BuildItem &item) { return item.buildStep->buildSystem(); });
|
||||||
if (!bs || !bs->isParsing())
|
};
|
||||||
|
|
||||||
|
const GroupItem abortPolicy
|
||||||
|
= ProjectExplorerPlugin::projectExplorerSettings().abortBuildAllOnError
|
||||||
|
? stopOnError : continueOnError;
|
||||||
|
|
||||||
|
QList<GroupItem> topLevel { abortPolicy, ParserAwaiterTask(onAwaiterSetup) };
|
||||||
|
Project *lastProject = nullptr;
|
||||||
|
Target *lastTarget = nullptr;
|
||||||
|
QList<GroupItem> targetTasks;
|
||||||
|
d->m_progress = 0;
|
||||||
|
d->m_maxProgress = 0;
|
||||||
|
|
||||||
|
for (const BuildItem &item : std::as_const(d->m_buildQueue)) {
|
||||||
|
BuildStep *buildStep = item.buildStep;
|
||||||
|
Target *target = buildStep->target();
|
||||||
|
if (lastTarget != target) {
|
||||||
|
if (!targetTasks.isEmpty())
|
||||||
|
topLevel.append(Group(targetTasks));
|
||||||
|
targetTasks.clear();
|
||||||
|
lastTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
Project *project = buildStep->project();
|
||||||
|
if (lastProject != project) {
|
||||||
|
targetTasks.append(Sync([projectName = buildStep->project()->displayName()] {
|
||||||
|
addToOutputWindow(Tr::tr("Running steps for project %1...")
|
||||||
|
.arg(projectName), BuildStep::OutputFormat::NormalMessage);
|
||||||
|
}));
|
||||||
|
lastProject = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!item.enabled) {
|
||||||
|
targetTasks.append(Sync([name = buildStep->displayName()] {
|
||||||
|
addToOutputWindow(Tr::tr("Skipping disabled step %1.")
|
||||||
|
.arg(name), BuildStep::OutputFormat::NormalMessage);
|
||||||
|
}));
|
||||||
continue;
|
continue;
|
||||||
d->m_scheduledBuild = QObject::connect(bs, &BuildSystem::parsingFinished,
|
}
|
||||||
BuildManager::instance(),
|
++d->m_maxProgress;
|
||||||
[](bool parsingSuccess) {
|
|
||||||
if (!d->m_scheduledBuild)
|
|
||||||
return;
|
|
||||||
QObject::disconnect(d->m_scheduledBuild);
|
|
||||||
d->m_scheduledBuild = {};
|
|
||||||
if (parsingSuccess)
|
|
||||||
startBuildQueue();
|
|
||||||
else
|
|
||||||
clearBuildQueue();
|
|
||||||
}, Qt::QueuedConnection);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->m_running) {
|
const auto onRecipeSetup = [buildStep, name = item.name] {
|
||||||
d->m_elapsed.start();
|
d->m_outputWindow->reset();
|
||||||
// Progress Reporting
|
buildStep->setupOutputFormatter(d->m_outputWindow->outputFormatter());
|
||||||
d->m_progressFutureInterface = new QFutureInterface<void>;
|
connect(buildStep, &BuildStep::progress, instance(), &BuildManager::progressChanged);
|
||||||
d->m_progressWatcher.setFuture(d->m_progressFutureInterface->future());
|
if (d->m_futureProgress)
|
||||||
ProgressManager::setApplicationLabel(QString());
|
d->m_futureProgress.data()->setTitle(name);
|
||||||
d->m_futureProgress = ProgressManager::addTask(d->m_progressFutureInterface->future(),
|
};
|
||||||
QString(), "ProjectExplorer.Task.Build",
|
const auto onRecipeDone = [buildStep] {
|
||||||
ProgressManager::KeepOnFinish | ProgressManager::ShowInApplicationIcon);
|
disconnect(buildStep, &BuildStep::progress, instance(), nullptr);
|
||||||
connect(d->m_futureProgress.data(), &FutureProgress::clicked,
|
d->m_outputWindow->flush();
|
||||||
m_instance, &BuildManager::showBuildResults);
|
++d->m_progress;
|
||||||
d->m_futureProgress.data()->setWidget(new Internal::BuildProgress(d->m_taskWindow));
|
d->m_progressFutureInterface->setProgressValueAndText(
|
||||||
d->m_futureProgress.data()->setStatusBarWidget(new Internal::BuildProgress(d->m_taskWindow,
|
100 * d->m_progress, msgProgress(d->m_progress, d->m_maxProgress));
|
||||||
Qt::Horizontal));
|
};
|
||||||
d->m_progress = 0;
|
const auto onRecipeError = [buildStep, target, onRecipeDone] {
|
||||||
d->m_progressFutureInterface->setProgressRange(0, d->m_maxProgress * 100);
|
onRecipeDone();
|
||||||
|
const QString projectName = buildStep->project()->displayName();
|
||||||
d->m_running = true;
|
const QString targetName = target->displayName();
|
||||||
d->m_allStepsSucceeded = true;
|
addToOutputWindow(Tr::tr("Error while building/deploying project %1 (kit: %2)")
|
||||||
d->m_progressFutureInterface->reportStarted();
|
.arg(projectName, targetName), BuildStep::OutputFormat::Stderr);
|
||||||
nextStep();
|
const Tasks kitTasks = target->kit()->validate();
|
||||||
} else {
|
if (!kitTasks.isEmpty()) {
|
||||||
// Already running
|
addToOutputWindow(Tr::tr("The kit %1 has configuration issues which might "
|
||||||
d->m_progressFutureInterface->setProgressRange(0, d->m_maxProgress * 100);
|
"be the root cause for this problem.")
|
||||||
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress));
|
.arg(targetName), BuildStep::OutputFormat::Stderr);
|
||||||
|
}
|
||||||
|
addToOutputWindow(Tr::tr("When executing step \"%1\"")
|
||||||
|
.arg(buildStep->displayName()), BuildStep::OutputFormat::Stderr);
|
||||||
|
};
|
||||||
|
const Group recipeGroup {
|
||||||
|
onGroupSetup(onRecipeSetup),
|
||||||
|
buildStep->runRecipe(),
|
||||||
|
onGroupDone(onRecipeDone),
|
||||||
|
onGroupError(onRecipeError),
|
||||||
|
};
|
||||||
|
targetTasks.append(recipeGroup);
|
||||||
}
|
}
|
||||||
|
if (!targetTasks.isEmpty())
|
||||||
|
topLevel.append(Group(targetTasks));
|
||||||
|
|
||||||
|
d->m_taskTree.reset(new TaskTree(Group{topLevel}));
|
||||||
|
const auto endHandler = [](bool success) {
|
||||||
|
d->m_taskTree.release()->deleteLater();
|
||||||
|
|
||||||
|
if (!success && d->m_progressFutureInterface)
|
||||||
|
d->m_progressFutureInterface->reportCanceled();
|
||||||
|
|
||||||
|
cleanupBuild();
|
||||||
|
|
||||||
|
if (d->m_pendingQueue.isEmpty()) {
|
||||||
|
d->m_poppedUpTaskWindow = false;
|
||||||
|
d->m_isDeploying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit m_instance->buildQueueFinished(success);
|
||||||
|
|
||||||
|
if (!d->m_pendingQueue.isEmpty()) {
|
||||||
|
d->m_buildQueue = d->m_pendingQueue;
|
||||||
|
d->m_pendingQueue.clear();
|
||||||
|
startBuildQueue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
connect(d->m_taskTree.get(), &TaskTree::done, instance(), [endHandler] { endHandler(true); });
|
||||||
|
connect(d->m_taskTree.get(), &TaskTree::errorOccurred, instance(),
|
||||||
|
[endHandler] { endHandler(false); });
|
||||||
|
|
||||||
|
// Progress Reporting
|
||||||
|
d->m_progressFutureInterface = new QFutureInterface<void>;
|
||||||
|
d->m_progressWatcher.setFuture(d->m_progressFutureInterface->future());
|
||||||
|
ProgressManager::setApplicationLabel({});
|
||||||
|
d->m_futureProgress = ProgressManager::addTask(d->m_progressFutureInterface->future(),
|
||||||
|
{}, "ProjectExplorer.Task.Build",
|
||||||
|
ProgressManager::KeepOnFinish | ProgressManager::ShowInApplicationIcon);
|
||||||
|
connect(d->m_futureProgress.data(), &FutureProgress::clicked,
|
||||||
|
m_instance, &BuildManager::showBuildResults);
|
||||||
|
d->m_futureProgress.data()->setWidget(new BuildProgress(d->m_taskWindow));
|
||||||
|
d->m_futureProgress.data()->setStatusBarWidget(new BuildProgress(d->m_taskWindow,
|
||||||
|
Qt::Horizontal));
|
||||||
|
d->m_progressFutureInterface->setProgressRange(0, d->m_maxProgress * 100);
|
||||||
|
d->m_progressFutureInterface->reportStarted();
|
||||||
|
|
||||||
|
d->m_elapsed.start();
|
||||||
|
d->m_taskTree->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildManager::showBuildResults()
|
void BuildManager::showBuildResults()
|
||||||
@@ -684,127 +753,15 @@ void BuildManager::addToOutputWindow(const QString &string, BuildStep::OutputFor
|
|||||||
d->m_outputWindow->appendText(stringToWrite, format);
|
d->m_outputWindow->appendText(stringToWrite, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildManager::nextBuildQueue()
|
|
||||||
{
|
|
||||||
d->m_outputWindow->flush();
|
|
||||||
disconnectOutput(d->m_currentBuildStep);
|
|
||||||
decrementActiveBuildSteps(d->m_currentBuildStep);
|
|
||||||
|
|
||||||
if (d->m_canceling) {
|
|
||||||
d->m_canceling = false;
|
|
||||||
QTimer::singleShot(0, m_instance, &BuildManager::emitCancelMessage);
|
|
||||||
|
|
||||||
//TODO NBS fix in qtconcurrent
|
|
||||||
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100,
|
|
||||||
Tr::tr("Build/Deployment canceled"));
|
|
||||||
clearBuildQueue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!d->m_skipDisabled)
|
|
||||||
++d->m_progress;
|
|
||||||
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress*100, msgProgress(d->m_progress, d->m_maxProgress));
|
|
||||||
|
|
||||||
const bool success = d->m_skipDisabled || d->m_lastStepSucceeded;
|
|
||||||
if (success) {
|
|
||||||
nextStep();
|
|
||||||
} else {
|
|
||||||
// Build Failure
|
|
||||||
d->m_allStepsSucceeded = false;
|
|
||||||
Target *t = d->m_currentBuildStep->target();
|
|
||||||
const QString projectName = d->m_currentBuildStep->project()->displayName();
|
|
||||||
const QString targetName = t->displayName();
|
|
||||||
addToOutputWindow(Tr::tr("Error while building/deploying project %1 (kit: %2)").arg(projectName, targetName), BuildStep::OutputFormat::Stderr);
|
|
||||||
const Tasks kitTasks = t->kit()->validate();
|
|
||||||
if (!kitTasks.isEmpty()) {
|
|
||||||
addToOutputWindow(Tr::tr("The kit %1 has configuration issues which might be the root cause for this problem.")
|
|
||||||
.arg(targetName), BuildStep::OutputFormat::Stderr);
|
|
||||||
}
|
|
||||||
addToOutputWindow(Tr::tr("When executing step \"%1\"").arg(d->m_currentBuildStep->displayName()), BuildStep::OutputFormat::Stderr);
|
|
||||||
|
|
||||||
bool abort = ProjectExplorerPlugin::projectExplorerSettings().abortBuildAllOnError;
|
|
||||||
if (!abort) {
|
|
||||||
while (!d->m_buildQueue.isEmpty()
|
|
||||||
&& d->m_buildQueue.front().buildStep->target() == t) {
|
|
||||||
BuildStep * const nextStepForFailedTarget = d->m_buildQueue.takeFirst().buildStep;
|
|
||||||
disconnectOutput(nextStepForFailedTarget);
|
|
||||||
decrementActiveBuildSteps(nextStepForFailedTarget);
|
|
||||||
}
|
|
||||||
if (d->m_buildQueue.isEmpty())
|
|
||||||
abort = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (abort) {
|
|
||||||
// NBS TODO fix in qtconcurrent
|
|
||||||
d->m_progressFutureInterface->setProgressValueAndText(d->m_progress * 100,
|
|
||||||
Tr::tr("Error while building/deploying project %1 (kit: %2)")
|
|
||||||
.arg(projectName, targetName));
|
|
||||||
clearBuildQueue();
|
|
||||||
} else {
|
|
||||||
nextStep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BuildManager::progressChanged(int percent, const QString &text)
|
void BuildManager::progressChanged(int percent, const QString &text)
|
||||||
{
|
{
|
||||||
if (d->m_progressFutureInterface)
|
if (d->m_progressFutureInterface)
|
||||||
d->m_progressFutureInterface->setProgressValueAndText(percent + 100 * d->m_progress, text);
|
d->m_progressFutureInterface->setProgressValueAndText(percent + 100 * d->m_progress, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildManager::nextStep()
|
|
||||||
{
|
|
||||||
if (!d->m_buildQueue.empty()) {
|
|
||||||
const BuildItem item = d->m_buildQueue.takeFirst();
|
|
||||||
d->m_currentBuildStep = item.buildStep;
|
|
||||||
d->m_skipDisabled = !item.enabled;
|
|
||||||
if (d->m_futureProgress)
|
|
||||||
d->m_futureProgress.data()->setTitle(item.name);
|
|
||||||
|
|
||||||
if (d->m_currentBuildStep->project() != d->m_previousBuildStepProject) {
|
|
||||||
const QString projectName = d->m_currentBuildStep->project()->displayName();
|
|
||||||
addToOutputWindow(Tr::tr("Running steps for project %1...")
|
|
||||||
.arg(projectName), BuildStep::OutputFormat::NormalMessage);
|
|
||||||
d->m_previousBuildStepProject = d->m_currentBuildStep->project();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->m_skipDisabled) {
|
|
||||||
addToOutputWindow(Tr::tr("Skipping disabled step %1.")
|
|
||||||
.arg(d->m_currentBuildStep->displayName()), BuildStep::OutputFormat::NormalMessage);
|
|
||||||
nextBuildQueue();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const auto finishedHandler = [](bool success) {
|
|
||||||
d->m_outputWindow->flush();
|
|
||||||
d->m_lastStepSucceeded = success;
|
|
||||||
disconnect(d->m_currentBuildStep, nullptr, instance(), nullptr);
|
|
||||||
BuildManager::nextBuildQueue();
|
|
||||||
};
|
|
||||||
connect(d->m_currentBuildStep, &BuildStep::finished, instance(), finishedHandler);
|
|
||||||
connect(d->m_currentBuildStep, &BuildStep::progress,
|
|
||||||
instance(), &BuildManager::progressChanged);
|
|
||||||
d->m_outputWindow->reset();
|
|
||||||
d->m_currentBuildStep->setupOutputFormatter(d->m_outputWindow->outputFormatter());
|
|
||||||
d->m_currentBuildStep->run();
|
|
||||||
} else {
|
|
||||||
d->m_running = false;
|
|
||||||
d->m_poppedUpTaskWindow = false;
|
|
||||||
d->m_isDeploying = false;
|
|
||||||
d->m_previousBuildStepProject = nullptr;
|
|
||||||
d->m_progressFutureInterface->reportFinished();
|
|
||||||
d->m_progressWatcher.setFuture(QFuture<void>());
|
|
||||||
d->m_currentBuildStep = nullptr;
|
|
||||||
delete d->m_progressFutureInterface;
|
|
||||||
d->m_progressFutureInterface = nullptr;
|
|
||||||
d->m_maxProgress = 0;
|
|
||||||
emit m_instance->buildQueueFinished(d->m_allStepsSucceeded);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BuildManager::buildQueueAppend(const QList<BuildItem> &items, const QStringList &preambleMessage)
|
bool BuildManager::buildQueueAppend(const QList<BuildItem> &items, const QStringList &preambleMessage)
|
||||||
{
|
{
|
||||||
if (!d->m_running) {
|
if (!d->m_taskTree) {
|
||||||
d->m_outputWindow->clearContents();
|
d->m_outputWindow->clearContents();
|
||||||
if (ProjectExplorerPlugin::projectExplorerSettings().clearIssuesOnRebuild) {
|
if (ProjectExplorerPlugin::projectExplorerSettings().clearIssuesOnRebuild) {
|
||||||
TaskHub::clearTasks(Constants::TASK_CATEGORY_COMPILE);
|
TaskHub::clearTasks(Constants::TASK_CATEGORY_COMPILE);
|
||||||
@@ -819,34 +776,46 @@ bool BuildManager::buildQueueAppend(const QList<BuildItem> &items, const QString
|
|||||||
QList<BuildStep *> connectedSteps;
|
QList<BuildStep *> connectedSteps;
|
||||||
int enabledCount = 0;
|
int enabledCount = 0;
|
||||||
for (const BuildItem &item : items) {
|
for (const BuildItem &item : items) {
|
||||||
connect(item.buildStep, &BuildStep::addTask, m_instance, &BuildManager::addToTaskWindow);
|
BuildStep *buildStep = item.buildStep;
|
||||||
connect(item.buildStep, &BuildStep::addOutput, m_instance, &BuildManager::addToOutputWindow);
|
connect(buildStep, &BuildStep::addTask, m_instance, &BuildManager::addToTaskWindow);
|
||||||
connectedSteps.append(item.buildStep);
|
connect(buildStep, &BuildStep::addOutput, m_instance, &BuildManager::addToOutputWindow);
|
||||||
|
connectedSteps.append(buildStep);
|
||||||
if (!item.enabled)
|
if (!item.enabled)
|
||||||
continue;
|
continue;
|
||||||
++enabledCount;
|
++enabledCount;
|
||||||
if (item.buildStep->init())
|
if (!isBuilding(buildStep) && buildStep->init())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// init() failed, print something for the user...
|
// init() failed, print something for the user...
|
||||||
const QString projectName = item.buildStep->project()->displayName();
|
const QString projectName = buildStep->project()->displayName();
|
||||||
const QString targetName = item.buildStep->target()->displayName();
|
const QString targetName = buildStep->target()->displayName();
|
||||||
addToOutputWindow(Tr::tr("Error while building/deploying project %1 (kit: %2)")
|
addToOutputWindow(Tr::tr("Error while building/deploying project %1 (kit: %2)")
|
||||||
.arg(projectName, targetName), BuildStep::OutputFormat::Stderr);
|
.arg(projectName, targetName), BuildStep::OutputFormat::Stderr);
|
||||||
addToOutputWindow(Tr::tr("When executing step \"%1\"")
|
addToOutputWindow(Tr::tr("When executing step \"%1\"")
|
||||||
.arg(item.buildStep->displayName()), BuildStep::OutputFormat::Stderr);
|
.arg(buildStep->displayName()), BuildStep::OutputFormat::Stderr);
|
||||||
for (BuildStep *buildStep : std::as_const(connectedSteps))
|
for (BuildStep *buildStep : std::as_const(connectedSteps))
|
||||||
disconnectOutput(buildStep);
|
connect(buildStep, nullptr, m_instance, nullptr);
|
||||||
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
|
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
d->m_buildQueue << items;
|
if (d->m_taskTree)
|
||||||
d->m_maxProgress += enabledCount;
|
d->m_pendingQueue << items;
|
||||||
|
else
|
||||||
|
d->m_buildQueue = items;
|
||||||
|
|
||||||
|
if (d->m_buildQueue.isEmpty() && d->m_pendingQueue.isEmpty()) {
|
||||||
|
if (compileOutputSettings().popUp())
|
||||||
|
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
|
||||||
|
emit m_instance->buildQueueFinished(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
for (const BuildItem &item : items)
|
for (const BuildItem &item : items)
|
||||||
incrementActiveBuildSteps(item.buildStep);
|
incrementActiveBuildSteps(item.buildStep);
|
||||||
if (compileOutputSettings().popUp())
|
|
||||||
d->m_outputWindow->popup(IOutputPane::NoModeSwitch);
|
if (!d->m_taskTree)
|
||||||
startBuildQueue();
|
startBuildQueue();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -857,6 +826,7 @@ bool BuildManager::buildList(BuildStepList *bsl)
|
|||||||
|
|
||||||
bool BuildManager::buildLists(const QList<BuildStepList *> &bsls, const QStringList &preambleMessage)
|
bool BuildManager::buildLists(const QList<BuildStepList *> &bsls, const QStringList &preambleMessage)
|
||||||
{
|
{
|
||||||
|
const bool wasDeploying = d->m_isDeploying;
|
||||||
QList<BuildItem> buildItems;
|
QList<BuildItem> buildItems;
|
||||||
for (BuildStepList *list : bsls) {
|
for (BuildStepList *list : bsls) {
|
||||||
const QString name = displayNameForStepId(list->id());
|
const QString name = displayNameForStepId(list->id());
|
||||||
@@ -869,7 +839,7 @@ bool BuildManager::buildLists(const QList<BuildStepList *> &bsls, const QStringL
|
|||||||
if (buildQueueAppend(buildItems, preambleMessage))
|
if (buildQueueAppend(buildItems, preambleMessage))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
d->m_isDeploying = false;
|
d->m_isDeploying = wasDeploying;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,8 +875,8 @@ bool BuildManager::isBuilding(const ProjectConfiguration *p)
|
|||||||
|
|
||||||
bool BuildManager::isBuilding(BuildStep *step)
|
bool BuildManager::isBuilding(BuildStep *step)
|
||||||
{
|
{
|
||||||
return (d->m_currentBuildStep == step) || Utils::anyOf(
|
const auto checker = [step](const BuildItem &item) { return item.buildStep == step; };
|
||||||
d->m_buildQueue, [step](const BuildItem &item) { return item.buildStep == step; });
|
return Utils::anyOf(d->m_buildQueue, checker) || Utils::anyOf(d->m_pendingQueue, checker);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T> bool increment(QHash<T *, int> &hash, T *key)
|
template <class T> bool increment(QHash<T *, int> &hash, T *key)
|
||||||
@@ -956,10 +926,4 @@ void BuildManager::decrementActiveBuildSteps(BuildStep *bs)
|
|||||||
emit m_instance->buildStateChanged(bs->project());
|
emit m_instance->buildStateChanged(bs->project());
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildManager::disconnectOutput(BuildStep *bs)
|
|
||||||
{
|
|
||||||
disconnect(bs, &BuildStep::addTask, m_instance, nullptr);
|
|
||||||
disconnect(bs, &BuildStep::addOutput, m_instance, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
@@ -78,25 +78,21 @@ signals:
|
|||||||
void buildQueueFinished(bool success);
|
void buildQueueFinished(bool success);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void cleanupBuild();
|
||||||
static void addToTaskWindow(const ProjectExplorer::Task &task, int linkedOutputLines, int skipLines);
|
static void addToTaskWindow(const ProjectExplorer::Task &task, int linkedOutputLines, int skipLines);
|
||||||
static void addToOutputWindow(const QString &string, BuildStep::OutputFormat format,
|
static void addToOutputWindow(const QString &string, BuildStep::OutputFormat format,
|
||||||
BuildStep::OutputNewlineSetting newlineSettings = BuildStep::DoAppendNewline);
|
BuildStep::OutputNewlineSetting newlineSettings = BuildStep::DoAppendNewline);
|
||||||
|
|
||||||
static void nextBuildQueue();
|
|
||||||
static void progressChanged(int percent, const QString &text);
|
static void progressChanged(int percent, const QString &text);
|
||||||
static void emitCancelMessage();
|
|
||||||
static void showBuildResults();
|
static void showBuildResults();
|
||||||
static void updateTaskCount();
|
static void updateTaskCount();
|
||||||
static void finish();
|
static void finish();
|
||||||
|
|
||||||
static void startBuildQueue();
|
static void startBuildQueue();
|
||||||
static void nextStep();
|
|
||||||
static void clearBuildQueue();
|
|
||||||
static bool buildQueueAppend(const QList<BuildItem> &items,
|
static bool buildQueueAppend(const QList<BuildItem> &items,
|
||||||
const QStringList &preambleMessage = {});
|
const QStringList &preambleMessage = {});
|
||||||
static void incrementActiveBuildSteps(BuildStep *bs);
|
static void incrementActiveBuildSteps(BuildStep *bs);
|
||||||
static void decrementActiveBuildSteps(BuildStep *bs);
|
static void decrementActiveBuildSteps(BuildStep *bs);
|
||||||
static void disconnectOutput(BuildStep *bs);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
@@ -132,6 +132,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
using ProjectConfiguration::parent;
|
using ProjectConfiguration::parent;
|
||||||
|
|
||||||
|
friend class BuildManager;
|
||||||
virtual Tasking::GroupItem runRecipe() = 0;
|
virtual Tasking::GroupItem runRecipe() = 0;
|
||||||
|
|
||||||
BuildStepList * const m_stepList;
|
BuildStepList * const m_stepList;
|
||||||
|
Reference in New Issue
Block a user