diff options
author | hjk <hjk@qt.io> | 2017-05-09 10:25:11 +0200 |
---|---|---|
committer | hjk <hjk@qt.io> | 2017-05-15 14:35:03 +0000 |
commit | 89f02cba2ca65f84d99b0b35f555da024f3e2234 (patch) | |
tree | 408bd4b2da13e00227697f871cefbf1ea9c4ab98 | |
parent | 9b93d5a330a4898d12ce99414a51d1bd6cda51ec (diff) |
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 <christian.stenger@qt.io>
56 files changed, 1267 insertions, 1840 deletions
diff --git a/src/libs/utils/port.h b/src/libs/utils/port.h index c05c8b2d38..e668c46265 100644 --- a/src/libs/utils/port.h +++ b/src/libs/utils/port.h @@ -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; }; diff --git a/src/plugins/android/androidanalyzesupport.cpp b/src/plugins/android/androidanalyzesupport.cpp index bf5579c867..4ee0463489 100644 --- a/src/plugins/android/androidanalyzesupport.cpp +++ b/src/plugins/android/androidanalyzesupport.cpp @@ -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()); diff --git a/src/plugins/android/androidanalyzesupport.h b/src/plugins/android/androidanalyzesupport.h index 887796153d..6c96fc658a 100644 --- a/src/plugins/android/androidanalyzesupport.h +++ b/src/plugins/android/androidanalyzesupport.h @@ -34,7 +34,7 @@ namespace Android { namespace Internal { -class AndroidAnalyzeSupport : public ProjectExplorer::ToolRunner +class AndroidAnalyzeSupport : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/android/androidrunnable.h b/src/plugins/android/androidrunnable.h index c6ff742112..0c1a894250 100644 --- a/src/plugins/android/androidrunnable.h +++ b/src/plugins/android/androidrunnable.h @@ -40,6 +40,7 @@ struct ANDROID_EXPORT AndroidRunnable QVector<QStringList> afterFinishADBCommands; QString deviceSerialNumber; + QString displayName() const { return packageName; } static void *staticTypeId; }; diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 37721ec772..43fdf32bc0 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -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(); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h index 28d7600493..3c6b4267d7 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h @@ -47,7 +47,7 @@ struct AnalyzeUnit { }; typedef QList<AnalyzeUnit> AnalyzeUnits; -class ClangStaticAnalyzerToolRunner : public ProjectExplorer::ToolRunner +class ClangStaticAnalyzerToolRunner : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp index e1e7c2adef..c8f1f6c8ba 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp @@ -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"), diff --git a/src/plugins/debugger/analyzer/analyzermanager.h b/src/plugins/debugger/analyzer/analyzermanager.h index 3558a79646..9a3dedd9d9 100644 --- a/src/plugins/debugger/analyzer/analyzermanager.h +++ b/src/plugins/debugger/analyzer/analyzermanager.h @@ -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 diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index d99a2cdec0..31a3997dd5 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -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)) diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 75a1174af9..aa927b89dd 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -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, diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index c712f8246b..5af6473faf 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -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; diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 9e62606f36..2e5f42db98 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -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 diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index fef388cc91..29c5a7e545 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -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 diff --git a/src/plugins/ios/iosanalyzesupport.cpp b/src/plugins/ios/iosanalyzesupport.cpp index 5bdb9a2da7..795da9d1aa 100644 --- a/src/plugins/ios/iosanalyzesupport.cpp +++ b/src/plugins/ios/iosanalyzesupport.cpp @@ -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)) { diff --git a/src/plugins/ios/iosanalyzesupport.h b/src/plugins/ios/iosanalyzesupport.h index 6c3677d1a7..2b621034ea 100644 --- a/src/plugins/ios/iosanalyzesupport.h +++ b/src/plugins/ios/iosanalyzesupport.h @@ -34,7 +34,7 @@ namespace Internal { class IosRunner; -class IosAnalyzeSupport : public ProjectExplorer::ToolRunner +class IosAnalyzeSupport : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/ios/iosrunfactories.cpp b/src/plugins/ios/iosrunfactories.cpp index b331fdb9f4..5571258d63 100644 --- a/src/plugins/ios/iosrunfactories.cpp +++ b/src/plugins/ios/iosrunfactories.cpp @@ -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(); diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp index 3757a0e7b7..ce5511e910 100644 --- a/src/plugins/projectexplorer/appoutputpane.cpp +++ b/src/plugins/projectexplorer/appoutputpane.cpp @@ -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; diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp index 60f4a39ca7..c5396677e8 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.cpp @@ -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 diff --git a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h index e326557469..c298b6fbd0 100644 --- a/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h +++ b/src/plugins/projectexplorer/devicesupport/deviceusedportsgatherer.h @@ -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 diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index a48962c674..a93a029821 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -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; + virtual std::function<RunWorker *(RunControl *)> workerCreator(Core::Id) const { return {}; } + enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown }; DeviceState deviceState() const; void setDeviceState(const DeviceState state); diff --git a/src/plugins/projectexplorer/runconfiguration.cpp b/src/plugins/projectexplorer/runconfiguration.cpp index a7d75c38e9..219cc5baff 100644 --- a/src/plugins/projectexplorer/runconfiguration.cpp +++ b/src/plugins/projectexplorer/runconfiguration.cpp @@ -48,6 +48,8 @@ #include <QDir> #include <QPushButton> #include <QTimer> +#include <QLoggingCategory> +#include <QSettings> #ifdef Q_OS_OSX #include <ApplicationServices/ApplicationServices.h> @@ -60,7 +62,9 @@ using namespace Utils; using namespace ProjectExplorer::Internal; -const bool debugStates = false; +namespace { +Q_LOGGING_CATEGORY(statesLog, "qtc.projectmanager.states") +} namespace ProjectExplorer { @@ -506,6 +510,70 @@ IRunConfigurationAspect *IRunControlFactory::createRunConfigurationAspect(RunCon namespace Internal { +enum class RunWorkerState +{ + Initialized, Starting, Running, Stopping, Done, Failed +}; + +//static QString stateName(RunWorkerState s) +//{ +//# define SN(x) case x: return QLatin1String(#x); +// switch (s) { +// SN(RunWorkerState::Initialized) +// SN(RunWorkerState::Starting) +// SN(RunWorkerState::Running) +// SN(RunWorkerState::Stopping) +// SN(RunWorkerState::Done) +// SN(RunWorkerState::Failed) +// } +// return QLatin1String("<unknown>"); +//# undef SN +//} + +class RunWorkerPrivate : public QObject +{ +public: + RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl); + + bool canStart() const; + void timerEvent(QTimerEvent *ev) override; + + RunWorker *q; + RunWorkerState state = RunWorkerState::Initialized; + RunControl *runControl; + QList<RunWorker *> dependencies; + QString displayName; + + QVariantMap data; + int startWatchdogInterval = 0; + int startWatchdogTimerId = -1; + int stopWatchdogInterval = 0; // 5000; + int stopWatchdogTimerId = -1; +}; + +enum class RunControlState +{ + Initialized, // Default value after creation. + Starting, // Actual process/tool starts. + Running, // All good and running. + Stopping, // initiateStop() was called, stop application/tool + Stopped, // all good, but stopped. Can possibly be re-started +}; + +static QString stateName(RunControlState s) +{ +# define SN(x) case x: return QLatin1String(#x); + switch (s) { + SN(RunControlState::Initialized) + SN(RunControlState::Starting) + SN(RunControlState::Running) + SN(RunControlState::Stopping) + SN(RunControlState::Stopped) + } + return QLatin1String("<unknown>"); +# undef SN +} + class RunControlPrivate : public QObject { public: @@ -524,63 +592,30 @@ public: ~RunControlPrivate() { - QTC_CHECK(state == State::Stopped || state == State::Initialized); - delete targetRunner; - delete toolRunner; + QTC_CHECK(state == RunControlState::Stopped || state == RunControlState::Initialized); + qDeleteAll(m_workers); delete outputFormatter; } - enum class State { - Initialized, // Default value after creation. - TargetPreparing, // initiateStart() was called, target boots up, connects, etc - ToolPreparing, // Target is acessible, tool boots - TargetStarting, // Late corrections on the target side after tool is available. - ToolStarting, // Actual process/tool starts. - Running, // All good and running. - ToolStopping, // initiateStop() was called, stop application/tool - TargetStopping, // Potential clean up on target, set idle state, etc. - Stopped, // all good, but stopped. Can possibly be re-started - }; - Q_ENUM(State) - - void checkState(State expectedState); - void setState(State state); + Q_ENUM(RunControlState) + + void checkState(RunControlState expectedState); + void setState(RunControlState state); void debugMessage(const QString &msg); - QString stateName(State s) const; void initiateStart(); - - void onTargetPrepared(); - void onTargetPrepareFailed(const QString &msg); - - void onToolPrepared(); - void onToolPrepareFailed(const QString &msg); - - void onTargetStarted(); - void onTargetStartFailed(const QString &msg); - - void onToolStarted(); - void onToolStartFailed(const QString &msg); - + void continueStart(); void initiateStop(); - void onToolStopped(); - void onToolStopFailed(const QString &msg); + void continueStop(); - void onTargetStopped(); - void onTargetStopFailed(const QString &msg); - - void onToolFailed(const QString &msg); - void onToolSuccess(); - - void onTargetFailed(const QString &msg); - void onTargetSuccess(); - - void handleFailure(); + void onWorkerStarted(RunWorker *worker); + void onWorkerStopped(RunWorker *worker); + void onWorkerFailed(RunWorker *worker, const QString &msg); void showError(const QString &msg); - static bool isAllowedTransition(State from, State to); + static bool isAllowedTransition(RunControlState from, RunControlState to); RunControl *q; QString displayName; @@ -591,17 +626,17 @@ public: Utils::Icon icon; const QPointer<RunConfiguration> runConfiguration; // Not owned. QPointer<Project> project; // Not owned. - QPointer<TargetRunner> targetRunner; // Owned. QPointer as "extra safety" for now. - QPointer<ToolRunner> toolRunner; // Owned. QPointer as "extra safety" for now. Utils::OutputFormatter *outputFormatter = nullptr; std::function<bool(bool*)> promptToStop; // A handle to the actual application process. Utils::ProcessHandle applicationProcessHandle; - State state = State::Initialized; + RunControlState state = RunControlState::Initialized; bool supportsReRunning = true; + QList<QPointer<RunWorker>> m_workers; + #ifdef Q_OS_OSX // This is used to bring apps in the foreground on Mac int foregroundCount; @@ -615,8 +650,6 @@ using namespace Internal; RunControl::RunControl(RunConfiguration *runConfiguration, Core::Id mode) : d(new RunControlPrivate(this, runConfiguration, mode)) { - (void) new TargetRunner(this); - (void) new ToolRunner(this); #ifdef WITH_JOURNALD JournaldWatcher::instance()->subscribe(this, [this](const JournaldWatcher::LogEntry &entry) { if (entry.value("_MACHINE_ID") != JournaldWatcher::instance()->machineId()) @@ -667,204 +700,178 @@ void RunControl::stop() d->initiateStop(); } -void RunControlPrivate::initiateStart() -{ - checkState(State::Initialized); - setState(State::TargetPreparing); - debugMessage("Queue: Prepare target runner"); - QTimer::singleShot(0, targetRunner, [this](){ targetRunner->prepare(); }); -} - -void RunControlPrivate::onTargetPrepared() -{ - checkState(State::TargetPreparing); - setState(State::ToolPreparing); - debugMessage("Queue: Prepare tool runner"); - QTimer::singleShot(0, toolRunner, [this](){ toolRunner->prepare(); }); -} - -void RunControlPrivate::onTargetPrepareFailed(const QString &msg) -{ - checkState(State::TargetPreparing); - toolRunner->onTargetFailure(); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onToolPrepared() -{ - checkState(State::ToolPreparing); - setState(State::TargetStarting); - debugMessage("Queue: Start target runner"); - QTimer::singleShot(0, targetRunner, [this](){ targetRunner->start(); }); -} +using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>; -void RunControlPrivate::onToolPrepareFailed(const QString &msg) +static WorkerCreators &theWorkerCreators() { - checkState(State::ToolPreparing); - targetRunner->onToolFailure(); - showError(msg); - setState(State::Stopped); + static WorkerCreators creators; + return creators; } -void RunControlPrivate::onTargetStarted() +void RunControl::registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator) { - checkState(State::TargetStarting); - setState(State::ToolStarting); - debugMessage("Queue: Start tool runner"); - QTimer::singleShot(0, toolRunner, [this](){ toolRunner->start(); }); + theWorkerCreators().insert(id, workerCreator); + auto keys = theWorkerCreators().keys(); + Q_UNUSED(keys); } -void RunControlPrivate::onTargetStartFailed(const QString &msg) +QList<QPointer<RunWorker> > RunControl::workers() const { - checkState(State::TargetStarting); - toolRunner->onTargetFailure(); - showError(msg); - setState(State::Stopped); + return d->m_workers; } -void RunControlPrivate::onToolStarted() +RunWorker *RunControl::createWorker(Core::Id id) { - checkState(State::ToolStarting); - setState(State::Running); + auto keys = theWorkerCreators().keys(); + Q_UNUSED(keys); + RunWorkerCreator creator = theWorkerCreators().value(id); + if (creator) + return creator(this); + creator = device()->workerCreator(id); + if (creator) + return creator(this); + return nullptr; } -void RunControlPrivate::onToolStartFailed(const QString &msg) +void RunControlPrivate::initiateStart() { - checkState(State::ToolStarting); - targetRunner->onToolFailure(); - showError(msg); - setState(State::Stopped); + checkState(RunControlState::Initialized); + setState(RunControlState::Starting); + debugMessage("Queue: Starting"); + + continueStart(); +} + +void RunControlPrivate::continueStart() +{ + checkState(RunControlState::Starting); + bool allDone = true; + debugMessage("Looking for next worker"); + for (RunWorker *worker : m_workers) { + if (worker) { + debugMessage(" Examining worker " + worker->displayName()); + switch (worker->d->state) { + case RunWorkerState::Initialized: + debugMessage(" " + worker->displayName() + " is not done yet."); + if (worker->d->canStart()) { + debugMessage("Starting " + worker->displayName()); + worker->d->state = RunWorkerState::Starting; + QTimer::singleShot(0, worker, &RunWorker::initiateStart); + return; + } + allDone = false; + debugMessage(" " + worker->displayName() + " cannot start."); + break; + case RunWorkerState::Starting: + debugMessage(" " + worker->displayName() + " currently starting"); + allDone = false; + break; + case RunWorkerState::Running: + debugMessage(" " + worker->displayName() + " currently running"); + break; + case RunWorkerState::Stopping: + debugMessage(" " + worker->displayName() + " currently stopping"); + continue; + case RunWorkerState::Failed: + // Should not happen. + debugMessage(" " + worker->displayName() + " failed before"); + QTC_CHECK(false); + //setState(RunControlState::Stopped); + break; + case RunWorkerState::Done: + debugMessage(" " + worker->displayName() + " was done before"); + break; + } + } else { + debugMessage("Found unknown deleted worker while starting"); + } + } + if (allDone) + setState(RunControlState::Running); } void RunControlPrivate::initiateStop() { - checkState(State::Running); - setState(State::ToolStopping); - debugMessage("Queue: Stop tool runner"); - QTimer::singleShot(0, toolRunner, [this](){ toolRunner->stop(); }); -} - -void RunControlPrivate::onToolStopped() -{ - toolRunner->onStop(); - debugMessage("Tool stopped"); - checkState(State::ToolStopping); - setState(State::TargetStopping); - debugMessage("Queue: Stop target runner"); - QTimer::singleShot(0, targetRunner, [this](){ targetRunner->stop(); }); -} - -void RunControlPrivate::onToolStopFailed(const QString &msg) -{ - checkState(State::ToolStopping); - targetRunner->onToolFailure(); - debugMessage("Tool stop failed"); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onTargetStopped() -{ - targetRunner->onStop(); - debugMessage("Target stopped"); - checkState(State::TargetStopping); - setState(State::Stopped); -} - -void RunControlPrivate::onTargetStopFailed(const QString &msg) -{ - debugMessage("Target stop failed"); - checkState(State::TargetStopping); - toolRunner->onTargetFailure(); - showError(msg); - setState(State::Stopped); -} - -void RunControlPrivate::onTargetFailed(const QString &msg) -{ - debugMessage("Target operation failed"); - if (state == State::TargetPreparing) { - onTargetPrepareFailed(msg); - } else if (state == State::TargetStarting) { - onTargetStartFailed(msg); - } else if (state == State::TargetStopping) { - onTargetStopFailed(msg); - } else { - showError(msg); - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); + checkState(RunControlState::Running); + setState(RunControlState::Stopping); + debugMessage("Queue: Stopping"); + + continueStop(); +} + +void RunControlPrivate::continueStop() +{ + debugMessage("Continue Stopping"); + checkState(RunControlState::Stopping); + for (RunWorker *worker : m_workers) { + if (worker) { + debugMessage(" Examining worker " + worker->displayName()); + switch (worker->d->state) { + case RunWorkerState::Initialized: + debugMessage(" " + worker->displayName() + " was Initialized, setting to Done"); + worker->d->state = RunWorkerState::Done; + break; + case RunWorkerState::Stopping: + debugMessage(" " + worker->displayName() + " was already Stopping. Keeping it that way"); + break; + case RunWorkerState::Starting: + worker->d->state = RunWorkerState::Stopping; + debugMessage(" " + worker->displayName() + " was Starting, queuing stop"); + QTimer::singleShot(0, worker, &RunWorker::initiateStop); + return; // Sic. + case RunWorkerState::Running: + debugMessage(" " + worker->displayName() + " was Running, queuing stop"); + worker->d->state = RunWorkerState::Stopping; + QTimer::singleShot(0, worker, &RunWorker::initiateStop); + return; // Sic. + case RunWorkerState::Done: + debugMessage(" " + worker->displayName() + " was Done. Good."); + break; + case RunWorkerState::Failed: + debugMessage(" " + worker->displayName() + " was Failed. Good"); + break; + } + } else { + debugMessage("Found unknown deleted worker"); + } } + debugMessage("All workers stopped. Set runControl to Stopped"); + setState(RunControlState::Stopped); } -void RunControlPrivate::onTargetSuccess() +void RunControlPrivate::onWorkerStarted(RunWorker *worker) { - debugMessage("Target operation successful"); - if (state == State::TargetPreparing) { - onTargetPrepared(); - } else if (state == State::TargetStarting) { - onTargetStarted(); - } else if (state == State::TargetStopping) { - onTargetStopped(); - } else { - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); - } -} + worker->d->state = RunWorkerState::Running; -void RunControlPrivate::onToolFailed(const QString &msg) -{ - debugMessage("Tool operation failed"); - if (state == State::ToolPreparing) { - onToolPrepareFailed(msg); - } else if (state == State::ToolStarting) { - onToolStartFailed(msg); - } else if (state == State::ToolStopping) { - onToolStartFailed(msg); - } else { - showError(msg); - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); + if (state == RunControlState::Starting) { + debugMessage(worker->displayName() + " start succeeded"); + continueStart(); + return; } + showError(tr("Unexpected run control state %1 when worker %2 started") + .arg(stateName(state)) + .arg(worker->displayName())); + //setState(RunControlState::Stopped); } -void RunControlPrivate::onToolSuccess() +void RunControlPrivate::onWorkerFailed(RunWorker *worker, const QString &msg) { - debugMessage("Tool operation successful"); - if (state == State::ToolPreparing) { - onToolPrepared(); - } else if (state == State::ToolStarting) { - onToolStarted(); - } else if (state == State::ToolStopping) { - onToolStopped(); - } else { - showError(RunControl::tr("Unexpected state: %1").arg(int(state))); - setState(State::Stopped); - } -} + worker->d->state = RunWorkerState::Failed; + showError(msg); + setState(RunControlState::Stopped); +} -void RunControlPrivate::handleFailure() +void RunControlPrivate::onWorkerStopped(RunWorker *worker) { - switch (state) { - case State::Initialized: - case State::TargetPreparing: - case State::ToolPreparing: - case State::TargetStarting: - case State::ToolStarting: - case State::Running: - case State::ToolStopping: - case State::TargetStopping: - case State::Stopped: - setState(State::Stopped); - break; - } + debugMessage(worker->displayName() + " stopped."); + continueStop(); } void RunControlPrivate::showError(const QString &msg) { if (!msg.isEmpty()) - q->appendMessage(msg, ErrorMessageFormat); + q->appendMessage(msg + '\n', ErrorMessageFormat); } Utils::OutputFormatter *RunControl::outputFormatter() const @@ -897,28 +904,6 @@ void RunControl::setConnection(const Connection &connection) d->connection = connection; } -ToolRunner *RunControl::toolRunner() const -{ - return d->toolRunner; -} - -void RunControl::setToolRunner(ToolRunner *tool) -{ - delete d->toolRunner; - d->toolRunner = tool; -} - -TargetRunner *RunControl::targetRunner() const -{ - return d->targetRunner; -} - -void RunControl::setTargetRunner(TargetRunner *runner) -{ - delete d->targetRunner; - d->targetRunner = runner; -} - QString RunControl::displayName() const { return d->displayName; @@ -1028,7 +1013,17 @@ void RunControl::setSupportsReRunning(bool reRunningSupported) bool RunControl::isRunning() const { - return d->state == RunControlPrivate::State::Running; + return d->state == RunControlState::Running; +} + +bool RunControl::isStarting() const +{ + return d->state == RunControlState::Starting; +} + +bool RunControl::isStopping() const +{ + return d->state == RunControlState::Stopping; } /*! @@ -1066,61 +1061,36 @@ bool RunControl::showPromptToStopDialog(const QString &title, return close; } -bool RunControlPrivate::isAllowedTransition(State from, State to) +bool RunControlPrivate::isAllowedTransition(RunControlState from, RunControlState to) { switch (from) { - case State::Initialized: - return to == State::TargetPreparing; - case State::TargetPreparing: - return to == State::ToolPreparing; - case State::ToolPreparing: - return to == State::TargetStarting; - case State::TargetStarting: - return to == State::ToolStarting; - case State::ToolStarting: - return to == State::Running; - case State::Running: - return to == State::ToolStopping - || to == State::Stopped; - case State::ToolStopping: - return to == State::TargetStopping; - case State::TargetStopping: - return to == State::Stopped; - case State::Stopped: + case RunControlState::Initialized: + return to == RunControlState::Starting; + case RunControlState::Starting: + return to == RunControlState::Running; + case RunControlState::Running: + return to == RunControlState::Stopping + || to == RunControlState::Stopped; + case RunControlState::Stopping: + return to == RunControlState::Stopped; + case RunControlState::Stopped: return false; } - qDebug() << "UNKNOWN DEBUGGER STATE:" << from; return false; } -void RunControlPrivate::checkState(State expectedState) +void RunControlPrivate::checkState(RunControlState expectedState) { if (state != expectedState) - qDebug() << "Unexpected state " << expectedState << " have: " << state; + qDebug() << "Unexpected run control state " << stateName(expectedState) + << " have: " << stateName(state); } -QString RunControlPrivate::stateName(State s) const -{ -# define SN(x) case x: return QLatin1String(#x); - switch (s) { - SN(State::Initialized) - SN(State::TargetPreparing) - SN(State::ToolPreparing) - SN(State::TargetStarting) - SN(State::ToolStarting) - SN(State::Running) - SN(State::ToolStopping) - SN(State::TargetStopping) - SN(State::Stopped) - } - return QLatin1String("<unknown>"); -# undef SN -} - -void RunControlPrivate::setState(State newState) +void RunControlPrivate::setState(RunControlState newState) { if (!isAllowedTransition(state, newState)) - qDebug() << "Invalid run state transition from " << state << " to " << newState; + qDebug() << "Invalid run control state transition from " << stateName(state) + << " to " << stateName(newState); state = newState; @@ -1128,14 +1098,15 @@ void RunControlPrivate::setState(State newState) // Extra reporting. switch (state) { - case State::Running: + case RunControlState::Running: emit q->started(); break; - case State::Stopped: + case RunControlState::Stopped: q->setApplicationProcessHandle(Utils::ProcessHandle()); - toolRunner->onFinished(); - targetRunner->onFinished(); - state = State::Initialized; // Reset for potential re-running. + foreach (auto worker, m_workers) + if (worker) + worker->onFinished(); + //state = RunControlState::Initialized; // Reset for potential re-running. emit q->finished(); break; default: @@ -1145,8 +1116,8 @@ void RunControlPrivate::setState(State newState) void RunControlPrivate::debugMessage(const QString &msg) { - if (debugStates) - q->appendMessage(msg + '\n', Utils::DebugFormat); + //q->appendMessage(msg + '\n', Utils::DebugFormat); + qCDebug(statesLog()) << msg; } /*! @@ -1166,20 +1137,12 @@ void RunControl::bringApplicationToForeground() void RunControl::reportApplicationStart() { - // QTC_CHECK(false); FIXME: Legacy, ToolRunner should emit started() instead. - d->onToolStarted(); - emit started(); + QTC_CHECK(false);// FIXME: Legacy } void RunControl::reportApplicationStop() { - // QTC_CHECK(false); FIXME: Legacy, ToolRunner should emit stopped() instead. - if (d->state == RunControlPrivate::State::Stopped) { - // FIXME: Currently various tool implementations call reportApplicationStop() - // multiple times. Fix it there and then add a soft assert here. - return; - } - d->onTargetStopped(); + QTC_CHECK(false);// FIXME: Legacy } void RunControl::bringApplicationToForegroundInternal() @@ -1222,8 +1185,9 @@ static bool isSynchronousLauncher(RunControl *runControl) // SimpleTargetRunner SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl) - : TargetRunner(runControl) + : RunWorker(runControl) { + setDisplayName("SimpleTargetRunner"); } void SimpleTargetRunner::start() @@ -1231,11 +1195,13 @@ void SimpleTargetRunner::start() m_launcher.disconnect(this); Runnable r = runControl()->runnable(); + QString msg = RunControl::tr("Starting %1...").arg(r.displayName()); + appendMessage(msg, Utils::NormalMessageFormat); if (isSynchronousLauncher(runControl())) { connect(&m_launcher, &ApplicationLauncher::appendMessage, - this, &TargetRunner::appendMessage); + this, &SimpleTargetRunner::appendMessage); connect(&m_launcher, &ApplicationLauncher::processStarted, this, &SimpleTargetRunner::onProcessStarted); connect(&m_launcher, &ApplicationLauncher::processExited, @@ -1249,15 +1215,15 @@ void SimpleTargetRunner::start() reportFailure(RunControl::tr("Executable %1 does not exist.") .arg(QDir::toNativeSeparators(executable))); } else { - QString msg = RunControl::tr("Starting %1...").arg(QDir::toNativeSeparators(executable)) + '\n'; - appendMessage(msg, Utils::NormalMessageFormat); m_launcher.start(r); } } else { connect(&m_launcher, &ApplicationLauncher::reportError, - this, &TargetRunner::reportFailure); + this, [this](const QString &msg) { + reportFailure(msg); + }); connect(&m_launcher, &ApplicationLauncher::remoteStderr, this, [this](const QByteArray &output) { @@ -1272,12 +1238,29 @@ void SimpleTargetRunner::start() connect(&m_launcher, &ApplicationLauncher::finished, this, [this] { m_launcher.disconnect(this); - reportSuccess(); + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::processStarted, + this, [this] { + appendMessage("Application launcher started", Utils::NormalMessageFormat); +// reportStarted(); + }); + + connect(&m_launcher, &ApplicationLauncher::processExited, + this, [this] { + m_launcher.disconnect(this); + reportStopped(); + }); + + connect(&m_launcher, &ApplicationLauncher::remoteProcessStarted, + this, [this] { + reportStarted(); }); connect(&m_launcher, &ApplicationLauncher::reportProgress, this, [this](const QString &progressString) { - appendMessage(progressString + '\n', Utils::NormalMessageFormat); + appendMessage(progressString, Utils::NormalMessageFormat); }); m_launcher.start(r, runControl()->device()); @@ -1294,145 +1277,190 @@ void SimpleTargetRunner::onProcessStarted() // Console processes only know their pid after being started runControl()->setApplicationProcessHandle(m_launcher.applicationPID()); runControl()->bringApplicationToForeground(); - reportSuccess(); + reportStarted(); } void SimpleTargetRunner::onProcessFinished(int exitCode, QProcess::ExitStatus status) { QString msg; - QString exe = runControl()->runnable().as<StandardRunnable>().executable; if (status == QProcess::CrashExit) - msg = tr("%1 crashed.").arg(QDir::toNativeSeparators(exe)); + msg = tr("%1 crashed."); else - msg = tr("%1 exited with code %2").arg(QDir::toNativeSeparators(exe)).arg(exitCode); - appendMessage(msg + '\n', Utils::NormalMessageFormat); + msg = tr("%2 exited with code %1").arg(exitCode); + appendMessage(msg.arg(runnable().displayName()), Utils::NormalMessageFormat); reportStopped(); } +void RunControl::reportFailure(const QString &msg) +{ + d->showError(msg); + d->setState(RunControlState::Stopped); +} -// TargetRunner +// RunWorkerPrivate -TargetRunner::TargetRunner(RunControl *runControl) - : m_runControl(runControl) +RunWorkerPrivate::RunWorkerPrivate(RunWorker *runWorker, RunControl *runControl) + : q(runWorker), runControl(runControl) { - runControl->setTargetRunner(this); + runControl->d->m_workers.append(runWorker); } -TargetRunner::~TargetRunner() +bool RunWorkerPrivate::canStart() const { + if (state != RunWorkerState::Initialized) + return false; + for (RunWorker *worker : dependencies) { + QTC_ASSERT(worker, return true); + if (worker->d->state != RunWorkerState::Done + && worker->d->state != RunWorkerState::Running) + return false; + } + return true; } -RunControl *TargetRunner::runControl() const +void RunWorkerPrivate::timerEvent(QTimerEvent *ev) { - return m_runControl; + if (ev->timerId() == startWatchdogTimerId) { + q->reportFailure(tr("Worker start timed out")); + return; + } + if (ev->timerId() == stopWatchdogTimerId) { + q->reportFailure(tr("Worker stop timed out")); + return; + } } -void TargetRunner::appendMessage(const QString &msg, OutputFormat format) +// RunWorker + +RunWorker::RunWorker(RunControl *runControl) + : d(new RunWorkerPrivate(this, runControl)) { - m_runControl->appendMessage(msg, format); } -IDevice::ConstPtr TargetRunner::device() const +RunWorker::~RunWorker() { - return m_runControl->device(); + delete d; } -void TargetRunner::prepare() +void RunWorker::initiateStart() { - reportSuccess(); // By default nothing to do, all is fine. + if (d->startWatchdogInterval != 0) + d->startWatchdogTimerId = d->startTimer(d->startWatchdogInterval); + + start(); } -void TargetRunner::start() +void RunWorker::reportStarted() { - reportSuccess(); + if (d->startWatchdogInterval != 0) + d->killTimer(d->startWatchdogTimerId); + d->runControl->d->onWorkerStarted(this); + emit started(); } -void TargetRunner::stop() +void RunWorker::initiateStop() { - reportSuccess(); // By default all is fine. + if (d->stopWatchdogInterval != 0) + d->stopWatchdogTimerId = d->startTimer(d->stopWatchdogInterval); + + d->runControl->d->debugMessage("Initiate stop for " + displayName()); + stop(); } -void TargetRunner::reportStopped() +void RunWorker::reportStopped() { - m_runControl->d->onTargetStopped(); + if (d->stopWatchdogInterval != 0) + d->killTimer(d->stopWatchdogTimerId); + d->runControl->d->onWorkerStopped(this); + emit stopped(); } -void TargetRunner::reportSuccess() +void RunWorker::reportFailure(const QString &msg) { - m_runControl->d->onTargetSuccess(); + d->runControl->d->onWorkerFailed(this, msg); } -void TargetRunner::reportFailure(const QString &msg) +void RunWorker::appendMessage(const QString &msg, OutputFormat format) { - m_runControl->d->onTargetFailed(msg); + if (msg.endsWith('\n')) + d->runControl->appendMessage(msg, format); + else + d->runControl->appendMessage(msg + '\n', format); } -// ToolRunner +IDevice::ConstPtr RunWorker::device() const +{ + return d->runControl->device(); +} -ToolRunner::ToolRunner(RunControl *runControl) - : m_runControl(runControl) +const Runnable &RunWorker::runnable() const { - if (runControl) - runControl->setToolRunner(this); + return d->runControl->runnable(); } -ToolRunner::~ToolRunner() +const Connection &RunWorker::connection() const { + return d->runControl->connection(); } -RunControl *ToolRunner::runControl() const +Core::Id RunWorker::runMode() const { - return m_runControl; + return d->runControl->runMode(); } -void ToolRunner::appendMessage(const QString &msg, OutputFormat format) +void RunWorker::addDependency(RunWorker *dependency) { - m_runControl->appendMessage(msg, format); + d->dependencies.append(dependency); } -IDevice::ConstPtr ToolRunner::device() const +RunControl *RunWorker::runControl() const { - return m_runControl->device(); + return d->runControl; } -const Runnable &ToolRunner::runnable() const +QString RunWorker::displayName() const { - return m_runControl->runnable(); + return d->displayName; } -const Connection &ToolRunner::connection() const +void RunWorker::setDisplayName(const QString &displayName) { - return m_runControl->connection(); + d->displayName = displayName; } -void ToolRunner::prepare() +void RunWorker::setStartTimeout(int ms) { - reportSuccess(); + d->startWatchdogInterval = ms; } -void ToolRunner::start() +void RunWorker::setStopTimeout(int ms) { - reportSuccess(); + d->stopWatchdogInterval = ms; } -void ToolRunner::stop() +void RunWorker::reportData(int channel, const QVariant &data) { - reportSuccess(); + emit dataReported(channel, data); } -void ToolRunner::reportStopped() +void RunWorker::recordData(const QString &channel, const QVariant &data) { - m_runControl->d->onToolStopped(); + d->data[channel] = data; } -void ToolRunner::reportSuccess() +QVariant RunWorker::recordedData(const QString &channel) { - m_runControl->d->onToolSuccess(); + return d->data[channel]; } -void ToolRunner::reportFailure(const QString &msg) +void RunWorker::start() { - m_runControl->d->onToolFailed(msg); + reportStarted(); +} + +void RunWorker::stop() +{ + reportStopped(); } } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/runconfiguration.h b/src/plugins/projectexplorer/runconfiguration.h index 368e95978f..17f14e6457 100644 --- a/src/plugins/projectexplorer/runconfiguration.h +++ b/src/plugins/projectexplorer/runconfiguration.h @@ -51,11 +51,10 @@ class RunConfiguration; class RunConfigWidget; class RunControl; class Target; -class TargetRunner; -class ToolRunner; namespace Internal { class RunControlPrivate; +class RunWorkerPrivate; class SimpleRunControlPrivate; } // Internal @@ -148,6 +147,7 @@ class PROJECTEXPLORER_EXPORT Runnable virtual ~Concept() {} virtual Concept *clone() const = 0; virtual bool canReUseOutputPane(const std::unique_ptr<Concept> &other) const = 0; + virtual QString displayName() const = 0; virtual void *typeId() const = 0; }; @@ -168,6 +168,8 @@ class PROJECTEXPLORER_EXPORT Runnable return m_data == that->m_data; } + QString displayName() const override { return m_data.displayName(); } + void *typeId() const override { return T::staticTypeId; } T m_data; @@ -190,6 +192,7 @@ public: } bool canReUseOutputPane(const Runnable &other) const; + QString displayName() const { return d->displayName(); } private: std::unique_ptr<Concept> d; @@ -351,6 +354,61 @@ signals: void displayNameChanged(const QString &); }; +class PROJECTEXPLORER_EXPORT RunWorker : public QObject +{ + Q_OBJECT + +public: + explicit RunWorker(RunControl *runControl); + ~RunWorker() override; + + RunControl *runControl() const; + + void addDependency(RunWorker *dependency); + + QString displayName() const; + void setDisplayName(const QString &displayName); + + void setStartTimeout(int ms); + void setStopTimeout(int ms); + + void reportData(int channel, const QVariant &data); + + void recordData(const QString &channel, const QVariant &data); + QVariant recordedData(const QString &channel); + + // Part of read-only interface of RunControl for convenience. + void appendMessage(const QString &msg, Utils::OutputFormat format); + IDevice::ConstPtr device() const; + const Runnable &runnable() const; + const Connection &connection() const; + Core::Id runMode() const; + + // States + void initiateStart(); + void reportStarted(); + + void initiateStop(); + void reportStopped(); + + void reportFailure(const QString &msg = QString()); + +signals: + void dataReported(int channel, const QVariant &data); + void started(); + void stopped(); + +protected: + void virtual start(); + void virtual stop(); + void virtual onFinished() {} + +private: + friend class Internal::RunControlPrivate; + friend class Internal::RunWorkerPrivate; + Internal::RunWorkerPrivate *d; +}; + /** * A RunControl controls the running of an application or tool * on a target device. It controls start and stop, and handles @@ -380,6 +438,8 @@ public: void setDisplayName(const QString &displayName); bool isRunning() const; + bool isStarting() const; + bool isStopping() const; void setIcon(const Utils::Icon &icon); Utils::Icon icon() const; @@ -402,12 +462,6 @@ public: const Connection &connection() const; void setConnection(const Connection &connection); - ToolRunner *toolRunner() const; - void setToolRunner(ToolRunner *tool); - - TargetRunner *targetRunner() const; - void setTargetRunner(TargetRunner *tool); - virtual void appendMessage(const QString &msg, Utils::OutputFormat format); virtual void bringApplicationToForeground(); @@ -415,8 +469,9 @@ public: virtual void notifyRemoteSetupFailed(const QString &) {} // Same. virtual void notifyRemoteFinished() {} // Same. - void reportApplicationStart(); // Call this when the application starts to run - void reportApplicationStop(); // Call this when the application has stopped for any reason + void reportApplicationStart(); // FIXME: Don't use + void reportApplicationStop(); // FIXME: Don't use + void reportFailure(const QString &msg = QString()); static bool showPromptToStopDialog(const QString &title, const QString &text, const QString &stopButtonText = QString(), @@ -426,6 +481,25 @@ public: virtual void start(); virtual void stop(); + using WorkerCreator = std::function<RunWorker *(RunControl *)>; + static void registerWorkerCreator(Core::Id id, const WorkerCreator &workerCreator); + RunWorker *workerById(Core::Id id) const; + QList<QPointer<RunWorker>> workers() const; + + template <class T> T *worker() const { + for (const QPointer<RunWorker> &worker : workers()) { + if (worker) { + if (auto res = qobject_cast<T *>(worker.data())) + return res; + } + } + return nullptr; + } + + using RunWorkerCreator = std::function<RunWorker *(RunControl *)>; + static void registerRunWorkerCreator(Core::Id id, const RunWorkerCreator &creator); + RunWorker *createWorker(Core::Id id); + signals: void appendMessageRequested(ProjectExplorer::RunControl *runControl, const QString &msg, Utils::OutputFormat format); @@ -436,114 +510,29 @@ signals: void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle private: - friend class Internal::RunControlPrivate; - friend class TargetRunner; - friend class ToolRunner; + friend class RunWorker; + friend class Internal::RunWorkerPrivate; void bringApplicationToForegroundInternal(); Internal::RunControlPrivate *d; }; -/** - * A base for target-specific additions to the RunControl. - */ - -class PROJECTEXPLORER_EXPORT TargetRunner : public QObject -{ - Q_OBJECT - -public: - explicit TargetRunner(RunControl *runControl); - ~TargetRunner() override; - - RunControl *runControl() const; - void appendMessage(const QString &msg, Utils::OutputFormat format); - IDevice::ConstPtr device() const; - - // Preparation phase. - virtual void prepare(); // Initiate setup. Needs to report result. - // Startup phase. - virtual void start(); // Initiates start. Needs to report result. - // Stopping phase. - virtual void stop(); // Initiates stop. Needs to report result. - - // - void reportStopped(); - // Generic success report, proceed to next stage. - void reportSuccess(); - // Generic error, start ramp down. - void reportFailure(const QString &msg = QString()); - - // Customization points. No reporting required nor wanted. - virtual void onStop() {} - virtual void onToolFailure() {} - virtual void onTargetFailure() {} - virtual void onFinished() {} - -private: - QPointer<RunControl> m_runControl; -}; - -/** - * A base for tool-specific additions to RunControl. - */ - -class PROJECTEXPLORER_EXPORT ToolRunner : public QObject -{ - Q_OBJECT - -public: - explicit ToolRunner(RunControl *runControl); - ~ToolRunner() override; - - RunControl *runControl() const; - - // Part of read-only interface of RunControl for convenience. - void appendMessage(const QString &msg, Utils::OutputFormat format); - IDevice::ConstPtr device() const; - const Runnable &runnable() const; - const Connection &connection() const; - - // Preparation phase. - virtual void prepare(); // Initiates preparation, needs to report success or failure. - // Start phase. - virtual void start(); - // Stop phase. - virtual void stop(); - - // - void reportStopped(); - // Generic success report, proceed to next stage. - void reportSuccess(); - // Generic error, start ramp down. - void reportFailure(const QString &msg = QString()); - - // Customization points. No reporting required nor wanted. - virtual void onStop() {} - virtual void onToolFailure() {} - virtual void onTargetFailure() {} - virtual void onFinished() {} - -private: - QPointer<RunControl> m_runControl; -}; /** * A simple TargetRunner for cases where a plain ApplicationLauncher is * sufficient for running purposes. */ -class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public TargetRunner +class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker { public: explicit SimpleTargetRunner(RunControl *runControl); - ApplicationLauncher *applicationLauncher() { return &m_launcher; } - -private: +protected: void start() override; void stop() override; +private: void onProcessStarted(); void onProcessFinished(int exitCode, QProcess::ExitStatus status); diff --git a/src/plugins/projectexplorer/runnables.h b/src/plugins/projectexplorer/runnables.h index 088a6a872d..3d286a8b83 100644 --- a/src/plugins/projectexplorer/runnables.h +++ b/src/plugins/projectexplorer/runnables.h @@ -32,6 +32,7 @@ #include <utils/environment.h> +#include <QDir> #include <QUrl> namespace ProjectExplorer { @@ -46,6 +47,7 @@ public: ApplicationLauncher::Mode runMode = ApplicationLauncher::Gui; IDevice::ConstPtr device; // Override the kit's device. Keep unset by default. + QString displayName() const { return QDir::toNativeSeparators(executable); } static void *staticTypeId; }; diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index aa2af74b79..bc537fbb78 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -67,7 +67,6 @@ namespace QmlProfiler { class QmlProfilerRunControl::QmlProfilerRunControlPrivate { public: - Internal::QmlProfilerTool *m_tool = 0; QmlProfilerStateManager *m_profilerState = 0; QTimer m_noDebugOutputTimer; }; @@ -76,15 +75,13 @@ public: // QmlProfilerRunControl // -QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration, - Internal::QmlProfilerTool *tool) +QmlProfilerRunControl::QmlProfilerRunControl(RunConfiguration *runConfiguration) : RunControl(runConfiguration, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) , d(new QmlProfilerRunControlPrivate) { setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); setSupportsReRunning(false); - d->m_tool = tool; // Only wait 4 seconds for the 'Waiting for connection' on application output, then just try to connect // (application output might be redirected / blocked) d->m_noDebugOutputTimer.setSingleShot(true); @@ -104,7 +101,7 @@ QmlProfilerRunControl::~QmlProfilerRunControl() void QmlProfilerRunControl::start() { reportApplicationStart(); - d->m_tool->finalizeRunControl(this); + Internal::QmlProfilerTool::instance()->finalizeRunControl(this); QTC_ASSERT(d->m_profilerState, reportApplicationStop(); return); QTC_ASSERT(connection().is<AnalyzerConnection>(), reportApplicationStop(); return); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h index 69686a1e35..9ece8c5067 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.h +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.h @@ -32,15 +32,12 @@ namespace QmlProfiler { -namespace Internal { class QmlProfilerTool; } - class QmlProfilerRunControl : public ProjectExplorer::RunControl { Q_OBJECT public: - QmlProfilerRunControl(ProjectExplorer::RunConfiguration *runConfiguration, - Internal::QmlProfilerTool *tool); + QmlProfilerRunControl(ProjectExplorer::RunConfiguration *runConfiguration); ~QmlProfilerRunControl() override; void registerProfilerStateManager( QmlProfilerStateManager *profilerState ); diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp index e489c3b5aa..577564f3d2 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrolfactory.cpp @@ -92,10 +92,7 @@ RunControl *QmlProfilerRunControlFactory::create(RunConfiguration *runConfigurat connection.analyzerPort = LocalQmlProfilerRunner::findFreePort(connection.analyzerHost); } - auto runControl = qobject_cast<QmlProfilerRunControl *> - (Debugger::createAnalyzerRunControl(runConfiguration, mode)); - QTC_ASSERT(runControl, return 0); - + auto runControl = new QmlProfilerRunControl(runConfiguration); runControl->setRunnable(runnable); runControl->setConnection(connection); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index dc7b580a62..09d884e4d1 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -127,9 +127,12 @@ public: bool m_toolBusy = false; }; +static QmlProfilerTool *s_instance; + QmlProfilerTool::QmlProfilerTool(QObject *parent) : QObject(parent), d(new QmlProfilerToolPrivate) { + s_instance = this; setObjectName(QLatin1String("QmlProfilerTool")); d->m_profilerState = new QmlProfilerStateManager(this); @@ -244,8 +247,9 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) // is available, then we can populate the file finder d->m_profilerModelManager->populateFileFinder(); - auto runControlCreator = [this](RunConfiguration *runConfiguration, Core::Id) { - return createRunControl(runConfiguration); + auto runWorkerCreator = [this](RunControl *runControl) { +// return createRunControl(runConfiguration); + return nullptr; // FIXME }; QString description = tr("The QML Profiler can be used to find performance " @@ -254,7 +258,7 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) d->m_startAction = Debugger::createStartAction(); d->m_stopAction = Debugger::createStopAction(); - Debugger::registerAction(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, runControlCreator); + RunControl::registerWorkerCreator(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, runWorkerCreator); act = new QAction(tr("QML Profiler"), this); act->setToolTip(description); menu->addAction(ActionManager::registerAction(act, "QmlProfiler.Local"), @@ -270,7 +274,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent) act->setEnabled(d->m_startAction->isEnabled()); }); - Debugger::registerAction(ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, runControlCreator); act = new QAction(tr("QML Profiler (External)"), this); act->setToolTip(description); menu->addAction(ActionManager::registerAction(act, "QmlProfiler.Remote"), @@ -305,6 +308,11 @@ QmlProfilerTool::~QmlProfilerTool() delete d; } +QmlProfilerTool *QmlProfilerTool::instance() +{ + return s_instance; +} + void QmlProfilerTool::updateRunActions() { if (d->m_toolBusy) { @@ -336,11 +344,11 @@ RunControl *QmlProfilerTool::createRunControl(RunConfiguration *runConfiguration } } - auto runControl = new QmlProfilerRunControl(runConfiguration, this); + auto runControl = new QmlProfilerRunControl(runConfiguration); connect(runControl, &RunControl::finished, this, [this, runControl] { d->m_toolBusy = false; updateRunActions(); - disconnect(d->m_stopAction, &QAction::triggered, runControl, &QmlProfilerRunControl::stop); + disconnect(d->m_stopAction, &QAction::triggered, runControl, &RunControl::stop); }); connect(d->m_stopAction, &QAction::triggered, runControl, &QmlProfilerRunControl::stop); diff --git a/src/plugins/qmlprofiler/qmlprofilertool.h b/src/plugins/qmlprofiler/qmlprofilertool.h index 85715f8120..c9600051b3 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.h +++ b/src/plugins/qmlprofiler/qmlprofilertool.h @@ -49,6 +49,8 @@ public: explicit QmlProfilerTool(QObject *parent); ~QmlProfilerTool(); + static QmlProfilerTool *instance(); + ProjectExplorer::RunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration = 0); void finalizeRunControl(QmlProfilerRunControl *runControl); diff --git a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp index c7ef5f1b4e..2171f45f60 100644 --- a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp +++ b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp @@ -24,6 +24,9 @@ ****************************************************************************/ #include "localqmlprofilerrunner_test.h" + +#include "../qmlprofilerruncontrol.h" + #include <debugger/analyzer/analyzermanager.h> #include <debugger/analyzer/analyzerstartparameters.h> #include <QtTest> @@ -57,8 +60,7 @@ void LocalQmlProfilerRunnerTest::testRunner() // should not be used anywhere but cannot be empty configuration.socket = connection.analyzerSocket = QString("invalid"); - rc = Debugger::createAnalyzerRunControl( - nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + rc = new QmlProfilerRunControl(nullptr); rc->setConnection(connection); auto runner = new LocalQmlProfilerRunner(configuration, rc); connectRunner(runner); @@ -79,8 +81,7 @@ void LocalQmlProfilerRunnerTest::testRunner1() configuration.debuggee.commandLineArguments = QString("-test QmlProfiler,"); delete rc; - rc = Debugger::createAnalyzerRunControl( - nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + rc = new QmlProfilerRunControl(nullptr); rc->setConnection(connection); auto runner = new LocalQmlProfilerRunner(configuration, rc); connectRunner(runner); @@ -100,8 +101,7 @@ void LocalQmlProfilerRunnerTest::testRunner2() connection.analyzerSocket.clear(); configuration.port = connection.analyzerPort = LocalQmlProfilerRunner::findFreePort(connection.analyzerHost); - rc = Debugger::createAnalyzerRunControl( - nullptr, ProjectExplorer::Constants::QML_PROFILER_RUN_MODE); + rc = new QmlProfilerRunControl(nullptr); rc->setConnection(connection); auto runner = new LocalQmlProfilerRunner(configuration, rc); connectRunner(runner); diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro index 64874c929a..b50f4b27fb 100644 --- a/src/plugins/qnx/qnx.pro +++ b/src/plugins/qnx/qnx.pro @@ -9,13 +9,11 @@ SOURCES += qnxplugin.cpp \ qnxdevicewizard.cpp \ qnxrunconfiguration.cpp \ qnxruncontrolfactory.cpp \ - qnxabstractrunsupport.cpp \ qnxanalyzesupport.cpp \ qnxdebugsupport.cpp \ qnxdeploystepfactory.cpp \ qnxdeployconfigurationfactory.cpp \ qnxrunconfigurationfactory.cpp \ - qnxruncontrol.cpp \ qnxqtversionfactory.cpp \ qnxqtversion.cpp \ qnxdeployconfiguration.cpp \ @@ -44,13 +42,11 @@ HEADERS += qnxplugin.h\ qnxdevicewizard.h \ qnxrunconfiguration.h \ qnxruncontrolfactory.h \ - qnxabstractrunsupport.h \ qnxanalyzesupport.h \ qnxdebugsupport.h \ qnxdeploystepfactory.h \ qnxdeployconfigurationfactory.h \ qnxrunconfigurationfactory.h \ - qnxruncontrol.h \ qnxqtversionfactory.h \ qnxqtversion.h \ qnxdeployconfiguration.h \ diff --git a/src/plugins/qnx/qnx.qbs b/src/plugins/qnx/qnx.qbs index d57a93259b..eee52f0f5d 100644 --- a/src/plugins/qnx/qnx.qbs +++ b/src/plugins/qnx/qnx.qbs @@ -33,8 +33,6 @@ QtcPlugin { "qnxconstants.h", "qnxconfiguration.cpp", "qnxconfiguration.h", - "qnxabstractrunsupport.cpp", - "qnxabstractrunsupport.h", "qnxanalyzesupport.cpp", "qnxanalyzesupport.h", "qnxdebugsupport.cpp", @@ -78,8 +76,6 @@ QtcPlugin { "qnxrunconfiguration.h", "qnxrunconfigurationfactory.cpp", "qnxrunconfigurationfactory.h", - "qnxruncontrol.cpp", - "qnxruncontrol.h", "qnxruncontrolfactory.cpp", "qnxruncontrolfactory.h", "qnxutils.cpp", diff --git a/src/plugins/qnx/qnxabstractrunsupport.cpp b/src/plugins/qnx/qnxabstractrunsupport.cpp deleted file mode 100644 index 52d2110bb4..0000000000 --- a/src/plugins/qnx/qnxabstractrunsupport.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "qnxabstractrunsupport.h" -#include "qnxrunconfiguration.h" - -#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> -#include <projectexplorer/kitinformation.h> -#include <projectexplorer/target.h> -#include <utils/portlist.h> -#include <utils/qtcassert.h> - -using namespace ProjectExplorer; -using namespace RemoteLinux; - -namespace Qnx { -namespace Internal { - -QnxAbstractRunSupport::QnxAbstractRunSupport(RunControl *runControl) - : ToolRunner(runControl) - , m_state(Inactive) -{ - m_launcher = new ApplicationLauncher(this); - m_portsGatherer = new DeviceUsedPortsGatherer(this); - - connect(m_portsGatherer, &DeviceUsedPortsGatherer::error, - this, &QnxAbstractRunSupport::handleError); - connect(m_portsGatherer, &DeviceUsedPortsGatherer::portListReady, - this, &QnxAbstractRunSupport::handlePortListReady); -} - -void QnxAbstractRunSupport::handleAdapterSetupRequested() -{ - QTC_ASSERT(m_state == Inactive, return); - - m_state = GatheringPorts; - m_portsGatherer->start(m_device); -} - -void QnxAbstractRunSupport::handlePortListReady() -{ - QTC_ASSERT(m_state == GatheringPorts, return); - m_portList = device()->freePorts(); - startExecution(); -} - -void QnxAbstractRunSupport::handleRemoteProcessStarted() -{ - m_state = Running; -} - -void QnxAbstractRunSupport::handleRemoteProcessFinished(bool) -{ -} - -void QnxAbstractRunSupport::setFinished() -{ - if (m_state != GatheringPorts && m_state != Inactive) - m_launcher->stop(); - - m_state = Inactive; -} - -QnxAbstractRunSupport::State QnxAbstractRunSupport::state() const -{ - return m_state; -} - -void QnxAbstractRunSupport::setState(QnxAbstractRunSupport::State state) -{ - m_state = state; -} - -ApplicationLauncher *QnxAbstractRunSupport::appRunner() const -{ - return m_launcher; -} - -void QnxAbstractRunSupport::handleProgressReport(const QString &) -{ -} - -void QnxAbstractRunSupport::handleRemoteOutput(const QByteArray &) -{ -} - -void QnxAbstractRunSupport::handleError(const QString &) -{ -} - -bool QnxAbstractRunSupport::setPort(Utils::Port &port) -{ - port = m_portsGatherer->getNextFreePort(&m_portList); - if (!port.isValid()) { - handleError(tr("Not enough free ports on device for debugging.")); - return false; - } - return true; -} - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxabstractrunsupport.h b/src/plugins/qnx/qnxabstractrunsupport.h deleted file mode 100644 index f0e9a58c5b..0000000000 --- a/src/plugins/qnx/qnxabstractrunsupport.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <projectexplorer/devicesupport/idevice.h> -#include <projectexplorer/runconfiguration.h> - -#include <utils/environment.h> -#include <utils/portlist.h> - -#include <QObject> -#include <QString> - -namespace ProjectExplorer { -class ApplicationLauncher; -class DeviceUsedPortsGatherer; -} - -namespace Qnx { -namespace Internal { - -class QnxAbstractRunSupport : public ProjectExplorer::ToolRunner -{ - Q_OBJECT -protected: - enum State { - Inactive, - GatheringPorts, - StartingRemoteProcess, - Running - }; - -public: - explicit QnxAbstractRunSupport(ProjectExplorer::RunControl *runControl); - -protected: - bool setPort(Utils::Port &port); - virtual void startExecution() = 0; - - void setFinished(); - - State state() const; - void setState(State state); - - ProjectExplorer::ApplicationLauncher *appRunner() const; - -public slots: - virtual void handleAdapterSetupRequested(); - - virtual void handleRemoteProcessStarted(); - virtual void handleRemoteProcessFinished(bool); - virtual void handleProgressReport(const QString &progressOutput); - virtual void handleRemoteOutput(const QByteArray &output); - virtual void handleError(const QString &); - -private slots: - void handlePortListReady(); - -private: - ProjectExplorer::DeviceUsedPortsGatherer * m_portsGatherer; - Utils::PortList m_portList; - ProjectExplorer::IDevice::ConstPtr m_device; - ProjectExplorer::ApplicationLauncher *m_launcher; - State m_state; -}; - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp index 59ee41810d..5215010790 100644 --- a/src/plugins/qnx/qnxanalyzesupport.cpp +++ b/src/plugins/qnx/qnxanalyzesupport.cpp @@ -29,12 +29,15 @@ #include "qnxrunconfiguration.h" #include "slog2inforunner.h" +#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> #include <projectexplorer/kitinformation.h> +#include <projectexplorer/runnables.h> #include <projectexplorer/target.h> #include <utils/qtcassert.h> #include <utils/qtcprocess.h> #include <qmldebug/qmldebugcommandlinearguments.h> +#include <qmldebug/qmloutputparser.h> using namespace ProjectExplorer; using namespace Utils; @@ -42,122 +45,64 @@ using namespace Utils; namespace Qnx { namespace Internal { -QnxAnalyzeSupport::QnxAnalyzeSupport(RunControl *runControl) - : QnxAbstractRunSupport(runControl) - , m_runnable(runControl->runnable().as<StandardRunnable>()) - , m_qmlPort(-1) +class QnxAnalyzeeRunner : public ProjectExplorer::SimpleTargetRunner { - const ApplicationLauncher *runner = appRunner(); - connect(runner, &ApplicationLauncher::reportError, - this, &QnxAnalyzeSupport::handleError); - connect(runner, &ApplicationLauncher::remoteProcessStarted, - this, &QnxAbstractRunSupport::handleRemoteProcessStarted); - connect(runner, &ApplicationLauncher::finished, - this, &QnxAnalyzeSupport::handleRemoteProcessFinished); - connect(runner, &ApplicationLauncher::reportProgress, - this, &QnxAnalyzeSupport::handleProgressReport); - connect(runner, &ApplicationLauncher::remoteStdout, - this, &QnxAnalyzeSupport::handleRemoteOutput); - connect(runner, &ApplicationLauncher::remoteStderr, - this, &QnxAnalyzeSupport::handleRemoteOutput); - - connect(runControl, &RunControl::starting, - this, &QnxAnalyzeSupport::handleAdapterSetupRequested); - connect(runControl, &RunControl::finished, - this, &QnxAnalyzeSupport::setFinished); - - connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &QnxAnalyzeSupport::remoteIsRunning); - - IDevice::ConstPtr dev = DeviceKitInformation::device(runControl->runConfiguration()->target()->kit()); - QnxDevice::ConstPtr qnxDevice = dev.dynamicCast<const QnxDevice>(); - - auto qnxRunConfig = qobject_cast<QnxRunConfiguration *>(runControl->runConfiguration()); - const QString applicationId = FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); - m_slog2Info = new Slog2InfoRunner(applicationId, qnxDevice, this); - connect(m_slog2Info, &Slog2InfoRunner::output, - this, &QnxAnalyzeSupport::showMessage); - connect(runner, &ApplicationLauncher::remoteProcessStarted, - m_slog2Info, &Slog2InfoRunner::start); - if (qnxDevice->qnxVersion() > 0x060500) - connect(m_slog2Info, &Slog2InfoRunner::commandMissing, - this, &QnxAnalyzeSupport::printMissingWarning); -} +public: + QnxAnalyzeeRunner(ProjectExplorer::RunControl *runControl) + : SimpleTargetRunner(runControl) + { + setDisplayName("QnxAnalyzeeRunner"); + } -void QnxAnalyzeSupport::handleAdapterSetupRequested() -{ - QTC_ASSERT(state() == Inactive, return); +private: + void start() override + { + auto portsGatherer = runControl()->worker<PortsGatherer>(); + Utils::Port port = portsGatherer->findPort(); - showMessage(tr("Preparing remote side...") + QLatin1Char('\n'), NormalMessageFormat); - QnxAbstractRunSupport::handleAdapterSetupRequested(); -} + auto r = runnable().as<StandardRunnable>(); + if (!r.commandLineArguments.isEmpty()) + r.commandLineArguments += ' '; + r.commandLineArguments += + QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, port); -void QnxAnalyzeSupport::startExecution() -{ - if (state() == Inactive) - return; + runControl()->setRunnable(r); - if (!setPort(m_qmlPort) && !m_qmlPort.isValid()) - return; + SimpleTargetRunner::start(); + } +}; - setState(StartingRemoteProcess); - StandardRunnable r = m_runnable; - if (!r.commandLineArguments.isEmpty()) - r.commandLineArguments += QLatin1Char(' '); - r.commandLineArguments += QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, - m_qmlPort); - appRunner()->start(r, device()); -} +// QnxDebugSupport -void QnxAnalyzeSupport::handleRemoteProcessFinished(bool success) +QnxAnalyzeSupport::QnxAnalyzeSupport(RunControl *runControl) + : RunWorker(runControl) { - if (!success) - showMessage(tr("The %1 process closed unexpectedly.").arg(m_runnable.executable), - NormalMessageFormat); - runControl()->notifyRemoteFinished(); + setDisplayName("QnxAnalyzeSupport"); + appendMessage(tr("Preparing remote side..."), Utils::LogMessageFormat); - m_slog2Info->stop(); -} + auto portsGatherer = new PortsGatherer(runControl); -void QnxAnalyzeSupport::handleProgressReport(const QString &progressOutput) -{ - showMessage(progressOutput + QLatin1Char('\n'), NormalMessageFormat); -} + auto debuggeeRunner = new QnxAnalyzeeRunner(runControl); + debuggeeRunner->addDependency(portsGatherer); -void QnxAnalyzeSupport::handleRemoteOutput(const QByteArray &output) -{ - QTC_ASSERT(state() == Inactive || state() == Running, return); + auto slog2InfoRunner = new Slog2InfoRunner(runControl); + slog2InfoRunner->addDependency(debuggeeRunner); - showMessage(QString::fromUtf8(output), StdOutFormat); -} - -void QnxAnalyzeSupport::handleError(const QString &error) -{ - if (state() == Running) { - showMessage(error, ErrorMessageFormat); - } else if (state() != Inactive) { - showMessage(tr("Initial setup failed: %1").arg(error), NormalMessageFormat); - setFinished(); - } -} + addDependency(slog2InfoRunner); -void QnxAnalyzeSupport::remoteIsRunning() -{ - runControl()->notifyRemoteSetupDone(m_qmlPort); -} + // QmlDebug::QmlOutputParser m_outputParser; + // FIXME: m_outputParser needs to be fed with application output + // connect(&m_outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, + // this, &QnxAnalyzeSupport::remoteIsRunning); -void QnxAnalyzeSupport::showMessage(const QString &msg, OutputFormat format) -{ - if (state() != Inactive) - runControl()->appendMessage(msg, format); - m_outputParser.processOutput(msg); + // m_outputParser.processOutput(msg); } -void QnxAnalyzeSupport::printMissingWarning() +void QnxAnalyzeSupport::start() { - showMessage(tr("Warning: \"slog2info\" is not found on the device, debug output not available."), - ErrorMessageFormat); + // runControl()->notifyRemoteSetupDone(m_qmlPort); + reportStarted(); } } // namespace Internal diff --git a/src/plugins/qnx/qnxanalyzesupport.h b/src/plugins/qnx/qnxanalyzesupport.h index bd665c8436..cb049866f8 100644 --- a/src/plugins/qnx/qnxanalyzesupport.h +++ b/src/plugins/qnx/qnxanalyzesupport.h @@ -25,18 +25,14 @@ #pragma once -#include "qnxabstractrunsupport.h" - -#include <projectexplorer/runnables.h> -#include <utils/outputformat.h> -#include <qmldebug/qmloutputparser.h> +#include <projectexplorer/runconfiguration.h> namespace Qnx { namespace Internal { class Slog2InfoRunner; -class QnxAnalyzeSupport : public QnxAbstractRunSupport +class QnxAnalyzeSupport : public ProjectExplorer::RunWorker { Q_OBJECT @@ -44,24 +40,7 @@ public: explicit QnxAnalyzeSupport(ProjectExplorer::RunControl *runControl); private: - void handleAdapterSetupRequested() override; - - void handleRemoteProcessFinished(bool success) override; - void handleProgressReport(const QString &progressOutput) override; - void handleRemoteOutput(const QByteArray &output) override; - void handleError(const QString &error) override; - - void showMessage(const QString &, Utils::OutputFormat); - void printMissingWarning(); - - void remoteIsRunning(); - void startExecution() override; - - ProjectExplorer::StandardRunnable m_runnable; - QmlDebug::QmlOutputParser m_outputParser; - Utils::Port m_qmlPort; - - Slog2InfoRunner *m_slog2Info; + void start() override; }; } // namespace Internal diff --git a/src/plugins/qnx/qnxattachdebugsupport.cpp b/src/plugins/qnx/qnxattachdebugsupport.cpp index 2a0d57531d..5319b14d80 100644 --- a/src/plugins/qnx/qnxattachdebugsupport.cpp +++ b/src/plugins/qnx/qnxattachdebugsupport.cpp @@ -146,9 +146,9 @@ void QnxAttachDebugSupport::attachToProcess() stopPDebug(); return; } - connect(qobject_cast<Debugger::DebuggerRunTool *>(runControl->toolRunner()), - &Debugger::DebuggerRunTool::stateChanged, - this, &QnxAttachDebugSupport::handleDebuggerStateChanged); +// connect(qobject_cast<Debugger::DebuggerRunTool *>(runControl->toolRunner()), +// &Debugger::DebuggerRunTool::stateChanged, +// this, &QnxAttachDebugSupport::handleDebuggerStateChanged); ProjectExplorerPlugin::startRunControl(runControl); } diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index 5099c2224f..f86c20647c 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -28,182 +28,123 @@ #include "qnxdevice.h" #include "qnxrunconfiguration.h" #include "slog2inforunner.h" +#include "qnxqtversion.h" +#include "qnxutils.h" -#include <debugger/debuggerrunconfigurationaspect.h> #include <debugger/debuggerruncontrol.h> -#include <debugger/debuggerstartparameters.h> + +#include <projectexplorer/applicationlauncher.h> #include <projectexplorer/devicesupport/deviceusedportsgatherer.h> #include <projectexplorer/kitinformation.h> #include <projectexplorer/runnables.h> #include <projectexplorer/target.h> + +#include <qmldebug/qmldebugcommandlinearguments.h> +#include <qtsupport/qtkitinformation.h> + #include <utils/qtcassert.h> #include <utils/qtcprocess.h> -#include <qmldebug/qmldebugcommandlinearguments.h> +using namespace Debugger; using namespace ProjectExplorer; namespace Qnx { namespace Internal { -QnxDebugSupport::QnxDebugSupport(RunControl *runControl) - : QnxAbstractRunSupport(runControl) -{ - auto runConfig = runControl->runConfiguration(); - m_useCppDebugger = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useCppDebugger(); - m_useQmlDebugger = runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>()->useQmlDebugger(); - m_runnable = runConfig->runnable().as<StandardRunnable>(); - - const ApplicationLauncher *runner = appRunner(); - connect(runner, &ApplicationLauncher::reportError, this, &QnxDebugSupport::handleError); - connect(runner, &ApplicationLauncher::remoteProcessStarted, this, &QnxDebugSupport::handleRemoteProcessStarted); - connect(runner, &ApplicationLauncher::finished, this, &QnxDebugSupport::handleRemoteProcessFinished); - connect(runner, &ApplicationLauncher::reportProgress, this, &QnxDebugSupport::handleProgressReport); - connect(runner, &ApplicationLauncher::remoteStdout, this, &QnxDebugSupport::handleRemoteOutput); - connect(runner, &ApplicationLauncher::remoteStderr, this, &QnxDebugSupport::handleRemoteOutput); - - connect(toolRunner(), &Debugger::DebuggerRunTool::requestRemoteSetup, - this, &QnxDebugSupport::handleAdapterSetupRequested); - connect(runControl, &RunControl::finished, - this, &QnxDebugSupport::handleDebuggingFinished); - - auto qnxRunConfig = qobject_cast<QnxRunConfiguration *>(runControl->runConfiguration()); - const QString applicationId = Utils::FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); - IDevice::ConstPtr dev = DeviceKitInformation::device(runConfig->target()->kit()); - QnxDevice::ConstPtr qnxDevice = dev.dynamicCast<const QnxDevice>(); - - m_slog2Info = new Slog2InfoRunner(applicationId, qnxDevice, this); - connect(m_slog2Info, &Slog2InfoRunner::output, this, &QnxDebugSupport::handleApplicationOutput); - connect(runner, &ApplicationLauncher::remoteProcessStarted, m_slog2Info, &Slog2InfoRunner::start); - if (qnxDevice->qnxVersion() > 0x060500) - connect(m_slog2Info, &Slog2InfoRunner::commandMissing, this, &QnxDebugSupport::printMissingWarning); -} +// QnxDebuggeeRunner -void QnxDebugSupport::handleAdapterSetupRequested() +class QnxDebuggeeRunner : public ProjectExplorer::SimpleTargetRunner { - QTC_ASSERT(state() == Inactive, return); - - toolRunner()->showMessage(tr("Preparing remote side...") + '\n', Debugger::AppStuff); - QnxAbstractRunSupport::handleAdapterSetupRequested(); -} +public: + QnxDebuggeeRunner(ProjectExplorer::RunControl *runControl) + : SimpleTargetRunner(runControl) + { + setDisplayName("QnxDebuggeeRunner"); + } -void QnxDebugSupport::startExecution() -{ - if (state() == Inactive) - return; - - if (m_useCppDebugger && !setPort(m_pdebugPort)) - return; - if (m_useQmlDebugger && !setPort(m_qmlPort)) - return; - - setState(StartingRemoteProcess); - - StandardRunnable r = m_runnable; - QStringList arguments; - if (m_useCppDebugger) - arguments << QString::number(m_pdebugPort.number()); - else { - if (m_useQmlDebugger) { +private: + void start() override + { + auto portsGatherer = runControl()->worker<GdbServerPortsGatherer>(); + + StandardRunnable r = runnable().as<StandardRunnable>(); + QStringList arguments; + if (portsGatherer->useGdbServer()) { + Utils::Port pdebugPort = portsGatherer->gdbServerPort(); + r.executable = Constants::QNX_DEBUG_EXECUTABLE; + arguments.append(pdebugPort.toString()); + } + if (portsGatherer->useQmlServer()) { arguments.append(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, - m_qmlPort)); + portsGatherer->qmlServerPort())); } arguments.append(Utils::QtcProcess::splitArgs(r.commandLineArguments)); - } + r.commandLineArguments = Utils::QtcProcess::joinArgs(arguments); - r.executable = processExecutable(); - r.commandLineArguments = Utils::QtcProcess::joinArgs(arguments); - r.environment = m_runnable.environment; - r.workingDirectory = m_runnable.workingDirectory; - appRunner()->start(r, device()); -} + SimpleTargetRunner::start(); + } +}; -void QnxDebugSupport::handleRemoteProcessStarted() -{ - QnxAbstractRunSupport::handleRemoteProcessStarted(); - Debugger::RemoteSetupResult result; - result.success = true; - result.gdbServerPort = m_pdebugPort; - result.qmlServerPort = m_qmlPort; - toolRunner()->notifyEngineRemoteSetupFinished(result); -} -void QnxDebugSupport::handleRemoteProcessFinished(bool success) -{ - if (state() == Inactive) - return; - - if (state() == Running) { - if (!success) - toolRunner()->notifyInferiorIll(); - - } else { - Debugger::RemoteSetupResult result; - result.success = false; - result.reason = tr("The %1 process closed unexpectedly.").arg(processExecutable()); - toolRunner()->notifyEngineRemoteSetupFinished(result); - } -} +// QnxDebugSupport -void QnxDebugSupport::handleDebuggingFinished() +QnxDebugSupport::QnxDebugSupport(RunControl *runControl) + : DebuggerRunTool(runControl) { - // setFinished() will kill "pdebug", but we also have to kill - // the inferior process, as invoking "kill" in gdb doesn't work - // on QNX gdb - setFinished(); - m_slog2Info->stop(); - killInferiorProcess(); -} + setDisplayName("QnxDebugSupport"); + appendMessage(tr("Preparing remote side..."), Utils::LogMessageFormat); -QString QnxDebugSupport::processExecutable() const -{ - return m_useCppDebugger? QLatin1String(Constants::QNX_DEBUG_EXECUTABLE) : m_runnable.executable; -} + auto portsGatherer = new GdbServerPortsGatherer(runControl); + portsGatherer->setUseGdbServer(isCppDebugging()); + portsGatherer->setUseQmlServer(isQmlDebugging()); -void QnxDebugSupport::killInferiorProcess() -{ - device()->signalOperation()->killProcess(m_runnable.executable); -} + auto debuggeeRunner = new QnxDebuggeeRunner(runControl); + debuggeeRunner->addDependency(portsGatherer); -void QnxDebugSupport::handleProgressReport(const QString &progressOutput) -{ - toolRunner()->showMessage(progressOutput + QLatin1Char('\n'), Debugger::AppStuff); -} + auto slog2InfoRunner = new Slog2InfoRunner(runControl); + slog2InfoRunner->addDependency(debuggeeRunner); -void QnxDebugSupport::handleRemoteOutput(const QByteArray &output) -{ - QTC_ASSERT(state() == Inactive || state() == Running, return); - toolRunner()->showMessage(QString::fromUtf8(output), Debugger::AppOutput); + addDependency(slog2InfoRunner); } -void QnxDebugSupport::handleError(const QString &error) +void QnxDebugSupport::start() { - if (state() == Running) { - toolRunner()->showMessage(error, Debugger::AppError); - toolRunner()->notifyInferiorIll(); - } else if (state() != Inactive) { - setFinished(); - Debugger::RemoteSetupResult result; - result.success = false; - result.reason = tr("Initial setup failed: %1").arg(error); - toolRunner()->notifyEngineRemoteSetupFinished(result); + auto portsGatherer = runControl()->worker<GdbServerPortsGatherer>(); + Utils::Port pdebugPort = portsGatherer->gdbServerPort(); + + auto runConfig = qobject_cast<QnxRunConfiguration *>(runControl()->runConfiguration()); + QTC_ASSERT(runConfig, return); + Target *target = runConfig->target(); + Kit *k = target->kit(); + + DebuggerStartParameters params; + params.startMode = AttachToRemoteServer; + params.useCtrlCStub = true; + params.inferior.executable = runConfig->remoteExecutableFilePath(); + params.symbolFile = runConfig->localExecutableFilePath(); + params.remoteChannel = QString("%1:%2").arg(device()->sshParameters().host).arg(pdebugPort.number()); + params.closeMode = KillAtClose; + params.inferior.commandLineArguments = runConfig->arguments(); + + if (isQmlDebugging()) { + params.qmlServer.host = device()->sshParameters().host; + params.qmlServer.port = portsGatherer->qmlServerPort(); + params.inferior.commandLineArguments.replace("%qml_port%", params.qmlServer.port.toString()); } -} -void QnxDebugSupport::printMissingWarning() -{ - toolRunner()->showMessage(tr("Warning: \"slog2info\" is not found " - "on the device, debug output not available."), Debugger::AppError); -} + auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitInformation::qtVersion(k)); + if (qtVersion) + params.solibSearchPath = QnxUtils::searchPaths(qtVersion); -void QnxDebugSupport::handleApplicationOutput(const QString &msg, Utils::OutputFormat outputFormat) -{ - Q_UNUSED(outputFormat); - toolRunner()->showMessage(msg, Debugger::AppOutput); + reportStarted(); } -Debugger::DebuggerRunTool *QnxDebugSupport::toolRunner() +void QnxDebugSupport::stop() { - return qobject_cast<Debugger::DebuggerRunTool *>(runControl()->toolRunner()); + // We have to kill the inferior process, as invoking "kill" in + // gdb doesn't work on QNX gdb. + auto stdRunnable = runnable().as<StandardRunnable>(); + device()->signalOperation()->killProcess(stdRunnable.executable); } } // namespace Internal diff --git a/src/plugins/qnx/qnxdebugsupport.h b/src/plugins/qnx/qnxdebugsupport.h index 5e198a2469..e408f703f3 100644 --- a/src/plugins/qnx/qnxdebugsupport.h +++ b/src/plugins/qnx/qnxdebugsupport.h @@ -25,55 +25,21 @@ #pragma once -#include "qnxabstractrunsupport.h" - -#include <projectexplorer/runnables.h> - -#include <utils/outputformat.h> - -namespace Debugger { class DebuggerRunTool; } +#include <debugger/debuggerruncontrol.h> namespace Qnx { namespace Internal { -class Slog2InfoRunner; - -class QnxDebugSupport : public QnxAbstractRunSupport +class QnxDebugSupport : public Debugger::DebuggerRunTool { Q_OBJECT public: explicit QnxDebugSupport(ProjectExplorer::RunControl *runControl); - void handleDebuggingFinished(); - private: - void handleAdapterSetupRequested() override; - - void handleRemoteProcessStarted() override; - void handleRemoteProcessFinished(bool success) override; - void handleProgressReport(const QString &progressOutput) override; - void handleRemoteOutput(const QByteArray &output) override; - void handleError(const QString &error) override; - - void printMissingWarning(); - void handleApplicationOutput(const QString &msg, Utils::OutputFormat outputFormat); - - void startExecution() override; - - Debugger::DebuggerRunTool *toolRunner(); - QString processExecutable() const; - - void killInferiorProcess(); - - ProjectExplorer::StandardRunnable m_runnable; - Slog2InfoRunner *m_slog2Info; - - Utils::Port m_pdebugPort; - Utils::Port m_qmlPort; - - bool m_useCppDebugger; - bool m_useQmlDebugger; + void start() override; + void stop() override; }; } // namespace Internal diff --git a/src/plugins/qnx/qnxruncontrol.cpp b/src/plugins/qnx/qnxruncontrol.cpp deleted file mode 100644 index 926274c501..0000000000 --- a/src/plugins/qnx/qnxruncontrol.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BlackBerry Limited. All rights reserved. -** Contact: KDAB (info@kdab.com) -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "qnxruncontrol.h" -#include "qnxdevice.h" -#include "qnxrunconfiguration.h" -#include "slog2inforunner.h" - -#include <projectexplorer/kitinformation.h> -#include <projectexplorer/runconfiguration.h> -#include <projectexplorer/target.h> - -using namespace ProjectExplorer; -using namespace Utils; - -namespace Qnx { -namespace Internal { - -QnxRunControl::QnxRunControl(RunConfiguration *runConfig) - : RunControl(runConfig, ProjectExplorer::Constants::NORMAL_RUN_MODE) - , m_slog2Info(0) -{ - IDevice::ConstPtr dev = DeviceKitInformation::device(runConfig->target()->kit()); - QnxDevice::ConstPtr qnxDevice = dev.dynamicCast<const QnxDevice>(); - - QnxRunConfiguration *qnxRunConfig = qobject_cast<QnxRunConfiguration *>(runConfig); - QTC_CHECK(qnxRunConfig); - - const QString applicationId = FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); - m_slog2Info = new Slog2InfoRunner(applicationId, qnxDevice, this); - connect(m_slog2Info, &Slog2InfoRunner::output, - this, static_cast<void(RunControl::*)(const QString &, OutputFormat)>(&RunControl::appendMessage)); - connect(this, &RunControl::started, m_slog2Info, &Slog2InfoRunner::start); - if (qnxDevice->qnxVersion() > 0x060500) - connect(m_slog2Info, &Slog2InfoRunner::commandMissing, this, &QnxRunControl::printMissingWarning); -} - -void QnxRunControl::stop() -{ - m_slog2Info->stop(); - RunControl::stop(); -} - -void QnxRunControl::printMissingWarning() -{ - appendMessage(tr("Warning: \"slog2info\" is not found on the device, debug output not available."), ErrorMessageFormat); -} - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxruncontrol.h b/src/plugins/qnx/qnxruncontrol.h deleted file mode 100644 index a447682101..0000000000 --- a/src/plugins/qnx/qnxruncontrol.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 BlackBerry Limited. All rights reserved. -** Contact: KDAB (info@kdab.com) -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include <projectexplorer/runconfiguration.h> - -namespace Qnx { -namespace Internal { - -class Slog2InfoRunner; - -class QnxRunControl : public ProjectExplorer::RunControl -{ - Q_OBJECT -public: - explicit QnxRunControl(ProjectExplorer::RunConfiguration *runConfig); - - void stop() override; - -private: - void printMissingWarning(); - - Slog2InfoRunner *m_slog2Info; -}; - -} // namespace Internal -} // namespace Qnx diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp index 36dfe09766..a1e6019802 100644 --- a/src/plugins/qnx/qnxruncontrolfactory.cpp +++ b/src/plugins/qnx/qnxruncontrolfactory.cpp @@ -30,7 +30,7 @@ #include "qnxdevice.h" #include "qnxanalyzesupport.h" #include "qnxqtversion.h" -#include "qnxruncontrol.h" +#include "slog2inforunner.h" #include "qnxutils.h" #include <debugger/debuggerruncontrol.h> @@ -53,38 +53,6 @@ using namespace ProjectExplorer; namespace Qnx { namespace Internal { -static DebuggerStartParameters createDebuggerStartParameters(QnxRunConfiguration *runConfig) -{ - DebuggerStartParameters params; - Target *target = runConfig->target(); - Kit *k = target->kit(); - - const IDevice::ConstPtr device = DeviceKitInformation::device(k); - if (device.isNull()) - return params; - - params.startMode = AttachToRemoteServer; - params.useCtrlCStub = true; - params.inferior.executable = runConfig->remoteExecutableFilePath(); - params.symbolFile = runConfig->localExecutableFilePath(); - params.remoteChannel = device->sshParameters().host + QLatin1String(":-1"); - params.remoteSetupNeeded = true; - params.closeMode = KillAtClose; - params.inferior.commandLineArguments = runConfig->arguments(); - - auto aspect = runConfig->extraAspect<DebuggerRunConfigurationAspect>(); - if (aspect->useQmlDebugger()) { - params.qmlServer.host = device->sshParameters().host; - params.qmlServer.port = Utils::Port(); // QML port is handed out later - } - - auto qtVersion = dynamic_cast<QnxQtVersion *>(QtSupport::QtKitInformation::qtVersion(k)); - if (qtVersion) - params.solibSearchPath = QnxUtils::searchPaths(qtVersion); - - return params; -} - QnxRunControlFactory::QnxRunControlFactory(QObject *parent) : IRunControlFactory(parent) { @@ -108,48 +76,28 @@ bool QnxRunControlFactory::canRun(RunConfiguration *runConfiguration, Core::Id m if (dev.isNull()) return false; - if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE - || mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - auto aspect = runConfiguration->extraAspect<DebuggerRunConfigurationAspect>(); - int portsUsed = aspect ? aspect->portsUsedByDebugger() : 0; - return portsUsed <= dev->freePorts().count(); - } - return true; } RunControl *QnxRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, QString *) { QTC_ASSERT(canRun(runConfig, mode), return 0); - auto rc = qobject_cast<QnxRunConfiguration *>(runConfig); - QTC_ASSERT(rc, return 0); if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) { - auto runControl = new QnxRunControl(rc); + auto runControl = new RunControl(runConfig, mode); (void) new SimpleTargetRunner(runControl); return runControl; } if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE) { - const DebuggerStartParameters params = createDebuggerStartParameters(rc); auto runControl = new RunControl(runConfig, mode); - // (void) new DebuggerRunTool(runControl, params, errorMessage); FIXME (void) new QnxDebugSupport(runControl); return runControl; } if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - Kit *kit = runConfig->target()->kit(); - const IDevice::ConstPtr device = DeviceKitInformation::device(kit); - if (device.isNull()) - return 0; - RunControl *runControl = Debugger::createAnalyzerRunControl(runConfig, mode); - QTC_ASSERT(runControl, return 0); - AnalyzerConnection connection; - connection.connParams = device->sshParameters(); - connection.analyzerHost = connection.connParams.host; - connection.analyzerPort = Utils::Port(connection.connParams.port); - runControl->setConnection(connection); + RunControl *runControl = new RunControl(runConfig, mode); + runControl->createWorker(mode); (void) new QnxAnalyzeSupport(runControl); return runControl; } diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp index 7b5f0f38bf..3bde0d4301 100644 --- a/src/plugins/qnx/slog2inforunner.cpp +++ b/src/plugins/qnx/slog2inforunner.cpp @@ -25,7 +25,9 @@ #include "slog2inforunner.h" +#include "qnxdevice.h" #include "qnxdeviceprocess.h" +#include "qnxrunconfiguration.h" #include <projectexplorer/runnables.h> #include <utils/qtcassert.h> @@ -33,28 +35,33 @@ #include <QRegExp> using namespace ProjectExplorer; +using namespace Utils; namespace Qnx { namespace Internal { -Slog2InfoRunner::Slog2InfoRunner(const QString &applicationId, - const RemoteLinux::LinuxDevice::ConstPtr &device, QObject *parent) - : QObject(parent) - , m_applicationId(applicationId) - , m_found(false) - , m_currentLogs(false) +Slog2InfoRunner::Slog2InfoRunner(RunControl *runControl) + : RunWorker(runControl) { + auto qnxRunConfig = qobject_cast<QnxRunConfiguration *>(runControl->runConfiguration()); + QTC_ASSERT(qnxRunConfig, return); + m_applicationId = FileName::fromString(qnxRunConfig->remoteExecutableFilePath()).fileName(); +} + +void Slog2InfoRunner::printMissingWarning() +{ + appendMessage(tr("Warning: \"slog2info\" is not found on the device, debug output not available."), ErrorMessageFormat); // See QTCREATORBUG-10712 for details. // We need to limit length of ApplicationId to 63 otherwise it would not match one in slog2info. m_applicationId.truncate(63); - m_testProcess = new QnxDeviceProcess(device, this); + m_testProcess = new QnxDeviceProcess(device(), this); connect(m_testProcess, &DeviceProcess::finished, this, &Slog2InfoRunner::handleTestProcessCompleted); - m_launchDateTimeProcess = new SshDeviceProcess(device, this); + m_launchDateTimeProcess = new SshDeviceProcess(device(), this); connect(m_launchDateTimeProcess, &DeviceProcess::finished, this, &Slog2InfoRunner::launchSlog2Info); - m_logProcess = new QnxDeviceProcess(device, this); + m_logProcess = new QnxDeviceProcess(device(), this); connect(m_logProcess, &DeviceProcess::readyReadStandardOutput, this, &Slog2InfoRunner::readLogStandardOutput); connect(m_logProcess, &DeviceProcess::readyReadStandardError, this, &Slog2InfoRunner::readLogStandardError); connect(m_logProcess, &DeviceProcess::error, this, &Slog2InfoRunner::handleLogError); @@ -88,10 +95,14 @@ bool Slog2InfoRunner::commandFound() const void Slog2InfoRunner::handleTestProcessCompleted() { m_found = (m_testProcess->exitCode() == 0); - if (m_found) + if (m_found) { readLaunchTime(); - else - emit commandMissing(); + } else { + QnxDevice::ConstPtr qnxDevice = device().dynamicCast<const QnxDevice>(); + if (qnxDevice->qnxVersion() > 0x060500) { + printMissingWarning(); + } + } } void Slog2InfoRunner::readLaunchTime() @@ -174,18 +185,18 @@ void Slog2InfoRunner::processLogLine(const QString &line) if (bufferName == QLatin1String("default") && bufferId == 8900) return; - emit output(regexp.cap(6).trimmed() + QLatin1Char('\n'), Utils::StdOutFormat); + appendMessage(regexp.cap(6).trimmed() + '\n', Utils::StdOutFormat); } void Slog2InfoRunner::readLogStandardError() { - const QString message = QString::fromLatin1(m_logProcess->readAllStandardError()); - emit output(message, Utils::StdErrFormat); + appendMessage(QString::fromLatin1(m_logProcess->readAllStandardError()), Utils::StdErrFormat); } void Slog2InfoRunner::handleLogError() { - emit output(tr("Cannot show slog2info output. Error: %1").arg(m_logProcess->errorString()), Utils::StdErrFormat); + appendMessage(tr("Cannot show slog2info output. Error: %1") + .arg(m_logProcess->errorString()), Utils::StdErrFormat); } } // namespace Internal diff --git a/src/plugins/qnx/slog2inforunner.h b/src/plugins/qnx/slog2inforunner.h index 4e08b5f950..048915baac 100644 --- a/src/plugins/qnx/slog2inforunner.h +++ b/src/plugins/qnx/slog2inforunner.h @@ -27,6 +27,7 @@ #include <QObject> +#include <projectexplorer/runconfiguration.h> #include <remotelinux/linuxdevice.h> #include <utils/outputformat.h> @@ -38,26 +39,23 @@ namespace ProjectExplorer { class SshDeviceProcess; } namespace Qnx { namespace Internal { -class Slog2InfoRunner : public QObject +class Slog2InfoRunner : public ProjectExplorer::RunWorker { Q_OBJECT public: - explicit Slog2InfoRunner(const QString &applicationId, const RemoteLinux::LinuxDevice::ConstPtr &device, QObject *parent = 0); + explicit Slog2InfoRunner(ProjectExplorer::RunControl *runControl); - void stop(); + void start() override; + void stop() override; bool commandFound() const; -public slots: - void start(); - signals: void commandMissing(); void started(); void finished(); - void output(const QString &msg, Utils::OutputFormat format); -private slots: +private: void handleTestProcessCompleted(); void launchSlog2Info(); @@ -65,22 +63,21 @@ private slots: void readLogStandardError(); void handleLogError(); -private: + void printMissingWarning(); void readLaunchTime(); void processLog(bool force); void processLogLine(const QString &line); QString m_applicationId; - bool m_found; - QDateTime m_launchDateTime; - bool m_currentLogs; + bool m_found = false; + bool m_currentLogs = false; QString m_remainingData; - ProjectExplorer::SshDeviceProcess *m_launchDateTimeProcess; - ProjectExplorer::SshDeviceProcess *m_testProcess; - ProjectExplorer::SshDeviceProcess *m_logProcess; + ProjectExplorer::SshDeviceProcess *m_launchDateTimeProcess = nullptr; + ProjectExplorer::SshDeviceProcess *m_testProcess = nullptr; + ProjectExplorer::SshDeviceProcess *m_logProcess = nullptr; }; } // namespace Internal diff --git a/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp b/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp index 4dc313d5e6..15521b8ddb 100644 --- a/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp @@ -25,89 +25,34 @@ #include "abstractremotelinuxrunsupport.h" -#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> #include <projectexplorer/kitinformation.h> #include <projectexplorer/runnables.h> #include <projectexplorer/target.h> #include <utils/environment.h> #include <utils/portlist.h> +#include <utils/qtcprocess.h> + +#include <qmldebug/qmldebugcommandlinearguments.h> using namespace ProjectExplorer; using namespace Utils; namespace RemoteLinux { -namespace Internal { - -class AbstractRemoteLinuxRunSupportPrivate -{ -public: - ApplicationLauncher launcher; - DeviceUsedPortsGatherer portsGatherer; - ApplicationLauncher fifoCreator; - PortList portList; - QString fifo; - bool usesFifo = false; -}; - -} // namespace Internal - -using namespace Internal; - -AbstractRemoteLinuxRunSupport::AbstractRemoteLinuxRunSupport(RunControl *runControl) - : TargetRunner(runControl), - d(new AbstractRemoteLinuxRunSupportPrivate) -{ -} -AbstractRemoteLinuxRunSupport::~AbstractRemoteLinuxRunSupport() -{ - delete d; -} - -ApplicationLauncher *AbstractRemoteLinuxRunSupport::applicationLauncher() -{ - return &d->launcher; -} - -void AbstractRemoteLinuxRunSupport::setUsesFifo(bool on) -{ - d->usesFifo = on; -} - -Port AbstractRemoteLinuxRunSupport::findPort() const -{ - return d->portsGatherer.getNextFreePort(&d->portList); -} - -QString AbstractRemoteLinuxRunSupport::fifo() const -{ - return d->fifo; -} +// FifoGatherer -void AbstractRemoteLinuxRunSupport::prepare() +FifoGatherer::FifoGatherer(RunControl *runControl) + : RunWorker(runControl) { - if (d->usesFifo) - createRemoteFifo(); - else - startPortsGathering(); + setDisplayName("FifoGatherer"); } -void AbstractRemoteLinuxRunSupport::startPortsGathering() +FifoGatherer::~FifoGatherer() { - appendMessage(tr("Checking available ports...") + '\n', NormalMessageFormat); - connect(&d->portsGatherer, &DeviceUsedPortsGatherer::error, this, [&](const QString &msg) { - reportFailure(msg); - }); - connect(&d->portsGatherer, &DeviceUsedPortsGatherer::portListReady, this, [&] { - d->portList = device()->freePorts(); - //appendMessage(tr("Found %1 free ports").arg(d->portList.count()), NormalMessageFormat); - reportSuccess(); - }); - d->portsGatherer.start(device()); } -void AbstractRemoteLinuxRunSupport::createRemoteFifo() +void FifoGatherer::start() { appendMessage(tr("Creating remote socket...") + '\n', NormalMessageFormat); @@ -120,77 +65,35 @@ void AbstractRemoteLinuxRunSupport::createRemoteFifo() QSharedPointer<QByteArray> output(new QByteArray); QSharedPointer<QByteArray> errors(new QByteArray); - connect(&d->fifoCreator, &ApplicationLauncher::finished, + connect(&m_fifoCreator, &ApplicationLauncher::finished, this, [this, output, errors](bool success) { if (!success) { reportFailure(QString("Failed to create fifo: %1").arg(QLatin1String(*errors))); } else { - d->fifo = QString::fromLatin1(*output); - //appendMessage(tr("Created fifo").arg(d->fifo), NormalMessageFormat); - reportSuccess(); + m_fifo = QString::fromLatin1(*output); + appendMessage(tr("Created fifo: %1").arg(m_fifo), NormalMessageFormat); + reportStarted(); } }); - connect(&d->fifoCreator, &ApplicationLauncher::remoteStdout, + connect(&m_fifoCreator, &ApplicationLauncher::remoteStdout, this, [output](const QByteArray &data) { output->append(data); }); - connect(&d->fifoCreator, &ApplicationLauncher::remoteStderr, - this, [errors](const QByteArray &data) { - errors->append(data); + connect(&m_fifoCreator, &ApplicationLauncher::remoteStderr, + this, [this, errors](const QByteArray &) { + reportFailure(); +// errors->append(data); }); - d->fifoCreator.start(r, device()); -} - -void AbstractRemoteLinuxRunSupport::start() -{ - connect(&d->launcher, &ApplicationLauncher::remoteStderr, - this, &AbstractRemoteLinuxRunSupport::handleRemoteErrorOutput); - connect(&d->launcher, &ApplicationLauncher::remoteStdout, - this, &AbstractRemoteLinuxRunSupport::handleRemoteOutput); - connect(&d->launcher, &ApplicationLauncher::finished, - this, &AbstractRemoteLinuxRunSupport::handleAppRunnerFinished); - connect(&d->launcher, &ApplicationLauncher::reportProgress, - this, &AbstractRemoteLinuxRunSupport::handleProgressReport); - connect(&d->launcher, &ApplicationLauncher::reportError, - this, &AbstractRemoteLinuxRunSupport::handleAppRunnerError); - connect(&d->launcher, &ApplicationLauncher::remoteProcessStarted, - this, &TargetRunner::reportSuccess); - d->launcher.start(runControl()->runnable(), device()); -} - -void AbstractRemoteLinuxRunSupport::onFinished() -{ - d->launcher.disconnect(this); - d->launcher.stop(); - d->portsGatherer.disconnect(this); + m_fifoCreator.start(r, device()); } -void AbstractRemoteLinuxRunSupport::handleAppRunnerFinished(bool success) +void FifoGatherer::onFinished() { - success ? reportStopped() : reportFailure(); + m_fifoCreator.stop(); } -void AbstractRemoteLinuxRunSupport::handleAppRunnerError(const QString &error) -{ - reportFailure(error); -} - -void AbstractRemoteLinuxRunSupport::handleRemoteOutput(const QByteArray &output) -{ - appendMessage(QString::fromUtf8(output), StdOutFormat); -} - -void AbstractRemoteLinuxRunSupport::handleRemoteErrorOutput(const QByteArray &output) -{ - appendMessage(QString::fromUtf8(output), StdErrFormat); -} - -void AbstractRemoteLinuxRunSupport::handleProgressReport(const QString &progressOutput) -{ - appendMessage(progressOutput + '\n', LogMessageFormat); -} } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/abstractremotelinuxrunsupport.h b/src/plugins/remotelinux/abstractremotelinuxrunsupport.h index a914d48ea7..2a6be032bc 100644 --- a/src/plugins/remotelinux/abstractremotelinuxrunsupport.h +++ b/src/plugins/remotelinux/abstractremotelinuxrunsupport.h @@ -27,46 +27,28 @@ #include "remotelinux_export.h" -#include <projectexplorer/devicesupport/idevice.h> #include <projectexplorer/runconfiguration.h> -#include <utils/port.h> - namespace RemoteLinux { -namespace Internal { class AbstractRemoteLinuxRunSupportPrivate; } - -class REMOTELINUX_EXPORT AbstractRemoteLinuxRunSupport : public ProjectExplorer::TargetRunner +class REMOTELINUX_EXPORT FifoGatherer : public ProjectExplorer::RunWorker { Q_OBJECT public: - explicit AbstractRemoteLinuxRunSupport(ProjectExplorer::RunControl *runControl); - ~AbstractRemoteLinuxRunSupport(); - - ProjectExplorer::ApplicationLauncher *applicationLauncher(); + explicit FifoGatherer(ProjectExplorer::RunControl *runControl); + ~FifoGatherer(); - void setUsesFifo(bool on); - - Utils::Port findPort() const; - QString fifo() const; + QString fifo() const { return m_fifo; } private: - void prepare() override; void start() override; void onFinished() override; void createRemoteFifo(); - void startPortsGathering(); - - void handleAppRunnerError(const QString &error); - void handleRemoteOutput(const QByteArray &output); - void handleRemoteErrorOutput(const QByteArray &output); - void handleAppRunnerFinished(bool success); - void handleProgressReport(const QString &progressOutput); - void handleAdapterSetupDone(); - Internal::AbstractRemoteLinuxRunSupportPrivate * const d; + ProjectExplorer::ApplicationLauncher m_fifoCreator; + QString m_fifo; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp index 4652734e2f..a2519b7b67 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp @@ -1,210 +1,172 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "remotelinuxanalyzesupport.h" - -#include "remotelinuxrunconfiguration.h" - -#include <projectexplorer/buildconfiguration.h> -#include <projectexplorer/project.h> -#include <projectexplorer/target.h> -#include <projectexplorer/toolchain.h> -#include <projectexplorer/kitinformation.h> -#include <projectexplorer/runnables.h> - -#include <utils/qtcassert.h> -#include <utils/qtcprocess.h> -#include <qmldebug/qmloutputparser.h> -#include <qmldebug/qmldebugcommandlinearguments.h> - -#include <QPointer> - -using namespace QSsh; -using namespace ProjectExplorer; -using namespace Utils; - -namespace RemoteLinux { -namespace Internal { - -class RemoteLinuxAnalyzeSupportPrivate -{ -public: - RemoteLinuxAnalyzeSupportPrivate(RunControl *runControl) - { - if (runControl->runMode() == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - usesFifo = true; - RunConfiguration *runConfiguration = runControl->runConfiguration(); - QTC_ASSERT(runConfiguration, return); - IRunConfigurationAspect *perfAspect = - runConfiguration->extraAspect("Analyzer.Perf.Settings"); - QTC_ASSERT(perfAspect, return); - perfRecordArguments = - perfAspect->currentSettings()->property("perfRecordArguments").toStringList() - .join(' '); - } - } - - Utils::Port qmlPort; - QString remoteFifo; - QString perfRecordArguments; - - ApplicationLauncher outputGatherer; - QmlDebug::QmlOutputParser outputParser; - bool usesFifo = false; -}; - -} // namespace Internal - -using namespace Internal; - -RemoteLinuxAnalyzeSupport::RemoteLinuxAnalyzeSupport(RunControl *runControl) - : ToolRunner(runControl), - d(new RemoteLinuxAnalyzeSupportPrivate(runControl)) -{ - connect(&d->outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, - this, &RemoteLinuxAnalyzeSupport::remoteIsRunning); - targetRunner()->setUsesFifo(runControl->runMode() == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE); -} - -RemoteLinuxAnalyzeSupport::~RemoteLinuxAnalyzeSupport() -{ - delete d; -} - -void RemoteLinuxAnalyzeSupport::showMessage(const QString &msg, Utils::OutputFormat format) -{ - appendMessage(msg, format); - d->outputParser.processOutput(msg); -} - -void RemoteLinuxAnalyzeSupport::start() -{ - const Core::Id runMode = runControl()->runMode(); - if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - d->qmlPort = targetRunner()->findPort(); - if (!d->qmlPort.isValid()) { - reportFailure(tr("Not enough free ports on device for profiling.")); - return; - } - } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - d->remoteFifo = targetRunner()->fifo(); - if (d->remoteFifo.isEmpty()) { - reportFailure(tr("FIFO for profiling data could not be created.")); - return; - } - } - - ApplicationLauncher *runner = targetRunner()->applicationLauncher(); - connect(runner, &ApplicationLauncher::remoteStderr, - this, &RemoteLinuxAnalyzeSupport::handleRemoteErrorOutput); - connect(runner, &ApplicationLauncher::remoteStdout, - this, &RemoteLinuxAnalyzeSupport::handleRemoteOutput); - connect(runner, &ApplicationLauncher::remoteProcessStarted, - this, &RemoteLinuxAnalyzeSupport::handleRemoteProcessStarted); - connect(runner, &ApplicationLauncher::finished, - this, &RemoteLinuxAnalyzeSupport::handleAppRunnerFinished); - connect(runner, &ApplicationLauncher::reportProgress, - this, &RemoteLinuxAnalyzeSupport::handleProgressReport); - connect(runner, &ApplicationLauncher::reportError, - this, &RemoteLinuxAnalyzeSupport::handleAppRunnerError); - - auto r = runControl()->runnable().as<StandardRunnable>(); - - if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { - if (!r.commandLineArguments.isEmpty()) - r.commandLineArguments.append(QLatin1Char(' ')); - r.commandLineArguments += QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, - d->qmlPort); - } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - r.commandLineArguments = QLatin1String("-c 'perf record -o - ") + d->perfRecordArguments - + QLatin1String(" -- ") + r.executable + QLatin1String(" ") - + r.commandLineArguments + QLatin1String(" > ") + d->remoteFifo - + QLatin1String("'"); - r.executable = QLatin1String("sh"); - - connect(&d->outputGatherer, SIGNAL(remoteStdout(QByteArray)), - runControl(), SIGNAL(analyzePerfOutput(QByteArray))); - connect(&d->outputGatherer, SIGNAL(finished(bool)), - runControl(), SIGNAL(perfFinished())); - - StandardRunnable outputRunner; - outputRunner.executable = QLatin1String("sh"); - outputRunner.commandLineArguments = - QString::fromLatin1("-c 'cat %1 && rm -r `dirname %1`'").arg(d->remoteFifo); - d->outputGatherer.start(outputRunner, device()); - remoteIsRunning(); - } - runner->start(r, device()); -} - -void RemoteLinuxAnalyzeSupport::handleAppRunnerError(const QString &error) -{ - showMessage(error, Utils::ErrorMessageFormat); - reportFailure(error); -} - -void RemoteLinuxAnalyzeSupport::handleAppRunnerFinished(bool success) -{ - // reset needs to be called first to ensure that the correct state is set. - if (!success) - showMessage(tr("Failure running remote process."), Utils::NormalMessageFormat); - runControl()->notifyRemoteFinished(); -} - -void RemoteLinuxAnalyzeSupport::remoteIsRunning() -{ - runControl()->notifyRemoteSetupDone(d->qmlPort); -} - -AbstractRemoteLinuxRunSupport *RemoteLinuxAnalyzeSupport::targetRunner() const -{ - return qobject_cast<AbstractRemoteLinuxRunSupport *>(runControl()->targetRunner()); -} - -void RemoteLinuxAnalyzeSupport::handleRemoteOutput(const QByteArray &output) -{ - showMessage(QString::fromUtf8(output), Utils::StdOutFormat); -} - -void RemoteLinuxAnalyzeSupport::handleRemoteErrorOutput(const QByteArray &output) -{ - showMessage(QString::fromUtf8(output), Utils::StdErrFormat); -} - -void RemoteLinuxAnalyzeSupport::handleProgressReport(const QString &progressOutput) -{ - showMessage(progressOutput + QLatin1Char('\n'), Utils::NormalMessageFormat); -} - -void RemoteLinuxAnalyzeSupport::handleAdapterSetupFailed(const QString &error) -{ - showMessage(tr("Initial setup failed: %1").arg(error), Utils::NormalMessageFormat); -} - -void RemoteLinuxAnalyzeSupport::handleRemoteProcessStarted() -{ -} - -} // namespace RemoteLinux +///**************************************************************************** +//** +//** Copyright (C) 2016 The Qt Company Ltd. +//** Contact: https://www.qt.io/licensing/ +//** +//** This file is part of Qt Creator. +//** +//** Commercial License Usage +//** Licensees holding valid commercial Qt licenses may use this file in +//** accordance with the commercial license agreement provided with the +//** Software or, alternatively, in accordance with the terms contained in +//** a written agreement between you and The Qt Company. For licensing terms +//** and conditions see https://www.qt.io/terms-conditions. For further +//** information use the contact form at https://www.qt.io/contact-us. +//** +//** GNU General Public License Usage +//** Alternatively, this file may be used under the terms of the GNU +//** General Public License version 3 as published by the Free Software +//** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +//** included in the packaging of this file. Please review the following +//** information to ensure the GNU General Public License requirements will +//** be met: https://www.gnu.org/licenses/gpl-3.0.html. +//** +//****************************************************************************/ + +//#include "remotelinuxanalyzesupport.h" + +//#include "remotelinuxrunconfiguration.h" + +//#include <projectexplorer/buildconfiguration.h> +//#include <projectexplorer/project.h> +//#include <projectexplorer/target.h> +//#include <projectexplorer/toolchain.h> +//#include <projectexplorer/kitinformation.h> +//#include <projectexplorer/runnables.h> + +//#include <utils/qtcassert.h> +//#include <utils/qtcprocess.h> +//#include <qmldebug/qmloutputparser.h> +//#include <qmldebug/qmldebugcommandlinearguments.h> + +//#include <QPointer> + +//using namespace QSsh; +//using namespace ProjectExplorer; +//using namespace Utils; + +//namespace RemoteLinux { +//namespace Internal { + +//const char RemoteLinuxAnalyzeSupportWorkerId[] = "RemoteLinux.AnalyzeSupportWorker"; + +//class RemoteLinuxAnalyzeSupportPrivate +//{ +//public: +// RemoteLinuxAnalyzeSupportPrivate(RunControl *runControl) +// { +// bool isPerf = runControl->runMode() == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE; +// needFifo = isPerf; +// if (needFifo) { +// RunConfiguration *runConfiguration = runControl->runConfiguration(); +// QTC_ASSERT(runConfiguration, return); +// IRunConfigurationAspect *perfAspect = +// runConfiguration->extraAspect("Analyzer.Perf.Settings"); +// QTC_ASSERT(perfAspect, return); +// perfRecordArguments = +// perfAspect->currentSettings()->property("perfRecordArguments").toStringList() +// .join(' '); +// } +// } + +// Utils::Port qmlPort; +// QString remoteFifo; +// QString perfRecordArguments; + +// ApplicationLauncher outputGatherer; +// QmlDebug::QmlOutputParser outputParser; +// bool needFifo = false; +// bool needPort = false; +//}; + +//} // namespace Internal + +//using namespace Internal; + +//RemoteLinuxAnalyzeSupport::RemoteLinuxAnalyzeSupport(RunControl *runControl) +// : ToolRunner(runControl), +// d(new RemoteLinuxAnalyzeSupportPrivate(runControl)) +//{ +// setId(RemoteLinuxAnalyzeSupportWorkerId); + +// connect(&d->outputParser, &QmlDebug::QmlOutputParser::waitingForConnectionOnPort, +// this, &RemoteLinuxAnalyzeSupport::remoteIsRunning); + +// if (d->needFifo) +// addDependency(FifoCreatorWorkerId); +// if (d->needPort) +// addDependency(PortsGathererWorkerId); +//} + +//RemoteLinuxAnalyzeSupport::~RemoteLinuxAnalyzeSupport() +//{ +// delete d; +//} + +////void RemoteLinuxAnalyzeSupport::showMessage(const QString &msg, Utils::OutputFormat format) +////{ +//// appendMessage(msg, format); +//// d->outputParser.processOutput(msg); +////} + +//void RemoteLinuxAnalyzeSupport::start() +//{ +// if (d->needPort) { +// RunWorker *worker = qobject_cast<PortsGatherer>(); +// QTC_ASSERT(worker, reportFailure(); return); +// runControl()->worker(PortsGathererWorkerId)->result(); +// d->qmlPort = targetRunner()->findPort(); +// if (!d->qmlPort.isValid()) { +// reportFailure(tr("Not enough free ports on device for profiling.")); +// return; +// } +// } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { +// d->remoteFifo = targetRunner()->fifo(); +// if (d->remoteFifo.isEmpty()) { +// reportFailure(tr("FIFO for profiling data could not be created.")); +// return; +// } +// } + +// ApplicationLauncher *runner = targetRunner()->applicationLauncher(); + +// auto r = runControl()->runnable().as<StandardRunnable>(); + +// if (runMode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE) { +// if (!r.commandLineArguments.isEmpty()) +// r.commandLineArguments.append(QLatin1Char(' ')); +// r.commandLineArguments += QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlProfilerServices, +// d->qmlPort); +// } else if (runMode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { +// r.commandLineArguments = QLatin1String("-c 'perf record -o - ") + d->perfRecordArguments +// + QLatin1String(" -- ") + r.executable + QLatin1String(" ") +// + r.commandLineArguments + QLatin1String(" > ") + d->remoteFifo +// + QLatin1String("'"); +// r.executable = QLatin1String("sh"); + +// connect(&d->outputGatherer, SIGNAL(remoteStdout(QByteArray)), +// runControl(), SIGNAL(analyzePerfOutput(QByteArray))); +// connect(&d->outputGatherer, SIGNAL(finished(bool)), +// runControl(), SIGNAL(perfFinished())); + +// StandardRunnable outputRunner; +// outputRunner.executable = QLatin1String("sh"); +// outputRunner.commandLineArguments = +// QString::fromLatin1("-c 'cat %1 && rm -r `dirname %1`'").arg(d->remoteFifo); +// d->outputGatherer.start(outputRunner, device()); +// remoteIsRunning(); +// } +// runner->start(r, device()); +//} + +//void RemoteLinuxAnalyzeSupport::remoteIsRunning() +//{ +// runControl()->notifyRemoteSetupDone(d->qmlPort); +//} + +//AbstractRemoteLinuxRunSupport *RemoteLinuxAnalyzeSupport::targetRunner() const +//{ +// return qobject_cast<AbstractRemoteLinuxRunSupport *>(runControl()->targetRunner()); +//} + +//} // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.h b/src/plugins/remotelinux/remotelinuxanalyzesupport.h index f125deba91..e1cefa6f97 100644 --- a/src/plugins/remotelinux/remotelinuxanalyzesupport.h +++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.h @@ -1,67 +1,54 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "abstractremotelinuxrunsupport.h" - -#include <projectexplorer/projectexplorerconstants.h> -#include <projectexplorer/runconfiguration.h> - -#include <utils/outputformat.h> - -namespace RemoteLinux { - -namespace Internal { class RemoteLinuxAnalyzeSupportPrivate; } - -class REMOTELINUX_EXPORT RemoteLinuxAnalyzeSupport : public ProjectExplorer::ToolRunner -{ - Q_OBJECT -public: - RemoteLinuxAnalyzeSupport(ProjectExplorer::RunControl *runControl); - ~RemoteLinuxAnalyzeSupport() override; - -private: - void start() override; - void handleAdapterSetupFailed(const QString &error); - - void handleRemoteSetupRequested(); - void handleAppRunnerError(const QString &error); - void handleRemoteOutput(const QByteArray &output); - void handleRemoteErrorOutput(const QByteArray &output); - void handleAppRunnerFinished(bool success); - void handleProgressReport(const QString &progressOutput); - - void handleRemoteProcessStarted(); - - void remoteIsRunning(); - AbstractRemoteLinuxRunSupport *targetRunner() const; - - void showMessage(const QString &, Utils::OutputFormat); - - Internal::RemoteLinuxAnalyzeSupportPrivate * const d; -}; - -} // namespace RemoteLinux +///**************************************************************************** +//** +//** Copyright (C) 2016 The Qt Company Ltd. +//** Contact: https://www.qt.io/licensing/ +//** +//** This file is part of Qt Creator. +//** +//** Commercial License Usage +//** Licensees holding valid commercial Qt licenses may use this file in +//** accordance with the commercial license agreement provided with the +//** Software or, alternatively, in accordance with the terms contained in +//** a written agreement between you and The Qt Company. For licensing terms +//** and conditions see https://www.qt.io/terms-conditions. For further +//** information use the contact form at https://www.qt.io/contact-us. +//** +//** GNU General Public License Usage +//** Alternatively, this file may be used under the terms of the GNU +//** General Public License version 3 as published by the Free Software +//** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +//** included in the packaging of this file. Please review the following +//** information to ensure the GNU General Public License requirements will +//** be met: https://www.gnu.org/licenses/gpl-3.0.html. +//** +//****************************************************************************/ + +//#pragma once + +//#include "abstractremotelinuxrunsupport.h" + +//#include <projectexplorer/projectexplorerconstants.h> +//#include <projectexplorer/runconfiguration.h> + +//#include <utils/outputformat.h> + +//namespace RemoteLinux { + +//namespace Internal { class RemoteLinuxAnalyzeSupportPrivate; } + +//class REMOTELINUX_EXPORT RemoteLinuxAnalyzeSupport : public ProjectExplorer::RunWorker +//{ +// Q_OBJECT +//public: +// RemoteLinuxAnalyzeSupport(ProjectExplorer::RunControl *runControl); +// ~RemoteLinuxAnalyzeSupport() override; + +//private: +// void start() override; + +// void remoteIsRunning(); + +// Internal::RemoteLinuxAnalyzeSupportPrivate * const d; +//}; + +//} // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 9bcdc5b207..331b5c3ad3 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -47,10 +47,35 @@ using namespace Utils; namespace RemoteLinux { -LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString *errorMessage) +LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl) : DebuggerRunTool(runControl) { - RunConfiguration *runConfig = runControl->runConfiguration(); + setDisplayName("DebugSupport"); + + auto portsGatherer = new GdbServerPortsGatherer(runControl); + portsGatherer->setUseGdbServer(isCppDebugging()); + portsGatherer->setUseQmlServer(isQmlDebugging()); + + auto gdbServer = new GdbServerRunner(runControl); + gdbServer->addDependency(portsGatherer); + + addDependency(gdbServer); +} + +LinuxDeviceDebugSupport::~LinuxDeviceDebugSupport() +{ +} + +void LinuxDeviceDebugSupport::start() +{ + auto portsGatherer = runControl()->worker<GdbServerPortsGatherer>(); + QTC_ASSERT(portsGatherer, reportFailure(); return); + + const QString host = device()->sshParameters().host; + const Port gdbServerPort = portsGatherer->gdbServerPort(); + const Port qmlServerPort = portsGatherer->qmlServerPort(); + + RunConfiguration *runConfig = runControl()->runConfiguration(); QString symbolFile; if (auto rlrc = qobject_cast<RemoteLinuxRunConfiguration *>(runConfig)) @@ -58,7 +83,7 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString if (auto rlrc = qobject_cast<Internal::RemoteLinuxCustomRunConfiguration *>(runConfig)) symbolFile = rlrc->localExecutableFilePath(); if (symbolFile.isEmpty()) { - *errorMessage = tr("Cannot debug: Local executable is not set."); +// *errorMessage = tr("Cannot debug: Local executable is not set."); return; } @@ -68,8 +93,10 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString params.remoteSetupNeeded = false; if (isQmlDebugging()) { - params.qmlServer.host = device()->sshParameters().host; - params.qmlServer.port = Utils::Port(); // port is selected later on + params.qmlServer.host = host; + params.qmlServer.port = qmlServerPort; + params.inferior.commandLineArguments.replace("%qml_port%", + QString::number(qmlServerPort.number())); } if (isCppDebugging()) { Runnable r = runnable(); @@ -83,69 +110,14 @@ LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunControl *runControl, QString params.inferior.commandLineArguments.prepend( QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices)); } - params.remoteChannel = device()->sshParameters().host + ":-1"; + + params.remoteChannel = QString("%1:%2").arg(host).arg(gdbServerPort.number()); params.symbolFile = symbolFile; } setStartParameters(params); -} -LinuxDeviceDebugSupport::~LinuxDeviceDebugSupport() -{ -} - -void LinuxDeviceDebugSupport::prepare() -{ - auto targetRunner = qobject_cast<AbstractRemoteLinuxRunSupport *>(runControl()->targetRunner()); - - if (isCppDebugging()) { - m_gdbServerPort = targetRunner->findPort(); - if (!m_gdbServerPort.isValid()) { - reportFailure(tr("Not enough free ports on device for C++ debugging.")); - return; - } - } - if (isQmlDebugging()) { - m_qmlPort = targetRunner->findPort(); - if (!m_qmlPort.isValid()) { - reportFailure(tr("Not enough free ports on device for QML debugging.")); - return; - } - } - - runControl()->setRunnable(realRunnable()); - - RemoteSetupResult result; - result.success = true; - result.gdbServerPort = m_gdbServerPort; - result.qmlServerPort = m_qmlPort; - setRemoteParameters(result); - - DebuggerRunTool::prepare(); -} - -Runnable LinuxDeviceDebugSupport::realRunnable() const -{ - StandardRunnable r = runControl()->runnable().as<StandardRunnable>(); - QStringList args = QtcProcess::splitArgs(r.commandLineArguments, OsTypeLinux); - QString command; - - if (isQmlDebugging()) - args.prepend(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, m_qmlPort)); - - if (isQmlDebugging() && !isCppDebugging()) { - command = r.executable; - } else { - command = device()->debugServerPath(); - if (command.isEmpty()) - command = QLatin1String("gdbserver"); - args.clear(); - args.append(QString::fromLatin1("--multi")); - args.append(QString::fromLatin1(":%1").arg(m_gdbServerPort.number())); - } - r.executable = command; - r.commandLineArguments = QtcProcess::joinArgs(args, OsTypeLinux); - return r; + DebuggerRunTool::start(); } } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.h b/src/plugins/remotelinux/remotelinuxdebugsupport.h index 7473f05593..d670be1b3a 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.h +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.h @@ -36,18 +36,11 @@ class REMOTELINUX_EXPORT LinuxDeviceDebugSupport : public Debugger::DebuggerRunT Q_OBJECT public: - LinuxDeviceDebugSupport(ProjectExplorer::RunControl *runControl, - QString *errorMessage = nullptr); + LinuxDeviceDebugSupport(ProjectExplorer::RunControl *runControl); ~LinuxDeviceDebugSupport() override; -protected: - virtual ProjectExplorer::Runnable realRunnable() const; - private: - void prepare() override; - - Utils::Port m_gdbServerPort; - Utils::Port m_qmlPort; + void start() override; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 978bb9aa90..76911168e8 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -30,18 +30,12 @@ #include "remotelinuxcustomrunconfiguration.h" #include "remotelinuxrunconfiguration.h" -#include <debugger/analyzer/analyzermanager.h> -#include <debugger/analyzer/analyzerstartparameters.h> - #include <debugger/debuggerruncontrol.h> -#include <debugger/debuggerrunconfigurationaspect.h> -#include <debugger/debuggerstartparameters.h> #include <projectexplorer/kitinformation.h> #include <projectexplorer/runnables.h> #include <projectexplorer/target.h> - #include <utils/portlist.h> #include <utils/qtcassert.h> @@ -62,7 +56,8 @@ bool RemoteLinuxRunControlFactory::canRun(RunConfiguration *runConfiguration, Co && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE && mode != ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN && mode != ProjectExplorer::Constants::QML_PROFILER_RUN_MODE - && mode != ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { +// && mode != ProjectExplorer::Constants::PERFPROFILER_RUN_MODE + ) { return false; } @@ -73,34 +68,37 @@ bool RemoteLinuxRunControlFactory::canRun(RunConfiguration *runConfiguration, Co } RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Core::Id mode, - QString *errorMessage) + QString *) { QTC_ASSERT(canRun(runConfig, mode), return 0); if (mode == ProjectExplorer::Constants::NORMAL_RUN_MODE) { auto runControl = new RunControl(runConfig, mode); - (void) new AbstractRemoteLinuxRunSupport(runControl); + (void) new SimpleTargetRunner(runControl); return runControl; } if (mode == ProjectExplorer::Constants::DEBUG_RUN_MODE || mode == ProjectExplorer::Constants::DEBUG_RUN_MODE_WITH_BREAK_ON_MAIN) { auto runControl = new RunControl(runConfig, mode); - (void) new AbstractRemoteLinuxRunSupport(runControl); - (void) new LinuxDeviceDebugSupport(runControl, errorMessage); + (void) new LinuxDeviceDebugSupport(runControl); return runControl; } - if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE || - mode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE) { - auto runControl = Debugger::createAnalyzerRunControl(runConfig, mode); - AnalyzerConnection connection; - connection.connParams = - DeviceKitInformation::device(runConfig->target()->kit())->sshParameters(); - connection.analyzerHost = connection.connParams.host; - runControl->setConnection(connection); - (void) new AbstractRemoteLinuxRunSupport(runControl); - (void) new RemoteLinuxAnalyzeSupport(runControl); + if (mode == ProjectExplorer::Constants::QML_PROFILER_RUN_MODE +// || mode == ProjectExplorer::Constants::PERFPROFILER_RUN_MODE + ) { + auto runControl = new RunControl(runConfig, mode); + runControl->createWorker(mode); +// AnalyzerConnection connection; +// connection.connParams = +// DeviceKitInformation::device(runConfig->target()->kit())->sshParameters(); +// connection.analyzerHost = connection.connParams.host; +// runControl->setConnection(connection); +// (void) new SimpleTargetRunner(runControl); +// (void) new PortsGatherer(runControl); +// (void) new FifoGatherer(runControl); +// (void) new RemoteLinuxAnalyzeSupport(runControl); return runControl; } diff --git a/src/plugins/valgrind/callgrindtool.cpp b/src/plugins/valgrind/callgrindtool.cpp index 01aac21877..7137659025 100644 --- a/src/plugins/valgrind/callgrindtool.cpp +++ b/src/plugins/valgrind/callgrindtool.cpp @@ -255,14 +255,11 @@ CallgrindTool::CallgrindTool(QObject *parent) QString toolTip = tr("Valgrind Function Profiler uses the " "Callgrind tool to record function calls when a program runs."); - auto rcc = [this](RunConfiguration *runConfiguration, Id mode) { - auto runControl = new RunControl(runConfiguration, mode); - (void) createRunTool(runControl); - return runControl; - }; + RunControl::registerWorkerCreator(CALLGRIND_RUN_MODE, [this](RunControl *runControl) { + return createRunTool(runControl); + }); if (!Utils::HostOsInfo::isWindowsHost()) { - Debugger::registerAction(CALLGRIND_RUN_MODE, rcc); auto action = new QAction(tr("Valgrind Function Profiler"), this); action->setToolTip(toolTip); menu->addAction(ActionManager::registerAction(action, CallgrindLocalActionId), @@ -279,7 +276,6 @@ CallgrindTool::CallgrindTool(QObject *parent) }); } - Debugger::registerAction(CALLGRIND_RUN_MODE, rcc); auto action = new QAction(tr("Valgrind Function Profiler (External Application)"), this); action->setToolTip(toolTip); menu->addAction(ActionManager::registerAction(action, CallgrindRemoteActionId), diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 4c8d421a6c..f452a845df 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -244,7 +244,7 @@ class MemcheckTool : public QObject public: MemcheckTool(QObject *parent); - RunControl *createRunControl(RunConfiguration *runConfiguration, Core::Id runMode); + RunWorker *createRunWorker(RunControl *runControl); private: void updateRunActions(); @@ -395,8 +395,10 @@ MemcheckTool::MemcheckTool(QObject *parent) ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER); QString toolTip = tr("Valgrind Analyze Memory uses the Memcheck tool to find memory leaks."); + RunControl::registerWorkerCreator(MEMCHECK_RUN_MODE, std::bind(&MemcheckTool::createRunWorker, this, _1)); + RunControl::registerWorkerCreator(MEMCHECK_WITH_GDB_RUN_MODE, std::bind(&MemcheckTool::createRunWorker, this, _1)); + if (!Utils::HostOsInfo::isWindowsHost()) { - Debugger::registerAction(MEMCHECK_RUN_MODE, std::bind(&MemcheckTool::createRunControl, this, _1, _2)); action = new QAction(this); action->setText(tr("Valgrind Memory Analyzer")); action->setToolTip(toolTip); @@ -414,7 +416,6 @@ MemcheckTool::MemcheckTool(QObject *parent) action->setEnabled(m_startAction->isEnabled()); }); - Debugger::registerAction(MEMCHECK_WITH_GDB_RUN_MODE, std::bind(&MemcheckTool::createRunControl, this, _1, _2)); action = new QAction(this); action->setText(tr("Valgrind Memory Analyzer with GDB")); action->setToolTip(tr("Valgrind Analyze Memory with GDB uses the " @@ -435,7 +436,6 @@ MemcheckTool::MemcheckTool(QObject *parent) }); } - Debugger::registerAction(MEMCHECK_RUN_MODE, std::bind(&MemcheckTool::createRunControl, this, _1, _2)); action = new QAction(this); action->setText(tr("Valgrind Memory Analyzer (External Application)")); action->setToolTip(toolTip); @@ -452,8 +452,8 @@ MemcheckTool::MemcheckTool(QObject *parent) return; TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID); Debugger::selectPerspective(MemcheckPerspectiveId); - RunControl *rc = createRunControl(runConfig, MEMCHECK_RUN_MODE); - QTC_ASSERT(rc, return); + RunControl *rc = new RunControl(runConfig, MEMCHECK_RUN_MODE); + rc->createWorker(MEMCHECK_RUN_MODE); const auto runnable = dlg.runnable(); rc->setRunnable(runnable); AnalyzerConnection connection; @@ -560,14 +560,14 @@ void MemcheckTool::maybeActiveRunConfigurationChanged() updateFromSettings(); } -RunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration, Core::Id runMode) +RunWorker *MemcheckTool::createRunWorker(RunControl *runControl) { - m_errorModel.setRelevantFrameFinder(makeFrameFinder(runConfiguration - ? runConfiguration->target()->project()->files(Project::AllFiles) : QStringList())); + RunConfiguration *runConfig = runControl->runConfiguration(); + m_errorModel.setRelevantFrameFinder(makeFrameFinder(runConfig + ? runConfig->target()->project()->files(Project::AllFiles) : QStringList())); - auto runControl = new RunControl(runConfiguration, runMode); MemcheckToolRunner *runTool = 0; - if (runMode == MEMCHECK_RUN_MODE) + if (runControl->runMode() == MEMCHECK_RUN_MODE) runTool = new MemcheckToolRunner(runControl); else runTool = new MemcheckWithGdbToolRunner(runControl); @@ -583,7 +583,7 @@ RunControl *MemcheckTool::createRunControl(RunConfiguration *runConfiguration, C m_toolBusy = true; updateRunActions(); - return runControl; + return runTool; } void MemcheckTool::engineStarting(const MemcheckToolRunner *runTool) @@ -739,7 +739,9 @@ public: RunControl *create(RunConfiguration *runConfiguration, Core::Id mode, QString *errorMessage) override { Q_UNUSED(errorMessage); - return m_tool->createRunControl(runConfiguration, mode); + auto runControl = new RunControl(runConfiguration, mode); + runControl->createWorker(mode); + return runControl; } // Do not create an aspect, let the Callgrind tool create one and use that, too. diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index a10e709b3a..c2df034ecf 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -54,7 +54,7 @@ namespace Valgrind { namespace Internal { ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) - : ToolRunner(runControl) + : RunWorker(runControl) { runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR); runControl->setSupportsReRunning(false); @@ -102,7 +102,7 @@ void ValgrindToolRunner::start() return; } - reportSuccess(); + reportStarted(); } void ValgrindToolRunner::stop() @@ -160,7 +160,7 @@ void ValgrindToolRunner::runnerFinished() disconnect(runner(), &ValgrindRunner::finished, this, &ValgrindToolRunner::runnerFinished); - reportSuccess(); + reportStarted(); } void ValgrindToolRunner::receiveProcessOutput(const QString &output, OutputFormat format) diff --git a/src/plugins/valgrind/valgrindengine.h b/src/plugins/valgrind/valgrindengine.h index 874fdf284c..6a41d68000 100644 --- a/src/plugins/valgrind/valgrindengine.h +++ b/src/plugins/valgrind/valgrindengine.h @@ -37,7 +37,7 @@ namespace Valgrind { namespace Internal { -class ValgrindToolRunner : public ProjectExplorer::ToolRunner +class ValgrindToolRunner : public ProjectExplorer::RunWorker { Q_OBJECT diff --git a/src/plugins/winrt/winrtdebugsupport.cpp b/src/plugins/winrt/winrtdebugsupport.cpp index a3f31072a1..1cb2c6b124 100644 --- a/src/plugins/winrt/winrtdebugsupport.cpp +++ b/src/plugins/winrt/winrtdebugsupport.cpp @@ -49,7 +49,7 @@ namespace Internal { using namespace ProjectExplorer; WinRtDebugSupport::WinRtDebugSupport(RunControl *runControl, WinRtRunnerHelper *runner) - : ToolRunner(runControl) + : RunWorker(runControl) , m_runner(runner) { connect(runControl, &RunControl::finished, this, &WinRtDebugSupport::finish); diff --git a/src/plugins/winrt/winrtdebugsupport.h b/src/plugins/winrt/winrtdebugsupport.h index 630463d44c..177e8157c1 100644 --- a/src/plugins/winrt/winrtdebugsupport.h +++ b/src/plugins/winrt/winrtdebugsupport.h @@ -35,7 +35,7 @@ namespace Internal { class WinRtRunConfiguration; class WinRtRunnerHelper; -class WinRtDebugSupport : public ProjectExplorer::ToolRunner +class WinRtDebugSupport : public ProjectExplorer::RunWorker { Q_OBJECT public: |