diff options
Diffstat (limited to 'src/plugins/projectexplorer/runconfiguration.cpp')
-rw-r--r-- | src/plugins/projectexplorer/runconfiguration.cpp | 299 |
1 files changed, 176 insertions, 123 deletions
diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index d098411706..bc3eaac911 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -183,13 +183,16 @@ void IRunConfigurationAspect::resetProjectToGlobalSettings() for a target, but still be runnable via the output tab. */ +static std::vector<RunConfiguration::AspectFactory> theAspectFactories; + RunConfiguration::RunConfiguration(Target *target, Core::Id id) : ProjectConfiguration(target, id) { Q_ASSERT(target); ctor(); - addExtraAspects(); + for (const AspectFactory &factory : theAspectFactories) + addExtraAspect(factory(this)); } RunConfiguration::RunConfiguration(Target *target, RunConfiguration *source) : @@ -209,10 +212,9 @@ RunConfiguration::~RunConfiguration() qDeleteAll(m_aspects); } -void RunConfiguration::addExtraAspects() +void RunConfiguration::addAspectFactory(const AspectFactory &aspectFactory) { - foreach (IRunControlFactory *factory, ExtensionSystem::PluginManager::getObjects<IRunControlFactory>()) - addExtraAspect(factory->createRunConfigurationAspect(this)); + theAspectFactories.push_back(aspectFactory); } void RunConfiguration::addExtraAspect(IRunConfigurationAspect *aspect) @@ -365,7 +367,7 @@ IRunConfigurationAspect *RunConfiguration::extraAspect(Core::Id id) const A target specific \l RunConfiguration implementation can specify what information it considers necessary to execute a process - on the target. Target specific) \n IRunControlFactory implementation + on the target. Target specific) \n RunWorker implementation can use that information either unmodified or tweak it or ignore it when setting up a RunControl. @@ -471,29 +473,6 @@ QList<IRunConfigurationFactory *> IRunConfigurationFactory::find(Target *parent) }); } -/*! - \class ProjectExplorer::IRunControlFactory - - \brief The IRunControlFactory class creates RunControl objects matching a - run configuration. -*/ - -/*! - \fn RunConfigWidget *ProjectExplorer::IRunConfigurationAspect::createConfigurationWidget() - - Returns a widget used to configure this runner. Ownership is transferred to - the caller. - - Returns null if @p \a runConfiguration is not suitable for RunControls from this - factory, or no user-accessible - configuration is required. -*/ - -IRunControlFactory::IRunControlFactory(QObject *parent) - : QObject(parent) -{ -} - using WorkerFactories = std::vector<RunControl::WorkerFactory>; static WorkerFactories &theWorkerFactories() @@ -504,50 +483,13 @@ static WorkerFactories &theWorkerFactories() bool RunControl::WorkerFactory::canRun(RunConfiguration *runConfiguration, Core::Id runMode) const { - if (runMode != runMode) + if (runMode != this->runMode) return false; if (!constraint) return true; return constraint(runConfiguration); } -bool IRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id runMode) const -{ - for (const RunControl::WorkerFactory &factory : theWorkerFactories()) { - if (factory.canRun(runConfiguration, runMode)) - return true; - }; - return false; -} - -RunControl *IRunControlFactory::create(RunConfiguration *runConfiguration, Core::Id runMode, QString *) -{ - for (const RunControl::WorkerFactory &factory : theWorkerFactories()) { - if (factory.canRun(runConfiguration, runMode)) { - auto runControl = new RunControl(runConfiguration, runMode); - factory.producer(runControl); - return runControl; - } - }; - return nullptr; -} - -/*! - Returns an IRunConfigurationAspect to carry options for RunControls this - factory can create. - - If no extra options are required, it is allowed to return null like the - default implementation does. This function is intended to be called from the - RunConfiguration constructor, so passing a RunConfiguration pointer makes - no sense because that object is under construction at the time. -*/ - -IRunConfigurationAspect *IRunControlFactory::createRunConfigurationAspect(RunConfiguration *rc) -{ - Q_UNUSED(rc); - return nullptr; -} - /*! \class ProjectExplorer::RunControl \brief The RunControl class instances represent one item that is run. @@ -562,18 +504,6 @@ IRunConfigurationAspect *IRunControlFactory::createRunConfigurationAspect(RunCon */ -const char PRIORITY_KEY[] = "RunControlFactoryPriority"; - -int ProjectExplorer::IRunControlFactory::priority() const -{ - return property(PRIORITY_KEY).toInt(); // 0 by default. -} - -void IRunControlFactory::setPriority(int priority) -{ - setProperty(PRIORITY_KEY, priority); -} - namespace Internal { enum class RunWorkerState @@ -592,7 +522,7 @@ static QString stateName(RunWorkerState s) SN(RunWorkerState::Done) SN(RunWorkerState::Failed) } - return QLatin1String("<unknown>"); + return QString("<unknown: %1>").arg(int(s)); # undef SN } @@ -606,7 +536,7 @@ public: RunWorker *q; RunWorkerState state = RunWorkerState::Initialized; - RunControl *runControl; + QPointer<RunControl> runControl; QList<RunWorker *> dependencies; QString id; @@ -625,6 +555,8 @@ enum class RunControlState Running, // All good and running. Stopping, // initiateStop() was called, stop application/tool Stopped, // all good, but stopped. Can possibly be re-started + Finishing, // Application tab manually closed + Finished // Final state, will self-destruct with deleteLater() }; static QString stateName(RunControlState s) @@ -636,8 +568,10 @@ static QString stateName(RunControlState s) SN(RunControlState::Running) SN(RunControlState::Stopping) SN(RunControlState::Stopped) + SN(RunControlState::Finishing) + SN(RunControlState::Finished) } - return QLatin1String("<unknown>"); + return QString("<unknown: %1>").arg(int(s)); # undef SN } @@ -659,8 +593,11 @@ public: ~RunControlPrivate() { - QTC_CHECK(state == RunControlState::Stopped || state == RunControlState::Initialized); + QTC_CHECK(state == RunControlState::Finished || state == RunControlState::Initialized); + disconnect(); + q = nullptr; qDeleteAll(m_workers); + m_workers.clear(); delete outputFormatter; } @@ -675,7 +612,7 @@ public: void initiateReStart(); void continueStart(); void initiateStop(); - void continueStop(); + void initiateFinish(); void onWorkerStarted(RunWorker *worker); void onWorkerStopped(RunWorker *worker); @@ -694,7 +631,7 @@ public: Utils::Icon icon; const QPointer<RunConfiguration> runConfiguration; // Not owned. QPointer<Project> project; // Not owned. - Utils::OutputFormatter *outputFormatter = nullptr; + QPointer<Utils::OutputFormatter> outputFormatter = nullptr; std::function<bool(bool*)> promptToStop; std::vector<RunControl::WorkerFactory> m_factories; @@ -759,6 +696,11 @@ void RunControl::initiateStop() d->initiateStop(); } +void RunControl::initiateFinish() +{ + d->initiateFinish(); +} + using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>; static WorkerCreators &theWorkerCreators() @@ -789,12 +731,22 @@ RunWorker *RunControl::createWorker(Core::Id id) RunControl::WorkerCreator RunControl::producer(RunConfiguration *runConfiguration, Core::Id runMode) { - for (const auto &factory : theWorkerFactories()) { - if (factory.runMode == runMode - && (!factory.constraint || factory.constraint(runConfiguration))) - return factory.producer; + WorkerFactories candidates; + for (const RunControl::WorkerFactory &factory : theWorkerFactories()) { + if (factory.canRun(runConfiguration, runMode)) + candidates.push_back(factory); + } + + if (candidates.empty()) + return {}; + + RunControl::WorkerFactory bestFactory = *candidates.begin(); + for (const RunControl::WorkerFactory &factory : candidates) { + if (factory.priority > bestFactory.priority) + bestFactory = factory; } - return {}; + + return bestFactory.producer; } void RunControl::addWorkerFactory(const RunControl::WorkerFactory &workerFactory) @@ -880,15 +832,58 @@ void RunControlPrivate::initiateStop() { checkState(RunControlState::Running); setState(RunControlState::Stopping); - debugMessage("Queue: Stopping"); + debugMessage("Queue: Stopping for all workers"); - continueStop(); + bool allDone = true; + for (RunWorker *worker : m_workers) { + if (worker) { + const QString &workerId = worker->d->id; + debugMessage(" Examining worker " + workerId); + switch (worker->d->state) { + case RunWorkerState::Initialized: + debugMessage(" " + workerId + " was Initialized, setting to Done"); + worker->d->state = RunWorkerState::Done; + break; + case RunWorkerState::Stopping: + debugMessage(" " + workerId + " was already Stopping. Keeping it that way"); + allDone = false; + break; + case RunWorkerState::Starting: + debugMessage(" " + workerId + " was Starting, queuing stop"); + worker->d->state = RunWorkerState::Stopping; + QTimer::singleShot(0, worker, &RunWorker::initiateStop); + allDone = false; + break; + case RunWorkerState::Running: + debugMessage(" " + workerId + " was Running, queuing stop"); + worker->d->state = RunWorkerState::Stopping; + allDone = false; + QTimer::singleShot(0, worker, &RunWorker::initiateStop); + break; + case RunWorkerState::Done: + debugMessage(" " + workerId + " was Done. Good."); + break; + case RunWorkerState::Failed: + debugMessage(" " + workerId + " was Failed. Good"); + break; + } + } else { + debugMessage("Found unknown deleted worker"); + } + } + if (allDone) { + debugMessage("All stopped."); + setState(RunControlState::Stopped); + } else { + debugMessage("Not all workers stopped. Waiting..."); + } } -void RunControlPrivate::continueStop() +void RunControlPrivate::initiateFinish() { - debugMessage("Continue Stopping"); - checkState(RunControlState::Stopping); + setState(RunControlState::Finishing); + debugMessage("Ramping down"); + bool allDone = true; for (RunWorker *worker : m_workers) { if (worker) { @@ -904,17 +899,17 @@ void RunControlPrivate::continueStop() allDone = false; break; case RunWorkerState::Starting: - worker->d->state = RunWorkerState::Stopping; debugMessage(" " + workerId + " was Starting, queuing stop"); - allDone = false; + worker->d->state = RunWorkerState::Stopping; QTimer::singleShot(0, worker, &RunWorker::initiateStop); - return; // Sic. + allDone = false; + break; case RunWorkerState::Running: debugMessage(" " + workerId + " was Running, queuing stop"); worker->d->state = RunWorkerState::Stopping; allDone = false; QTimer::singleShot(0, worker, &RunWorker::initiateStop); - return; // Sic. + break; case RunWorkerState::Done: debugMessage(" " + workerId + " was Done. Good."); break; @@ -927,8 +922,9 @@ void RunControlPrivate::continueStop() } } if (allDone) { - debugMessage("All workers stopped. Set runControl to Stopped"); - setState(RunControlState::Stopped); + setState(RunControlState::Finished); + } else { + debugMessage("Not all workers finished. Waiting..."); } } @@ -944,7 +940,6 @@ void RunControlPrivate::onWorkerStarted(RunWorker *worker) showError(tr("Unexpected run control state %1 when worker %2 started") .arg(stateName(state)) .arg(worker->d->id)); - //setState(RunControlState::Stopped); } void RunControlPrivate::onWorkerFailed(RunWorker *worker, const QString &msg) @@ -968,13 +963,72 @@ void RunControlPrivate::onWorkerStopped(RunWorker *worker) worker->d->state = RunWorkerState::Done; debugMessage(workerId + " stopped expectedly."); break; + case RunWorkerState::Done: + worker->d->state = RunWorkerState::Done; + debugMessage(workerId + " stopped twice. Huh? But harmless."); + return; // Sic! default: debugMessage(workerId + " stopped unexpectedly in state" + stateName(worker->d->state)); worker->d->state = RunWorkerState::Failed; break; } - continueStop(); + + debugMessage("Checking whether all stopped"); + bool allDone = true; + for (RunWorker *worker : m_workers) { + if (worker) { + const QString &workerId = worker->d->id; + debugMessage(" Examining worker " + workerId); + switch (worker->d->state) { + case RunWorkerState::Initialized: + debugMessage(" " + workerId + " was Initialized, setting to Done"); + worker->d->state = RunWorkerState::Done; + break; + case RunWorkerState::Starting: + worker->d->state = RunWorkerState::Stopping; + debugMessage(" " + workerId + " was Starting, queuing stop"); + allDone = false; + break; + case RunWorkerState::Running: + debugMessage(" " + workerId + " was Running, queuing stop"); + worker->d->state = RunWorkerState::Stopping; + allDone = false; + break; + case RunWorkerState::Stopping: + debugMessage(" " + workerId + " was already Stopping. Keeping it that way"); + allDone = false; + break; + case RunWorkerState::Done: + debugMessage(" " + workerId + " was Done. Good."); + break; + case RunWorkerState::Failed: + debugMessage(" " + workerId + " was Failed. Good"); + break; + } + } else { + debugMessage("Found unknown deleted worker"); + } + } + if (state == RunControlState::Finishing) { + if (allDone) { + debugMessage("All finished. Deleting myself"); + setState(RunControlState::Finished); + } else { + debugMessage("Not all workers finished. Waiting..."); + } + } else { + if (allDone) { + if (state == RunControlState::Stopped) { + debugMessage("All workers stopped, but runControl was already stopped."); + } else { + debugMessage("All workers stopped. Set runControl to Stopped"); + setState(RunControlState::Stopped); + } + } else { + debugMessage("Not all workers stopped. Waiting..."); + } + } } void RunControlPrivate::showError(const QString &msg) @@ -1175,15 +1229,23 @@ bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlStat { switch (from) { case RunControlState::Initialized: - return to == RunControlState::Starting; + return to == RunControlState::Starting + || to == RunControlState::Finishing; case RunControlState::Starting: - return to == RunControlState::Running; + return to == RunControlState::Running + || to == RunControlState::Finishing; case RunControlState::Running: return to == RunControlState::Stopping - || to == RunControlState::Stopped; + || to == RunControlState::Stopped + || to == RunControlState::Finishing; case RunControlState::Stopping: - return to == RunControlState::Stopped; + return to == RunControlState::Stopped + || to == RunControlState::Finishing; case RunControlState::Stopped: + return to == RunControlState::Finishing; + case RunControlState::Finishing: + return to == RunControlState::Finished; + case RunControlState::Finished: return false; } return false; @@ -1213,11 +1275,13 @@ void RunControlPrivate::setState(RunControlState newState) break; case RunControlState::Stopped: q->setApplicationProcessHandle(Utils::ProcessHandle()); - foreach (auto worker, m_workers) - if (worker) - worker->onFinished(); emit q->stopped(); break; + case RunControlState::Finished: + emit q->finished(); + debugMessage("All finished. Deleting myself"); + deleteLater(); + break; default: break; } @@ -1228,18 +1292,6 @@ void RunControlPrivate::debugMessage(const QString &msg) qCDebug(statesLog()) << msg; } -/*! - Brings the application determined by this RunControl's \c applicationProcessHandle - to the foreground. - - The default implementation raises the application on Mac, and does - nothing elsewhere. -*/ -void RunControl::bringApplicationToForeground() -{ - d->applicationProcessHandle.activate(); -} - void RunControl::appendMessage(const QString &msg, Utils::OutputFormat format) { emit appendMessageRequested(this, msg, format); @@ -1358,8 +1410,9 @@ void SimpleTargetRunner::stop() void SimpleTargetRunner::onProcessStarted() { // Console processes only know their pid after being started - runControl()->setApplicationProcessHandle(m_launcher.applicationPID()); - runControl()->bringApplicationToForeground(); + ProcessHandle pid = m_launcher.applicationPID(); + runControl()->setApplicationProcessHandle(pid); + pid.activate(); reportStarted(); } |