Add line for debugging
[kdevelopdvcssupport.git] / vcs / dvcs / dvcsjob.cpp
blobaed208c11c50039f9392d5e5de5c8a4039698ea1
1 /***************************************************************************
2 * This file was partly taken from KDevelop's cvs plugin *
3 * Copyright 2002-2003 Christian Loose <christian.loose@hamburg.de> *
4 * Copyright 2007 Robert Gruber <rgruber@users.sourceforge.net> *
5 * *
6 * Adapted for DVCS *
7 * Copyright 2008 Evgeniy Ivanov <powerfox@kde.ru> *
8 * *
9 * This program is free software; you can redistribute it and/or *
10 * modify it under the terms of the GNU General Public License as *
11 * published by the Free Software Foundation; either version 2 of *
12 * the License or (at your option) version 3 or any later version *
13 * accepted by the membership of KDE e.V. (or its successor approved *
14 * by the membership of KDE e.V.), which shall act as a proxy *
15 * defined in Section 14 of version 3 of the license. *
16 * *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
24 ***************************************************************************/
26 #include "dvcsjob.h"
28 #include <QtCore/QFile>
29 #include <QtCore/QFileInfo>
30 #include <QtCore/QList>
31 #include <QtCore/QStringList>
33 #include <KDE/KDebug>
34 #include <KDE/KLocale>
36 #include <util/processlinemaker.h>
37 #include <interfaces/iplugin.h>
39 struct DVCSjobPrivate
41 DVCSjobPrivate() : commMode(KProcess::SeparateChannels), vcsplugin(0)
43 childproc = new KProcess;
44 lineMaker = new KDevelop::ProcessLineMaker( childproc );
45 isRunning = failed = wasStarted = false;
48 ~DVCSjobPrivate() {
49 if (lineMaker) delete lineMaker;
50 if (childproc) delete childproc;
53 KDevelop::ProcessLineMaker* lineMaker;
55 KProcess* childproc;
56 QStringList command;
57 QString server;
58 QString directory;
59 bool isRunning;
60 bool wasStarted;
61 bool failed;
62 QStringList outputLines;
63 KProcess::OutputChannelMode commMode;
64 KDevelop::IPlugin* vcsplugin;
67 DVCSjob::DVCSjob(KDevelop::IPlugin* parent)
68 : VcsJob(parent), d(new DVCSjobPrivate)
70 d->vcsplugin = parent;
73 DVCSjob::~DVCSjob()
75 delete d;
78 void DVCSjob::clear()
80 //Do not use KProcess::clearEnvironment() (it sets the environment to kde_dummy.
81 //Also DVCSjob can't set it, so it's ok.
82 d->command.clear();
83 d->outputLines.clear();
84 d->server.clear();
85 d->directory.clear();
86 d->isRunning = d->failed = d->wasStarted = false;
89 void DVCSjob::setServer(const QString& server)
91 d->server = server;
94 void DVCSjob::setDirectory(const QString& directory)
96 d->directory = directory;
99 void DVCSjob::setStandardInputFile(const QString &fileName)
101 d->childproc->setStandardInputFile(fileName);
104 QString DVCSjob::getDirectory()
106 return d->directory;
109 bool DVCSjob::isRunning() const
111 return d->isRunning;
114 DVCSjob& DVCSjob::operator<<(const QString& arg)
116 d->command.append( arg );
117 return *this;
120 DVCSjob& DVCSjob::operator<<(const char* arg)
122 d->command.append( arg );
123 return *this;
126 DVCSjob& DVCSjob::operator<<(const QStringList& args)
128 d->command << args;
129 return *this;
132 QString DVCSjob::dvcsCommand() const
134 return d->command.join(" ");
137 QString DVCSjob::output() const
139 return d->outputLines.join("\n");
142 void DVCSjob::setResults(const QVariant &res)
144 results = res;
147 QVariant DVCSjob::fetchResults()
149 return results;
152 void DVCSjob::setExitStatus(const bool exitStatus)
154 d->failed = exitStatus;
157 void DVCSjob::start()
159 Q_ASSERT_X(!d->isRunning, "DVCSjob::start", "Another proccess was started using this job class");
160 d->wasStarted = true;
162 //do not allow to run commands in the application's working dir
163 //TODO: change directory to KUrl, check if it's a relative path
164 if(d->directory.isEmpty() )
166 kDebug() << "No working directory specified for DVCS command";
167 slotProcessError(QProcess::UnknownError);
168 return;
171 kDebug() << "Working directory:" << d->directory;
172 d->childproc->setWorkingDirectory(d->directory);
175 connect(d->childproc, SIGNAL(finished(int, QProcess::ExitStatus)),
176 SLOT(slotProcessExited(int, QProcess::ExitStatus)));
177 connect(d->childproc, SIGNAL(error( QProcess::ProcessError )),
178 SLOT(slotProcessError(QProcess::ProcessError)));
180 connect(d->lineMaker, SIGNAL(receivedStdoutLines(const QStringList&)),
181 SLOT(slotReceivedStdout(const QStringList&)));
182 connect(d->lineMaker, SIGNAL(receivedStderrLines(const QStringList&)),
183 SLOT(slotReceivedStderr(const QStringList&)) );
185 kDebug() << "Execute dvcs command:" << dvcsCommand();
187 d->outputLines.clear();
188 d->isRunning = true;
189 d->childproc->setOutputChannelMode( d->commMode );
190 d->childproc->setProgram( d->command );
191 d->childproc->setEnvironment(QProcess::systemEnvironment());
192 //the started() and error() signals may be delayed! It causes crash with deferred deletion!!!
193 d->childproc->waitForStarted();
194 d->childproc->start();
197 void DVCSjob::setCommunicationMode(KProcess::OutputChannelMode comm)
199 d->commMode = comm;
202 void DVCSjob::cancel()
204 d->childproc->kill();
207 void DVCSjob::slotProcessError( QProcess::ProcessError err )
209 // disconnect all connections to childproc's signals; they are no longer needed
210 d->childproc->disconnect();
212 d->isRunning = false;
214 //NOTE: some DVCS commands can use stderr...
215 d->failed = true;
217 //Do not use d->childproc->exitCode() to set an error! If we have FailedToStart exitCode will return 0,
218 //and if exec is used, exec will return true and thet is wrong!
219 setError(UserDefinedError);
220 setErrorText( i18n("Process exited with status %1", d->childproc->exitCode() ) );
222 QString errorValue;
223 //if trolls add Q_ENUMS for QProcess, then we can use better solution than switch:
224 //QMetaObject::indexOfEnumerator(char*), QLatin1String(QMetaEnum::valueToKey())...
225 switch (err)
227 case QProcess::FailedToStart:
228 errorValue = "FailedToStart";
229 break;
230 case QProcess::Crashed:
231 errorValue = "Crashed";
232 break;
233 case QProcess::Timedout:
234 errorValue = "Timedout";
235 break;
236 case QProcess::WriteError:
237 errorValue = "WriteErro";
238 break;
239 case QProcess::ReadError:
240 errorValue = "ReadError";
241 break;
242 case QProcess::UnknownError:
243 errorValue = "UnknownError";
244 break;
246 kDebug() << "oops, found an error while running" << dvcsCommand() << ":" << errorValue
247 << "Exit code is:" << d->childproc->exitCode();
248 jobIsReady();
251 void DVCSjob::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
253 // disconnect all connections to childproc's signals; they are no longer needed
254 d->childproc->disconnect();
256 d->isRunning = false;
258 if (exitStatus != QProcess::NormalExit || exitCode != 0)
259 slotProcessError(QProcess::UnknownError);
261 kDebug() << "process has finished with no errors";
262 jobIsReady();
265 void DVCSjob::slotReceivedStdout(const QStringList& output)
267 // accumulate output
268 d->outputLines += output;
270 kDebug()<<"received output:";
271 kDebug()<<output.join("\n");
274 void DVCSjob::slotReceivedStderr(const QStringList& output)
276 // accumulate output
277 d->outputLines += output;
279 kDebug()<<"received error:";
280 kDebug()<<output.join("\n");
283 KDevelop::VcsJob::JobStatus DVCSjob::status() const
285 if (!d->wasStarted)
286 return KDevelop::VcsJob::JobNotStarted;
287 if (d->failed)
288 return KDevelop::VcsJob::JobFailed;
289 if (d->isRunning)
290 return KDevelop::VcsJob::JobRunning;
291 return KDevelop::VcsJob::JobSucceeded;
294 KDevelop::IPlugin* DVCSjob::vcsPlugin() const
296 return d->vcsplugin;
299 void DVCSjob::jobIsReady()
301 emit readyForParsing(this); //let parsers to set status
302 emitResult(); //KJob
303 emit resultsReady(this); //VcsJob
306 KProcess* DVCSjob::getChildproc() {return d->childproc;}