File indexing completed on 2024-05-05 04:38:43
0001 /* 0002 SPDX-FileCopyrightText: 2009 Andreas Pakulat <apaku@gmx.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "commandexecutor.h" 0008 0009 #include "processlinemaker.h" 0010 0011 #include <KProcess> 0012 #include <KShell> 0013 0014 #include <QMap> 0015 #include <QStringList> 0016 #include <QString> 0017 0018 namespace KDevelop { 0019 0020 class CommandExecutorPrivate 0021 { 0022 public: 0023 explicit CommandExecutorPrivate(CommandExecutor* cmd) 0024 : m_exec(cmd) 0025 , m_useShell(false) 0026 { 0027 } 0028 CommandExecutor* m_exec; 0029 KProcess* m_process; 0030 ProcessLineMaker* m_lineMaker; 0031 QString m_command; 0032 QStringList m_args; 0033 QString m_workDir; 0034 QMap<QString, QString> m_env; 0035 bool m_useShell; 0036 void procError(QProcess::ProcessError error) 0037 { 0038 Q_UNUSED(error) 0039 m_lineMaker->flushBuffers(); 0040 emit m_exec->failed(error); 0041 } 0042 void procFinished(int code, QProcess::ExitStatus status) 0043 { 0044 m_lineMaker->flushBuffers(); 0045 if (status == QProcess::NormalExit) 0046 emit m_exec->completed(code); 0047 } 0048 }; 0049 0050 CommandExecutor::CommandExecutor(const QString& command, QObject* parent) 0051 : QObject(parent) 0052 , d_ptr(new CommandExecutorPrivate(this)) 0053 { 0054 Q_D(CommandExecutor); 0055 0056 d->m_process = new KProcess(this); 0057 d->m_process->setOutputChannelMode(KProcess::SeparateChannels); 0058 d->m_lineMaker = new ProcessLineMaker(d->m_process); 0059 d->m_command = command; 0060 connect(d->m_lineMaker, &ProcessLineMaker::receivedStdoutLines, 0061 this, &CommandExecutor::receivedStandardOutput); 0062 connect(d->m_lineMaker, &ProcessLineMaker::receivedStderrLines, 0063 this, &CommandExecutor::receivedStandardError); 0064 connect(d->m_process, &QProcess::errorOccurred, 0065 this, [this](QProcess::ProcessError error) { 0066 Q_D(CommandExecutor); 0067 d->procError(error); 0068 }); 0069 connect(d->m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), 0070 this, [this](int code, QProcess::ExitStatus status) { 0071 Q_D(CommandExecutor); 0072 d->procFinished(code, status); 0073 }); 0074 } 0075 0076 CommandExecutor::~CommandExecutor() 0077 { 0078 Q_D(CommandExecutor); 0079 0080 delete d->m_process; 0081 delete d->m_lineMaker; 0082 } 0083 0084 void CommandExecutor::setEnvironment(const QMap<QString, QString>& env) 0085 { 0086 Q_D(CommandExecutor); 0087 0088 d->m_env = env; 0089 } 0090 0091 void CommandExecutor::setEnvironment(const QStringList& env) 0092 { 0093 Q_D(CommandExecutor); 0094 0095 QMap<QString, QString> envmap; 0096 for (const QString& var : env) { 0097 int sep = var.indexOf(QLatin1Char('=')); 0098 envmap.insert(var.left(sep), var.mid(sep + 1)); 0099 } 0100 0101 d->m_env = envmap; 0102 } 0103 0104 void CommandExecutor::setArguments(const QStringList& args) 0105 { 0106 Q_D(CommandExecutor); 0107 0108 d->m_args = args; 0109 } 0110 0111 void CommandExecutor::setWorkingDirectory(const QString& dir) 0112 { 0113 Q_D(CommandExecutor); 0114 0115 d->m_workDir = dir; 0116 } 0117 0118 bool CommandExecutor::useShell() const 0119 { 0120 Q_D(const CommandExecutor); 0121 0122 return d->m_useShell; 0123 } 0124 0125 void CommandExecutor::setUseShell(bool shell) 0126 { 0127 Q_D(CommandExecutor); 0128 0129 d->m_useShell = shell; 0130 } 0131 0132 void CommandExecutor::start() 0133 { 0134 Q_D(CommandExecutor); 0135 0136 for (auto it = d->m_env.constBegin(), itEnd = d->m_env.constEnd(); it != itEnd; ++it) { 0137 d->m_process->setEnv(it.key(), it.value()); 0138 } 0139 0140 d->m_process->setWorkingDirectory(d->m_workDir); 0141 if (!d->m_useShell) { 0142 d->m_process->setProgram(d->m_command, d->m_args); 0143 } else { 0144 QStringList arguments; 0145 arguments.reserve(d->m_args.size()); 0146 for (const QString& a : qAsConst(d->m_args)) { 0147 arguments << KShell::quoteArg(a); 0148 } 0149 0150 d->m_process->setShellCommand(d->m_command + QLatin1Char(' ') + arguments.join(QLatin1Char(' '))); 0151 } 0152 0153 d->m_process->start(); 0154 } 0155 0156 void CommandExecutor::setCommand(const QString& command) 0157 { 0158 Q_D(CommandExecutor); 0159 0160 d->m_command = command; 0161 } 0162 0163 void CommandExecutor::kill() 0164 { 0165 Q_D(CommandExecutor); 0166 0167 d->m_process->kill(); 0168 } 0169 0170 QString CommandExecutor::command() const 0171 { 0172 Q_D(const CommandExecutor); 0173 0174 return d->m_command; 0175 } 0176 0177 QStringList CommandExecutor::arguments() const 0178 { 0179 Q_D(const CommandExecutor); 0180 0181 return d->m_args; 0182 } 0183 0184 QString CommandExecutor::workingDirectory() const 0185 { 0186 Q_D(const CommandExecutor); 0187 0188 return d->m_workDir; 0189 } 0190 0191 } 0192 0193 #include "moc_commandexecutor.cpp"