diff --git a/plugins/execute/nativeappjob.cpp b/plugins/execute/nativeappjob.cpp index 0f4017035..37c8fb421 100644 --- a/plugins/execute/nativeappjob.cpp +++ b/plugins/execute/nativeappjob.cpp @@ -1,142 +1,155 @@ /* This file is part of KDevelop Copyright 2009 Andreas Pakulat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "nativeappjob.h" #include #include #include +#include #include #include #include #include #include #include #include #include #include #include -#include "iexecuteplugin.h" +#include "executeplugin.h" #include "debug.h" using namespace KDevelop; NativeAppJob::NativeAppJob(QObject* parent, KDevelop::ILaunchConfiguration* cfg) : KDevelop::OutputExecuteJob( parent ) - , m_cfgname(cfg->name()) + , m_name(cfg->name()) { + { + auto cfgGroup = cfg->config(); + if (cfgGroup.readEntry(ExecutePlugin::isExecutableEntry, false)) { + m_name = cfgGroup.readEntry(ExecutePlugin::executableEntry, cfg->name()).section('/', -1); + } + } setCapabilities(Killable); IExecutePlugin* iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecutePlugin"), QStringLiteral("kdevexecute"))->extension(); Q_ASSERT(iface); KDevelop::EnvironmentGroupList l(KSharedConfig::openConfig()); QString envgrp = iface->environmentGroup(cfg); QString err; QUrl executable = iface->executable( cfg, err ); if( !err.isEmpty() ) { setError( -1 ); setErrorText( err ); return; } if( envgrp.isEmpty() ) { qWarning() << "Launch Configuration:" << cfg->name() << i18n("No environment group specified, looks like a broken " "configuration, please check run configuration '%1'. " "Using default environment group.", cfg->name() ); envgrp = l.defaultGroup(); } setEnvironmentProfile(envgrp); QStringList arguments = iface->arguments( cfg, err ); if( !err.isEmpty() ) { setError( -2 ); setErrorText( err ); } if( error() != 0 ) { qWarning() << "Launch Configuration:" << cfg->name() << "oops, problem" << errorText(); return; } setStandardToolView(KDevelop::IOutputView::RunView); setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll); setFilteringStrategy(OutputModel::NativeAppErrorFilter); setProperties(DisplayStdout | DisplayStderr); // Now setup the process parameters QUrl wc = iface->workingDirectory( cfg ); if( !wc.isValid() || wc.isEmpty() ) { wc = QUrl::fromLocalFile( QFileInfo( executable.toLocalFile() ).absolutePath() ); } setWorkingDirectory( wc ); qCDebug(PLUGIN_EXECUTE) << "setting app:" << executable << arguments; if (iface->useTerminal(cfg)) { QString terminalCommand = iface->terminal(cfg); terminalCommand.replace(QLatin1String("%exe"), KShell::quoteArg( executable.toLocalFile()) ); terminalCommand.replace(QLatin1String("%workdir"), KShell::quoteArg( wc.toLocalFile()) ); QStringList args = KShell::splitArgs(terminalCommand); args.append( arguments ); *this << args; } else { *this << executable.toLocalFile(); *this << arguments; } - setJobName(cfg->name()); + setJobName(m_name); } NativeAppJob* findNativeJob(KJob* j) { NativeAppJob* job = qobject_cast(j); if (!job) { const QList jobs = j->findChildren(); if (!jobs.isEmpty()) job = jobs.first(); } return job; } void NativeAppJob::start() { // we kill any execution of the configuration - foreach(KJob* j, ICore::self()->runController()->currentJobs()) { - NativeAppJob* job = findNativeJob(j); - if (job && job != this && job->m_cfgname == m_cfgname) { - QMessageBox::StandardButton button = QMessageBox::question(nullptr, i18n("Job already running"), i18n("'%1' is already being executed. Should we kill the previous instance?", m_cfgname)); - if (button != QMessageBox::No && ICore::self()->runController()->currentJobs().contains(j)) - j->kill(); + auto currentJobs = ICore::self()->runController()->currentJobs(); + for (auto it = currentJobs.begin(); it != currentJobs.end();) { + NativeAppJob* job = findNativeJob(*it); + if (job && job != this && job->m_name == m_name) { + QMessageBox::StandardButton button = QMessageBox::question(nullptr, i18n("Job already running"), i18n("'%1' is already being executed. Should we kill the previous instance?", m_name)); + if (button != QMessageBox::No && ICore::self()->runController()->currentJobs().contains(*it)) { + (*it)->kill(); + } + currentJobs = ICore::self()->runController()->currentJobs(); + it = currentJobs.begin(); + } else { + ++it; } } OutputExecuteJob::start(); } diff --git a/plugins/execute/nativeappjob.h b/plugins/execute/nativeappjob.h index 45a287aa5..1e530b785 100644 --- a/plugins/execute/nativeappjob.h +++ b/plugins/execute/nativeappjob.h @@ -1,47 +1,47 @@ /* This file is part of KDevelop Copyright 2009 Andreas Pakulat This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVPLATFORM_PLUGIN_NATIVEAPPJOB_H #define KDEVPLATFORM_PLUGIN_NATIVEAPPJOB_H #include #include namespace KDevelop { class ILaunchConfiguration; } class KProcess; class NativeAppJob : public KDevelop::OutputExecuteJob { Q_OBJECT public: NativeAppJob( QObject* parent, KDevelop::ILaunchConfiguration* cfg ); void start() override; private: - QString m_cfgname; + QString m_name; }; #endif diff --git a/util/executecompositejob.cpp b/util/executecompositejob.cpp index f05c1ed8c..689c6d7ce 100644 --- a/util/executecompositejob.cpp +++ b/util/executecompositejob.cpp @@ -1,147 +1,149 @@ /* This file is part of KDevelop Copyright 2007-2008 Hamish Rodda This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "executecompositejob.h" #include "debug.h" namespace KDevelop { class ExecuteCompositeJobPrivate { public: void startNextJob(KJob* job); bool m_killing = false; bool m_abortOnError = true; int m_jobIndex = -1; int m_jobCount = 0; }; ExecuteCompositeJob::ExecuteCompositeJob(QObject* parent, const QList& jobs) : KCompositeJob(parent), d(new ExecuteCompositeJobPrivate) { setCapabilities(Killable); qCDebug(UTIL) << "execute composite" << jobs; foreach(KJob* job, jobs) { if (!job) { qCWarning(UTIL) << "Added null job!"; continue; } addSubjob(job); if (objectName().isEmpty()) setObjectName(job->objectName()); } } ExecuteCompositeJob::~ExecuteCompositeJob() { delete d; } void ExecuteCompositeJobPrivate::startNextJob(KJob* job) { ++m_jobIndex; qCDebug(UTIL) << "starting:" << job; job->start(); } void ExecuteCompositeJob::start() { if(hasSubjobs()) { d->startNextJob(subjobs().first()); } else { emitResult(); } } bool ExecuteCompositeJob::addSubjob(KJob* job) { const bool success = KCompositeJob::addSubjob(job); if (!success) return false; ++d->m_jobCount; connect(job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(slotPercent(KJob*, unsigned long))); return true; } void ExecuteCompositeJob::slotPercent(KJob* job, unsigned long percent) { Q_UNUSED(job); Q_ASSERT(d->m_jobCount > 0); Q_ASSERT(d->m_jobIndex >= 0 && d->m_jobIndex < d->m_jobCount); const float ratio = (float)d->m_jobIndex / d->m_jobCount; const unsigned long totalPercent = ratio * 100 + ((float)percent / d->m_jobCount); emitPercent(totalPercent, 100); } void ExecuteCompositeJob::slotResult(KJob* job) { disconnect(job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(slotPercent(KJob*, unsigned long))); // jobIndex + 1 because this job just finished const float ratio = d->m_jobIndex != -1 ? (d->m_jobIndex + 1.0) / d->m_jobCount : 1.0; emitPercent(ratio * 100, 100); qCDebug(UTIL) << "finished: "<< job << job->error() << "percent:" << ratio * 100; + bool emitDone = false; if (d->m_abortOnError && job->error()) { qCDebug(UTIL) << "JOB ERROR:" << job->error() << job->errorString(); - KCompositeJob::slotResult(job); + KCompositeJob::slotResult(job); // calls emitResult() + emitDone = true; } else removeSubjob(job); if (hasSubjobs() && !error() && !d->m_killing) { qCDebug(UTIL) << "remaining: " << subjobs().count() << subjobs(); d->startNextJob(subjobs().first()); - } else { + } else if (!emitDone) { setError(job->error()); setErrorText(job->errorString()); emitResult(); } } bool ExecuteCompositeJob::doKill() { qCDebug(UTIL) << "Killing subjobs:" << subjobs().size(); d->m_killing = true; while(hasSubjobs()) { KJob* j = subjobs().first(); if (!j || j->kill()) { removeSubjob(j); } else { return false; } } return true; } void ExecuteCompositeJob::setAbortOnError(bool abort) { d->m_abortOnError = abort; } }