Commit 89f02cba authored by hjk's avatar hjk

ProjectExplorer: Split Target and ToolRunners into smaller tasks

This increases re-usability of activities like 'port gathering',
and makes their use less dependent on actual device implementations.

Change-Id: I017cb74874f2b38c487ba2d03906a675d5618647
Reviewed-by: Christian Stenger's avatarChristian Stenger <christian.stenger@qt.io>
parent 9b93d5a3
......@@ -27,8 +27,11 @@
#include "utils_global.h"
#include "qtcassert.h"
#include <limits>
#include <QMetaType>
#include <QString>
#include <limits>
namespace Utils {
......@@ -50,6 +53,8 @@ public:
quint16 number() const { QTC_ASSERT(isValid(), return 0); return quint16(m_port); }
bool isValid() const { return m_port != -1; }
QString toString() const { return QString::number(m_port); }
private:
int m_port;
};
......
......@@ -48,7 +48,8 @@ namespace Internal {
RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(RunConfiguration *runConfig, Core::Id runMode)
{
RunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, runMode);
auto runControl = new RunControl(runConfig, runMode);
runControl->createWorker(runMode);
QTC_ASSERT(runControl, return 0);
AnalyzerConnection connection;
if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) {
......@@ -64,7 +65,7 @@ RunControl *AndroidAnalyzeSupport::createAnalyzeRunControl(RunConfiguration *run
}
AndroidAnalyzeSupport::AndroidAnalyzeSupport(RunControl *runControl)
: ToolRunner(runControl)
: RunWorker(runControl)
{
auto runner = new AndroidRunner(this, runControl->runConfiguration(), runControl->runMode());
......
......@@ -34,7 +34,7 @@
namespace Android {
namespace Internal {
class AndroidAnalyzeSupport : public ProjectExplorer::ToolRunner
class AndroidAnalyzeSupport : public ProjectExplorer::RunWorker
{
Q_OBJECT
......
......@@ -40,6 +40,7 @@ struct ANDROID_EXPORT AndroidRunnable
QVector<QStringList> afterFinishADBCommands;
QString deviceSerialNumber;
QString displayName() const { return packageName; }
static void *staticTypeId;
};
......
......@@ -71,8 +71,9 @@ namespace Internal {
ClangStaticAnalyzerToolRunner::ClangStaticAnalyzerToolRunner(RunControl *runControl,
QString *errorMessage)
: ToolRunner(runControl)
: RunWorker(runControl)
{
setDisplayName("ClangStaticAnalyzerRunner");
runControl->setDisplayName(tr("Clang Static Analyzer"));
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
runControl->setSupportsReRunning(false);
......@@ -585,7 +586,7 @@ void ClangStaticAnalyzerToolRunner::start()
return;
}
reportSuccess();
reportStarted();
while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
analyzeNextFile();
......
......@@ -47,7 +47,7 @@ struct AnalyzeUnit {
};
typedef QList<AnalyzeUnit> AnalyzeUnits;
class ClangStaticAnalyzerToolRunner : public ProjectExplorer::ToolRunner
class ClangStaticAnalyzerToolRunner : public ProjectExplorer::RunWorker
{
Q_OBJECT
......
......@@ -145,7 +145,7 @@ ClangStaticAnalyzerTool::ClangStaticAnalyzerTool()
{{ClangStaticAnalyzerDockId, m_diagnosticView, {}, Perspective::SplitVertical}}
));
Debugger::registerAction(Constants::CLANGSTATICANALYZER_RUN_MODE, {});
//Debugger::registerAction(Constants::CLANGSTATICANALYZER_RUN_MODE, {});
action = new QAction(tr("Clang Static Analyzer"), this);
action->setToolTip(toolTip);
menu->addAction(ActionManager::registerAction(action, "ClangStaticAnalyzer.Action"),
......
......@@ -59,16 +59,12 @@ enum ToolMode {
//AnyMode = DebugMode | ProfileMode | ReleaseMode
};
using RunControlCreator = std::function<ProjectExplorer::RunControl *
(ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode)>;
// FIXME: Merge with something sensible.
DEBUGGER_EXPORT bool wantRunTool(ToolMode toolMode, const QString &toolName);
DEBUGGER_EXPORT void showCannotStartDialog(const QString &toolName);
DEBUGGER_EXPORT ProjectExplorer::RunConfiguration *startupRunConfiguration();
// Register a tool for a given start mode.
DEBUGGER_EXPORT void registerAction(Core::Id runMode, const RunControlCreator &runControlCreator);
DEBUGGER_EXPORT void registerPerspective(const QByteArray &perspectiveId, const Utils::Perspective *perspective);
DEBUGGER_EXPORT void registerToolbar(const QByteArray &perspectiveId, const Utils::ToolbarDescription &desc);
......@@ -85,7 +81,4 @@ DEBUGGER_EXPORT void showPermanentStatusMessage(const QString &message);
DEBUGGER_EXPORT QAction *createStartAction();
DEBUGGER_EXPORT QAction *createStopAction();
DEBUGGER_EXPORT ProjectExplorer::RunControl *createAnalyzerRunControl(
ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode);
} // namespace Debugger
......@@ -561,7 +561,7 @@ void DebuggerEngine::setRunTool(DebuggerRunTool *runTool)
d->m_runTool = runTool;
}
void DebuggerEngine::prepare()
void DebuggerEngine::start()
{
QTC_ASSERT(d->m_runTool, notifyEngineSetupFailed(); return);
......@@ -602,25 +602,7 @@ void DebuggerEngine::prepare()
}
d->queueSetupEngine();
}
void DebuggerEngine::start()
{
Internal::runControlStarted(this);
// We might get a synchronous startFailed() notification on Windows,
// when launching the process fails. Emit a proper finished() sequence.
//runControl()->reportApplicationStart();
showMessage("QUEUE: SETUP INFERIOR");
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
// if (isMasterEngine())
d->queueSetupInferior();
}
void DebuggerEngine::startDebugger()
{
d->queueRunEngine();
}
void DebuggerEngine::resetLocation()
......@@ -822,7 +804,9 @@ void DebuggerEngine::notifyEngineSetupOk()
QTC_ASSERT(state() == EngineSetupRequested, qDebug() << this << state());
setState(EngineSetupOk);
runTool()->reportSuccess();
Internal::runControlStarted(this);
d->queueSetupInferior();
}
void DebuggerEngine::setupSlaveInferior()
......@@ -1313,6 +1297,11 @@ void DebuggerEngine::setState(DebuggerState state, bool forced)
DebuggerToolTipManager::registerEngine(this);
}
if (state == InferiorUnrunnable || state == InferiorRunOk) {
if (isMasterEngine() && runTool())
runTool()->reportStarted();
}
if (state == DebuggerFinished) {
// Give up ownership on claimed breakpoints.
foreach (Breakpoint bp, breakHandler()->engineBreakpoints(this))
......
......@@ -202,11 +202,8 @@ public:
virtual void setRunTool(DebuggerRunTool *runTool);
DebuggerRunTool *runTool() const;
void prepare();
void start();
void startDebugger();
enum {
// Remove need to qualify each use.
NeedsTemporaryStop = DebuggerCommand::NeedsTemporaryStop,
......
......@@ -973,7 +973,6 @@ public:
QPointer<QWidget> m_modeWindow;
QPointer<DebugMode> m_mode;
QHash<Id, RunControlCreator> m_runControlCreators;
ActionContainer *m_menu = 0;
// DockWidgetEventFilter m_resizeEventFilter;
......@@ -3527,11 +3526,6 @@ bool wantRunTool(ToolMode toolMode, const QString &toolName)
return true;
}
void registerAction(Id runMode, const RunControlCreator &runControlCreator)
{
dd->m_runControlCreators.insert(runMode, runControlCreator);
}
void registerToolbar(const QByteArray &perspectiveId, const ToolbarDescription &desc)
{
auto toolbar = new QWidget;
......@@ -3605,14 +3599,6 @@ void showPermanentStatusMessage(const QString &message)
dd->m_mainWindow->showStatusMessage(message, -1);
}
RunControl *createAnalyzerRunControl(RunConfiguration *runConfiguration, Id runMode)
{
RunControlCreator rcc = dd->m_runControlCreators.value(runMode);
if (rcc)
return rcc(runConfiguration, runMode);
return nullptr;
}
namespace Internal {
static bool s_testRun = false;
......
......@@ -109,19 +109,15 @@ static QLatin1String engineTypeName(DebuggerEngineType et)
return QLatin1String("No engine");
}
void DebuggerRunTool::prepare()
void DebuggerRunTool::start()
{
Debugger::Internal::saveModeToRestore();
Debugger::selectPerspective(Debugger::Constants::CppPerspectiveId);
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_DEBUGINFO);
TaskHub::clearTasks(Debugger::Constants::TASK_CATEGORY_DEBUGGER_RUNTIME);
m_engine->prepare();
}
void DebuggerRunTool::start()
{
DebuggerEngine *engine = m_engine;
QTC_ASSERT(engine, return);
const DebuggerRunParameters &rp = engine->runParameters();
// User canceled input dialog asking for executable when working on library project.
......@@ -177,11 +173,6 @@ void DebuggerRunTool::notifyEngineRemoteSetupFinished(const RemoteSetupResult &r
m_engine->notifyEngineRemoteSetupFinished(result);
}
void DebuggerRunTool::setRemoteParameters(const RemoteSetupResult &result)
{
m_engine->setRemoteParameters(result);
}
void DebuggerRunTool::stop()
{
m_engine->quitDebugger();
......@@ -199,7 +190,7 @@ void DebuggerRunTool::onTargetFailure()
void DebuggerRunTool::debuggingFinished()
{
runControl()->reportApplicationStop();
reportStopped();
}
DebuggerStartParameters &DebuggerRunTool::startParameters()
......@@ -495,10 +486,11 @@ static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runContr
/// DebuggerRunTool
DebuggerRunTool::DebuggerRunTool(RunControl *runControl)
: ToolRunner(runControl),
: RunWorker(runControl),
m_isCppDebugging(debuggerAspect(runControl)->useCppDebugger()),
m_isQmlDebugging(debuggerAspect(runControl)->useQmlDebugger())
{
setDisplayName("DebuggerRunTool");
}
DebuggerRunTool::DebuggerRunTool(RunControl *runControl, const DebuggerStartParameters &sp, QString *errorMessage)
......@@ -577,7 +569,7 @@ DebuggerRunTool::~DebuggerRunTool()
void DebuggerRunTool::onFinished()
{
appendMessage(tr("Debugging has finished") + '\n', NormalMessageFormat);
appendMessage(tr("Debugging has finished"), NormalMessageFormat);
runControlFinished(m_engine);
}
......@@ -619,8 +611,9 @@ public:
QTC_ASSERT(runConfig, return 0);
QTC_ASSERT(mode == DebugRunMode || mode == DebugRunModeWithBreakOnMain, return 0);
DebuggerStartParameters sp;
auto runControl = new RunControl(runConfig, mode);
(void) new DebuggerRunTool(runControl, DebuggerStartParameters(), errorMessage);
(void) new DebuggerRunTool(runControl, sp, errorMessage);
return runControl;
}
......@@ -690,10 +683,109 @@ RunControl *createAndScheduleRun(const DebuggerRunParameters &rp, Kit *kit)
QTC_ASSERT(runConfig, return nullptr);
auto runControl = new RunControl(runConfig, DebugRunMode);
(void) new DebuggerRunTool(runControl, rp);
QTC_ASSERT(runControl, return nullptr);
ProjectExplorerPlugin::startRunControl(runControl);
return runControl;
}
} // Internal
// GdbServerPortGatherer
GdbServerPortsGatherer::GdbServerPortsGatherer(RunControl *runControl)
: RunWorker(runControl)
{
}
GdbServerPortsGatherer::~GdbServerPortsGatherer()
{
}
void GdbServerPortsGatherer::start()
{
appendMessage(tr("Checking available ports..."), NormalMessageFormat);
connect(&m_portsGatherer, &DeviceUsedPortsGatherer::error, this, [this](const QString &msg) {
reportFailure(msg);
});
connect(&m_portsGatherer, &DeviceUsedPortsGatherer::portListReady, this, [this] {
Utils::PortList portList = device()->freePorts();
appendMessage(tr("Found %1 free ports").arg(portList.count()), NormalMessageFormat);
if (m_useGdbServer) {
m_gdbServerPort = m_portsGatherer.getNextFreePort(&portList);
if (!m_gdbServerPort.isValid()) {
reportFailure(tr("Not enough free ports on device for C++ debugging."));
return;
}
}
if (m_useQmlServer) {
m_qmlServerPort = m_portsGatherer.getNextFreePort(&portList);
if (!m_qmlServerPort.isValid()) {
reportFailure(tr("Not enough free ports on device for QML debugging."));
return;
}
}
reportStarted();
});
m_portsGatherer.start(device());
}
// GdbServerRunner
GdbServerRunner::GdbServerRunner(RunControl *runControl)
: RunWorker(runControl)
{
setDisplayName("GdbServerRunner");
}
GdbServerRunner::~GdbServerRunner()
{
}
void GdbServerRunner::start()
{
auto portsGatherer = runControl()->worker<GdbServerPortsGatherer>();
QTC_ASSERT(portsGatherer, reportFailure(); return);
StandardRunnable r = runnable().as<StandardRunnable>();
QStringList args = QtcProcess::splitArgs(r.commandLineArguments, OsTypeLinux);
QString command;
const bool isQmlDebugging = portsGatherer->useQmlServer();
const bool isCppDebugging = portsGatherer->useGdbServer();
if (isQmlDebugging) {
args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices,
portsGatherer->qmlServerPort()));
}
if (isQmlDebugging && !isCppDebugging) {
command = r.executable;
} else {
command = device()->debugServerPath();
if (command.isEmpty())
command = "gdbserver";
args.clear();
args.append(QString("--multi"));
args.append(QString(":%1").arg(portsGatherer->gdbServerPort().number()));
}
r.executable = command;
r.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux);
connect(&m_gdbServer, &ApplicationLauncher::error, this, [this] {
reportFailure(tr("GDBserver start failed"));
});
connect(&m_gdbServer, &ApplicationLauncher::remoteProcessStarted, this, [this] {
appendMessage(tr("GDBserver started") + '\n', NormalMessageFormat);
reportStarted();
});
appendMessage(tr("Starting GDBserver...") + '\n', NormalMessageFormat);
m_gdbServer.start(r, device());
}
void GdbServerRunner::onFinished()
{
m_gdbServer.stop();
}
} // namespace Debugger
......@@ -30,13 +30,14 @@
#include "debuggerengine.h"
#include <projectexplorer/runconfiguration.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
namespace Debugger {
class RemoteSetupResult;
class DebuggerStartParameters;
class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::ToolRunner
class DEBUGGER_EXPORT DebuggerRunTool : public ProjectExplorer::RunWorker
{
Q_OBJECT
......@@ -60,16 +61,14 @@ public:
void showMessage(const QString &msg, int channel = LogDebug, int timeout = -1);
void prepare() override;
void start() override;
void stop() override;
void onTargetFailure() override;
void onFinished() override;
void startFailed();
void onTargetFailure();
void notifyEngineRemoteServerRunning(const QByteArray &msg, int pid);
void notifyEngineRemoteSetupFinished(const RemoteSetupResult &result);
void setRemoteParameters(const RemoteSetupResult &result);
void notifyInferiorIll();
Q_SLOT void notifyInferiorExited();
void quitDebugger();
......@@ -97,4 +96,48 @@ private:
const bool m_isQmlDebugging;
};
class DEBUGGER_EXPORT GdbServerPortsGatherer : public ProjectExplorer::RunWorker
{
Q_OBJECT
public:
explicit GdbServerPortsGatherer(ProjectExplorer::RunControl *runControl);
~GdbServerPortsGatherer();
void setUseGdbServer(bool useIt) { m_useGdbServer = useIt; }
bool useGdbServer() const { return m_useGdbServer; }
Utils::Port gdbServerPort() const { return m_gdbServerPort; }
void setUseQmlServer(bool useIt) { m_useQmlServer = useIt; }
bool useQmlServer() const { return m_useQmlServer; }
Utils::Port qmlServerPort() const { return m_qmlServerPort; }
private:
void start();
ProjectExplorer::DeviceUsedPortsGatherer m_portsGatherer;
bool m_useGdbServer = false;
bool m_useQmlServer = false;
Utils::Port m_gdbServerPort;
Utils::Port m_qmlServerPort;
};
class DEBUGGER_EXPORT GdbServerRunner : public ProjectExplorer::RunWorker
{
Q_OBJECT
public:
explicit GdbServerRunner(ProjectExplorer::RunControl *runControl);
~GdbServerRunner();
private:
void start() override;
void onFinished() override;
ProjectExplorer::ApplicationLauncher m_gdbServer;
};
extern DEBUGGER_EXPORT const char GdbServerRunnerWorkerId[];
extern DEBUGGER_EXPORT const char GdbServerPortGathererWorkerId[];
} // namespace Debugger
......@@ -32,7 +32,7 @@ namespace Ios {
namespace Internal {
IosAnalyzeSupport::IosAnalyzeSupport(RunControl *runControl, bool cppDebug, bool qmlDebug)
: ToolRunner(runControl),
: RunWorker(runControl),
m_runner(new IosRunner(this, runControl, cppDebug, qmlDebug ? QmlDebug::QmlProfilerServices :
QmlDebug::NoQmlDebugServices))
{
......
......@@ -34,7 +34,7 @@ namespace Internal {
class IosRunner;
class IosAnalyzeSupport : public ProjectExplorer::ToolRunner
class IosAnalyzeSupport : public ProjectExplorer::RunWorker
{
Q_OBJECT
......
......@@ -184,11 +184,8 @@ RunControl *IosRunControlFactory::create(RunConfiguration *runConfig,
if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE)
res = new Ios::Internal::IosRunControl(rc);
else if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) {
RunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode);
QTC_ASSERT(runControl, return 0);
IDevice::ConstPtr device = DeviceKitInformation::device(target->kit());
if (device.isNull())
return 0;
auto runControl = new RunControl(runConfig, mode);
runControl->createWorker(mode);
auto iosRunConfig = qobject_cast<IosRunConfiguration *>(runConfig);
StandardRunnable runnable;
runnable.executable = iosRunConfig->localExecutable().toUserOutput();
......
......@@ -525,11 +525,16 @@ void AppOutputPane::attachToRunControl()
void AppOutputPane::stopRunControl()
{
const int index = currentIndex();
QTC_ASSERT(index != -1 && m_runControlTabs.at(index).runControl->isRunning(), return);
QTC_ASSERT(index != -1, return);
RunControl *rc = m_runControlTabs.at(index).runControl;
QTC_ASSERT(rc, return);
if (rc->isRunning() && optionallyPromptToStop(rc))
rc->initiateStop();
else if (rc->isStarting()) {
QTC_CHECK(false);
rc->initiateStop();
}
if (debug)
qDebug() << "OutputPane::stopRunControl " << rc;
......
......@@ -190,4 +190,40 @@ void DeviceUsedPortsGatherer::handleRemoteStdErr()
d->remoteStderr += d->process->readAllStandardError();
}
// PortGatherer
PortsGatherer::PortsGatherer(RunControl *runControl)
: RunWorker(runControl)
{
setDisplayName("PortGatherer");
}
PortsGatherer::~PortsGatherer()
{
}
void PortsGatherer::start()
{
appendMessage(tr("Checking available ports...") + '\n', NormalMessageFormat);
connect(&m_portsGatherer, &DeviceUsedPortsGatherer::error, this, [this](const QString &msg) {
reportFailure(msg);
});
connect(&m_portsGatherer, &DeviceUsedPortsGatherer::portListReady, this, [this] {
m_portList = device()->freePorts();
appendMessage(tr("Found %1 free ports").arg(m_portList.count()) + '\n', NormalMessageFormat);
reportStarted();
});
m_portsGatherer.start(device());
}
Port PortsGatherer::findPort()
{
return m_portsGatherer.getNextFreePort(&m_portList);
}
void PortsGatherer::stop()
{
m_portsGatherer.stop();
}
} // namespace ProjectExplorer
......@@ -27,10 +27,9 @@
#include "idevice.h"
namespace Utils {
class Port;
class PortList;
} // namespace Utils
#include <projectexplorer/runconfiguration.h>
#include <utils/portlist.h>
namespace ProjectExplorer {
namespace Internal { class DeviceUsedPortsGathererPrivate; }
......@@ -64,4 +63,23 @@ private:
Internal::DeviceUsedPortsGathererPrivate * const d;
};
class PROJECTEXPLORER_EXPORT PortsGatherer : public RunWorker
{
Q_OBJECT
public:
explicit PortsGatherer(RunControl *runControl);
~PortsGatherer() override;
Utils::Port findPort();
protected:
void start() override;
void stop() override;
private:
DeviceUsedPortsGatherer m_portsGatherer;
Utils::PortList m_portList;
};
} // namespace ProjectExplorer
......@@ -35,6 +35,8 @@
#include <QSharedPointer>
#include <QVariantMap>
#include <functional>
QT_BEGIN_NAMESPACE
class QWidget;
QT_END_NAMESPACE
......@@ -54,6 +56,8 @@ class Connection;
class DeviceProcess;
class DeviceProcessList;
class Kit;
class RunControl;
class RunWorker;
namespace Internal { class IDevicePrivate; }
......@@ -162,6 +166,8 @@ public:
virtual DeviceProcessSignalOperation::Ptr signalOperation() const = 0;
virtual DeviceEnvironmentFetcher::Ptr environmentFetcher() const;