Mercurial > hg > easyhg
diff hgrunner.cpp @ 113:5fc7b4fc77a8
* Better error handling/reporting; some futile changes to termios handling; avoid weirdly stretching panned view in panner
author | Chris Cannam |
---|---|
date | Fri, 26 Nov 2010 21:04:40 +0000 |
parents | 151209bc5bd6 |
children | bb2d2eecdd60 |
line wrap: on
line diff
--- a/hgrunner.cpp Fri Nov 26 17:02:55 2010 +0000 +++ b/hgrunner.cpp Fri Nov 26 21:04:40 2010 +0000 @@ -34,30 +34,17 @@ #ifndef Q_OS_WIN32 #include <unistd.h> +#include <termios.h> #include <fcntl.h> #endif HgRunner::HgRunner(QWidget * parent): QProgressBar(parent) { - m_proc = new QProcess(this); - - QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); - env.insert("LANG", "en_US.utf8"); - env.insert("LC_ALL", "en_US.utf8"); - env.insert("HGPLAIN", "1"); - m_proc->setProcessEnvironment(env); + m_proc = 0; setTextVisible(false); setVisible(false); m_isRunning = false; - - connect(m_proc, SIGNAL(started()), this, SLOT(started())); - connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(finished(int, QProcess::ExitStatus))); - connect(m_proc, SIGNAL(readyReadStandardOutput()), - this, SLOT(dataReadyStdout())); - connect(m_proc, SIGNAL(readyReadStandardError()), - this, SLOT(dataReadyStderr())); } HgRunner::~HgRunner() @@ -124,7 +111,7 @@ void HgRunner::getUsername() { - if (m_procInput) { + if (m_ptyFile) { bool ok = false; QString prompt = tr("User name:"); if (m_realm != "") { @@ -135,8 +122,8 @@ tr("Enter user name"), prompt, QLineEdit::Normal, QString(), &ok); if (ok) { - m_procInput->write(QString("%1\n").arg(pwd).toUtf8()); - m_procInput->flush(); + m_ptyFile->write(QString("%1\n").arg(pwd).toUtf8()); + m_ptyFile->flush(); return; } else { DEBUG << "HgRunner::getUsername: user cancelled" << endl; @@ -151,7 +138,7 @@ void HgRunner::getPassword() { - if (m_procInput) { + if (m_ptyFile) { bool ok = false; QString prompt = tr("Password:"); if (m_userName != "") { @@ -168,8 +155,8 @@ tr("Enter password"), prompt, QLineEdit::Password, QString(), &ok); if (ok) { - m_procInput->write(QString("%1\n").arg(pwd).toUtf8()); - m_procInput->flush(); + m_ptyFile->write(QString("%1\n").arg(pwd).toUtf8()); + m_ptyFile->flush(); return; } else { DEBUG << "HgRunner::getPassword: user cancelled" << endl; @@ -182,7 +169,7 @@ killCurrentCommand(); } -void HgRunner::checkPrompts(QString chunk) +bool HgRunner::checkPrompts(QString chunk) { //DEBUG << "checkPrompts: " << chunk << endl; @@ -190,11 +177,11 @@ QString lower = text.toLower(); if (lower.endsWith("password:")) { getPassword(); - return; + return true; } if (lower.endsWith("user:")) { getUsername(); - return; + return true; } QRegExp userRe("\\buser:\\s*([^\\s]+)"); if (userRe.indexIn(text) >= 0) { @@ -204,22 +191,36 @@ if (realmRe.indexIn(text) >= 0) { noteRealm(realmRe.cap(1)); } + return false; } void HgRunner::dataReadyStdout() { DEBUG << "dataReadyStdout" << endl; QString chunk = QString::fromUtf8(m_proc->readAllStandardOutput()); - m_stdout += chunk; - checkPrompts(chunk); + if (!checkPrompts(chunk)) { + m_stdout += chunk; + } } void HgRunner::dataReadyStderr() { DEBUG << "dataReadyStderr" << endl; QString chunk = QString::fromUtf8(m_proc->readAllStandardError()); - m_stderr += chunk; - checkPrompts(chunk); + DEBUG << chunk; + if (!checkPrompts(chunk)) { + m_stderr += chunk; + } +} + +void HgRunner::dataReadyPty() +{ + DEBUG << "dataReadyPty" << endl; + QString chunk = QString::fromUtf8(m_ptyFile->readAll()); + DEBUG << "chunk of " << chunk.length() << " chars" << endl; + if (!checkPrompts(chunk)) { + m_stdout += chunk; + } } void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus) @@ -235,18 +236,23 @@ m_currentAction = HgAction(); closeProcInput(); + delete m_proc; + m_proc = 0; if (completedAction.action == ACT_NONE) { DEBUG << "HgRunner::finished: WARNING: completed action is ACT_NONE" << endl; - } - - if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) { - DEBUG << "HgRunner::finished: Command completed successfully" << endl; - emit commandCompleted(completedAction, m_stdout); } else { - DEBUG << "HgRunner::finished: Command failed, stderr follows" << endl; - DEBUG << m_stderr << endl; - emit commandFailed(completedAction, m_stderr); + if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) { + DEBUG << "HgRunner::finished: Command completed successfully" + << endl; + emit commandCompleted(completedAction, m_stdout); + } else { + DEBUG << "HgRunner::finished: Command failed, exit code " + << procExitCode << ", exit status " << procExitStatus + << ", stderr follows" << endl; + DEBUG << m_stderr << endl; + emit commandFailed(completedAction, m_stderr); + } } checkQueue(); @@ -255,7 +261,8 @@ void HgRunner::killCurrentCommand() { if (m_isRunning) { - m_proc -> kill(); + m_currentAction.action = ACT_NONE; // so that we don't bother to notify + m_proc->kill(); } } @@ -306,6 +313,22 @@ m_realm = ""; m_userName = ""; + m_proc = new QProcess; + + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LANG", "en_US.utf8"); + env.insert("LC_ALL", "en_US.utf8"); + env.insert("HGPLAIN", "1"); + m_proc->setProcessEnvironment(env); + + connect(m_proc, SIGNAL(started()), this, SLOT(started())); + connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(finished(int, QProcess::ExitStatus))); + connect(m_proc, SIGNAL(readyReadStandardOutput()), + this, SLOT(dataReadyStdout())); + connect(m_proc, SIGNAL(readyReadStandardError()), + this, SLOT(dataReadyStderr())); + if (!action.workingDir.isEmpty()) { m_proc->setWorkingDirectory(action.workingDir); } @@ -313,7 +336,10 @@ if (interactive) { openTerminal(); if (m_ptySlaveFilename != "") { + DEBUG << "HgRunner: connecting to pseudoterminal" << endl; m_proc->setStandardInputFile(m_ptySlaveFilename); + m_proc->setStandardOutputFile(m_ptySlaveFilename); +// m_proc->setStandardErrorFile(m_ptySlaveFilename); } } @@ -324,6 +350,10 @@ m_currentAction = action; + // fill these out with what we actually ran + m_currentAction.executable = executable; + m_currentAction.params = params; + DEBUG << "set current action to " << m_currentAction.action << endl; m_proc->start(executable, params); @@ -347,6 +377,16 @@ perror("openpt failed"); return; } + struct termios t; + if (tcgetattr(master, &t)) { + DEBUG << "tcgetattr failed" << endl; + perror("tcgetattr failed"); + } + cfmakeraw(&t); + if (tcsetattr(master, TCSANOW, &t)) { + DEBUG << "tcsetattr failed" << endl; + perror("tcsetattr failed"); + } if (grantpt(master)) { perror("grantpt failed"); } @@ -360,8 +400,11 @@ return; } m_ptyMasterFd = master; - m_procInput = new QFile(); - m_procInput->open(m_ptyMasterFd, QFile::WriteOnly); + m_ptyFile = new QFile(); + connect(m_ptyFile, SIGNAL(readyRead()), this, SLOT(dataReadyPty())); + if (!m_ptyFile->open(m_ptyMasterFd, QFile::ReadWrite)) { + DEBUG << "HgRunner::openTerminal: Failed to open QFile on master fd" << endl; + } m_ptySlaveFilename = slave; DEBUG << "HgRunner::openTerminal: succeeded, slave is " << m_ptySlaveFilename << endl; @@ -372,8 +415,8 @@ { #ifndef Q_OS_WIN32 if (m_ptySlaveFilename != "") { - delete m_procInput; - m_procInput = 0; + delete m_ptyFile; + m_ptyFile = 0; ::close(m_ptyMasterFd); m_ptySlaveFilename = ""; }