• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdevelop API Reference
  • KDE Home
  • Contact Us
 

kdevplatform/vcs

  • sources
  • kfour-appscomplete
  • kdevelop
  • kdevplatform
  • vcs
  • dvcs
dvcsjob.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * This file was partly taken from KDevelop's cvs plugin *
3  * Copyright 2002-2003 Christian Loose <[email protected]> *
4  * Copyright 2007 Robert Gruber <[email protected]> *
5  * *
6  * Adapted for DVCS *
7  * Copyright 2008 Evgeniy Ivanov <[email protected]> *
8  * Copyright Aleix Pol Gonzalez <[email protected]> *
9  * *
10  * This program is free software; you can redistribute it and/or *
11  * modify it under the terms of the GNU General Public License as *
12  * published by the Free Software Foundation; either version 2 of *
13  * the License or (at your option) version 3 or any later version *
14  * accepted by the membership of KDE e.V. (or its successor approved *
15  * by the membership of KDE e.V.), which shall act as a proxy *
16  * defined in Section 14 of version 3 of the license. *
17  * *
18  * This program is distributed in the hope that it will be useful, *
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21  * GNU General Public License for more details. *
22  * *
23  * You should have received a copy of the GNU General Public License *
24  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
25  ***************************************************************************/
26 
27 #include "dvcsjob.h"
28 #include "debug.h"
29 
30 #include <QFile>
31 #include <QList>
32 #include <QStringList>
33 #include <QDir>
34 #include <QUrl>
35 
36 #include <KLocalizedString>
37 #include <KShell>
38 
39 #include <interfaces/iplugin.h>
40 #include <outputview/outputmodel.h>
41 
42 using namespace KDevelop;
43 
44 class KDevelop::DVcsJobPrivate
45 {
46 public:
47  DVcsJobPrivate() : childproc(new KProcess)
48  {}
49 
50  ~DVcsJobPrivate() {
51  delete childproc;
52  }
53 
54  KProcess* childproc;
55  VcsJob::JobStatus status;
56  QByteArray output;
57  QByteArray errorOutput;
58  IPlugin* vcsplugin = nullptr;
59 
60  QVariant results;
61  OutputModel* model;
62 
63  bool ignoreError = false;
64 };
65 
66 DVcsJob::DVcsJob(const QDir& workingDir, IPlugin* parent, OutputJob::OutputJobVerbosity verbosity)
67  : VcsJob(parent, verbosity)
68  , d_ptr(new DVcsJobPrivate)
69 {
70  Q_D(DVcsJob);
71 
72  Q_ASSERT(workingDir.exists());
73  d->status = JobNotStarted;
74  d->vcsplugin = parent;
75  d->childproc->setWorkingDirectory(workingDir.absolutePath());
76  d->model = new OutputModel;
77  d->ignoreError = false;
78  setModel(d->model);
79  setCapabilities(Killable);
80 
81  connect(d->childproc, QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),
82  this, &DVcsJob::slotProcessExited);
83  connect(d->childproc, &QProcess::errorOccurred,
84  this, &DVcsJob::slotProcessError);
85 
86  connect(d->childproc, &KProcess::readyReadStandardOutput,
87  this, &DVcsJob::slotReceivedStdout);
88 
89 }
90 
91 DVcsJob::~DVcsJob() = default;
92 
93 QDir DVcsJob::directory() const
94 {
95  Q_D(const DVcsJob);
96 
97  return QDir(d->childproc->workingDirectory());
98 }
99 
100 DVcsJob& DVcsJob::operator<<(const QString& arg)
101 {
102  Q_D(DVcsJob);
103 
104  *d->childproc << arg;
105  return *this;
106 }
107 
108 DVcsJob& DVcsJob::operator<<(const char* arg)
109 {
110  Q_D(DVcsJob);
111 
112  *d->childproc << QString::fromUtf8(arg);
113  return *this;
114 }
115 
116 DVcsJob& DVcsJob::operator<<(const QStringList& args)
117 {
118  Q_D(DVcsJob);
119 
120  *d->childproc << args;
121  return *this;
122 }
123 
124 QStringList DVcsJob::dvcsCommand() const
125 {
126  Q_D(const DVcsJob);
127 
128  return d->childproc->program();
129 }
130 
131 QString DVcsJob::output() const
132 {
133  Q_D(const DVcsJob);
134 
135  QByteArray stdoutbuf = rawOutput();
136  int endpos = stdoutbuf.size();
137  if (d->status==JobRunning) { // We may have received only part of a code-point. apol: ASSERT?
138  endpos = stdoutbuf.lastIndexOf('\n')+1; // Include the final newline or become 0, when there is no newline
139  }
140 
141  return QString::fromLocal8Bit(stdoutbuf.constData(), endpos);
142 }
143 
144 QByteArray DVcsJob::rawOutput() const
145 {
146  Q_D(const DVcsJob);
147 
148  return d->output;
149 }
150 
151 QByteArray DVcsJob::errorOutput() const
152 {
153  Q_D(const DVcsJob);
154 
155  return d->errorOutput;
156 }
157 
158 void DVcsJob::setIgnoreError(bool ignore)
159 {
160  Q_D(DVcsJob);
161 
162  d->ignoreError = ignore;
163 }
164 
165 void DVcsJob::setResults(const QVariant &res)
166 {
167  Q_D(DVcsJob);
168 
169  d->results = res;
170 }
171 
172 QVariant DVcsJob::fetchResults()
173 {
174  Q_D(DVcsJob);
175 
176  return d->results;
177 }
178 
179 void DVcsJob::start()
180 {
181  Q_D(DVcsJob);
182 
183  Q_ASSERT_X(d->status != JobRunning, "DVCSjob::start", "Another process was started using this job class");
184 
185  const QDir& workingdir = directory();
186  if( !workingdir.exists() ) {
187  QString error = i18n( "Working Directory does not exist: %1", d->childproc->workingDirectory() );
188  d->model->appendLine(error);
189  setError( 255 );
190  setErrorText(error);
191  d->status = JobFailed;
192  emitResult();
193  return;
194  }
195  if( !workingdir.isAbsolute() ) {
196  QString error = i18n( "Working Directory is not absolute: %1", d->childproc->workingDirectory() );
197  d->model->appendLine(error);
198  setError( 255 );
199  setErrorText(error);
200  d->status = JobFailed;
201  emitResult();
202  return;
203  }
204 
205  QString commandDisplay = KShell::joinArgs(dvcsCommand());
206  qCDebug(VCS) << "Execute dvcs command:" << commandDisplay;
207 
208  QString service;
209  if(d->vcsplugin)
210  service = d->vcsplugin->objectName();
211  setObjectName(service + QLatin1String(": ") + commandDisplay);
212 
213  d->status = JobRunning;
214  d->childproc->setOutputChannelMode(KProcess::SeparateChannels);
215  //the started() and error() signals may be delayed! It causes crash with deferred deletion!!!
216  d->childproc->start();
217 
218  d->model->appendLine(directory().path() + QLatin1String("> ") + commandDisplay);
219 }
220 
221 void DVcsJob::setCommunicationMode(KProcess::OutputChannelMode comm)
222 {
223  Q_D(DVcsJob);
224 
225  d->childproc->setOutputChannelMode(comm);
226 }
227 
228 void DVcsJob::cancel()
229 {
230  Q_D(DVcsJob);
231 
232  d->childproc->kill();
233 }
234 
235 void DVcsJob::slotProcessError( QProcess::ProcessError err )
236 {
237  Q_D(DVcsJob);
238 
239  d->status = JobFailed;
240 
241  setError(OutputJob::FailedShownError); //we don't want to trigger a message box
242 
243  d->errorOutput = d->childproc->readAllStandardError();
244 
245  QString displayCommand = KShell::joinArgs(dvcsCommand());
246  QString completeErrorText = i18n("Process '%1' exited with status %2\n%3", displayCommand, d->childproc->exitCode(), QString::fromLocal8Bit(d->errorOutput) );
247  setErrorText( completeErrorText );
248 
249  QString errorValue;
250  //if trolls add Q_ENUMS for QProcess, then we can use better solution than switch:
251  //QMetaObject::indexOfEnumerator(char*), QQStringLiteral(QMetaEnum::valueToKey())...
252  switch (err)
253  {
254  case QProcess::FailedToStart:
255  errorValue = QStringLiteral("FailedToStart");
256  break;
257  case QProcess::Crashed:
258  errorValue = QStringLiteral("Crashed");
259  break;
260  case QProcess::Timedout:
261  errorValue = QStringLiteral("Timedout");
262  break;
263  case QProcess::WriteError:
264  errorValue = QStringLiteral("WriteError");
265  break;
266  case QProcess::ReadError:
267  errorValue = QStringLiteral("ReadError");
268  break;
269  case QProcess::UnknownError:
270  errorValue = QStringLiteral("UnknownError");
271  break;
272  }
273  qCDebug(VCS) << "Found an error while running" << displayCommand << ":" << errorValue
274  << "Exit code is:" << d->childproc->exitCode();
275  qCDebug(VCS) << "Error:" << completeErrorText;
276  displayOutput(QString::fromLocal8Bit(d->errorOutput));
277  d->model->appendLine(i18n("Command finished with error %1.", errorValue));
278 
279  if(verbosity()==Silent) {
280  setVerbosity(Verbose);
281  startOutput();
282  }
283  emitResult();
284 }
285 
286 void DVcsJob::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
287 {
288  Q_D(DVcsJob);
289 
290  d->status = JobSucceeded;
291  d->model->appendLine(i18n("Command exited with value %1.", exitCode));
292 
293  if (exitStatus == QProcess::CrashExit)
294  slotProcessError(QProcess::Crashed);
295 
296  else if (exitCode != 0 && !d->ignoreError)
297  slotProcessError(QProcess::UnknownError);
298 
299  else
300  jobIsReady();
301 }
302 
303 void DVcsJob::displayOutput(const QString& data)
304 {
305  Q_D(DVcsJob);
306 
307  d->model->appendLines(data.split(QLatin1Char('\n')));
308 }
309 
310 void DVcsJob::slotReceivedStdout()
311 {
312  Q_D(DVcsJob);
313 
314  QByteArray output = d->childproc->readAllStandardOutput();
315 
316  // accumulate output
317  d->output.append(output);
318 
319  displayOutput(QString::fromLocal8Bit(output));
320 }
321 
322 VcsJob::JobStatus DVcsJob::status() const
323 {
324  Q_D(const DVcsJob);
325 
326  return d->status;
327 }
328 
329 IPlugin* DVcsJob::vcsPlugin() const
330 {
331  Q_D(const DVcsJob);
332 
333  return d->vcsplugin;
334 }
335 
336 DVcsJob& DVcsJob::operator<<(const QUrl& url)
337 {
338  Q_D(DVcsJob);
339 
340  *d->childproc << url.toLocalFile();
341  return *this;
342 }
343 
344 DVcsJob& DVcsJob::operator<<(const QList< QUrl >& urls)
345 {
346  for (const QUrl& url : urls) {
347  operator<<(url);
348  }
349  return *this;
350 }
351 
352 bool DVcsJob::doKill()
353 {
354  Q_D(DVcsJob);
355 
356  if (d->childproc->state() == QProcess::NotRunning) {
357  return true;
358  }
359 
360  static const int terminateKillTimeout = 1000; // ms
361  d->childproc->terminate();
362  bool terminated = d->childproc->waitForFinished( terminateKillTimeout );
363  if( !terminated ) {
364  d->childproc->kill();
365  terminated = d->childproc->waitForFinished( terminateKillTimeout );
366  }
367  return terminated;
368 }
369 
370 void DVcsJob::jobIsReady()
371 {
372  emit readyForParsing(this); //let parsers to set status
373  emitResult(); //KJob
374  emit resultsReady(this); //VcsJob
375 }
376 
377 KProcess* DVcsJob::process() const
378 {
379  Q_D(const DVcsJob);
380 
381  return d->childproc;
382 }
QDir::exists
bool exists() const
KDevelop::DVcsJob::slotProcessError
virtual void slotProcessError(QProcess::ProcessError)
Definition: dvcsjob.cpp:235
KDevelop::DVcsJob::operator<<
DVcsJob & operator<<(const QString &arg)
Call this method to set command to execute and its arguments.
Definition: dvcsjob.cpp:100
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
KDevelop::DVcsJob::vcsPlugin
KDevelop::IPlugin * vcsPlugin() const override
Returns pointer to IPlugin (which was used to create a job).
Definition: dvcsjob.cpp:329
QString::fromUtf8
QString fromUtf8(const char *str, int size)
KDevelop::DVcsJob::doKill
bool doKill() override
Definition: dvcsjob.cpp:352
dvcsjob.h
QUrl
QDir
KDevelop::DVcsJob::process
KProcess * process() const
Definition: dvcsjob.cpp:377
IPlugin
KDevelop::DVcsJob::setCommunicationMode
void setCommunicationMode(KProcess::OutputChannelMode comm)
In some cases it's needed to specify the communication mode between the process and the job object.
Definition: dvcsjob.cpp:221
KDevelop::DVcsJob::rawOutput
QByteArray rawOutput() const
Definition: dvcsjob.cpp:144
QProcess::finished
void finished(int exitCode)
KDevelop::DVcsJob::errorOutput
QByteArray errorOutput() const
Definition: dvcsjob.cpp:151
QList< QUrl >
KDevelop::DVcsJob
This class is capable of running our dvcs commands.
Definition: dvcsjob.h:86
QDir::isAbsolute
bool isAbsolute() const
KDevelop::VcsJob::JobNotStarted
The job is not yet started.
Definition: vcsjob.h:91
KDevelop::DVcsJob::dvcsCommand
QStringList dvcsCommand() const
Definition: dvcsjob.cpp:124
QByteArray::lastIndexOf
int lastIndexOf(char ch, int from) const
KDevelop::DVcsJob::cancel
void cancel()
Cancel slot.
Definition: dvcsjob.cpp:228
KDevelop::VcsJob::JobFailed
The job failed.
Definition: vcsjob.h:90
KDevelop::DVcsJob::DVcsJob
DVcsJob(const QDir &workingDir, KDevelop::IPlugin *parent=nullptr, KDevelop::OutputJob::OutputJobVerbosity verbosity=KDevelop::OutputJob::Verbose)
Definition: dvcsjob.cpp:66
QString::fromLocal8Bit
QString fromLocal8Bit(const char *str, int size)
QString
KDevelop::DVcsJob::displayOutput
void displayOutput(const QString &output)
Definition: dvcsjob.cpp:303
KDevelop::VcsJob::resultsReady
void resultsReady(KDevelop::VcsJob *)
This signal is emitted when new results are available.
KDevelop::DVcsJob::~DVcsJob
~DVcsJob() override
QUrl::toLocalFile
QString toLocalFile() const
QDir::absolutePath
QString absolutePath() const
KDevelop::DVcsJob::setIgnoreError
void setIgnoreError(bool ignore)
Ignore a non-zero exit code depending on ignore.
Definition: dvcsjob.cpp:158
KDevelop::VcsJob::JobRunning
The job is running.
Definition: vcsjob.h:87
KDevelop::VcsJob
This class provides an extension of KJob to get various VCS-specific information about the job.
Definition: vcsjob.h:43
QByteArray::constData
const char * constData() const
QLatin1Char
KDevelop::DVcsJob::start
void start() override
Call this method to start this job.
Definition: dvcsjob.cpp:179
KDevelop::QLatin1String
QLatin1String("^[-+]{3} [ab]/(.*)"))) Q_GLOBAL_STATIC_WITH_ARGS(const QRegularExpression
KDevelop
Definition: dvcsevent.h:33
KDevelop::DVcsJob::output
QString output() const
Definition: dvcsjob.cpp:131
KDevelop::VcsJob::JobSucceeded
The job succeeded.
Definition: vcsjob.h:88
QByteArray::size
int size() const
KDevelop::DVcsJob::directory
QDir directory() const
Returns current working directory.
Definition: dvcsjob.cpp:93
QVariant
KDevelop::DVcsJob::status
KDevelop::VcsJob::JobStatus status() const override
Returns JobStatus.
Definition: dvcsjob.cpp:322
KDevelop::DVcsJob::fetchResults
QVariant fetchResults() override
Returns execution results stored in QVariant.
Definition: dvcsjob.cpp:172
KDevelop::DVcsJob::setResults
virtual void setResults(const QVariant &res)
Sets executions results.
Definition: dvcsjob.cpp:165
KDevelop::VcsJob::JobStatus
JobStatus
Simple enum to define how the job finished.
Definition: vcsjob.h:85
QString::append
QString & append(QChar ch)
QByteArray
KDevelop::DVcsJob::readyForParsing
void readyForParsing(KDevelop::DVcsJob *job)
QStringList
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Apr 10 2021 23:31:23 by doxygen 1.8.16 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevplatform/vcs

Skip menu "kdevplatform/vcs"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdevelop API Reference

Skip menu "kdevelop API Reference"
  • kdevplatform
  •   debugger
  •   documentation
  •   interfaces
  •   language
  •     assistant
  •     backgroundparser
  •     checks
  •     classmodel
  •     codecompletion
  •     codegen
  •     duchain
  •     editor
  •     highlighting
  •     interfaces
  •     util
  •   outputview
  •   project
  •   serialization
  •   shell
  •   sublime
  •   tests
  •   util
  •   vcs

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal