Chris@57: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@57: Chris@57: /* Chris@57: EasyMercurial Chris@57: Chris@57: Based on HgExplorer by Jari Korhonen Chris@57: Copyright (c) 2010 Jari Korhonen Chris@57: Copyright (c) 2010 Chris Cannam Chris@57: Copyright (c) 2010 Queen Mary, University of London Chris@57: Chris@57: This program is free software; you can redistribute it and/or Chris@57: modify it under the terms of the GNU General Public License as Chris@57: published by the Free Software Foundation; either version 2 of the Chris@57: License, or (at your option) any later version. See the file Chris@57: COPYING included with this distribution for more information. Chris@57: */ jtkorhonen@0: jtkorhonen@0: #include "hgrunner.h" Chris@62: #include "common.h" Chris@57: #include "debug.h" Chris@50: Chris@50: #include Chris@50: #include Chris@50: #include Chris@50: #include Chris@50: #include Chris@62: #include Chris@75: #include jtkorhonen@0: Chris@43: #include jtkorhonen@0: #include Chris@75: #include Chris@75: #include jtkorhonen@0: Chris@76: #ifndef Q_OS_WIN32 Chris@80: #ifdef Q_OS_MAC Chris@80: #include Chris@80: #else Chris@76: #include Chris@76: #endif Chris@80: #endif Chris@76: jtkorhonen@0: HgRunner::HgRunner(QWidget * parent): QProgressBar(parent) jtkorhonen@0: { jtkorhonen@0: proc = new QProcess(this); jtkorhonen@0: cannam@45: QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); cannam@45: env.insert("LANG", "en_US.utf8"); cannam@45: env.insert("LC_ALL", "en_US.utf8"); cannam@45: proc->setProcessEnvironment(env); cannam@45: jtkorhonen@0: setTextVisible(false); jtkorhonen@0: setVisible(false); jtkorhonen@0: isRunning = false; jtkorhonen@0: jtkorhonen@0: stdOut.clear(); jtkorhonen@0: stdErr.clear(); jtkorhonen@0: Chris@75: procInput = 0; Chris@76: #ifndef Q_OS_WIN32 Chris@75: char name[1024]; Chris@75: if (openpty(&ptyMasterFd, &ptySlaveFd, name, NULL, NULL)) { Chris@75: perror("openpty failed"); Chris@75: } else { Chris@75: DEBUG << "openpty succeeded: master " << ptyMasterFd Chris@75: << " slave " << ptySlaveFd << " filename " << name << endl; Chris@75: procInput = new QFile; Chris@75: procInput->open(ptyMasterFd, QFile::WriteOnly); Chris@75: ptySlaveFilename = name; Chris@75: proc->setStandardInputFile(ptySlaveFilename); Chris@75: ::close(ptySlaveFd); Chris@75: } Chris@76: #endif jtkorhonen@0: connect(proc, SIGNAL(started()), this, SLOT(started())); Chris@62: connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)), Chris@62: this, SLOT(finished(int, QProcess::ExitStatus))); Chris@75: connect(proc, SIGNAL(readyReadStandardOutput()), Chris@75: this, SLOT(stdOutReady())); Chris@75: connect(proc, SIGNAL(readyReadStandardError()), Chris@75: this, SLOT(stdErrReady())); Chris@62: Chris@62: reportErrors = false; jtkorhonen@0: } jtkorhonen@0: jtkorhonen@0: HgRunner::~HgRunner() jtkorhonen@0: { Chris@75: if (ptySlaveFilename != "") { Chris@75: ::close(ptyMasterFd); Chris@75: // ::close(ptySlaveFd); Chris@75: } jtkorhonen@0: delete proc; jtkorhonen@0: } jtkorhonen@0: Chris@62: QString HgRunner::getHgBinaryName() Chris@62: { Chris@62: QSettings settings; Chris@77: QString hg = settings.value("hgbinary", "").toString(); Chris@77: if (hg == "") { Chris@77: hg = findExecutable("hg"); Chris@77: } Chris@77: if (hg != "hg") { Chris@77: settings.setValue("hgbinary", hg); Chris@77: } Chris@62: return hg; Chris@62: } Chris@62: jtkorhonen@0: void HgRunner::started() jtkorhonen@0: { Chris@75: /* Chris@75: if (procInput) procInput->write("blah\n"); Chris@75: if (procInput) procInput->write("blah\n"); Chris@75: if (procInput) { Chris@75: procInput->close(); Chris@75: // ::close(ptyMasterFd); Chris@75: } jtkorhonen@0: proc -> closeWriteChannel(); Chris@75: */ jtkorhonen@0: } jtkorhonen@0: Chris@62: void HgRunner::saveOutput() Chris@62: { Chris@75: stdOut += QString::fromUtf8(proc -> readAllStandardOutput()); Chris@75: stdErr += QString::fromUtf8(proc -> readAllStandardError()); Chris@64: Chris@64: DEBUG << "saveOutput: " << stdOut.split("\n").size() << " line(s) of stdout, " << stdErr.split("\n").size() << " line(s) of stderr" << endl; Chris@64: Chris@64: // std::cerr << "stdout was " << stdOut.toStdString() << std::endl; Chris@62: } Chris@62: jtkorhonen@0: void HgRunner::setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus) jtkorhonen@0: { jtkorhonen@0: exitCode = procExitCode; jtkorhonen@0: exitStatus = procExitStatus; jtkorhonen@0: } jtkorhonen@0: jtkorhonen@0: QString HgRunner::getLastCommandLine() jtkorhonen@0: { jtkorhonen@0: return QString("Command line: " + lastHgCommand + " " + lastParams); jtkorhonen@0: } jtkorhonen@0: Chris@75: void HgRunner::stdOutReady() Chris@75: { Chris@75: DEBUG << "stdOutReady" << endl; Chris@75: QString chunk = QString::fromUtf8(proc->readAllStandardOutput()); Chris@80: //DEBUG << "stdout was " << chunk << endl; Chris@75: stdOut += chunk; Chris@75: } Chris@75: Chris@75: void HgRunner::stdErrReady() Chris@75: { Chris@75: DEBUG << "stdErrReady" << endl; Chris@75: QString chunk = QString::fromUtf8(proc->readAllStandardError()); Chris@80: //DEBUG << "stderr was " << chunk << endl; Chris@75: stdErr += chunk; Chris@75: if (procInput) { Chris@75: if (chunk.toLower().trimmed() == "password:") { Chris@75: bool ok = false; Chris@75: QString pwd = QInputDialog::getText Chris@75: (qobject_cast(parent()), Chris@75: tr("Enter password"), tr("Password (but for what user name and repository??"), Chris@75: QLineEdit::Password, QString(), &ok); Chris@75: if (ok) { Chris@75: procInput->write(QString("%1\n").arg(pwd).toUtf8()); Chris@75: procInput->flush(); Chris@75: } else { Chris@75: //!!! do what? close the terminal? Chris@75: } Chris@75: } Chris@75: } Chris@75: } Chris@75: jtkorhonen@0: void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus) jtkorhonen@0: { jtkorhonen@0: setProcExitInfo(procExitCode, procExitStatus); Chris@64: saveOutput(); Chris@62: isRunning = false; jtkorhonen@0: Chris@74: if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) { Chris@74: DEBUG << "HgRunner::finished: Command completed successfully: stderr says: " << stdErr << endl; Chris@62: emit commandCompleted(); Chris@62: } else { Chris@74: DEBUG << "HgRunner::finished: Command failed: stderr says: " << stdErr << endl; Chris@62: emit commandFailed(); jtkorhonen@0: } jtkorhonen@0: } jtkorhonen@0: Chris@62: bool HgRunner::isCommandRunning() jtkorhonen@0: { jtkorhonen@0: return isRunning; jtkorhonen@0: } jtkorhonen@0: Chris@62: void HgRunner::killCurrentCommand() jtkorhonen@0: { Chris@62: if (isCommandRunning()) { jtkorhonen@0: proc -> kill(); jtkorhonen@0: } jtkorhonen@0: } jtkorhonen@0: Chris@62: void HgRunner::startHgCommand(QString workingDir, QStringList params) Chris@62: { Chris@62: startCommand(getHgBinaryName(), workingDir, params); Chris@62: } jtkorhonen@0: Chris@62: void HgRunner::startCommand(QString command, QString workingDir, QStringList params) jtkorhonen@0: { jtkorhonen@0: isRunning = true; jtkorhonen@0: setRange(0, 0); jtkorhonen@0: setVisible(true); jtkorhonen@0: stdOut.clear(); jtkorhonen@0: stdErr.clear(); jtkorhonen@0: exitCode = 0; jtkorhonen@0: exitStatus = QProcess::NormalExit; jtkorhonen@0: jtkorhonen@0: if (!workingDir.isEmpty()) jtkorhonen@0: { jtkorhonen@0: proc -> setWorkingDirectory(workingDir); jtkorhonen@0: } jtkorhonen@0: Chris@62: lastHgCommand = command; jtkorhonen@0: lastParams = params.join(" "); jtkorhonen@0: Chris@62: QString cmdline = command; Chris@57: foreach (QString param, params) cmdline += " " + param; Chris@64: DEBUG << "HgRunner: starting: " << cmdline << " with cwd " Chris@64: << workingDir << endl; Chris@43: Chris@62: proc -> start(command, params); jtkorhonen@0: } jtkorhonen@0: jtkorhonen@0: int HgRunner::getExitCode() jtkorhonen@0: { jtkorhonen@0: return exitCode; jtkorhonen@0: } jtkorhonen@0: jtkorhonen@0: QString HgRunner::getStdOut() jtkorhonen@0: { jtkorhonen@0: return stdOut; jtkorhonen@0: } jtkorhonen@0: jtkorhonen@0: void HgRunner::hideProgBar() jtkorhonen@0: { jtkorhonen@0: setVisible(false); jtkorhonen@0: } jtkorhonen@0: jtkorhonen@0: