// Copyright (C) 2019 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once #include "devicesupport/idevicefwd.h" #include "runconfiguration.h" #include #include #include #include #include #include #include #include #include #include #include namespace Utils { class Icon; class MacroExpander; class OutputLineParser; } // Utils namespace ProjectExplorer { class RunConfiguration; class RunControl; class Target; namespace Internal { class RunControlPrivate; class RunWorkerConflictTest; } // Internal class PROJECTEXPLORER_EXPORT RunWorkerFactory { public: using RecipeCreator = std::function; RunWorkerFactory(); ~RunWorkerFactory(); static void dumpAll(); // For debugging only. Utils::Id id() const { return m_id; } protected: void setId(Utils::Id id) { m_id = id; } void setRecipeProducer(const RecipeCreator &producer); void setSupportedRunConfigs(const QList &runConfigs); void setExecutionType(Utils::Id executionType); void addSupportedRunMode(Utils::Id runMode); void addSupportedRunConfig(Utils::Id runConfig); void addSupportedDeviceType(Utils::Id deviceType); void addSupportForLocalRunConfigs(); void cloneProduct(Utils::Id exitstingStepId); private: friend class RunControl; friend class Internal::RunWorkerConflictTest; bool canCreate( Utils::Id runMode, Utils::Id deviceType, Utils::Id runConfigId, Utils::Id executionType) const; QtTaskTree::Group createRecipe(RunControl *runControl) const; RecipeCreator m_recipeCreator; QList m_supportedRunModes; QList m_supportedRunConfigurations; QList m_supportedDeviceTypes; Utils::Id m_executionType; Utils::Id m_id; }; using Canceler = std::function()>; class ProcessSetupConfig { public: bool suppressDefaultStdOutHandling = false; bool setupCanceler = true; }; /** * 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 final : public QObject { Q_OBJECT public: explicit RunControl(Utils::Id mode); ~RunControl() final; QtTaskTree::Group noRecipeTask(); QtTaskTree::Group errorTask(const QString &message); // The returned recipe sends RunControl::started() signal. QtTaskTree::Group processRecipe(const Utils::ProcessTask &processTask); template QtTaskTree::Group processRecipe(const Modifier &startModifier = {}, const ProcessSetupConfig &config = {}) { return processRecipe(processTaskWithModifier(startModifier, config)); } template Utils::ProcessTask processTaskWithModifier(const Modifier &startModifier, const ProcessSetupConfig &config = {}) { // R, V stands for: Setup[R]esult, [V]oid static constexpr bool isR = isModifierInvocable(); static constexpr bool isV = isModifierInvocable(); static_assert(isR || isV, "Process modifier needs to take (Process &) as an argument and has to return void or " "SetupResult. The passed handler doesn't fulfill these requirements."); if constexpr (isR) { return processTask(startModifier, config); } else { const auto modifier = [startModifier](Utils::Process &process) { startModifier(process); return QtTaskTree::SetupResult::Continue; }; return processTask(modifier, config); } } Utils::ProcessTask processTask( const std::function &startModifier = {}, const ProcessSetupConfig &config = {}); void start(); void reportStarted(); void setBuildConfiguration(BuildConfiguration *bc); void setKit(Kit *kit); void copyDataFromRunConfiguration(RunConfiguration *runConfig); void copyDataFromRunControl(RunControl *runControl); void setRunRecipe(const QtTaskTree::Group &group); void initiateStart(); void initiateStop(); void forceStop(); bool promptToStop(bool *optionalPrompt = nullptr) const; void setPromptToStop(const std::function &promptToStop); QString displayName() const; void setDisplayName(const QString &displayName); bool isRunning() const; bool isStopped() const; void setIcon(const Utils::Icon &icon); Utils::Icon icon() const; Utils::ProcessHandle applicationProcessHandle() const; void setApplicationProcessHandle(const Utils::ProcessHandle &handle); IDeviceConstPtr device() const; // FIXME: Try to cut down to amount of functions. BuildConfiguration *buildConfiguration() const; Target *target() const; // FIXME: Eliminate callers and remove again. Project *project() const; Kit *kit() const; const Utils::MacroExpander *macroExpander() const; const Utils::BaseAspect::Data *aspectData(Utils::Id instanceId) const; const Utils::BaseAspect::Data *aspectData(Utils::BaseAspect::Data::ClassId classId) const; template const typename T::Data *aspectData() const { return dynamic_cast(aspectData(&T::staticMetaObject)); } QString buildKey() const; Utils::FilePath buildDirectory() const; Utils::Environment buildEnvironment() const; Utils::Store settingsData(Utils::Id id) const; Utils::FilePath targetFilePath() const; Utils::FilePath projectFilePath() const; void setupFormatter(Utils::OutputFormatter *formatter) const; Utils::Id runMode() const; bool isPrintEnvironmentEnabled() const; const Utils::ProcessRunData &runnable() const; const Utils::CommandLine &commandLine() const; void setCommandLine(const Utils::CommandLine &command); const Utils::FilePath &workingDirectory() const; void setWorkingDirectory(const Utils::FilePath &workingDirectory); const Utils::Environment &environment() const; void setEnvironment(const Utils::Environment &environment); const QVariantHash &extraData() const; void setExtraData(const QVariantHash &extraData); static bool showPromptToStopDialog(const QString &title, const QString &text, const QString &stopButtonText = QString(), const QString &cancelButtonText = QString(), bool *prompt = nullptr); static void provideAskPassEntry(Utils::Environment &env); QtTaskTree::Group createRecipe(Utils::Id runMode); bool createMainRecipe(); static bool canRun( Utils::Id runMode, Utils::Id deviceType, Utils::Id runConfigId, Utils::Id executionType); void postMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true); void requestDebugChannel(); bool usesDebugChannel() const; QUrl debugChannel() const; // FIXME: Don't use. Convert existing users to portsgatherer. void setDebugChannel(const QUrl &channel); void requestQmlChannel(); bool usesQmlChannel() const; QUrl qmlChannel() const; // FIXME: Don't use. Convert existing users to portsgatherer. void setQmlChannel(const QUrl &channel); void requestPerfChannel(); bool usesPerfChannel() const; QUrl perfChannel() const; void requestWorkerChannel(); QUrl workerChannel() const; void setAttachPid(Utils::ProcessHandle pid); Utils::ProcessHandle attachPid() const; void showOutputPane(); Canceler canceler(); void handleProcessCancellation(Utils::Process *process); signals: void appendMessage(const QString &msg, Utils::OutputFormat format); void aboutToStart(); void started(); void canceled(); void stopped(); void applicationProcessHandleChanged(QPrivateSignal); void stdOutData(const QByteArray &data); private: void setDevice(const IDeviceConstPtr &device); // Just a helper template > static constexpr bool isModifierInvocable() { // Note, that std::is_invocable_r_v doesn't check Result type properly. if constexpr (std::is_invocable_r_v) return std::is_same_v>; return false; } const std::unique_ptr d; }; class PROJECTEXPLORER_EXPORT ProcessRunnerFactory : public RunWorkerFactory { public: explicit ProcessRunnerFactory(const QList &runConfig); }; PROJECTEXPLORER_EXPORT void addOutputParserFactory(const std::function &); PROJECTEXPLORER_EXPORT void addOutputParserFactory(const std::function &); PROJECTEXPLORER_EXPORT QList createOutputParsers(BuildConfiguration *bc); #ifdef WITH_TESTS namespace Internal { QObject *createRunWorkerConflictTest(); } #endif } // namespace ProjectExplorer