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> *
7 * Copyright 2008 Evgeniy Ivanov <powerfox@kde.ru> *
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. *
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. *
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 ***************************************************************************/
28 #include <QtCore/QFile>
29 #include <QtCore/QFileInfo>
30 #include <QtCore/QList>
31 #include <QtCore/QStringList>
34 #include <KDE/KLocale>
36 #include <util/processlinemaker.h>
37 #include <interfaces/iplugin.h>
41 DVCSjobPrivate() : commMode(KProcess::SeparateChannels
), vcsplugin(0)
43 childproc
= new KProcess
;
44 lineMaker
= new KDevelop::ProcessLineMaker( childproc
);
45 isRunning
= failed
= wasStarted
= false;
49 if (lineMaker
) delete lineMaker
;
50 if (childproc
) delete childproc
;
53 KDevelop::ProcessLineMaker
* lineMaker
;
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
;
80 //Do not use KProcess::clearEnvironment() (it sets the environment to kde_dummy.
81 //Also DVCSjob can't set it, so it's ok.
83 d
->outputLines
.clear();
86 d
->isRunning
= d
->failed
= d
->wasStarted
= false;
89 void DVCSjob::setServer(const QString
& 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()
109 bool DVCSjob::isRunning() const
114 DVCSjob
& DVCSjob::operator<<(const QString
& arg
)
116 d
->command
.append( arg
);
120 DVCSjob
& DVCSjob::operator<<(const char* arg
)
122 d
->command
.append( arg
);
126 DVCSjob
& DVCSjob::operator<<(const QStringList
& args
)
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
)
147 QVariant
DVCSjob::fetchResults()
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
);
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();
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
)
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...
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() ) );
223 //if trolls add Q_ENUMS for QProcess, then we can use better solution than switch:
224 //QMetaObject::indexOfEnumerator(char*), QLatin1String(QMetaEnum::valueToKey())...
227 case QProcess::FailedToStart
:
228 errorValue
= "FailedToStart";
230 case QProcess::Crashed
:
231 errorValue
= "Crashed";
233 case QProcess::Timedout
:
234 errorValue
= "Timedout";
236 case QProcess::WriteError
:
237 errorValue
= "WriteErro";
239 case QProcess::ReadError
:
240 errorValue
= "ReadError";
242 case QProcess::UnknownError
:
243 errorValue
= "UnknownError";
246 kDebug() << "oops, found an error while running" << dvcsCommand() << ":" << errorValue
247 << "Exit code is:" << d
->childproc
->exitCode();
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";
265 void DVCSjob::slotReceivedStdout(const QStringList
& output
)
268 d
->outputLines
+= output
;
270 kDebug()<<"received output:";
271 kDebug()<<output
.join("\n");
274 void DVCSjob::slotReceivedStderr(const QStringList
& output
)
277 d
->outputLines
+= output
;
279 kDebug()<<"received error:";
280 kDebug()<<output
.join("\n");
283 KDevelop::VcsJob::JobStatus
DVCSjob::status() const
286 return KDevelop::VcsJob::JobNotStarted
;
288 return KDevelop::VcsJob::JobFailed
;
290 return KDevelop::VcsJob::JobRunning
;
291 return KDevelop::VcsJob::JobSucceeded
;
294 KDevelop::IPlugin
* DVCSjob::vcsPlugin() const
299 void DVCSjob::jobIsReady()
301 emit
readyForParsing(this); //let parsers to set status
303 emit
resultsReady(this); //VcsJob
306 KProcess
* DVCSjob::getChildproc() {return d
->childproc
;}