diff --git a/src/plugins/docker/CMakeLists.txt b/src/plugins/docker/CMakeLists.txt index 5dd7fad2f29..c3131ecc3f6 100644 --- a/src/plugins/docker/CMakeLists.txt +++ b/src/plugins/docker/CMakeLists.txt @@ -2,6 +2,7 @@ add_qtc_plugin(Docker PLUGIN_DEPENDS Core ProjectExplorer SOURCES docker_global.h + dockerbuildstep.cpp dockerbuildstep.h dockerconstants.h dockerdevice.cpp dockerdevice.h diff --git a/src/plugins/docker/docker.pro b/src/plugins/docker/docker.pro index 694f116bb72..ac012006b73 100644 --- a/src/plugins/docker/docker.pro +++ b/src/plugins/docker/docker.pro @@ -3,6 +3,7 @@ include(../../qtcreatorplugin.pri) DEFINES += QT_RESTRICTED_CAST_FROM_ASCII SOURCES += \ + dockerbuildstep.cpp \ dockerdevice.cpp \ dockerplugin.cpp \ dockerrunconfiguration.cpp \ @@ -10,6 +11,7 @@ SOURCES += \ HEADERS += \ docker_global.h \ + dockerbuildstep.h \ dockerconstants.h \ dockerdevice.h \ dockerplugin.h \ diff --git a/src/plugins/docker/docker.qbs b/src/plugins/docker/docker.qbs index ed897109eb0..9db5db442e4 100644 --- a/src/plugins/docker/docker.qbs +++ b/src/plugins/docker/docker.qbs @@ -11,6 +11,8 @@ QtcPlugin { files: [ "docker_global.h", + "dockerbuildstep.h", + "dockerbuildstep.cpp", "dockerconstants.h", "dockerdevice.h", "dockerdevice.cpp", diff --git a/src/plugins/docker/dockerbuildstep.cpp b/src/plugins/docker/dockerbuildstep.cpp new file mode 100644 index 00000000000..332803f687a --- /dev/null +++ b/src/plugins/docker/dockerbuildstep.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 "dockerbuildstep.h" + +#include "dockerconstants.h" +#include "dockerdevice.h" +#include "dockersettings.h" + +#include +#include +#include +#include +#include + +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace Docker { +namespace Internal { + +const char DOCKER_COMMAND[] = "docker"; +const char DEFAULT_DOCKER_COMMAND[] = "run --read-only --rm %{BuildDevice:DockerImage}"; + +class DockerBuildStep : public AbstractProcessStep +{ +public: + DockerBuildStep(BuildStepList *bsl, Id id) + : AbstractProcessStep(bsl, id) + { + setDisplayName(tr("Docker build host step")); + + m_dockerCommand = addAspect(); + m_dockerCommand->setDisplayStyle(StringAspect::DisplayStyle::TextEditDisplay); + m_dockerCommand->setLabelText(tr("Docker Command:")); + m_dockerCommand->setMacroExpanderProvider([=] { return macroExpander(); }); + m_dockerCommand->setDefaultValue(QLatin1String(DEFAULT_DOCKER_COMMAND)); + m_dockerCommand->setPlaceHolderText(QLatin1String(DEFAULT_DOCKER_COMMAND)); + m_dockerCommand->setSettingsKey("DockerCommand"); + + auto setupField = [=](Utils::StringAspect* &aspect, const QString &label, + const QString &settingsKey) { + aspect = addAspect(); + aspect->setDisplayStyle(StringAspect::DisplayStyle::LineEditDisplay); + aspect->setLabelText(label); + aspect->setSettingsKey(settingsKey); + aspect->setMacroExpanderProvider([=] { return target()->kit()->macroExpander(); }); + }; + setupField(m_command, tr("Command:"), "Command"); + setupField(m_arguments, tr("Arguments:"), "Arguments"); + setupField(m_workingDirectory, tr("Working Directory:"), "WorkingDirectory"); + + setCommandLineProvider([=] { return commandLine(); }); + setWorkingDirectoryProvider([=] { + return dockerBuildDevice() ? FilePath() : workingDirectory(); + }); + setSummaryUpdater([=] { return summary(); }); + } + +private: + const DockerDevice *dockerBuildDevice() const + { + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(target()->kit()); + return dynamic_cast(device.get()); + } + + MacroExpander *macroExpander() const + { + MacroExpander *expander = target()->kit()->macroExpander(); + expander->registerVariable("BuildDevice:DockerImage", + "Build Host Docker Image ID", [=]() -> QString { + const DockerDevice *dockerDevice = dockerBuildDevice(); + return dockerDevice ? dockerDevice->data().imageId : QString(); + }, true); + return expander; + } + + CommandLine commandLine() const + { + MacroExpander *expander = target()->kit()->macroExpander(); + CommandLine cmd; + if (dockerBuildDevice()) { + CommandLine dockerCmd(QString::fromLatin1(DOCKER_COMMAND)); + QString dockerCommand = m_dockerCommand->value(); + + // Sneak working directory into docker "run" or "exec" call + const QString workDir = m_workingDirectory->value(); + if (!workDir.isEmpty()) + dockerCommand.replace(QRegularExpression("[[:<:]](run|exec)[[:>:]]"), + "\\1 --workdir " + workDir); + + dockerCmd.addArgs(expander->expand(dockerCommand), CommandLine::Raw); + dockerCmd.addArgs(expander->expand(m_command->value()), CommandLine::Raw); + cmd = dockerCmd; + } else { + CommandLine localCmd(expander->expand(m_command->value())); + cmd = localCmd; + } + cmd.addArgs(expander->expand(m_arguments->value()), CommandLine::Raw); + return cmd; + } + + FilePath workingDirectory() const + { + return FilePath::fromUserInput(target()->kit()->macroExpander()-> + expand(m_workingDirectory->value())); + } + + QString summary() const + { + const IDevice::ConstPtr d = BuildDeviceKitAspect::device(target()->kit()); + if (!d) + return QString(); // No build device selected in kit + m_dockerCommand->setEnabled(dockerBuildDevice() != nullptr); + const QString title = tr("Build on %1").arg(d->displayName()); + if (m_command->value().isEmpty()) { + // Procuring the red "Invalid command" summary. + ProcessParameters params; + params.effectiveCommand(); + return params.summary(title); + } else { + return tr("%1: %2").arg(title).arg(commandLine().toUserOutput()); + } + } + + Utils::StringAspect *m_dockerCommand = nullptr; + Utils::StringAspect *m_command = nullptr; + Utils::StringAspect *m_arguments = nullptr; + Utils::StringAspect *m_workingDirectory = nullptr; +}; + + +DockerBuildStepFactory::DockerBuildStepFactory() +{ + registerStep(Constants::DOCKER_BUILDHOST_BUILDSTEP_ID); + setDisplayName(DockerBuildStep::tr("Docker build host step")); + setSupportedStepLists({ProjectExplorer::Constants::BUILDSTEPS_BUILD, + ProjectExplorer::Constants::BUILDSTEPS_CLEAN}); +} + +} // Internal +} // Docker diff --git a/src/plugins/docker/dockerbuildstep.h b/src/plugins/docker/dockerbuildstep.h new file mode 100644 index 00000000000..c00184edd00 --- /dev/null +++ b/src/plugins/docker/dockerbuildstep.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2021 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 + +namespace Docker { +namespace Internal { + +class DockerBuildStepFactory final : public ProjectExplorer::BuildStepFactory +{ +public: + DockerBuildStepFactory(); +}; + +} // Internal +} // Docker diff --git a/src/plugins/docker/dockerconstants.h b/src/plugins/docker/dockerconstants.h index b91e62bcf20..10660696ce3 100644 --- a/src/plugins/docker/dockerconstants.h +++ b/src/plugins/docker/dockerconstants.h @@ -36,6 +36,8 @@ const char MENU_ID[] = "Docker.Menu"; const char DOCKER_DEVICE_TYPE[] = "DockerDeviceType"; const char DOCKER_RUN_FLAGS[] = "DockerRunFlags"; +const char DOCKER_BUILDHOST_BUILDSTEP_ID[] = "Docker.BuildStep.BuildHost"; + } // namespace Constants } // namespace Docker diff --git a/src/plugins/docker/dockerplugin.cpp b/src/plugins/docker/dockerplugin.cpp index d574da83545..6100c7a9c3e 100644 --- a/src/plugins/docker/dockerplugin.cpp +++ b/src/plugins/docker/dockerplugin.cpp @@ -27,6 +27,7 @@ #include "dockerconstants.h" +#include "dockerbuildstep.h" #include "dockerdevice.h" #include "dockerrunconfiguration.h" #include "dockersettings.h" @@ -55,6 +56,8 @@ public: {ProjectExplorer::Constants::NORMAL_RUN_MODE}, {containerRunConfigFactory.runConfigurationId()} }; + + DockerBuildStepFactory buildStepFactory; }; DockerPlugin::~DockerPlugin()