File indexing completed on 2024-04-28 04:38:40
0001 /* 0002 SPDX-FileCopyrightText: 2009 Andreas Pakulat <apaku@gmx.de> 0003 SPDX-FileCopyrightText: 2009 Niko Sams <niko.sams@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "scriptappjob.h" 0009 #include "executescriptplugin.h" 0010 0011 #include <QFileInfo> 0012 0013 #include <KLocalizedString> 0014 #include <KProcess> 0015 #include <KSharedConfig> 0016 #include <KShell> 0017 0018 #include <interfaces/ilaunchconfiguration.h> 0019 #include <interfaces/iruntimecontroller.h> 0020 #include <interfaces/iruntime.h> 0021 #include <outputview/outputmodel.h> 0022 #include <outputview/outputdelegate.h> 0023 #include <util/processlinemaker.h> 0024 #include <util/environmentprofilelist.h> 0025 0026 #include <interfaces/icore.h> 0027 #include <interfaces/iplugincontroller.h> 0028 #include <interfaces/idocumentcontroller.h> 0029 #include <project/projectmodel.h> 0030 #include <util/path.h> 0031 0032 #include "iexecutescriptplugin.h" 0033 #include "debug.h" 0034 0035 using namespace KDevelop; 0036 0037 ScriptAppJob::ScriptAppJob(ExecuteScriptPlugin* parent, KDevelop::ILaunchConfiguration* cfg) 0038 : KDevelop::OutputJob( parent ), proc(new KProcess( this )), lineMaker(new KDevelop::ProcessLineMaker( proc, this )) 0039 { 0040 qCDebug(PLUGIN_EXECUTESCRIPT) << "creating script app job"; 0041 setCapabilities(Killable); 0042 0043 auto* iface = KDevelop::ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IExecuteScriptPlugin"))->extension<IExecuteScriptPlugin>(); 0044 Q_ASSERT(iface); 0045 0046 const KDevelop::EnvironmentProfileList environmentProfiles(KSharedConfig::openConfig()); 0047 QString envProfileName = iface->environmentProfileName(cfg); 0048 0049 QString err; 0050 QString interpreterString = iface->interpreter( cfg, err ); 0051 // check for errors happens in the executescript plugin already 0052 KShell::Errors err_; 0053 QStringList interpreter = KShell::splitArgs( interpreterString, KShell::TildeExpand | KShell::AbortOnMeta, &err_ ); 0054 if ( interpreter.isEmpty() ) { 0055 // This should not happen, because of the checks done in the executescript plugin 0056 qCWarning(PLUGIN_EXECUTESCRIPT) << "no interpreter specified"; 0057 return; 0058 } 0059 0060 if( !err.isEmpty() ) 0061 { 0062 setError( -1 ); 0063 setErrorText( err ); 0064 return; 0065 } 0066 0067 QUrl script; 0068 if( !iface->runCurrentFile( cfg ) ) 0069 { 0070 script = iface->script( cfg, err ); 0071 } else { 0072 KDevelop::IDocument* document = KDevelop::ICore::self()->documentController()->activeDocument(); 0073 if( !document ) 0074 { 0075 setError( -1 ); 0076 setErrorText( i18n( "There is no active document to launch." ) ); 0077 return; 0078 } 0079 script = ICore::self()->runtimeController()->currentRuntime()->pathInRuntime(KDevelop::Path(document->url())).toUrl(); 0080 } 0081 0082 if( !err.isEmpty() ) 0083 { 0084 setError( -3 ); 0085 setErrorText( err ); 0086 return; 0087 } 0088 0089 QString remoteHost = iface->remoteHost( cfg, err ); 0090 if( !err.isEmpty() ) 0091 { 0092 setError( -4 ); 0093 setErrorText( err ); 0094 return; 0095 } 0096 0097 if (envProfileName.isEmpty()) { 0098 qCWarning(PLUGIN_EXECUTESCRIPT) << "Launch Configuration:" << cfg->name() << i18n("No environment profile specified, looks like a broken " 0099 "configuration, please check run configuration '%1'. " 0100 "Using default environment profile.", cfg->name() ); 0101 envProfileName = environmentProfiles.defaultProfileName(); 0102 } 0103 0104 QStringList arguments = iface->arguments( cfg, err ); 0105 if( !err.isEmpty() ) 0106 { 0107 setError( -2 ); 0108 setErrorText( err ); 0109 } 0110 0111 if( error() != 0 ) 0112 { 0113 qCWarning(PLUGIN_EXECUTESCRIPT) << "Launch Configuration:" << cfg->name() << "oops, problem" << errorText(); 0114 return; 0115 } 0116 0117 auto currentFilterMode = static_cast<KDevelop::OutputModel::OutputFilterStrategy>( iface->outputFilterModeId( cfg ) ); 0118 0119 setStandardToolView(KDevelop::IOutputView::RunView); 0120 setBehaviours(KDevelop::IOutputView::AllowUserClose | KDevelop::IOutputView::AutoScroll); 0121 auto* m = new KDevelop::OutputModel; 0122 m->setFilteringStrategy(currentFilterMode); 0123 setModel( m ); 0124 setDelegate( new KDevelop::OutputDelegate ); 0125 0126 connect( lineMaker, &ProcessLineMaker::receivedStdoutLines, model(), &OutputModel::appendLines ); 0127 connect(proc, &QProcess::errorOccurred, this, &ScriptAppJob::processError); 0128 connect( proc, QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished), this, &ScriptAppJob::processFinished ); 0129 0130 // Now setup the process parameters 0131 0132 proc->setEnvironment(environmentProfiles.createEnvironment(envProfileName, proc->systemEnvironment())); 0133 QUrl wc = iface->workingDirectory( cfg ); 0134 if( !wc.isValid() || wc.isEmpty() ) 0135 { 0136 wc = QUrl::fromLocalFile( QFileInfo( script.toLocalFile() ).absolutePath() ); 0137 } 0138 proc->setWorkingDirectory( ICore::self()->runtimeController()->currentRuntime()->pathInRuntime(KDevelop::Path(wc)).toLocalFile() ); 0139 proc->setProperty( "executable", interpreter.first() ); 0140 0141 QStringList program; 0142 if (!remoteHost.isEmpty()) { 0143 program << QStringLiteral("ssh"); 0144 QStringList parts = remoteHost.split(QLatin1Char(':')); 0145 program << parts.first(); 0146 if (parts.length() > 1) { 0147 program << QLatin1String("-p ") + parts.at(1); 0148 } 0149 } 0150 program << interpreter; 0151 program << script.toLocalFile(); 0152 program << arguments; 0153 0154 qCDebug(PLUGIN_EXECUTESCRIPT) << "setting app:" << program; 0155 0156 proc->setOutputChannelMode(KProcess::MergedChannels); 0157 0158 proc->setProgram( program ); 0159 0160 setTitle(cfg->name()); 0161 } 0162 0163 0164 void ScriptAppJob::start() 0165 { 0166 qCDebug(PLUGIN_EXECUTESCRIPT) << "launching?" << proc; 0167 if( proc ) 0168 { 0169 startOutput(); 0170 appendLine( i18n("Starting: %1", proc->program().join(QLatin1Char( ' ' ) ) ) ); 0171 ICore::self()->runtimeController()->currentRuntime()->startProcess(proc); 0172 } else 0173 { 0174 qCWarning(PLUGIN_EXECUTESCRIPT) << "No process, something went wrong when creating the job"; 0175 // No process means we've returned early on from the constructor, some bad error happened 0176 emitResult(); 0177 } 0178 } 0179 0180 bool ScriptAppJob::doKill() 0181 { 0182 if( proc ) { 0183 proc->kill(); 0184 appendLine( i18n( "*** Killed Application ***" ) ); 0185 } 0186 return true; 0187 } 0188 0189 0190 void ScriptAppJob::processFinished( int exitCode , QProcess::ExitStatus status ) 0191 { 0192 lineMaker->flushBuffers(); 0193 0194 if (exitCode == 0 && status == QProcess::NormalExit) { 0195 appendLine( i18n("*** Exited normally ***") ); 0196 } else if (status == QProcess::NormalExit) { 0197 appendLine( i18n("*** Exited with return code: %1 ***", QString::number(exitCode)) ); 0198 setError(OutputJob::FailedShownError); 0199 } else if (error() == KJob::KilledJobError) { 0200 appendLine( i18n("*** Process aborted ***") ); 0201 setError(KJob::KilledJobError); 0202 } else { 0203 appendLine( i18n("*** Crashed with return code: %1 ***", QString::number(exitCode)) ); 0204 setError(OutputJob::FailedShownError); 0205 } 0206 qCDebug(PLUGIN_EXECUTESCRIPT) << "Process done"; 0207 emitResult(); 0208 } 0209 0210 void ScriptAppJob::processError( QProcess::ProcessError error ) 0211 { 0212 qCDebug(PLUGIN_EXECUTESCRIPT) << proc->readAllStandardError(); 0213 qCDebug(PLUGIN_EXECUTESCRIPT) << proc->readAllStandardOutput(); 0214 qCDebug(PLUGIN_EXECUTESCRIPT) << proc->errorString(); 0215 if( error == QProcess::FailedToStart ) 0216 { 0217 setError( FailedShownError ); 0218 QString errmsg = i18n("*** Could not start program '%1'. Make sure that the " 0219 "path is specified correctly ***", proc->program().join(QLatin1Char( ' ' ) ) ); 0220 appendLine( errmsg ); 0221 setErrorText( errmsg ); 0222 emitResult(); 0223 } 0224 qCDebug(PLUGIN_EXECUTESCRIPT) << "Process error"; 0225 } 0226 0227 void ScriptAppJob::appendLine(const QString& l) 0228 { 0229 if (KDevelop::OutputModel* m = model()) { 0230 m->appendLine(l); 0231 } 0232 } 0233 0234 KDevelop::OutputModel* ScriptAppJob::model() 0235 { 0236 return qobject_cast<KDevelop::OutputModel*>(OutputJob::model()); 0237 } 0238 0239 #include "moc_scriptappjob.cpp"