File indexing completed on 2024-04-21 04:34:28

0001 /*
0002  * This file is part of KDevelop project
0003  * Copyright 2016 Patrick José Pereira <patrickelectric@gmail.com>
0004  * Based onde the work of:
0005  *  Hamish Rodda <rodda@kde.org>
0006  *
0007  * This program is free software; you can redistribute it and/or modify
0008  * it under the terms of the GNU Library General Public License as
0009  * published by the Free Software Foundation; either version 2 of the
0010  * License, or (at your option) any later version.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU General Public
0018  * License along with this program; if not, write to the
0019  * Free Software Foundation, Inc.,
0020  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0021  */
0022 
0023 #include "executeplugin.h"
0024 
0025 #include <QDebug>
0026 
0027 #include <KConfigGroup>
0028 #include <KJob>
0029 #include <KLocalizedString>
0030 #include <KMessageBox>
0031 #include <KParts/MainWindow>
0032 #include <KPluginFactory>
0033 #include <KShell>
0034 
0035 #include <interfaces/icore.h>
0036 #include <interfaces/isession.h>
0037 #include <interfaces/iruncontroller.h>
0038 #include <interfaces/ilaunchconfiguration.h>
0039 #include <interfaces/iprojectcontroller.h>
0040 #include <interfaces/iuicontroller.h>
0041 
0042 #include "debug.h"
0043 #include "toolkit.h"
0044 #include "embeddedlauncher.h"
0045 #include <project/projectmodel.h>
0046 #include <project/builderjob.h>
0047 #include <util/kdevstringhandler.h>
0048 
0049 QString ExecutePlugin::_nativeAppConfigTypeId = QStringLiteral("Embedded Application");
0050 QString ExecutePlugin::workingDirEntry = QStringLiteral("Working Directory");
0051 QString ExecutePlugin::executableEntry = QStringLiteral("Executable");
0052 QString ExecutePlugin::argumentsEntry = QStringLiteral("Arguments");
0053 QString ExecutePlugin::isExecutableEntry = QStringLiteral("isExecutable");
0054 QString ExecutePlugin::environmentProfileEntry = QStringLiteral("EnvironmentGroup");
0055 QString ExecutePlugin::useTerminalEntry = QStringLiteral("Use External Terminal");
0056 QString ExecutePlugin::commandEntry = QStringLiteral("Command");
0057 QString ExecutePlugin::boardEntry = QStringLiteral("Board Index");
0058 QString ExecutePlugin::mcuEntry = QStringLiteral("mcu Index");
0059 QString ExecutePlugin::userIdToRunEntry = QStringLiteral("User Id to Run");
0060 QString ExecutePlugin::dependencyActionEntry = QStringLiteral("Dependency Action");
0061 QString ExecutePlugin::projectTargetEntry = QStringLiteral("Project Target");
0062 QString ExecutePlugin::arduinoEntry = QStringLiteral("Arduino Entry");
0063 QString ExecutePlugin::launcherIndexEntry = QStringLiteral("Embedded Launcher Index");
0064 QString ExecutePlugin::openocdArgEntry = QStringLiteral("Openocd Arg Entry");
0065 QString ExecutePlugin::openocdWorkEntry = QStringLiteral("Openocd Work Entry");
0066 QString ExecutePlugin::openocdCommEntry = QStringLiteral("Openocd Command Entry");
0067 
0068 using namespace KDevelop;
0069 
0070 Q_LOGGING_CATEGORY(EpMsg, "Kdev.embedded.ep.msg")
0071 K_PLUGIN_FACTORY_WITH_JSON(KDevExecuteFactory, "kdevembedded-launcher.json", registerPlugin<ExecutePlugin>();)
0072 
0073 ExecutePlugin::ExecutePlugin(QObject *parent, const QVariantList&)
0074     : KDevelop::IPlugin(QStringLiteral("kdevembedded-launcher"), parent)
0075 {
0076     m_configType = new NativeAppConfigType();
0077     m_configType->addLauncher(new EmbeddedLauncher());
0078     qCDebug(EpMsg) << "adding native app launch config";
0079     core()->runController()->addConfigurationType(m_configType);
0080 }
0081 
0082 ExecutePlugin::~ExecutePlugin()
0083 {
0084     delete m_configType;
0085 }
0086 
0087 void ExecutePlugin::unload()
0088 {
0089     core()->runController()->removeConfigurationType(m_configType);
0090     delete m_configType;
0091     m_configType = nullptr;
0092 }
0093 
0094 QStringList ExecutePlugin::arguments(KDevelop::ILaunchConfiguration* cfg, QString& err_) const
0095 {
0096     qCDebug(EpMsg) << "ExecutePlugin::arguments";
0097     qCDebug(EpMsg) << "name" << cfg->name();
0098     qCDebug(EpMsg) << "entryMap" << cfg->config().entryMap();
0099     qCDebug(EpMsg) << "groupList" << cfg->config().groupList();
0100     qCDebug(EpMsg) << "keyList" << cfg->config().keyList();
0101 
0102     if (!cfg)
0103     {
0104         qCDebug(EpMsg) << "ExecutePlugin::arguments" << "!cfg";
0105         return QStringList();
0106     }
0107 
0108     KShell::Errors err;
0109     uint launcherIndex = cfg->config().readEntry(ExecutePlugin::launcherIndexEntry, 0);
0110 
0111     QStringList args;
0112     switch (launcherIndex)
0113     {
0114         case index::arduino:
0115             args = KShell::splitArgs(cfg->config().readEntry(ExecutePlugin::argumentsEntry, ""), KShell::TildeExpand | KShell::AbortOnMeta, &err);
0116         break;
0117 
0118         case index::openocd:
0119             args = KShell::splitArgs(cfg->config().readEntry(ExecutePlugin::openocdArgEntry, ""), KShell::TildeExpand | KShell::AbortOnMeta, &err);
0120         break;
0121     }
0122 
0123     if (err != KShell::NoError)
0124     {
0125 
0126         if (err == KShell::BadQuoting)
0127         {
0128             err_ = i18n("There is a quoting error in the arguments for "
0129                         "the launch configuration '%1'. Aborting start.", cfg->name());
0130         }
0131         else
0132         {
0133             err_ = i18n("A shell meta character was included in the "
0134                         "arguments for the launch configuration '%1', "
0135                         "this is not supported currently. Aborting start.", cfg->name());
0136         }
0137         args = QStringList();
0138         qWarning() << "Launch Configuration:" << cfg->name() << "arguments have meta characters";
0139     }
0140 
0141     switch (launcherIndex)
0142     {
0143         case index::arduino:
0144         {
0145             QStringList arduinoConfig = cfg->config().readEntry(ExecutePlugin::arduinoEntry, QStringList());
0146 
0147             for (QStringList::iterator it = args.begin(); it != args.end(); ++it)
0148             {
0149                 qCDebug(EpMsg) << *it;
0150                 if (!arduinoConfig.empty())
0151                 {
0152                     it->replace(QLatin1String("%mcu"), KShell::quoteArg(arduinoConfig[1]));
0153                     it->replace(QLatin1String("%baud"), KShell::quoteArg(arduinoConfig[2]));
0154                     it->replace(QLatin1String("%interface"), KShell::quoteArg(arduinoConfig[3]));
0155                     it->replace(QLatin1String("%hex"), KShell::quoteArg(arduinoConfig[4]));
0156                     it->replace(QLatin1String("%avrdudeconf"), KShell::quoteArg(arduinoConfig[5]));
0157                 }
0158             }
0159         }
0160 
0161         case index::openocd:
0162         {
0163             QString binary = cfg->config().readEntry(ExecutePlugin::executableEntry, QString());
0164 
0165             for (QStringList::iterator it = args.begin(); it != args.end(); ++it)
0166             {
0167                 qCDebug(EpMsg) << *it;
0168                 if (!binary.isEmpty())
0169                 {
0170                     it->replace(QLatin1String("%hex"), binary);
0171                 }
0172             }
0173         }
0174 
0175     }
0176 
0177     qCDebug(EpMsg) << "ExecutePlugin::arguments" << args;
0178     return args;
0179 }
0180 
0181 
0182 KJob* ExecutePlugin::dependencyJob(KDevelop::ILaunchConfiguration* cfg) const
0183 {
0184     Q_UNUSED(cfg)
0185     return nullptr;
0186 }
0187 
0188 
0189 QString ExecutePlugin::environmentProfileName(KDevelop::ILaunchConfiguration* cfg) const
0190 {
0191     if (!cfg)
0192     {
0193         return QString();
0194     }
0195 
0196     return cfg->config().readEntry(ExecutePlugin::environmentProfileEntry, "");
0197 }
0198 
0199 
0200 QUrl ExecutePlugin::executable(KDevelop::ILaunchConfiguration* cfg, QString& err) const
0201 {
0202     Q_UNUSED(err)
0203     if (!cfg)
0204     {
0205         qCDebug(EpMsg) << "ExecutePlugin::executable" << "!cfg";
0206         return QUrl();
0207     }
0208 
0209     QString exe;
0210     uint launcherIndex = cfg->config().readEntry(ExecutePlugin::launcherIndexEntry, 0);
0211     qCDebug(EpMsg) << "ExecutePlugin::executable" << "launcherIndex" << launcherIndex;
0212     switch (launcherIndex)
0213     {
0214         case index::arduino:
0215             exe = cfg->config().readEntry(ExecutePlugin::commandEntry, QString());
0216         break;
0217         case index::openocd:
0218             exe = cfg->config().readEntry(ExecutePlugin::openocdCommEntry, QString());
0219         break;
0220     }
0221     qCDebug(EpMsg) << "ExecutePlugin::executable" << "exe" << exe;
0222     if (!exe.isEmpty())
0223     {
0224         if (exe.contains(QLatin1String("%avrdude")))
0225         {
0226             exe.replace(QLatin1String("%avrdude"), Toolkit::instance().getAvrdudeFile());
0227         }
0228 
0229         if  (exe.contains(QLatin1String("%openocd")))
0230         {
0231             exe.replace(QLatin1String("%openocd"), Toolkit::instance().getOpenocdFile());
0232         }
0233 
0234     }
0235 
0236     return QUrl::fromLocalFile(exe);
0237 }
0238 
0239 
0240 bool ExecutePlugin::useTerminal(KDevelop::ILaunchConfiguration* cfg) const
0241 {
0242     if (!cfg)
0243     {
0244         return false;
0245     }
0246 
0247     return cfg->config().readEntry(ExecutePlugin::useTerminalEntry, false);
0248 }
0249 
0250 
0251 QString ExecutePlugin::terminal(KDevelop::ILaunchConfiguration* cfg) const
0252 {
0253     if (!cfg)
0254     {
0255         return QString();
0256     }
0257 
0258     return cfg->config().readEntry(ExecutePlugin::commandEntry, QString());
0259 }
0260 
0261 
0262 QUrl ExecutePlugin::workingDirectory(KDevelop::ILaunchConfiguration* cfg) const
0263 {
0264     if (!cfg)
0265     {
0266         return QUrl();
0267     }
0268 
0269     uint launcherIndex = cfg->config().readEntry(ExecutePlugin::launcherIndexEntry, 0);
0270 
0271     switch (launcherIndex)
0272     {
0273         case index::arduino:
0274             return cfg->config().readEntry(ExecutePlugin::openocdWorkEntry, QUrl());
0275         break;
0276 
0277         case index::openocd:
0278             return cfg->config().readEntry(ExecutePlugin::workingDirEntry, QUrl());
0279         break;
0280     }
0281 
0282     return QUrl();
0283 }
0284 
0285 
0286 QString ExecutePlugin::nativeAppConfigTypeId() const
0287 {
0288     return _nativeAppConfigTypeId;
0289 }
0290 
0291 
0292 #include "executeplugin.moc"