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  * Copyright 2009 Andreas Pakulat <apaku@gmx.de>
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU Library General Public License as
0008  * published by the Free Software Foundation; either version 2 of the
0009  * License, or (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public
0017  * License along with this program; if not, write to the
0018  * Free Software Foundation, Inc.,
0019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "launcherjob.h"
0023 #include "executeplugin.h"
0024 #include "toolkit.h"
0025 
0026 #include <QDebug>
0027 #include <QFileInfo>
0028 #include <QMessageBox>
0029 
0030 #include <KLocalizedString>
0031 #include <KShell>
0032 #include <KSharedConfig>
0033 #include <KConfigGroup>
0034 
0035 #include <interfaces/ilaunchconfiguration.h>
0036 #include <interfaces/iruncontroller.h>
0037 #include <outputview/outputmodel.h>
0038 #include <util/environmentprofilelist.h>
0039 
0040 #include <interfaces/icore.h>
0041 #include <interfaces/isession.h>
0042 #include <interfaces/iplugincontroller.h>
0043 #include <project/projectmodel.h>
0044 
0045 #include <execute/iexecuteplugin.h>
0046 
0047 #include "debug.h"
0048 
0049 using namespace KDevelop;
0050 
0051 Q_LOGGING_CATEGORY(LaMsg, "Kdev.embedded.la.msg")
0052 
0053 LauncherJob::LauncherJob(QObject* parent, KDevelop::ILaunchConfiguration* cfg)
0054     : KDevelop::OutputExecuteJob(parent)
0055     , m_cfgname(cfg->name())
0056 {
0057     qCDebug(LaMsg) << "LauncherJob::LauncherJob";
0058     qCDebug(LaMsg) << "name" << cfg->name();
0059     qCDebug(LaMsg) << "entryMap" << cfg->config().entryMap();
0060     qCDebug(LaMsg) << "groupList" << cfg->config().groupList();
0061     qCDebug(LaMsg) << "keyList" << cfg->config().keyList();
0062 
0063     setCapabilities(Killable);
0064 
0065     IExecutePlugin* iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevembedded-launcher"))->extension<IExecutePlugin>();
0066     Q_ASSERT(iface);
0067 
0068     KDevelop::EnvironmentProfileList l(KSharedConfig::openConfig());
0069     QString envProfileName = iface->environmentProfileName(cfg);
0070     qCDebug(LaMsg) << "LauncherJob::LauncherJob envProfileName" << envProfileName;
0071 
0072     QString err;
0073     QUrl executable = iface->executable(cfg, err);
0074     qCDebug(LaMsg) << "LauncherJob::LauncherJob executable" << executable;
0075 
0076     if (!err.isEmpty())
0077     {
0078         setError(-1);
0079         setErrorText(err);
0080         return;
0081     }
0082 
0083     if (envProfileName.isEmpty())
0084     {
0085         qWarning() << "Launch Configuration:" << cfg->name() << "no environment profile specified, looks like a broken "
0086                    "configuration, please check run configuration" << cfg->name()
0087                    << "Using default environment profile.";
0088         envProfileName = l.defaultProfileName();
0089     }
0090     setEnvironmentProfile(envProfileName);
0091 
0092     QStringList arguments = iface->arguments(cfg, err);
0093     qCDebug(LaMsg) << "LauncherJob::LauncherJob arguments" << arguments;
0094     if (!err.isEmpty())
0095     {
0096         setError(-2);
0097         setErrorText(err);
0098     }
0099 
0100     if (error() != 0)
0101     {
0102         qWarning() << "Launch Configuration:" << cfg->name() << "oops, problem" << errorText();
0103         return;
0104     }
0105 
0106     setStandardToolView(KDevelop::IOutputView::RunView);
0107     setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll);
0108     setFilteringStrategy(OutputModel::NativeAppErrorFilter);
0109     setProperties(DisplayStdout | DisplayStderr);
0110 
0111     // Now setup the process parameters
0112 
0113     QUrl wc = iface->workingDirectory(cfg);
0114     if (!wc.isValid() || wc.isEmpty())
0115     {
0116         wc = QUrl::fromLocalFile(QFileInfo(executable.toLocalFile()).absolutePath());
0117     }
0118     setWorkingDirectory(wc);
0119 
0120     qCDebug(EpMsg) << "setting app:" << executable << arguments;
0121 
0122     // Add terminal support in the future
0123     /*
0124     if (iface->useTerminal(cfg))
0125     {
0126         QStringList args = KShell::splitArgs(iface->terminal(cfg));
0127         for (QStringList::iterator it = args.begin(); it != args.end(); ++it)
0128         {
0129             if (*it == QLatin1String("%exe"))
0130             {
0131                 *it = KShell::quoteArg(executable.toLocalFile());
0132             }
0133             else if (*it == QLatin1String("%workdir"))
0134             {
0135                 *it = KShell::quoteArg(wc.toLocalFile());
0136             }
0137         }
0138         args.append(arguments);
0139         *this << args;
0140     }
0141     */
0142     *this << executable.toLocalFile();
0143     *this << arguments;
0144 
0145     setJobName(cfg->name());
0146 }
0147 
0148 LauncherJob* findNativeJob(KJob* j)
0149 {
0150     LauncherJob* job = qobject_cast<LauncherJob*>(j);
0151     if (!job)
0152     {
0153         const QList<LauncherJob*> jobs = j->findChildren<LauncherJob*>();
0154         if (!jobs.isEmpty())
0155             job = jobs.first();
0156     }
0157     return job;
0158 }
0159 
0160 void LauncherJob::start()
0161 {
0162     // We kill any execution of the configuration
0163     foreach (KJob* j, ICore::self()->runController()->currentJobs())
0164     {
0165         LauncherJob* job = findNativeJob(j);
0166         if (job && job != this && job->m_cfgname == m_cfgname)
0167         {
0168             QMessageBox::StandardButton button = QMessageBox::question(nullptr, i18n("Job already running"), i18n("'%1' is already being executed. Should we kill the previous instance?", m_cfgname));
0169             if (button != QMessageBox::No)
0170                 j->kill();
0171         }
0172     }
0173 
0174     OutputExecuteJob::start();
0175 }
0176 
0177 void LauncherJob::output(const QStringList& l)
0178 {
0179     if (KDevelop::OutputModel* m = model())
0180     {
0181         m->appendLines(l);
0182     }
0183 }
0184 
0185 KDevelop::OutputModel* LauncherJob::model()
0186 {
0187     return dynamic_cast<KDevelop::OutputModel*>(KDevelop::OutputJob::model());
0188 }