forked from qt-creator/qt-creator
Mercurial plugin, merge request with suggested fixes.
This commit is contained in:
176
src/plugins/mercurial/mercurialjobrunner.cpp
Normal file
176
src/plugins/mercurial/mercurialjobrunner.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "mercurialjobrunner.h"
|
||||
#include "mercurialplugin.h"
|
||||
#include "mercurialoutputwindow.h"
|
||||
#include "constants.h"
|
||||
#include "mercurialsettings.h"
|
||||
|
||||
#include <vcsbase/vcsbaseeditor.h>
|
||||
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QTime>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
using namespace Mercurial::Internal;
|
||||
using namespace Mercurial;
|
||||
|
||||
HgTask::HgTask(const QString &repositoryRoot, QStringList &arguments, bool emitRaw)
|
||||
: m_repositoryRoot(repositoryRoot),
|
||||
arguments(arguments),
|
||||
emitRaw(emitRaw),
|
||||
editor(0)
|
||||
{
|
||||
}
|
||||
|
||||
HgTask::HgTask(const QString &repositoryRoot, QStringList &arguments, VCSBase::VCSBaseEditor *editor)
|
||||
: m_repositoryRoot(repositoryRoot),
|
||||
arguments(arguments),
|
||||
emitRaw(false),
|
||||
editor(editor)
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
MercurialJobRunner::MercurialJobRunner()
|
||||
: keepRunning(true)
|
||||
{
|
||||
plugin = MercurialPlugin::instance();
|
||||
connect(this, SIGNAL(error(const QByteArray &)), plugin->outputPane(), SLOT(append(const QByteArray &)));
|
||||
connect(this, SIGNAL(info(const QString &)), plugin->outputPane(), SLOT(append(const QString &)));
|
||||
}
|
||||
|
||||
MercurialJobRunner::~MercurialJobRunner()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void MercurialJobRunner::stop()
|
||||
{
|
||||
mutex.lock();
|
||||
keepRunning = false;
|
||||
//Create a dummy task to break the cycle
|
||||
QSharedPointer<HgTask> job(0);
|
||||
jobs.enqueue(job);
|
||||
waiter.wakeAll();
|
||||
mutex.unlock();
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
void MercurialJobRunner::restart()
|
||||
{
|
||||
stop();
|
||||
mutex.lock();
|
||||
keepRunning = true;
|
||||
mutex.unlock();
|
||||
start();
|
||||
}
|
||||
|
||||
void MercurialJobRunner::getSettings()
|
||||
{
|
||||
MercurialSettings *settings = MercurialPlugin::instance()->settings();
|
||||
binary = settings->binary();
|
||||
timeout = settings->timeout();
|
||||
standardArguments = settings->standardArguments();
|
||||
}
|
||||
|
||||
void MercurialJobRunner::enqueueJob(QSharedPointer<HgTask> &job)
|
||||
{
|
||||
mutex.lock();
|
||||
jobs.enqueue(job);
|
||||
waiter.wakeAll();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void MercurialJobRunner::run()
|
||||
{
|
||||
getSettings();
|
||||
forever {
|
||||
mutex.lock();
|
||||
while (jobs.count() == 0)
|
||||
waiter.wait(&mutex);
|
||||
|
||||
if (!keepRunning) {
|
||||
jobs.clear();
|
||||
mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<HgTask> job = jobs.dequeue();
|
||||
mutex.unlock();
|
||||
|
||||
task(job);
|
||||
}
|
||||
}
|
||||
|
||||
void MercurialJobRunner::task(QSharedPointer<HgTask> &job)
|
||||
{
|
||||
HgTask *taskData = job.data();
|
||||
|
||||
if (taskData->shouldEmit())
|
||||
//Call the job's signal so the Initator of the job can process the data
|
||||
//Because the QSharedPointer that holds the HgTask will go out of scope and hence be deleted
|
||||
//we have to block and wait until the signal is delivered
|
||||
connect(this, SIGNAL(output(const QByteArray&)), taskData, SIGNAL(rawData(const QByteArray&)),
|
||||
Qt::BlockingQueuedConnection);
|
||||
else if (taskData->displayEditor())
|
||||
//An editor has been created to display the data so send it there
|
||||
connect(this, SIGNAL(output(const QByteArray&)), taskData->displayEditor(), SLOT(setPlainTextData(const QByteArray&)));
|
||||
else
|
||||
//Just output the data to the Mercurial output window
|
||||
connect(this, SIGNAL(output(const QByteArray &)), plugin->outputPane(), SLOT(append(const QByteArray &)));
|
||||
|
||||
QString time = QTime::currentTime().toString(QLatin1String("HH:mm"));
|
||||
QString starting = tr("%1 Calling: %2 %3\n").arg(time, "hg", taskData->args().join(" "));
|
||||
|
||||
//infom the user of what we are going to try and perform
|
||||
emit info(starting);
|
||||
|
||||
if (Constants::debug)
|
||||
qDebug() << Q_FUNC_INFO << "Repository root is " << taskData->repositoryRoot();
|
||||
|
||||
QProcess hgProcess;
|
||||
hgProcess.setWorkingDirectory(taskData->repositoryRoot());
|
||||
|
||||
QStringList args = standardArguments;
|
||||
args << taskData->args();
|
||||
|
||||
hgProcess.start(binary, args);
|
||||
|
||||
if (!hgProcess.waitForStarted()) {
|
||||
QByteArray errorArray(Constants::ERRORSTARTING);
|
||||
emit error(errorArray);
|
||||
return;
|
||||
}
|
||||
|
||||
hgProcess.closeWriteChannel();
|
||||
|
||||
if (!hgProcess.waitForFinished(timeout)) {
|
||||
hgProcess.terminate();
|
||||
QByteArray errorArray(Constants::TIMEDOUT);
|
||||
emit error(errorArray);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((hgProcess.exitStatus() == QProcess::NormalExit) && (hgProcess.exitCode() == 0)) {
|
||||
QByteArray stdout = hgProcess.readAllStandardOutput();
|
||||
/*
|
||||
* sometimes success means output is actually on error channel (stderr)
|
||||
* e.g. "hg revert" outputs "no changes needed to 'file'" on stderr if file has not changed
|
||||
* from revision specified
|
||||
*/
|
||||
if (stdout == "")
|
||||
stdout = hgProcess.readAllStandardError();
|
||||
emit output(stdout);
|
||||
} else {
|
||||
QByteArray stderr = hgProcess.readAllStandardError();
|
||||
emit error(stderr);
|
||||
}
|
||||
|
||||
hgProcess.close();
|
||||
//the signal connection is to last only for the duration of a job/task. next time a new
|
||||
//output signal connection must be made
|
||||
disconnect(this, SIGNAL(output(const QByteArray &)), 0, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user