aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/projectexplorer/runconfiguration.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/projectexplorer/runconfiguration.cpp')
-rw-r--r--src/plugins/projectexplorer/runconfiguration.cpp299
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();
}