2019-03-13 08:06:08 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2019 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 "applicationlauncher.h"
|
2019-08-30 12:00:57 +02:00
|
|
|
#include "buildconfiguration.h"
|
2019-03-13 08:06:08 +01:00
|
|
|
#include "devicesupport/idevice.h"
|
|
|
|
|
#include "projectexplorerconstants.h"
|
|
|
|
|
#include "runconfiguration.h"
|
|
|
|
|
|
|
|
|
|
#include <utils/environment.h>
|
|
|
|
|
#include <utils/processhandle.h>
|
|
|
|
|
#include <utils/qtcassert.h>
|
2019-05-28 18:59:45 +02:00
|
|
|
#include <utils/qtcprocess.h>
|
2019-03-13 08:06:08 +01:00
|
|
|
#include <utils/icon.h>
|
|
|
|
|
|
|
|
|
|
#include <QHash>
|
|
|
|
|
#include <QVariant>
|
|
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
|
|
namespace Utils {
|
|
|
|
|
class MacroExpander;
|
|
|
|
|
class OutputFormatter;
|
|
|
|
|
} // Utils
|
|
|
|
|
|
|
|
|
|
namespace ProjectExplorer {
|
|
|
|
|
class GlobalOrProjectAspect;
|
|
|
|
|
class Node;
|
|
|
|
|
class RunConfiguration;
|
|
|
|
|
class RunControl;
|
|
|
|
|
class Target;
|
|
|
|
|
|
|
|
|
|
namespace Internal {
|
|
|
|
|
class RunControlPrivate;
|
|
|
|
|
class RunWorkerPrivate;
|
|
|
|
|
} // Internal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PROJECTEXPLORER_EXPORT Runnable
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Runnable() = default;
|
|
|
|
|
|
2019-05-28 18:59:45 +02:00
|
|
|
Utils::CommandLine commandLine() const;
|
2019-05-29 19:12:45 +02:00
|
|
|
void setCommandLine(const Utils::CommandLine &cmdLine);
|
2019-05-28 18:59:45 +02:00
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
Utils::FilePath executable;
|
2019-03-13 08:06:08 +01:00
|
|
|
QString commandLineArguments;
|
|
|
|
|
QString workingDirectory;
|
|
|
|
|
Utils::Environment environment;
|
|
|
|
|
IDevice::ConstPtr device; // Override the kit's device. Keep unset by default.
|
|
|
|
|
QHash<Core::Id, QVariant> extraData;
|
|
|
|
|
|
|
|
|
|
// FIXME: Not necessarily a display name
|
2019-06-20 17:19:12 +02:00
|
|
|
QString displayName() const { return executable.toString(); }
|
2019-03-13 08:06:08 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class PROJECTEXPLORER_EXPORT RunWorker : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit RunWorker(RunControl *runControl);
|
|
|
|
|
~RunWorker() override;
|
|
|
|
|
|
|
|
|
|
RunControl *runControl() const;
|
|
|
|
|
|
|
|
|
|
void addStartDependency(RunWorker *dependency);
|
|
|
|
|
void addStopDependency(RunWorker *dependency);
|
|
|
|
|
|
|
|
|
|
void setId(const QString &id);
|
|
|
|
|
|
|
|
|
|
void setStartTimeout(int ms, const std::function<void()> &callback = {});
|
|
|
|
|
void setStopTimeout(int ms, const std::function<void()> &callback = {});
|
|
|
|
|
|
|
|
|
|
void recordData(const QString &channel, const QVariant &data);
|
|
|
|
|
QVariant recordedData(const QString &channel) const;
|
|
|
|
|
|
|
|
|
|
// Part of read-only interface of RunControl for convenience.
|
|
|
|
|
void appendMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true);
|
|
|
|
|
IDevice::ConstPtr device() const;
|
|
|
|
|
const Runnable &runnable() const;
|
|
|
|
|
|
|
|
|
|
// States
|
|
|
|
|
void initiateStart();
|
|
|
|
|
void reportStarted();
|
|
|
|
|
|
|
|
|
|
void initiateStop();
|
|
|
|
|
void reportStopped();
|
|
|
|
|
|
|
|
|
|
void reportDone();
|
|
|
|
|
|
|
|
|
|
void reportFailure(const QString &msg = QString());
|
|
|
|
|
void setSupportsReRunning(bool reRunningSupported);
|
|
|
|
|
bool supportsReRunning() const;
|
|
|
|
|
|
2019-06-20 17:19:12 +02:00
|
|
|
static QString userMessageForProcessError(QProcess::ProcessError,
|
|
|
|
|
const Utils::FilePath &programName);
|
2019-03-13 08:06:08 +01:00
|
|
|
|
|
|
|
|
bool isEssential() const;
|
|
|
|
|
void setEssential(bool essential);
|
|
|
|
|
|
|
|
|
|
signals:
|
|
|
|
|
void started();
|
|
|
|
|
void stopped();
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void virtual start();
|
|
|
|
|
void virtual stop();
|
|
|
|
|
void virtual onFinished() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
friend class Internal::RunControlPrivate;
|
|
|
|
|
friend class Internal::RunWorkerPrivate;
|
|
|
|
|
const std::unique_ptr<Internal::RunWorkerPrivate> d;
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-07 18:05:15 +02:00
|
|
|
class PROJECTEXPLORER_EXPORT RunWorkerFactory final
|
2019-03-13 08:06:08 +01:00
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using WorkerCreator = std::function<RunWorker *(RunControl *)>;
|
|
|
|
|
|
2019-08-07 18:05:15 +02:00
|
|
|
RunWorkerFactory(const WorkerCreator &producer,
|
|
|
|
|
const QList<Core::Id> &runModes,
|
|
|
|
|
const QList<Core::Id> &runConfigs = {},
|
|
|
|
|
const QList<Core::Id> &deviceTypes = {});
|
2019-03-13 08:06:08 +01:00
|
|
|
|
2019-08-07 18:05:15 +02:00
|
|
|
~RunWorkerFactory();
|
2019-04-04 08:26:44 +02:00
|
|
|
|
2019-08-08 15:52:41 +02:00
|
|
|
bool canRun(Core::Id runMode, Core::Id deviceType, const QString &runConfigId) const;
|
2019-03-13 08:06:08 +01:00
|
|
|
WorkerCreator producer() const { return m_producer; }
|
|
|
|
|
|
2019-08-07 18:05:15 +02:00
|
|
|
template <typename Worker>
|
|
|
|
|
static WorkerCreator make()
|
|
|
|
|
{
|
|
|
|
|
return [](RunControl *runControl) { return new Worker(runControl); };
|
|
|
|
|
}
|
2019-03-13 08:06:08 +01:00
|
|
|
|
2019-08-12 18:27:49 +02:00
|
|
|
// For debugging only.
|
|
|
|
|
static void dumpAll();
|
|
|
|
|
|
2019-08-07 18:05:15 +02:00
|
|
|
private:
|
|
|
|
|
WorkerCreator m_producer;
|
2019-03-13 08:06:08 +01:00
|
|
|
QList<Core::Id> m_supportedRunModes;
|
2019-04-04 08:26:44 +02:00
|
|
|
QList<Core::Id> m_supportedRunConfigurations;
|
2019-08-07 18:05:15 +02:00
|
|
|
QList<Core::Id> m_supportedDeviceTypes;
|
2019-03-13 08:06:08 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A RunControl controls the running of an application or tool
|
|
|
|
|
* on a target device. It controls start and stop, and handles
|
|
|
|
|
* application output.
|
|
|
|
|
*
|
|
|
|
|
* RunControls are created by RunControlFactories.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class PROJECTEXPLORER_EXPORT RunControl : public QObject
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit RunControl(Core::Id mode);
|
|
|
|
|
~RunControl() override;
|
|
|
|
|
|
|
|
|
|
void setRunConfiguration(RunConfiguration *runConfig);
|
|
|
|
|
void setTarget(Target *target);
|
|
|
|
|
void setKit(Kit *kit);
|
|
|
|
|
|
|
|
|
|
void initiateStart();
|
|
|
|
|
void initiateReStart();
|
|
|
|
|
void initiateStop();
|
|
|
|
|
void forceStop();
|
|
|
|
|
void initiateFinish();
|
|
|
|
|
|
|
|
|
|
bool promptToStop(bool *optionalPrompt = nullptr) const;
|
|
|
|
|
void setPromptToStop(const std::function<bool(bool *)> &promptToStop);
|
|
|
|
|
|
|
|
|
|
bool supportsReRunning() const;
|
|
|
|
|
|
|
|
|
|
virtual QString displayName() const;
|
|
|
|
|
void setDisplayName(const QString &displayName);
|
|
|
|
|
|
|
|
|
|
bool isRunning() const;
|
|
|
|
|
bool isStarting() const;
|
|
|
|
|
bool isStopping() const;
|
|
|
|
|
bool isStopped() const;
|
|
|
|
|
|
|
|
|
|
void setIcon(const Utils::Icon &icon);
|
|
|
|
|
Utils::Icon icon() const;
|
|
|
|
|
|
|
|
|
|
Utils::ProcessHandle applicationProcessHandle() const;
|
|
|
|
|
void setApplicationProcessHandle(const Utils::ProcessHandle &handle);
|
|
|
|
|
IDevice::ConstPtr device() const;
|
|
|
|
|
|
|
|
|
|
RunConfiguration *runConfiguration() const; // FIXME: Remove.
|
|
|
|
|
// FIXME: Try to cut down to amount of functions.
|
|
|
|
|
Target *target() const;
|
|
|
|
|
Project *project() const;
|
|
|
|
|
Kit *kit() const;
|
|
|
|
|
Utils::MacroExpander *macroExpander() const;
|
|
|
|
|
ProjectConfigurationAspect *aspect(Core::Id id) const;
|
|
|
|
|
template <typename T> T *aspect() const {
|
|
|
|
|
return runConfiguration() ? runConfiguration()->aspect<T>() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString buildKey() const;
|
2019-08-30 12:00:57 +02:00
|
|
|
BuildConfiguration::BuildType buildType() const;
|
|
|
|
|
Utils::FilePath buildDirectory() const;
|
|
|
|
|
Utils::Environment buildEnvironment() const;
|
2019-08-07 12:16:48 +02:00
|
|
|
|
2019-08-27 16:44:42 +02:00
|
|
|
QVariantMap settingsData(Core::Id id) const;
|
|
|
|
|
|
2019-08-07 12:16:48 +02:00
|
|
|
Utils::FilePath targetFilePath() const;
|
|
|
|
|
Utils::FilePath projectFilePath() const;
|
2019-03-13 08:06:08 +01:00
|
|
|
|
|
|
|
|
Utils::OutputFormatter *outputFormatter() const;
|
|
|
|
|
Core::Id runMode() const;
|
|
|
|
|
|
|
|
|
|
const Runnable &runnable() const;
|
|
|
|
|
void setRunnable(const Runnable &runnable);
|
|
|
|
|
|
|
|
|
|
static bool showPromptToStopDialog(const QString &title, const QString &text,
|
|
|
|
|
const QString &stopButtonText = QString(),
|
|
|
|
|
const QString &cancelButtonText = QString(),
|
|
|
|
|
bool *prompt = nullptr);
|
|
|
|
|
|
ProjectExplorer: Standardize RunWorker creation logic
This unifies the remaining paths of RunWorker creation to always
use RunWorkerFactories in the plugin pimpls.
There were, and are, still effectively three basic kinds of workers:
- "toplevel" tools corresponding to the run modes, that are often all
that's used for local runs and directly started via the fat buttons
or e.g. entries in the analyze menu, with factories already previously
located in the plugin pimpls
- core "tool helpers", providing tool specific functionality typically
used in conjunction with a remote device specific run mechanism,
set up via RunControl::registerWorkerCreator
- target/device specific runhelper like port gatherers contructed e.g.
via *Device::workerCreator(Core::Id id)
Worse, these categories are partially overlapping, so it was not
clear how a "clean" setup would look like, instead some ad-hoc cobbling
"to make it work" happened.
In some cases, the runMode id was used throughout the whole ensemble
of run workers for a given run, and which worker exactly was created
depended on which of the mechanism above was used in which order.
With the new central setup, the top-level runmodes remain, but the
second kind gets new ids, so the implicit dependencies on order
of setup mechanism are avoided.
This also helps in the cases where there was previously unclarity of where
and how to set up worker factories: It's always and only the plugin
pimpl now.
Change-Id: Icd9a08e2d53e19abe8b21fe546f469fae353a69f
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-08-23 15:31:35 +02:00
|
|
|
RunWorker *createWorker(Core::Id workerId);
|
2019-03-13 08:06:08 +01:00
|
|
|
|
2019-03-13 15:34:44 +01:00
|
|
|
bool createMainWorker();
|
2019-08-08 15:52:41 +02:00
|
|
|
static bool canRun(Core::Id runMode, Core::Id deviceType, Core::Id runConfigId);
|
2019-03-13 08:06:08 +01:00
|
|
|
|
|
|
|
|
signals:
|
|
|
|
|
void appendMessage(const QString &msg, Utils::OutputFormat format);
|
|
|
|
|
void aboutToStart();
|
|
|
|
|
void started();
|
|
|
|
|
void stopped();
|
|
|
|
|
void finished();
|
|
|
|
|
void applicationProcessHandleChanged(QPrivateSignal); // Use setApplicationProcessHandle
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void setDevice(const IDevice::ConstPtr &device);
|
|
|
|
|
|
|
|
|
|
friend class RunWorker;
|
|
|
|
|
friend class Internal::RunWorkerPrivate;
|
|
|
|
|
|
|
|
|
|
const std::unique_ptr<Internal::RunControlPrivate> d;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A simple TargetRunner for cases where a plain ApplicationLauncher is
|
|
|
|
|
* sufficient for running purposes.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
class PROJECTEXPLORER_EXPORT SimpleTargetRunner : public RunWorker
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
explicit SimpleTargetRunner(RunControl *runControl);
|
|
|
|
|
|
|
|
|
|
protected:
|
2019-09-02 18:22:35 +02:00
|
|
|
void setStarter(const std::function<void()> &starter);
|
|
|
|
|
void doStart(const Runnable &runnable, const IDevice::ConstPtr &device);
|
2019-03-13 08:06:08 +01:00
|
|
|
|
|
|
|
|
private:
|
2019-09-02 18:22:35 +02:00
|
|
|
void start() final;
|
|
|
|
|
void stop() final;
|
|
|
|
|
|
|
|
|
|
const Runnable &runnable() const = delete;
|
2019-03-13 08:06:08 +01:00
|
|
|
|
|
|
|
|
ApplicationLauncher m_launcher;
|
2019-09-02 18:22:35 +02:00
|
|
|
std::function<void()> m_starter;
|
|
|
|
|
|
2019-03-13 08:06:08 +01:00
|
|
|
bool m_stopReported = false;
|
|
|
|
|
bool m_useTerminal = false;
|
|
|
|
|
};
|
|
|
|
|
|
2019-08-06 10:57:59 +02:00
|
|
|
class PROJECTEXPLORER_EXPORT OutputFormatterFactory
|
|
|
|
|
{
|
|
|
|
|
protected:
|
|
|
|
|
OutputFormatterFactory();
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
virtual ~OutputFormatterFactory();
|
|
|
|
|
|
|
|
|
|
static Utils::OutputFormatter *createFormatter(Target *target);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void setFormatterCreator(const std::function<Utils::OutputFormatter *(Target *)> &creator);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
std::function<Utils::OutputFormatter *(Target *)> m_creator;
|
|
|
|
|
};
|
|
|
|
|
|
2019-03-13 08:06:08 +01:00
|
|
|
} // namespace ProjectExplorer
|