00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <unistd.h>
00010 #include <qapplication.h>
00011 #include <qeventloop.h>
00012 #include "exceptionmanager.h"
00013 #include "common.h"
00014 #include "domain.h"
00015 #include "myprocess.h"
00016
00017 MyProcess::MyProcess(QObject *go, Git* g, const QString& wd, bool err) : QProcess(g) {
00018
00019 guiObject = go;
00020 git = g;
00021 workDir = wd;
00022 receiver = NULL;
00023 runOutput = NULL;
00024 errorReportingEnabled = err;
00025 canceling = async = false;
00026 exitStatus = true;
00027 }
00028
00029 bool MyProcess::runAsync(SCRef rc, QObject* rcv, SCRef buf, QStringList* env) {
00030
00031 async = true;
00032 runCmd = rc;
00033 receiver = rcv;
00034 setupSignals();
00035 if (!launchMe(runCmd, buf, env))
00036 return false;
00037
00038 return true;
00039 }
00040
00041 bool MyProcess::runSync(SCRef rc, QByteArray* ro, QObject* rcv, SCRef buf, QStringList* env) {
00042
00043 async = false;
00044 runCmd = rc;
00045 runOutput = ro;
00046 receiver = rcv;
00047 if (runOutput)
00048 runOutput->resize(0);
00049
00050 setupSignals();
00051
00052 busy = true;
00053
00054 if (!launchMe(runCmd, buf, env))
00055 return false;
00056
00057
00058
00059 Domain* d = git->curContext();
00060 git->setCurContext(NULL);
00061
00062 EM_BEFORE_PROCESS_EVENTS;
00063
00064 while (busy) {
00065
00066
00067
00068
00069 on_readyReadStdout();
00070 usleep(20000);
00071 isRunning();
00072 }
00073
00074 EM_AFTER_PROCESS_EVENTS;
00075
00076 if (git->curContext())
00077 qDebug("ASSERT in MyProcess::runSync, context is %p "
00078 "instead of NULL", (void*)git->curContext());
00079
00080 git->setCurContext(d);
00081
00082 return exitStatus;
00083 }
00084
00085 void MyProcess::setupSignals() {
00086
00087 connect(git, SIGNAL(cancelAllProcesses()), this, SLOT(on_cancel()));
00088 connect(this, SIGNAL(readyReadStdout()), this, SLOT(on_readyReadStdout()));
00089 connect(this, SIGNAL(processExited()), this, SLOT(on_processExited()));
00090 if (receiver) {
00091 connect(this, SIGNAL(readyReadStderr()), this, SLOT(on_readyReadStderr()));
00092 connect(this, SIGNAL(procDataReady(const QByteArray&)),
00093 receiver, SLOT(on_procDataReady(const QByteArray&)));
00094 connect(this, SIGNAL(eof()), receiver, SLOT(on_eof()));
00095 }
00096 Domain* d = git->curContext();
00097 if (d)
00098 connect(d, SIGNAL(cancelDomainProcesses()), this, SLOT(on_cancel()));
00099 }
00100
00101 void MyProcess::sendErrorMsg(bool notStarted) {
00102
00103 if (!errorReportingEnabled)
00104 return;
00105
00106 QString errorDesc(readStderr());
00107 if (notStarted)
00108 errorDesc = QString::fromAscii("Unable to start the process!");
00109
00110 const QString cmd(arguments().join(" "));
00111 MainExecErrorEvent* e = new MainExecErrorEvent(cmd, errorDesc);
00112 QApplication::postEvent(guiObject, e);
00113 }
00114
00115 void MyProcess::appendSystemEnvironment(QStringList* env) {
00116
00117 if (!env)
00118 return;
00119
00120
00121
00122
00123 char** envval = ::environ;
00124 for ( ; *envval; envval++)
00125 *env << QString(*envval);
00126 }
00127
00128 bool MyProcess::launchMe(SCRef runCmd, SCRef buf, QStringList* env) {
00129
00130 const QStringList sl(splitArgList(runCmd));
00131 setArguments(sl);
00132 setWorkingDirectory(workDir);
00133 appendSystemEnvironment(env);
00134
00135 connect(this, SIGNAL(launchFinished()), this, SLOT(on_launchFinished()));
00136 isLaunching = true;
00137
00138 bool ok = launch(buf, env);
00139 if (!ok)
00140 sendErrorMsg(true);
00141
00142 while (isLaunching)
00143 EM_PROCESS_EVENTS;
00144
00145 return ok;
00146 }
00147
00148 void MyProcess::on_launchFinished() {
00149
00150 disconnect(this, SIGNAL(launchFinished()), this, SLOT(on_launchFinished()));
00151 isLaunching = false;
00152 }
00153
00154 void MyProcess::on_readyReadStdout() {
00155
00156
00157
00158
00159 if (canceling)
00160 return;
00161
00162 if (receiver)
00163 emit procDataReady(readStdout());
00164
00165 else if (runOutput)
00166 QGit::baAppend(*runOutput, readStdout());
00167 else
00168 readStdout();
00169 }
00170
00171 void MyProcess::on_readyReadStderr() {
00172
00173 if (canceling)
00174 return;
00175
00176 if (receiver)
00177 emit procDataReady(readStderr());
00178 else
00179 dbs("ASSERT in myReadFromStderr: NULL receiver");
00180 }
00181
00182 void MyProcess::on_processExited() {
00183
00184 if (canceling || !normalExit() || canReadLineStderr())
00185 exitStatus = false;
00186
00187 if (!canceling) {
00188
00189 if (receiver)
00190 emit eof();
00191
00192 if (!exitStatus)
00193 sendErrorMsg();
00194 }
00195 busy = false;
00196 if (async)
00197 deleteLater();
00198 }
00199
00200 void MyProcess::on_cancel() {
00201
00202 canceling = true;
00203 QProcess::tryTerminate();
00204 }
00205
00206 const QStringList MyProcess::splitArgList(SCRef cmd) {
00207
00208
00209
00210
00211
00212
00213
00214 if (!( cmd.contains(QGit::QUOTE_CHAR)
00215 || cmd.contains("\"")
00216 || cmd.contains("\'")))
00217 return QStringList::split(' ', cmd);
00218
00219
00220
00221 const QString sepList("#%&!?");
00222 uint i = 0;
00223 while (cmd.contains(sepList[i]) && i < sepList.length())
00224 i++;
00225
00226 if (i == sepList.length()) {
00227 dbs("ASSERT no unique separator found");
00228 return QStringList();
00229 }
00230 const QChar& sepChar(sepList[i]);
00231
00232
00233 QString newCmd(cmd);
00234 newCmd.replace(QChar(' '), sepChar);
00235
00236
00237 restoreSpaces(newCmd, sepChar);
00238
00239
00240
00241
00242
00243 newCmd.remove(QGit::QUOTE_CHAR);
00244
00245
00246
00247 QStringList sl(QStringList::split(sepChar, newCmd));
00248 QStringList::iterator it(sl.begin());
00249 for ( ; it != sl.end(); ++it) {
00250 if (((*it).left(1) == "\"" && (*it).right(1) == "\"") ||
00251 ((*it).left(1) == "\'" && (*it).right(1) == "\'"))
00252 *it = (*it).mid(1, (*it).length() - 2);
00253 }
00254 return sl;
00255 }
00256
00257 void MyProcess::restoreSpaces(QString& newCmd, SCRef sepChar) {
00258
00259
00260 QString quoteChar;
00261 bool replace = false;
00262 for (uint i = 0; i < newCmd.length(); i++) {
00263
00264 const QChar& c = newCmd[i];
00265
00266 if ( !replace
00267 && (c == QGit::QUOTE_CHAR || c == "\"" || c == "\'")
00268 && (newCmd.contains(c) % 2 == 0)) {
00269
00270 replace = true;
00271 quoteChar = c;
00272 continue;
00273 }
00274 if (replace && (c == quoteChar)) {
00275 replace = false;
00276 continue;
00277 }
00278 if (replace && c == sepChar)
00279 newCmd[i] = QChar(' ');
00280 }
00281 }