diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 92eef226d81..e19c0ed8342 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -115,3 +115,5 @@ if (WITH_QMLDESIGNER) endif() add_subdirectory(qnx) add_subdirectory(mcusupport) +add_subdirectory(qtapplicationmanager) + diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs index 7277e1afbb1..4b7af74a302 100644 --- a/src/plugins/plugins.qbs +++ b/src/plugins/plugins.qbs @@ -92,5 +92,6 @@ Project { "vcsbase/vcsbase.qbs", "webassembly/webassembly.qbs", "welcome/welcome.qbs", + "qtapplicationmanager/qtapplicationmanager.qbs", ].concat(project.additionalPlugins) } diff --git a/src/plugins/qtapplicationmanager/CMakeLists.txt b/src/plugins/qtapplicationmanager/CMakeLists.txt new file mode 100644 index 00000000000..7a633604d9e --- /dev/null +++ b/src/plugins/qtapplicationmanager/CMakeLists.txt @@ -0,0 +1,22 @@ +find_package(Qt6 COMPONENTS Widgets REQUIRED) + +add_qtc_plugin(QtApplicationManagerIntegration + PLUGIN_DEPENDS + Core Debugger ProjectExplorer QmakeProjectManager + QtSupport RemoteLinux + DEPENDS Qt::Network Qt::Widgets ExtensionSystem Utils + SOURCES + appmanagerconstants.h + appmanagercreatepackagestep.cpp appmanagercreatepackagestep.h + appmanagerdeployconfigurationautoswitcher.cpp appmanagerdeployconfigurationautoswitcher.h + appmanagerdeployconfigurationfactory.cpp appmanagerdeployconfigurationfactory.h + appmanagerdeploypackagestep.cpp appmanagerdeploypackagestep.h + appmanagerinstallpackagestep.cpp appmanagerinstallpackagestep.h + appmanagermakeinstallstep.cpp appmanagermakeinstallstep.h + appmanagerplugin.cpp appmanagerplugin.h + appmanagerrunconfiguration.cpp appmanagerrunconfiguration.h + appmanagerruncontrol.cpp appmanagerruncontrol.h + appmanagerstringaspect.cpp appmanagerstringaspect.h + appmanagertargetinformation.cpp appmanagertargetinformation.h + appmanagerutilities.cpp appmanagerutilities.h +) diff --git a/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in b/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in new file mode 100644 index 00000000000..c2acbce12f4 --- /dev/null +++ b/src/plugins/qtapplicationmanager/QtApplicationManagerIntegration.json.in @@ -0,0 +1,32 @@ +{ + "Name" : "QtApplicationManagerIntegration", + "Version" : "${IDE_VERSION}", + "CompatVersion" : "${IDE_VERSION_COMPAT}", + "Experimental" : true, + "Revision" : "${QTC_PLUGIN_REVISION}", + "Vendor" : "The Qt Company Ltd", + "Copyright" : "(C) 2020 Luxoft Sweden AB, (C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd", + "License" : [ "Commercial Usage", + "", + "Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.", + "", + "GNU General Public License Usage", + "", + "Alternatively, this plugin 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 plugin. 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." + ], + "Category" : "Device Support", + "Description" : "Support for QtApplicationManager on a variety of different target plattforms.", + "Url" : "http://www.qt.io", + ${IDE_PLUGIN_DEPENDENCIES}, + + "Mimetypes" : [ + "", + "", + " ", + " ", + " QtApplicationManager project file", + " ", + " ", + "" + ] +} diff --git a/src/plugins/qtapplicationmanager/appmanagerconstants.h b/src/plugins/qtapplicationmanager/appmanagerconstants.h new file mode 100644 index 00000000000..524ea764ed9 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerconstants.h @@ -0,0 +1,31 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace AppManager { +namespace Constants { + +const char APPMAN[] = "appman"; +const char APPMAN_CONTROLLER[] = "appman-controller"; +const char APPMAN_PACKAGER[] = "appman-packager"; +const char APPMAN_LAUNCHER_QML[] = "appman-launcher-qml"; + +const char DEBUG_LAUNCHER_ID[] = "ApplicationManagerPlugin.Debug.Launcher"; +const char DEPLOYCONFIGURATION_ID[] = "ApplicationManagerPlugin.Deploy.Configuration"; +const char MAKE_INSTALL_STEP_ID[] = "ApplicationManagerPlugin.Deploy.MakeInstallStep"; +const char CREATE_PACKAGE_STEP_ID[] = "ApplicationManagerPlugin.Deploy.CreatePackageStep"; +const char DEPLOY_PACKAGE_STEP_ID[] = "ApplicationManagerPlugin.Deploy.DeployPackageStep"; +const char INSTALL_PACKAGE_STEP_ID[] = "ApplicationManagerPlugin.Deploy.InstallPackageStep"; +const char RUNCONFIGURATION_ID[] = "ApplicationManagerPlugin.Run.Configuration"; + +const char QMAKE_AM_MANIFEST_VARIABLE[] = "AM_MANIFEST"; +const char QMAKE_AM_PACKAGE_DIR_VARIABLE[] = "AM_PACKAGE_DIR"; + +const char REMOTE_DEFAULT_BIN_PATH[] = "/usr/bin"; +const char REMOTE_DEFAULT_TMP_PATH[] = "/tmp"; + +} // namespace Constants +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp new file mode 100644 index 00000000000..cc7e29d8425 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.cpp @@ -0,0 +1,128 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagercreatepackagestep.h" + +#include "appmanagerconstants.h" +#include "appmanagerstringaspect.h" +#include "appmanagertargetinformation.h" +#include "appmanagerutilities.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace AppManager { +namespace Internal { + +#define SETTINGSPREFIX "ApplicationManagerPlugin.Deploy.CreatePackageStep." + +const char ArgumentsDefault[] = "create-package --verbose --json"; + +class AppManagerCreatePackageStep final : public AbstractProcessStep +{ +public: + AppManagerCreatePackageStep(BuildStepList *bsl, Id id); + + bool init() final; + +private: + AppManagerFilePathAspect executable{this}; + AppManagerStringAspect arguments{this}; + AppManagerFilePathAspect sourceDirectory{this}; + AppManagerFilePathAspect buildDirectory{this}; + AppManagerStringAspect packageFileName{this}; +}; + +AppManagerCreatePackageStep::AppManagerCreatePackageStep(BuildStepList *bsl, Id id) + : AbstractProcessStep(bsl, id) +{ + setDisplayName(tr("Create Application Manager package")); + + executable.setSettingsKey(SETTINGSPREFIX "Executable"); + executable.setHistoryCompleter(SETTINGSPREFIX "Executable.History"); + executable.setExpectedKind(PathChooser::ExistingCommand); + executable.setLabelText(tr("Executable:")); + executable.setPromptDialogFilter(getToolNameByDevice(Constants::APPMAN_PACKAGER)); + + arguments.setSettingsKey(SETTINGSPREFIX "Arguments"); + arguments.setHistoryCompleter(SETTINGSPREFIX "Arguments.History"); + arguments.setDisplayStyle(StringAspect::LineEditDisplay); + arguments.setLabelText(tr("Arguments:")); + + sourceDirectory.setSettingsKey(SETTINGSPREFIX "SourceDirectory"); + sourceDirectory.setHistoryCompleter(SETTINGSPREFIX "SourceDirectory.History"); + sourceDirectory.setExpectedKind(PathChooser::Directory); + sourceDirectory.setLabelText(tr("Source directory:")); + + buildDirectory.setSettingsKey(SETTINGSPREFIX "BuildDirectory"); + buildDirectory.setHistoryCompleter(SETTINGSPREFIX "BuildDirectory.History"); + buildDirectory.setExpectedKind(PathChooser::Directory); + buildDirectory.setLabelText(tr("Build directory:")); + + packageFileName.setSettingsKey(SETTINGSPREFIX "FileName"); + packageFileName.setHistoryCompleter(SETTINGSPREFIX "FileName.History"); + packageFileName.setDisplayStyle(StringAspect::LineEditDisplay); + packageFileName.setLabelText(tr("Package file name:")); + + const auto updateAspects = [this] { + const auto targetInformation = TargetInformation(target()); + + executable.setPlaceHolderPath(getToolFilePath(Constants::APPMAN_PACKAGER, target()->kit(), nullptr)); + arguments.setPlaceHolderText(ArgumentsDefault); + sourceDirectory.setPlaceHolderPath(targetInformation.packageSourcesDirectory.absolutePath()); + buildDirectory.setPlaceHolderPath(targetInformation.buildDirectory.absolutePath()); + packageFileName.setPlaceHolderText(targetInformation.packageFile.fileName()); + }; + + connect(target(), &Target::activeRunConfigurationChanged, this, updateAspects); + connect(target(), &Target::activeDeployConfigurationChanged, this, updateAspects); + connect(target(), &Target::parsingFinished, this, updateAspects); + connect(project(), &Project::displayNameChanged, this, updateAspects); + updateAspects(); +} + +bool AppManagerCreatePackageStep::init() +{ + if (!AbstractProcessStep::init()) + return false; + + const auto targetInformation = TargetInformation(target()); + if (!targetInformation.isValid()) + return false; + + const FilePath packager = executable.valueOrDefault(getToolFilePath(Constants::APPMAN_PACKAGER, target()->kit(), nullptr)); + const QString packagerArguments = arguments.valueOrDefault(ArgumentsDefault); + const FilePath packageSourcesDirectory = sourceDirectory.valueOrDefault(targetInformation.packageSourcesDirectory.absolutePath()); + const FilePath packageDirectory = buildDirectory.valueOrDefault(targetInformation.buildDirectory.absolutePath()); + const QString packageFile = packageFileName.valueOrDefault(targetInformation.packageFile.fileName()); + + CommandLine cmd(packager); + cmd.addArgs(packagerArguments, CommandLine::Raw); + cmd.addArgs({packageFile, packageSourcesDirectory.path()}); + processParameters()->setWorkingDirectory(packageDirectory); + processParameters()->setCommandLine(cmd); + + return true; +} + +// Factory + +AppManagerCreatePackageStepFactory::AppManagerCreatePackageStepFactory() +{ + registerStep(Constants::DEPLOY_PACKAGE_STEP_ID); + setDisplayName(AppManagerCreatePackageStep::tr("Create Application Manager package")); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.h b/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.h new file mode 100644 index 00000000000..5c4aedafad9 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagercreatepackagestep.h @@ -0,0 +1,20 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager { +namespace Internal { + +class AppManagerCreatePackageStepFactory final : public ProjectExplorer::BuildStepFactory +{ +public: + AppManagerCreatePackageStepFactory(); +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationautoswitcher.cpp b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationautoswitcher.cpp new file mode 100644 index 00000000000..36ca9bf15ec --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationautoswitcher.cpp @@ -0,0 +1,150 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerdeployconfigurationautoswitcher.h" + +#include "appmanagerconstants.h" + +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; + +namespace AppManager { +namespace Internal { + +class AppManagerDeployConfigurationAutoSwitcherPrivate +{ +public: + Project *project = nullptr; + Target *target = nullptr; + RunConfiguration *runConfiguration = nullptr; + DeployConfiguration *deployConfiguration = nullptr; + QHash deployConfigurationsUsageHistory; +}; + +AppManagerDeployConfigurationAutoSwitcher::AppManagerDeployConfigurationAutoSwitcher(QObject *parent) + : QObject(parent) + , d(new AppManagerDeployConfigurationAutoSwitcherPrivate()) +{ +} + +AppManagerDeployConfigurationAutoSwitcher::~AppManagerDeployConfigurationAutoSwitcher() = default; + +void AppManagerDeployConfigurationAutoSwitcher::onActiveDeployConfigurationChanged(DeployConfiguration *deployConfiguration) +{ + if (d->deployConfiguration != deployConfiguration) { + d->deployConfiguration = deployConfiguration; + if (deployConfiguration && deployConfiguration->target()) { + if (auto runConfiguration = deployConfiguration->target()->activeRunConfiguration()) { + d->deployConfigurationsUsageHistory.insert(runConfiguration, deployConfiguration); + } + } + } +} + +static bool isApplicationManagerRunConfiguration(const RunConfiguration *runConfiguration) +{ + return runConfiguration && runConfiguration->id() == Constants::RUNCONFIGURATION_ID; +} + +static bool isApplicationManagerDeployConfiguration(const DeployConfiguration *deployConfiguration) +{ + return deployConfiguration && deployConfiguration->id() == Constants::DEPLOYCONFIGURATION_ID; +} + +void AppManagerDeployConfigurationAutoSwitcher::onActiveRunConfigurationChanged(RunConfiguration *runConfiguration) +{ + if (d->runConfiguration != runConfiguration) { + d->runConfiguration = runConfiguration; + if (runConfiguration) { + if (auto target = runConfiguration->target()) { + const auto stored = d->deployConfigurationsUsageHistory.contains(runConfiguration); + if (stored) { + // deploy selection stored -> restore + auto deployConfiguration = d->deployConfigurationsUsageHistory.value(runConfiguration, nullptr); + target->setActiveDeployConfiguration(deployConfiguration, SetActive::NoCascade); + } else if (auto activeDeployConfiguration = target->activeDeployConfiguration()) { + // active deploy configuration exists + if (isApplicationManagerRunConfiguration(runConfiguration)) { + // current run configuration is AM + if (!isApplicationManagerDeployConfiguration(activeDeployConfiguration)) { + // current deploy configuration is not AM + for (auto deployConfiguration : target->deployConfigurations()) { + // find AM deploy configuration + if (isApplicationManagerDeployConfiguration(deployConfiguration)) { + // make it active + target->setActiveDeployConfiguration(deployConfiguration, SetActive::NoCascade); + break; + } + } + } + } else { + // current run configuration is not AM + if (isApplicationManagerDeployConfiguration(activeDeployConfiguration)) { + // current deploy configuration is AM + for (auto deployConfiguration : target->deployConfigurations()) { + // find not AM deploy configuration + if (!isApplicationManagerDeployConfiguration(deployConfiguration)) { + // make it active + target->setActiveDeployConfiguration(deployConfiguration, SetActive::NoCascade); + break; + } + } + } + } + } + } + } + } +} + +void AppManagerDeployConfigurationAutoSwitcher::onActiveTargetChanged(Target *target) +{ + if (d->target != target) { + if (d->target) { + disconnect(d->target, nullptr, this, nullptr); + } + d->target = target; + if (target) { + connect(target, &Target::activeRunConfigurationChanged, + this, &AppManagerDeployConfigurationAutoSwitcher::onActiveRunConfigurationChanged); + connect(target, &Target::activeDeployConfigurationChanged, + this, &AppManagerDeployConfigurationAutoSwitcher::onActiveDeployConfigurationChanged); + } + onActiveRunConfigurationChanged(target ? target->activeRunConfiguration() : nullptr); + onActiveDeployConfigurationChanged(target ? target->activeDeployConfiguration() : nullptr); + } +} + +void AppManagerDeployConfigurationAutoSwitcher::onStartupProjectChanged(Project *project) +{ + if (d->project != project) { + if (d->project) { + disconnect(d->project, nullptr, this, nullptr); + } + d->project = project; + if (project) { + connect(project, &Project::activeTargetChanged, + this, &AppManagerDeployConfigurationAutoSwitcher::onActiveTargetChanged); + } + onActiveTargetChanged(project ? project->activeTarget() : nullptr); + } +} + +void AppManagerDeployConfigurationAutoSwitcher::initialize() +{ + if (auto projectManager = ProjectManager::instance()) { + connect(projectManager, &ProjectManager::startupProjectChanged, + this, &AppManagerDeployConfigurationAutoSwitcher::onStartupProjectChanged, Qt::UniqueConnection); + onStartupProjectChanged(projectManager->startupProject()); + } +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationautoswitcher.h b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationautoswitcher.h new file mode 100644 index 00000000000..021ef783c1b --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationautoswitcher.h @@ -0,0 +1,36 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace AppManager { +namespace Internal { + +class AppManagerDeployConfigurationAutoSwitcherPrivate; + +class AppManagerDeployConfigurationAutoSwitcher : public QObject +{ + Q_OBJECT + + QScopedPointer d; + +public: + AppManagerDeployConfigurationAutoSwitcher(QObject *parent = nullptr); + ~AppManagerDeployConfigurationAutoSwitcher() override; + + void initialize(); + +private: + void onActiveDeployConfigurationChanged(ProjectExplorer::DeployConfiguration *dc); + void onActiveRunConfigurationChanged(ProjectExplorer::RunConfiguration *rc); + void onActiveTargetChanged(ProjectExplorer::Target *target); + void onStartupProjectChanged(ProjectExplorer::Project *project); +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp new file mode 100644 index 00000000000..13bcfe7f642 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerdeployconfigurationfactory.h" + +#include "appmanagerconstants.h" + +#include +#include +#include +#include + +#include + +using namespace ProjectExplorer; + +namespace AppManager { +namespace Internal { + +static bool isNecessaryToDeploy(const Target *target) +{ + auto device = DeviceKitAspect::device(target->kit()); + return device && device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; +} + +AppManagerDeployConfigurationFactory::AppManagerDeployConfigurationFactory() +{ + setConfigBaseId(Constants::DEPLOYCONFIGURATION_ID); + setDefaultDisplayName(QCoreApplication::translate("AppManager", "Deploy to AM Device")); + addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); + addSupportedTargetDeviceType(RemoteLinux::Constants::GenericLinuxOsType); + addInitialStep(Constants::MAKE_INSTALL_STEP_ID); + addInitialStep(Constants::CREATE_PACKAGE_STEP_ID); + addInitialStep(Constants::DEPLOY_PACKAGE_STEP_ID, isNecessaryToDeploy); + addInitialStep(Constants::INSTALL_PACKAGE_STEP_ID); +} + +} // namespace Internal +} // namespace AppManager + diff --git a/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.h b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.h new file mode 100644 index 00000000000..f7ac6f4e50f --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerdeployconfigurationfactory.h @@ -0,0 +1,20 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager { +namespace Internal { + +class AppManagerDeployConfigurationFactory : public ProjectExplorer::DeployConfigurationFactory +{ +public: + AppManagerDeployConfigurationFactory(); +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp new file mode 100644 index 00000000000..1085a7e4d44 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerdeploypackagestep.h" + +#include "appmanagerconstants.h" +#include "appmanagerstringaspect.h" +#include "appmanagertargetinformation.h" + +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ProjectExplorer; +using namespace RemoteLinux; +using namespace Tasking; +using namespace Utils; + +namespace AppManager::Internal { + +#define SETTINGSPREFIX "ApplicationManagerPlugin.Deploy.DeployPackageStep." + +class AppManagerDeployPackageStep : public BuildStep +{ + Q_DECLARE_TR_FUNCTIONS(AppManager::Internal::AppManagerDeployPackageStep) + +public: + AppManagerDeployPackageStep(BuildStepList *bsl, Id id) + : BuildStep(bsl, id) + { + setDisplayName(tr("Deploy Application Manager package")); + + packageFilePath.setSettingsKey(SETTINGSPREFIX "FilePath"); + packageFilePath.setHistoryCompleter(SETTINGSPREFIX "FilePath.History"); + packageFilePath.setExpectedKind(PathChooser::File); + packageFilePath.setLabelText(tr("Package file path:")); + + targetDirectory.setSettingsKey(SETTINGSPREFIX "TargetDirectory"); + targetDirectory.setHistoryCompleter(SETTINGSPREFIX "TargetDirectory.History"); + targetDirectory.setExpectedKind(PathChooser::Directory); + targetDirectory.setLabelText(tr("Target directory:")); + targetDirectory.setButtonsVisible(false); + + const auto updateAspects = [this] { + const auto targetInformation = TargetInformation(target()); + + packageFilePath.setPlaceHolderPath(targetInformation.packageFile.absoluteFilePath()); + targetDirectory.setPlaceHolderPath(targetInformation.runDirectory.absolutePath()); + }; + + connect(target(), &Target::activeRunConfigurationChanged, this, updateAspects); + connect(target(), &Target::activeDeployConfigurationChanged, this, updateAspects); + connect(target(), &Target::parsingFinished, this, updateAspects); + connect(project(), &Project::displayNameChanged, this, updateAspects); + + updateAspects(); + } + +private: + bool init() final { return TargetInformation(target()).isValid(); } + GroupItem runRecipe() final { + const auto onSetup = [this](FileStreamer &streamer) { + const TargetInformation targetInformation(target()); + const FilePath source = packageFilePath.valueOrDefault( + targetInformation.packageFile.absoluteFilePath()); + const FilePath targetDir = targetDirectory.valueOrDefault( + targetInformation.runDirectory.absolutePath()); + const FilePath target = targetInformation.device->filePath(targetDir.path()) + .pathAppended(source.fileName()); + streamer.setSource(source); + streamer.setDestination(target); + emit addOutput("Starting uploading", OutputFormat::NormalMessage); + }; + const auto onDone = [this](DoneWith result) { + if (result == DoneWith::Success) + emit addOutput(tr("Uploading finished"), OutputFormat::NormalMessage); + else + emit addOutput(tr("Uploading failed"), OutputFormat::ErrorMessage); + }; + return FileStreamerTask(onSetup, onDone); + } + + AppManagerFilePathAspect packageFilePath{this}; + AppManagerFilePathAspect targetDirectory{this}; +}; + +// Factory + +AppManagerDeployPackageStepFactory::AppManagerDeployPackageStepFactory() +{ + registerStep(Constants::DEPLOY_PACKAGE_STEP_ID); + setDisplayName(AppManagerDeployPackageStep::tr("Deploy Application Manager package")); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); +} + +} // namespace AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.h b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.h new file mode 100644 index 00000000000..63d0e23e199 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerdeploypackagestep.h @@ -0,0 +1,18 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager::Internal { + +class AppManagerDeployPackageStepFactory final : public ProjectExplorer::BuildStepFactory +{ +public: + AppManagerDeployPackageStepFactory(); +}; + +} // namespace AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp new file mode 100644 index 00000000000..3ea509ebf28 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.cpp @@ -0,0 +1,121 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerinstallpackagestep.h" + +#include "appmanagerstringaspect.h" +#include "appmanagerconstants.h" +#include "appmanagertargetinformation.h" +#include "appmanagerutilities.h" + +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace AppManager::Internal { + +#define SETTINGSPREFIX "ApplicationManagerPlugin.Deploy.InstallPackageStep." + +const char ArgumentsDefault[] = "install-package -a"; + +class AppManagerInstallPackageStep final : public AbstractProcessStep +{ + Q_DECLARE_TR_FUNCTIONS(AppManager::Internal::AppManagerInstallPackageStep) + +public: + AppManagerInstallPackageStep(BuildStepList *bsl, Id id); + +protected: + bool init() final; + +private: + AppManagerFilePathAspect executable{this}; + AppManagerStringAspect arguments{this}; + AppManagerStringAspect packageFileName{this}; + AppManagerFilePathAspect packageDirectory{this}; +}; + +AppManagerInstallPackageStep::AppManagerInstallPackageStep(BuildStepList *bsl, Id id) + : AbstractProcessStep(bsl, id) +{ + setDisplayName(tr("Install Application Manager package")); + + executable.setSettingsKey(SETTINGSPREFIX "Executable"); + executable.setHistoryCompleter(SETTINGSPREFIX "Executable.History"); + executable.setLabelText(tr("Executable:")); + + arguments.setSettingsKey(SETTINGSPREFIX "Arguments"); + arguments.setHistoryCompleter(SETTINGSPREFIX "Arguments.History"); + arguments.setDisplayStyle(StringAspect::LineEditDisplay); + arguments.setLabelText(tr("Arguments:")); + + packageFileName.setSettingsKey(SETTINGSPREFIX "FileName"); + packageFileName.setHistoryCompleter(SETTINGSPREFIX "FileName.History"); + packageFileName.setDisplayStyle(StringAspect::LineEditDisplay); + packageFileName.setLabelText(tr("File name:")); + + packageDirectory.setSettingsKey(SETTINGSPREFIX "Directory"); + packageDirectory.setHistoryCompleter(SETTINGSPREFIX "Directory.History"); + packageDirectory.setExpectedKind(PathChooser::Directory); + packageDirectory.setLabelText(tr("Directory:")); + + const auto updateAspects = [this] { + const TargetInformation targetInformation(target()); + + executable.setPromptDialogFilter(getToolNameByDevice(Constants::APPMAN_CONTROLLER, targetInformation.device)); + executable.setButtonsVisible(!targetInformation.remote); + executable.setExpectedKind(targetInformation.remote ? PathChooser::Command : PathChooser::ExistingCommand); + executable.setPlaceHolderPath(getToolFilePath(Constants::APPMAN_CONTROLLER, target()->kit(), targetInformation.device)); + arguments.setPlaceHolderText(ArgumentsDefault); + packageFileName.setPlaceHolderText(targetInformation.packageFile.fileName()); + packageDirectory.setPlaceHolderPath(targetInformation.runDirectory.absolutePath()); + packageDirectory.setButtonsVisible(!targetInformation.remote); + }; + + connect(target(), &Target::activeRunConfigurationChanged, this, updateAspects); + connect(target(), &Target::activeDeployConfigurationChanged, this, updateAspects); + connect(target(), &Target::parsingFinished, this, updateAspects); + connect(project(), &Project::displayNameChanged, this, updateAspects); + updateAspects(); +} + +bool AppManagerInstallPackageStep::init() +{ + if (!AbstractProcessStep::init()) + return false; + + const TargetInformation targetInformation(target()); + if (!targetInformation.isValid()) + return false; + + const FilePath controller = executable.valueOrDefault(getToolFilePath(Constants::APPMAN_CONTROLLER, target()->kit(), targetInformation.device)); + const QString controllerArguments = arguments.valueOrDefault(ArgumentsDefault); + const QString packageFile = packageFileName.valueOrDefault(targetInformation.packageFile.fileName()); + const FilePath packageDir = packageDirectory.valueOrDefault(targetInformation.runDirectory.absolutePath()); + + CommandLine cmd(targetInformation.device->filePath(controller.path())); + cmd.addArgs(controllerArguments, CommandLine::Raw); + cmd.addArg(packageFile); + processParameters()->setWorkingDirectory(packageDir); + processParameters()->setCommandLine(cmd); + + return true; +} + +// Factory + +AppManagerInstallPackageStepFactory::AppManagerInstallPackageStepFactory() +{ + registerStep(Constants::INSTALL_PACKAGE_STEP_ID); + setDisplayName(AppManagerInstallPackageStep::tr("Install Application Manager package")); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); +} + +} // namespace AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.h b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.h new file mode 100644 index 00000000000..775b1195cfb --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerinstallpackagestep.h @@ -0,0 +1,18 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager::Internal { + +class AppManagerInstallPackageStepFactory final : public ProjectExplorer::BuildStepFactory +{ +public: + AppManagerInstallPackageStepFactory(); +}; + +} // namespace AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagermakeinstallstep.cpp b/src/plugins/qtapplicationmanager/appmanagermakeinstallstep.cpp new file mode 100644 index 00000000000..680fa4aa118 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagermakeinstallstep.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagermakeinstallstep.h" + +#include "appmanagerconstants.h" +#include "appmanagertargetinformation.h" + +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace AppManager { +namespace Internal { + +class AppManagerMakeInstallStep final : public ProjectExplorer::MakeStep +{ + Q_DECLARE_TR_FUNCTIONS(AppManager::Internal::AppManagerMakeInstallStep) + +public: + AppManagerMakeInstallStep(BuildStepList *bsl, Utils::Id id) + : MakeStep(bsl, id) + { + setSelectedBuildTarget("install"); + } + + bool init() final + { + if (!MakeStep::init()) + return false; + + const auto targetInformation = TargetInformation(target()); + if (!targetInformation.isValid()) + return false; + + const auto buildDirectoryPath = targetInformation.buildDirectory.absolutePath(); + if (buildDirectoryPath.isEmpty()) + return false; + + const auto buildDirectoryPathQuoted = ProcessArgs::quoteArg(QDir::toNativeSeparators(buildDirectoryPath)); + const auto installRoot = QString("INSTALL_ROOT=%1").arg(buildDirectoryPathQuoted); + + processParameters()->setWorkingDirectory(FilePath::fromString(buildDirectoryPath)); + + CommandLine cmd = processParameters()->command(); + cmd.addArg(installRoot); + processParameters()->setCommandLine(cmd); + + return true; + } +}; + +// Factory + +AppManagerMakeInstallStepFactory::AppManagerMakeInstallStepFactory() +{ + registerStep(Constants::MAKE_INSTALL_STEP_ID); + setDisplayName(AppManagerMakeInstallStep::tr("Make install")); + setSupportedStepList(ProjectExplorer::Constants::BUILDSTEPS_DEPLOY); +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagermakeinstallstep.h b/src/plugins/qtapplicationmanager/appmanagermakeinstallstep.h new file mode 100644 index 00000000000..f984b8f5ca7 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagermakeinstallstep.h @@ -0,0 +1,20 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager { +namespace Internal { + +class AppManagerMakeInstallStepFactory final : public ProjectExplorer::BuildStepFactory +{ +public: + AppManagerMakeInstallStepFactory(); +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerplugin.cpp b/src/plugins/qtapplicationmanager/appmanagerplugin.cpp new file mode 100644 index 00000000000..ca074712b5f --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerplugin.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerplugin.h" + +#include "appmanagerconstants.h" +#include "appmanagercreatepackagestep.h" +#include "appmanagerdeployconfigurationautoswitcher.h" +#include "appmanagerdeployconfigurationfactory.h" +#include "appmanagerdeploypackagestep.h" +#include "appmanagerinstallpackagestep.h" +#include "appmanagermakeinstallstep.h" +#include "appmanagerrunconfiguration.h" +#include "appmanagerruncontrol.h" +#include "appmanagerutilities.h" + +#include + +#include +#include + +#include + +#include + +using namespace Core; +using namespace ProjectExplorer; +using namespace QtSupport; + +namespace AppManager::Internal { + +const char QdbLinuxOsType[] = "QdbLinuxOsType"; +const char QdbLinuxEmulatorOsType[] = "QdbLinuxEmulatorOsType"; + +void cloneAutodetectedBoot2QtKits() +{ + if (auto kitManager = KitManager::instance()) { + QHash boot2QtKits; + QHash genericLinuxDeviceKits; + for (auto kit : kitManager->kits()) { + if (auto qtVersion = QtKitAspect::qtVersion(kit)) { + const auto deviceTypeId = DeviceTypeKitAspect::deviceTypeId(kit); + if (deviceTypeId == RemoteLinux::Constants::GenericLinuxOsType) { + genericLinuxDeviceKits[qtVersion] = kit; + } else if (kit->isAutoDetected()) { + if (deviceTypeId == QdbLinuxOsType) { + boot2QtKits[qtVersion] = kit; + } else if (deviceTypeId == QdbLinuxEmulatorOsType) { + boot2QtKits[qtVersion] = kit; + } + } + } + } + for (auto qtVersion : boot2QtKits.keys()) { + if (!genericLinuxDeviceKits.contains(qtVersion)) { + const auto boot2QtKit = boot2QtKits.value(qtVersion); + const auto copyIntoKit = [boot2QtKit](Kit *k) { + k->copyFrom(boot2QtKit); + k->setAutoDetected(false); + k->setUnexpandedDisplayName(QString("%1 for Generic Linux Devices").arg(boot2QtKit->unexpandedDisplayName())); + DeviceTypeKitAspect::setDeviceTypeId(k, RemoteLinux::Constants::GenericLinuxOsType); + }; + if (auto genericLinuxDeviceKit = KitManager::instance()->registerKit(copyIntoKit)) { + genericLinuxDeviceKit->setup(); + } + } + } + } +} + +class AppManagerPluginPrivate +{ +public: + AppManagerMakeInstallStepFactory makeInstallStepFactory; + AppManagerCreatePackageStepFactory createPackageStepFactory; + AppManagerDeployPackageStepFactory deployPackageStepFactory; + AppManagerInstallPackageStepFactory installPackageStepFactory; + + AppManagerDeployConfigurationAutoSwitcher deployConfigurationAutoSwitcher; + AppManagerDeployConfigurationFactory deployConfigFactory; + + AppManagerRunConfigurationFactory runConfigFactory; + AppManagerDebugWorkerFactory debugWorkerFactory; + AppManagerRunWorkerFactory runWorkerFactory; +}; + +AppManagerPlugin::~AppManagerPlugin() +{ + delete d; +} + +void AppManagerPlugin::initialize() +{ + d = new AppManagerPluginPrivate; + d->deployConfigurationAutoSwitcher.initialize(); + + if (auto kitManager = KitManager::instance()) { + connect(kitManager, &KitManager::kitsLoaded, &cloneAutodetectedBoot2QtKits); + } +} + +} // AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerplugin.h b/src/plugins/qtapplicationmanager/appmanagerplugin.h new file mode 100644 index 00000000000..ca95268b900 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerplugin.h @@ -0,0 +1,26 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager::Internal { + +class AppManagerPlugin final : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "QtApplicationManagerIntegration.json") + +public: + ~AppManagerPlugin() final; + +private: + void initialize() final; + + class AppManagerPluginPrivate *d = nullptr; +}; + +} // AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp new file mode 100644 index 00000000000..4bd7581bfc3 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerrunconfiguration.h" + +#include "appmanagerconstants.h" +#include "appmanagertargetinformation.h" + +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace AppManager { +namespace Internal { + +AppManagerRunConfiguration::AppManagerRunConfiguration(Target *target, Id id) + : RunConfiguration(target, id) +{ + setDefaultDisplayName(tr("Run on AM Device")); +} + +QString AppManagerRunConfiguration::disabledReason() const +{ + if (activeBuildSystem()->isParsing()) + return tr("The project file \"%1\" is currently being parsed.").arg(project()->projectFilePath().toString()); + return QString(); +} + +class AppManagerRunConfigurationFactoryPrivate +{ +public: + FileSystemWatcher fileSystemWatcher; +}; + +AppManagerRunConfigurationFactory::AppManagerRunConfigurationFactory() + : RunConfigurationFactory() + , d(new AppManagerRunConfigurationFactoryPrivate()) +{ + registerRunConfiguration(Constants::RUNCONFIGURATION_ID); + addSupportedTargetDeviceType(ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE); + addSupportedTargetDeviceType(RemoteLinux::Constants::GenericLinuxOsType); +} + +AppManagerRunConfigurationFactory::~AppManagerRunConfigurationFactory() = default; + +QList AppManagerRunConfigurationFactory::availableCreators(Target *target) const +{ + QObject::connect(&d->fileSystemWatcher, &FileSystemWatcher::fileChanged, target->project(), &Project::displayNameChanged, Qt::UniqueConnection); + + const auto buildTargets = TargetInformation::readFromProject(target); + const auto result = Utils::transform(buildTargets, [this](const TargetInformation &ti) { + RunConfigurationCreationInfo rci; + rci.factory = this; + rci.buildKey = ti.buildKey; + rci.displayName = ti.displayName; + rci.displayNameUniquifier = ti.displayNameUniquifier; + rci.creationMode = RunConfigurationCreationInfo::AlwaysCreate; + rci.useTerminal = false; + if (!this->d->fileSystemWatcher.files().contains(ti.manifest.fileName)) { + this->d->fileSystemWatcher.addFile(ti.manifest.fileName, Utils::FileSystemWatcher::WatchAllChanges); + } + return rci; + }); + return result; +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.h b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.h new file mode 100644 index 00000000000..4cee68841ad --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerrunconfiguration.h @@ -0,0 +1,38 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager { +namespace Internal { + +class AppManagerRunConfiguration : public ProjectExplorer::RunConfiguration +{ + Q_OBJECT + +public: + AppManagerRunConfiguration(ProjectExplorer::Target *target, Utils::Id id); + + QString disabledReason() const override; +}; + +class AppManagerRunConfigurationFactoryPrivate; + +class AppManagerRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory +{ + QScopedPointer d; + +public: + AppManagerRunConfigurationFactory(); + ~AppManagerRunConfigurationFactory() override; + +protected: + QList availableCreators(ProjectExplorer::Target *parent) const override; +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp new file mode 100644 index 00000000000..307e254b257 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp @@ -0,0 +1,213 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerruncontrol.h" + +#include "appmanagerconstants.h" +#include "appmanagertargetinformation.h" +#include "appmanagerutilities.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace AppManager::Internal { + +// AppManagerRunner + +class AppManagerRunner : public SimpleTargetRunner +{ +public: + AppManagerRunner(RunControl *runControl) + : SimpleTargetRunner(runControl) + { + setId("ApplicationManagerPlugin.Run.TargetRunner"); + connect(this, &RunWorker::stopped, this, [this, runControl] { + appendMessage(tr("%1 exited").arg(runControl->runnable().command.toUserOutput()), + OutputFormat::NormalMessageFormat); + }); + + setStartModifier([this, runControl] { + const auto targetInformation = TargetInformation(runControl->target()); + if (!targetInformation.isValid()) + return; + + setWorkingDirectory(targetInformation.workingDirectory()); + setCommandLine({FilePath::fromString(getToolFilePath(Constants::APPMAN_CONTROLLER, runControl->kit(), + targetInformation.device)), + {"start-application", "-eio", targetInformation.manifest.id}}); + }); + } +}; + + +// AppManDebugLauncher + +class AppManDebugLauncher : public SimpleTargetRunner +{ +public: + AppManDebugLauncher(RunControl *runControl, Debugger::DebugServerPortsGatherer *portsGatherer) + : SimpleTargetRunner(runControl) + { + setId(AppManager::Constants::DEBUG_LAUNCHER_ID); + QTC_ASSERT(portsGatherer, return); + + setStartModifier([this, runControl, portsGatherer] { + + const auto targetInformation = TargetInformation(runControl->target()); + if (!targetInformation.isValid()) { + reportFailure(); + return; + } + + CommandLine cmd{FilePath::fromString(getToolFilePath(Constants::APPMAN_CONTROLLER, + runControl->kit(), + targetInformation.device))}; + cmd.addArg("debug-application"); + + if (portsGatherer->useGdbServer() || portsGatherer->useQmlServer()) { + QStringList debugArgs; + if (portsGatherer->useGdbServer()) { + debugArgs.append(QString("gdbserver :%1").arg(portsGatherer->gdbServer().port())); + } + if (portsGatherer->useQmlServer()) { + debugArgs.append(QString("%program% -qmljsdebugger=port:%1,block %arguments%") + .arg(portsGatherer->qmlServer().port())); + } + cmd.addArg(debugArgs.join(' ')); + } + + cmd.addArg("-eio"); + cmd.addArg(targetInformation.manifest.id); + + setCommandLine(cmd); + setWorkingDirectory(targetInformation.workingDirectory()); + + appendMessage(tr("Starting AppMan Debugging..."), NormalMessageFormat); + appendMessage(tr("Using: %1").arg(cmd.toUserOutput()), NormalMessageFormat); + }); + } +}; + + +// AppManagerDebugSupport + +class AppManagerDebugSupport : public Debugger::DebuggerRunTool +{ +public: + AppManagerDebugSupport(RunControl *runControl) + : DebuggerRunTool(runControl) + { + setId("ApplicationManagerPlugin.Debug.Support"); + + setUsePortsGatherer(isCppDebugging(), isQmlDebugging()); + + auto apmDebugLauncher = new Internal::AppManDebugLauncher(runControl, portsGatherer()); + apmDebugLauncher->addStartDependency(portsGatherer()); + + addStartDependency(apmDebugLauncher); + + Target *target = runControl->target(); + + const Internal::TargetInformation targetInformation(target); + if (!targetInformation.isValid()) + return; + + if (targetInformation.manifest.isQmlRuntime()) { + const Utils::FilePath dir = SysRootKitAspect::sysRoot(target->kit()); + // TODO: get real aspect from deploy configuration + QString amfolder = Constants::REMOTE_DEFAULT_BIN_PATH; + m_symbolFile = dir.toString() + amfolder + Constants::APPMAN_LAUNCHER_QML; + } else if (targetInformation.manifest.isNativeRuntime()) { + m_symbolFile = Utils::findOrDefault(target->buildSystem()->applicationTargets(), [&](const BuildTargetInfo &ti) { + return ti.buildKey == targetInformation.manifest.code || ti.projectFilePath.toString() == targetInformation.manifest.code; + }).targetFilePath.toString(); + } else { + reportFailure(tr("Cannot debug: Could not determine appman runtime.")); + } + } + +private: + void start() override; + + QString m_symbolFile; +}; + +void AppManagerDebugSupport::start() +{ + if (m_symbolFile.isEmpty()) { + reportFailure(tr("Cannot debug: Local executable is not set.")); + return; + } + + setStartMode(Debugger::AttachToRemoteServer); + setCloseMode(Debugger::KillAndExitMonitorAtClose); + + ProcessRunData inferior = runControl()->runnable(); + + if (isQmlDebugging()) + setQmlServer(portsGatherer()->qmlServer()); + + if (isCppDebugging()) { + setUseExtendedRemote(false); + setUseContinueInsteadOfRun(true); + inferior.command.setArguments({}); + if (isQmlDebugging()) { + inferior.command.addArg(QmlDebug::qmlDebugTcpArguments(QmlDebug::QmlDebuggerServices, + portsGatherer()->qmlServer())); + } + setRemoteChannel(portsGatherer()->gdbServer()); + setSymbolFile(FilePath::fromString(m_symbolFile)); + + QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(runControl()->kit()); + if (version) { + setSolibSearchPath(version->qtSoPaths()); + addSearchDirectory(version->qmlPath()); + } + + setSysRoot(SysRootKitAspect().sysRoot(runControl()->kit())); + } + setInferior(inferior); + + DebuggerRunTool::start(); +} + +// Factories + +AppManagerDebugWorkerFactory::AppManagerDebugWorkerFactory() +{ + setProduct(); + addSupportedRunMode(ProjectExplorer::Constants::DEBUG_RUN_MODE); + addSupportedRunConfig(Constants::RUNCONFIGURATION_ID); +} + +AppManagerRunWorkerFactory::AppManagerRunWorkerFactory() +{ + setProduct(); + addSupportedRunMode(ProjectExplorer::Constants::NORMAL_RUN_MODE); + addSupportedRunConfig(Constants::RUNCONFIGURATION_ID); +} + +} // AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.h b/src/plugins/qtapplicationmanager/appmanagerruncontrol.h new file mode 100644 index 00000000000..30d73cfe986 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.h @@ -0,0 +1,26 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager { +namespace Internal { + +class AppManagerRunWorkerFactory : public ProjectExplorer::RunWorkerFactory +{ +public: + AppManagerRunWorkerFactory(); +}; + +class AppManagerDebugWorkerFactory : public ProjectExplorer::RunWorkerFactory +{ +public: + AppManagerDebugWorkerFactory(); +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp b/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp new file mode 100644 index 00000000000..71d09e02068 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerstringaspect.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerstringaspect.h" + +#include +#include + +#include +#include +#include + +using namespace Utils; + +namespace AppManager { +namespace Internal { + +AppManagerStringAspect::AppManagerStringAspect(AspectContainer *container) + : StringAspect(container) +{ +} + +QString AppManagerStringAspect::valueOrDefault(const QString &defaultValue) const +{ + return value().isEmpty() ? defaultValue : value(); +} + +// FilePath + +AppManagerFilePathAspect::AppManagerFilePathAspect(AspectContainer *container) + : FilePathAspect(container) +{ +} + +void AppManagerFilePathAspect::setButtonsVisible(bool visible) +{ + if (m_buttonsVisibile != visible) { + m_buttonsVisibile = visible; + updateWidgets(); + } +} + +void AppManagerFilePathAspect::setPlaceHolderPath(const QString &value) +{ + if (m_placeHolderPath != value) { + m_placeHolderPath = value; + updateWidgets(); + } +} + +void AppManagerFilePathAspect::setPromptDialogFilter(const QString &value) +{ + if (m_promptDialogFilter != value) { + m_promptDialogFilter = value; + updateWidgets(); + } +} + +void AppManagerFilePathAspect::addToLayout(Layouting::LayoutItem &parent) +{ + FilePathAspect::addToLayout(parent); + updateWidgets(); +} + +FilePath AppManagerFilePathAspect::valueOrDefault(const FilePath &defaultValue) const +{ + return operator()().isEmpty() ? defaultValue : operator()(); +} + +FilePath AppManagerFilePathAspect::valueOrDefault(const QString &defaultValue) const +{ + return operator()().isEmpty() ? FilePath::fromUserInput(defaultValue) : operator()(); +} + +static bool callValidationFunction(const FancyLineEdit::ValidationFunction &f, FancyLineEdit *lineEdit, QString *errorMessage) +{ + if (f.index() == 0) { + QString oldText = lineEdit->text(); + auto future = std::get<0>(f)(oldText); + future.waitForFinished(); + auto res = future.result(); + if (res) { + if (oldText != *res && lineEdit->text() == *res) + lineEdit->setText(*res); + return true; + } + + if (errorMessage) + *errorMessage = res.error(); + + return false; + } + return std::get<1>(f)(lineEdit, errorMessage); +} + +bool AppManagerFilePathAspect::validatePathWithPlaceHolder(FancyLineEdit *lineEdit, QString *errorMessage) const +{ + if (!lineEdit) + return false; + if (auto pathChooser = qobject_cast(lineEdit->parent())) { + if (lineEdit->text().isEmpty() && !lineEdit->placeholderText().isEmpty()) { + FancyLineEdit temporaryLineEdit; + temporaryLineEdit.setText(lineEdit->placeholderText()); + PathChooser temporaryPathChooser; + temporaryPathChooser.setExpectedKind(pathChooser->expectedKind()); + return callValidationFunction(temporaryPathChooser.defaultValidationFunction(), &temporaryLineEdit, errorMessage); + } + return callValidationFunction(pathChooser->defaultValidationFunction(), lineEdit, errorMessage); + } + return callValidationFunction(lineEdit->defaultValidationFunction(), lineEdit, errorMessage); +} + +void AppManagerFilePathAspect::updateWidgets() +{ + const auto pathChooser = this->pathChooser(); + if (!pathChooser) + return; + for (auto button : pathChooser->findChildren()) + button->setVisible(m_buttonsVisibile); + for (auto fancyLineEdit : pathChooser->findChildren()) + fancyLineEdit->setPlaceholderText(m_placeHolderPath); + QFileInfo initialBrowsePath(m_placeHolderPath); + while (!initialBrowsePath.path().isEmpty() && !initialBrowsePath.isDir()) + initialBrowsePath.setFile(initialBrowsePath.path()); + if (initialBrowsePath.isDir()) + pathChooser->setInitialBrowsePathBackup(FilePath::fromString(initialBrowsePath.absoluteFilePath())); + pathChooser->setPromptDialogFilter(m_promptDialogFilter); + pathChooser->setValidationFunction( + [&](FancyLineEdit *edit, QString *error) { return validatePathWithPlaceHolder(edit, error); }); +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerstringaspect.h b/src/plugins/qtapplicationmanager/appmanagerstringaspect.h new file mode 100644 index 00000000000..fef58a648fa --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerstringaspect.h @@ -0,0 +1,43 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace AppManager::Internal { + +class AppManagerStringAspect : public Utils::StringAspect +{ +public: + AppManagerStringAspect(Utils::AspectContainer *container); + + QString valueOrDefault(const QString &defaultValue) const; +}; + +class AppManagerFilePathAspect : public Utils::FilePathAspect +{ +public: + AppManagerFilePathAspect(Utils::AspectContainer *container); + + void setButtonsVisible(bool visible); + void setPlaceHolderPath(const QString &value); + void setPromptDialogFilter(const QString &value); + + void addToLayout(Layouting::LayoutItem &parent) override; + + Utils::FilePath valueOrDefault(const Utils::FilePath &defaultValue) const; + Utils::FilePath valueOrDefault(const QString &defaultValue) const; + +private: + bool validatePathWithPlaceHolder(Utils::FancyLineEdit *lineEdit, QString *errorMessage) const; + void updateWidgets(); + + QString m_placeHolderPath; + QString m_promptDialogFilter; + bool m_buttonsVisibile = true; +}; + +} // AppManager::Internal diff --git a/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp b/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp new file mode 100644 index 00000000000..2f7c44a81b2 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagertargetinformation.cpp @@ -0,0 +1,270 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagertargetinformation.h" + +#include "appmanagerconstants.h" + +#include +#include +#include +#include +#include + +#include + +#include + +#include + +using namespace ProjectExplorer; +using namespace QmakeProjectManager; +using namespace QtSupport; +using namespace Utils; + +namespace AppManager { +namespace Internal { + +static QString trimmedAndUnquoted(const QByteArray &value) +{ + auto result = QString::fromUtf8(value.trimmed()); + if (result.length() > 2 + && result.startsWith('\'') + && result.endsWith('\'')) { + result.remove(result.length() - 1, 1); + result.remove(0, 1); + } + return result; +} + +Manifest::Manifest(const QString &fileNameIn) +{ + QFile file(fileNameIn); + if (file.exists() && file.open(QIODevice::ReadOnly)) { + fileName = fileNameIn; + // TODO: make reading valid and optimized + const auto lines = file.readAll().split('\n'); + for (const auto& line: lines) { + if (line.trimmed().isEmpty()) { + continue; + } + if (line.trimmed() == "---") { + continue; + } + const auto parts = line.split(':'); + if (parts.size() != 2) + continue; + if (parts.first().trimmed() == "formatVersion") { + formatVersion = parts.last().toInt(); + continue; + } + if (parts.first().trimmed() == "formatType") { + formatType = trimmedAndUnquoted(parts.last()); + continue; + } + if (parts.first().trimmed() == "id") { + id = trimmedAndUnquoted(parts.last()); + continue; + } + if (parts.first().trimmed() == "icon") { + icon = trimmedAndUnquoted(parts.last()); + continue; + } + if (parts.first().trimmed() == "code") { + code = trimmedAndUnquoted(parts.last()); + continue; + } + if (parts.first().trimmed() == "runtime") { + runtime = trimmedAndUnquoted(parts.last()); + continue; + } + } + file.close(); + } +} + +Manifest::Manifest(const QmakeProjectManager::InstallsList &installs) +{ + for (const auto &item : installs.items) { + if (item.active) { + for (const auto &file : item.files) { + const QFileInfo fileInfo(file.fileName); + if (fileInfo.fileName().toLower() == "info.yaml") { + Manifest result(fileInfo.absoluteFilePath()); + if (!result.fileName.isEmpty()) { + result.installPathSuffix = installs.targetPath; + *this = result; + return; + } + } + } + } + } +} + +QString readProVariable(QmakeBuildSystem *bs, QmakeProFile *file, const QString &variableName) +{ + QString result; + if (!file) + return result; + auto project = file->project(); + if (!project) + return result; + if (variableName.isEmpty()) + return result; + if (auto proFileReader = bs->createProFileReader(file)) { + const FilePath filePath = file->filePath(); + const QString deviceRoot = filePath.withNewPath("/").toFSPathString(); + if (auto proFile = proFileReader->parsedProFile(deviceRoot, filePath.path())) { + if (proFileReader->accept(proFile, QMakeEvaluator::LoadAll)) { + result = proFileReader->value(variableName); + } + } + bs->destroyProFileReader(proFileReader); + } + return result; +} + +FilePath destinationDirectoryFor(const QmakeProjectManager::TargetInformation &ti) +{ + if (ti.destDir.isEmpty()) + return ti.buildDir; + if (QDir::isRelativePath(ti.destDir.toString())) + return FilePath::fromString(QDir::cleanPath(ti.buildDir.toString() + '/' + ti.destDir.toString())); + return ti.destDir; +} + +QString packageFileNameFor(const QmakeProFile *file, const QString &baseName) +{ + if (!file) + return QString(); + if (baseName.isEmpty()) + return QString(); + + QmakeProjectManager::TargetInformation ti = file->targetInformation(); + if (!ti.valid) + return QString(); + + return QDir(destinationDirectoryFor(ti).toString()).absoluteFilePath(baseName + ".pkg"); +} + +QList TargetInformation::readFromProject(const Target *target , const QString &buildKey) +{ + QList result; + if (!target->project()->rootProjectNode()) + return result; + if (auto bs = qobject_cast(target->buildSystem())) { + const QmakeProFile *const file = bs->rootProFile(); + if (!file || file->parseInProgress()) + return result; + const auto rootInstallPathSuffix = readProVariable(bs, bs->rootProFile(), Constants::QMAKE_AM_PACKAGE_DIR_VARIABLE); + target->project()->rootProjectNode()->forEachProjectNode([&](const ProjectNode *pn) { + auto node = dynamic_cast(pn); + if (!node || !node->includedInExactParse()) + return; + if (!buildKey.isEmpty() && buildKey != node->filePath().toString()) + return; + QmakeProjectManager::TargetInformation ti = node->targetInformation(); + if (!ti.valid) + return; + TargetInformation ati; + const auto manifestFileName = readProVariable(bs, node->proFile(), Constants::QMAKE_AM_MANIFEST_VARIABLE); + if (!manifestFileName.isEmpty()) { + ati.manifest = manifestFileName; + if (ati.manifest.fileName.isEmpty()) { + ati.manifest = node->filePath().toFileInfo().dir().absoluteFilePath(manifestFileName); + } + } + if (ati.manifest.fileName.isEmpty()) { + ati.manifest = node->proFile()->installsList(); + } + if (ati.manifest.fileName.isEmpty()) + return; + QString destDir = ti.destDir.toString(); + QString workingDir; + if (!destDir.isEmpty()) { + bool workingDirIsBaseDir = false; + if (destDir == ti.buildTarget) + workingDirIsBaseDir = true; + if (QDir::isRelativePath(destDir)) + destDir = QDir::cleanPath(ti.buildDir.toString() + '/' + destDir); + + if (workingDirIsBaseDir) + workingDir = ti.buildDir.toString(); + else + workingDir = destDir; + } else { + workingDir = ti.buildDir.toString(); + } + ati.buildDirectory = QDir(workingDir); + ati.projectFile = node->filePath().toFileInfo(); + ati.packageFile = QFileInfo(packageFileNameFor(node->proFile(), ati.manifest.id)); + ati.buildKey = ati.projectFile.absoluteFilePath(); + ati.displayName = ati.packageFile.fileName(); + const FilePath relativePathInProject = node->filePath().relativeChildPath(bs->projectDirectory()); + if (!relativePathInProject.isEmpty()) { + ati.displayNameUniquifier = QString::fromLatin1(" (%1)").arg(relativePathInProject.toUserOutput()); + } + auto installPathSuffix = readProVariable(bs, node->proFile(), Constants::QMAKE_AM_PACKAGE_DIR_VARIABLE); + if (installPathSuffix.isEmpty()) + installPathSuffix = rootInstallPathSuffix; + if (!installPathSuffix.isEmpty()) { + ati.manifest.installPathSuffix = installPathSuffix; + while (installPathSuffix.startsWith('/')) + installPathSuffix.remove(0, 1); + ati.packageSourcesDirectory = QDir(QString("%1/%2").arg(ati.buildDirectory.absolutePath(), installPathSuffix)); + } else { + ati.packageSourcesDirectory = ati.buildDirectory; + } + result.append(ati); + }); + } + return result; +} + +TargetInformation::TargetInformation(const Target *target) +{ + if (!target) + return; + if (target->buildSystem()->isParsing()) + return; + auto project = target->project(); + if (!project) + return; + + const RunConfiguration *rc = target->activeRunConfiguration(); + if (!rc) + return; + if (rc->id() != Constants::RUNCONFIGURATION_ID) + return; + + const auto buildKey = rc->buildKey(); + if (buildKey.isEmpty()) + return; + + const auto targetInfoList = TargetInformation::readFromProject(target, buildKey); + if (targetInfoList.isEmpty()) + return; + + *this = targetInfoList.first(); + + device = DeviceKitAspect::device(target->kit()); + remote = device && device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + runDirectory = remote ? QDir(Constants::REMOTE_DEFAULT_TMP_PATH) : buildDirectory; +} + +bool TargetInformation::isValid() const +{ + static const QFileInfo INVALID_FILE_INFO = QFileInfo(); + return !manifest.fileName.isEmpty() && packageFile != INVALID_FILE_INFO; +} + +FilePath TargetInformation::workingDirectory() const +{ + return FilePath::fromString(runDirectory.absolutePath()); +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagertargetinformation.h b/src/plugins/qtapplicationmanager/appmanagertargetinformation.h new file mode 100644 index 00000000000..d188c4aa134 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagertargetinformation.h @@ -0,0 +1,65 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include + +namespace AppManager { +namespace Internal { + +class Manifest +{ +public: + QString installPathSuffix; + QString fileName; + + int formatVersion = 0; + QString formatType; + + QString id; + QString icon; + QString code; + QString runtime; + + bool isQmlRuntime() const { return runtime.toLower() == "qml"; } + bool isNativeRuntime() const { return runtime.toLower() == "native"; } + + Manifest() = default; + Manifest(const Manifest &other) = default; + Manifest(const QString &fileName); + Manifest(const QmakeProjectManager::InstallsList &installsList); +}; + +class TargetInformation final +{ +public: + Manifest manifest; + QDir buildDirectory; + QDir packageSourcesDirectory; + QDir runDirectory; + QFileInfo packageFile; + QFileInfo projectFile; + QSharedPointer device; + QString buildKey; + QString displayName; + QString displayNameUniquifier; + bool remote = false; + + bool isValid() const; + Utils::FilePath workingDirectory() const; + + TargetInformation() = default; + TargetInformation(const TargetInformation &other) = default; + TargetInformation(const ProjectExplorer::Target *target); + + static QList readFromProject(const ProjectExplorer::Target *target, const QString &buildKey = QString()); +}; + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerutilities.cpp b/src/plugins/qtapplicationmanager/appmanagerutilities.cpp new file mode 100644 index 00000000000..641027ec2ec --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerutilities.cpp @@ -0,0 +1,68 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "appmanagerutilities.h" + +#include "appmanagerconstants.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace ProjectExplorer; +using namespace QtSupport; +using namespace Utils; + +namespace AppManager { +namespace Internal { + +static QString getToolPathByQtVersion(const QtVersion *qtVersion, + const QString &toolname = QString(Constants::APPMAN_PACKAGER)) +{ + if (qtVersion) { + const auto toolExistsInDir = [&](const QDir &dir) { + const FilePath toolFilePath = FilePath::fromString(dir.absolutePath()) + .pathAppended(getToolNameByDevice(toolname)); + return toolFilePath.isFile(); + }; + const QDir qtHostBinsDir(qtVersion->hostBinPath().toString()); + if (toolExistsInDir(qtHostBinsDir)) + return qtHostBinsDir.absolutePath(); + const QDir qtBinDir(qtVersion->binPath().toString()); + if (toolExistsInDir(qtBinDir)) + return qtBinDir.absolutePath(); + } + return QString(); +} + +QString getToolFilePath(const QString &toolname, const Kit *kit, const IDevice::ConstPtr &device) +{ + const bool local = !device || device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + const auto path = local ? + getToolPathByQtVersion(QtKitAspect::qtVersion(kit)) : + QString(Constants::REMOTE_DEFAULT_BIN_PATH); + const auto name = getToolNameByDevice(toolname, device); + return !path.isEmpty() ? + QDir(path).absoluteFilePath(name) : + name; +} + +QString getToolNameByDevice(const QString &baseName, const QSharedPointer &device) +{ + return OsSpecificAspects::withExecutableSuffix(device ? device->osType() : HostOsInfo::hostOs(), baseName); +} + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/appmanagerutilities.h b/src/plugins/qtapplicationmanager/appmanagerutilities.h new file mode 100644 index 00000000000..92ad4f21375 --- /dev/null +++ b/src/plugins/qtapplicationmanager/appmanagerutilities.h @@ -0,0 +1,17 @@ +// Copyright (C) 2019 Luxoft Sweden AB +// Copyright (C) 2018 Pelagicore AG +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +namespace AppManager { +namespace Internal { + +QString getToolNameByDevice(const QString &baseName, const QSharedPointer &device = nullptr); +QString getToolFilePath(const QString &toolname, const ProjectExplorer::Kit *kit, const ProjectExplorer::IDevice::ConstPtr &device); + +} // namespace Internal +} // namespace AppManager diff --git a/src/plugins/qtapplicationmanager/qtapplicationmanager.qbs b/src/plugins/qtapplicationmanager/qtapplicationmanager.qbs new file mode 100644 index 00000000000..10074765c51 --- /dev/null +++ b/src/plugins/qtapplicationmanager/qtapplicationmanager.qbs @@ -0,0 +1,52 @@ +import qbs 1.0 + +QtcPlugin { + name: "QtApplicationManagerIntegration" + + Depends { name: "Boot2Qt"; required: false } + Depends { name: "Core" } + Depends { name: "Debugger" } + Depends { name: "ProjectExplorer" } + Depends { name: "QmakeProjectManager" } + Depends { name: "QmlJS" } + Depends { name: "QtSupport" } + Depends { name: "RemoteLinux" } + Depends { name: "ResourceEditor" } + Depends { name: "TextEditor" } + Depends { name: "Utils" } + Depends { name: "Qt"; submodules: ["widgets", "network"] } + + //Properties { + // condition: Boot2Qt.present + // cpp.defines: base.concat("HAVE_BOOT2QT") + // + + files: [ + "appmanagerconstants.h", + "appmanagercreatepackagestep.cpp", + "appmanagercreatepackagestep.h", + "appmanagerdeployconfigurationautoswitcher.cpp", + "appmanagerdeployconfigurationautoswitcher.h", + "appmanagerdeployconfigurationfactory.cpp", + "appmanagerdeployconfigurationfactory.h", + "appmanagerdeploypackagestep.cpp", + "appmanagerdeploypackagestep.h", + "appmanagerinstallpackagestep.cpp", + "appmanagerinstallpackagestep.h", + "appmanagermakeinstallstep.cpp", + "appmanagermakeinstallstep.h", + "appmanagerplugin.cpp", + "appmanagerplugin.h", + "appmanagerrunconfiguration.cpp", + "appmanagerrunconfiguration.h", + "appmanagerruncontrol.cpp", + "appmanagerruncontrol.h", + "appmanagerstringaspect.cpp", + "appmanagerstringaspect.h", + "appmanagertargetinformation.cpp", + "appmanagertargetinformation.h", + "appmanagerutilities.cpp", + "appmanagerutilities.h", + ] +} +