File indexing completed on 2024-05-05 04:39:43
0001 /* 0002 SPDX-FileCopyrightText: 2017 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #include "dockerplugin.h" 0008 #include "dockerruntime.h" 0009 #include "dockerpreferences.h" 0010 #include "dockerpreferencessettings.h" 0011 #include <interfaces/icore.h> 0012 #include <interfaces/iruntimecontroller.h> 0013 #include <interfaces/iuicontroller.h> 0014 #include <interfaces/context.h> 0015 #include <interfaces/contextmenuextension.h> 0016 #include <outputview/outputexecutejob.h> 0017 #include <project/projectmodel.h> 0018 #include <QStandardPaths> 0019 #include <QAction> 0020 #include <QRegularExpression> 0021 #include <QTemporaryDir> 0022 #include <QFileDialog> 0023 #include <QInputDialog> 0024 #include <QProcess> 0025 #include <KPluginFactory> 0026 #include <KActionCollection> 0027 #include <KLocalizedString> 0028 #include <KParts/MainWindow> 0029 #include <KJob> 0030 0031 K_PLUGIN_FACTORY_WITH_JSON(KDevDockerFactory, "kdevdocker.json", registerPlugin<DockerPlugin>();) 0032 0033 using namespace KDevelop; 0034 0035 DockerPlugin::DockerPlugin(QObject *parent, const QVariantList & /*args*/) 0036 : KDevelop::IPlugin( QStringLiteral("kdevdocker"), parent ) 0037 , m_settings(new DockerPreferencesSettings) 0038 { 0039 runtimeChanged(ICore::self()->runtimeController()->currentRuntime()); 0040 0041 setXMLFile( QStringLiteral("kdevdockerplugin.rc") ); 0042 connect(ICore::self()->runtimeController(), &IRuntimeController::currentRuntimeChanged, this, &DockerPlugin::runtimeChanged); 0043 0044 auto* process = new QProcess(this); 0045 connect(process, QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished), 0046 this, &DockerPlugin::imagesListFinished); 0047 process->start(QStringLiteral("docker"), {QStringLiteral("images"), QStringLiteral("--filter"), QStringLiteral("dangling=false"), QStringLiteral("--format"), QStringLiteral("{{.Repository}}:{{.Tag}}\t{{.ID}}")}, QIODevice::ReadOnly); 0048 0049 DockerRuntime::s_settings = m_settings.data(); 0050 } 0051 0052 DockerPlugin::~DockerPlugin() 0053 { 0054 DockerRuntime::s_settings = nullptr; 0055 } 0056 0057 void DockerPlugin::imagesListFinished(int code) 0058 { 0059 if (code != 0) 0060 return; 0061 0062 auto* process = qobject_cast<QProcess*>(sender()); 0063 Q_ASSERT(process); 0064 QTextStream stream(process); 0065 while(!stream.atEnd()) { 0066 const QString line = stream.readLine(); 0067 const QStringList parts = line.split(QLatin1Char('\t')); 0068 0069 const QString tag = parts[0] == QLatin1String("<none>") ? parts[1] : parts[0]; 0070 ICore::self()->runtimeController()->addRuntimes(new DockerRuntime(tag)); 0071 } 0072 0073 process->deleteLater(); 0074 Q_EMIT imagesListed(); 0075 } 0076 0077 void DockerPlugin::runtimeChanged(KDevelop::IRuntime* newRuntime) 0078 { 0079 const bool isDocker = qobject_cast<DockerRuntime*>(newRuntime); 0080 0081 const auto& actions = actionCollection()->actions(); 0082 for (auto action: actions) { 0083 action->setEnabled(isDocker); 0084 } 0085 } 0086 0087 KDevelop::ContextMenuExtension DockerPlugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent) 0088 { 0089 QList<QUrl> urls; 0090 0091 if ( context->type() == KDevelop::Context::FileContext ) { 0092 auto* filectx = static_cast<KDevelop::FileContext*>(context); 0093 urls = filectx->urls(); 0094 } else if ( context->type() == KDevelop::Context::ProjectItemContext ) { 0095 auto* projctx = static_cast<KDevelop::ProjectItemContext*>(context); 0096 const auto items = projctx->items(); 0097 for (KDevelop::ProjectBaseItem* item : items) { 0098 if ( item->file() ) { 0099 urls << item->path().toUrl(); 0100 } 0101 } 0102 } 0103 0104 for(auto it = urls.begin(); it != urls.end(); ) { 0105 if (it->isLocalFile() && it->fileName() == QLatin1String("Dockerfile")) { 0106 ++it; 0107 } else { 0108 it = urls.erase(it); 0109 } 0110 } 0111 0112 if ( !urls.isEmpty() ) { 0113 KDevelop::ContextMenuExtension ext; 0114 for (const QUrl& url : qAsConst(urls)) { 0115 const KDevelop::Path file(url); 0116 0117 auto action = new QAction(QIcon::fromTheme(QStringLiteral("text-dockerfile")), i18n("docker build '%1'", file.path()), parent); 0118 connect(action, &QAction::triggered, this, [this, file]() { 0119 const auto dir = file.parent(); 0120 const QString name = QInputDialog::getText( 0121 ICore::self()->uiController()->activeMainWindow(), i18nc("@title:window", "Choose Tag Name"), 0122 i18nc("@label:textbox", "Tag name for '%1':", file.path()), 0123 QLineEdit::Normal, dir.lastPathSegment() 0124 ); 0125 0126 auto process = new OutputExecuteJob; 0127 process->setExecuteOnHost(true); 0128 process->setProperties(OutputExecuteJob::DisplayStdout | OutputExecuteJob::DisplayStderr); 0129 // TODO: call process->setStandardToolView(IOutputView::?); to prevent creating a new tool view for each 0130 // job in OutputJob::startOutput(). Such nonstandard and unshared tool views are also not configurable. 0131 *process << QStringList{QStringLiteral("docker"), QStringLiteral("build"), QStringLiteral("--tag"), name, dir.toLocalFile()}; 0132 connect(process, &KJob::finished, this, [name] (KJob* job) { 0133 if (job->error() != 0) 0134 return; 0135 0136 ICore::self()->runtimeController()->addRuntimes(new DockerRuntime(name)); 0137 }); 0138 process->start(); 0139 }); 0140 ext.addAction(KDevelop::ContextMenuExtension::RunGroup, action); 0141 } 0142 0143 return ext; 0144 } 0145 0146 return KDevelop::IPlugin::contextMenuExtension(context, parent); 0147 } 0148 0149 int DockerPlugin::configPages() const 0150 { 0151 return 1; 0152 } 0153 0154 KDevelop::ConfigPage* DockerPlugin::configPage(int number, QWidget* parent) 0155 { 0156 if (number == 0) { 0157 return new DockerPreferences(this, m_settings.data(), parent); 0158 } 0159 return nullptr; 0160 } 0161 0162 #include "dockerplugin.moc" 0163 #include "moc_dockerplugin.cpp"