comparison hgrunner.cpp @ 111:151209bc5bd6

* Fixes to terminal lifecycle (only the first of a series of interactive commands was working before). Also switch from openpty to POSIX/Unix98 openpt
author Chris Cannam
date Fri, 26 Nov 2010 16:28:18 +0000
parents 0f039d3cc38e
children 5fc7b4fc77a8
comparison
equal deleted inserted replaced
110:0f039d3cc38e 111:151209bc5bd6
26 #include <QVBoxLayout> 26 #include <QVBoxLayout>
27 #include <QSettings> 27 #include <QSettings>
28 #include <QInputDialog> 28 #include <QInputDialog>
29 29
30 #include <iostream> 30 #include <iostream>
31 #include <unistd.h>
32 #include <errno.h> 31 #include <errno.h>
33 #include <stdio.h> 32 #include <stdio.h>
33 #include <stdlib.h>
34 34
35 #ifndef Q_OS_WIN32 35 #ifndef Q_OS_WIN32
36 #ifdef Q_OS_MAC 36 #include <unistd.h>
37 #include <util.h> 37 #include <fcntl.h>
38 #else
39 #include <pty.h>
40 #endif
41 #endif 38 #endif
42 39
43 HgRunner::HgRunner(QWidget * parent): QProgressBar(parent) 40 HgRunner::HgRunner(QWidget * parent): QProgressBar(parent)
44 { 41 {
45 m_proc = new QProcess(this); 42 m_proc = new QProcess(this);
63 this, SLOT(dataReadyStderr())); 60 this, SLOT(dataReadyStderr()));
64 } 61 }
65 62
66 HgRunner::~HgRunner() 63 HgRunner::~HgRunner()
67 { 64 {
68 if (m_ptySlaveFilename != "") { 65 closeTerminal();
69 ::close(m_ptyMasterFd);
70 }
71 delete m_proc; 66 delete m_proc;
72 } 67 }
73 68
74 void HgRunner::requestAction(HgAction action) 69 void HgRunner::requestAction(HgAction action)
75 { 70 {
141 QLineEdit::Normal, QString(), &ok); 136 QLineEdit::Normal, QString(), &ok);
142 if (ok) { 137 if (ok) {
143 m_procInput->write(QString("%1\n").arg(pwd).toUtf8()); 138 m_procInput->write(QString("%1\n").arg(pwd).toUtf8());
144 m_procInput->flush(); 139 m_procInput->flush();
145 return; 140 return;
141 } else {
142 DEBUG << "HgRunner::getUsername: user cancelled" << endl;
143 killCurrentCommand();
144 return;
146 } 145 }
147 } 146 }
148 // user cancelled or something went wrong 147 // user cancelled or something went wrong
148 DEBUG << "HgRunner::getUsername: something went wrong" << endl;
149 killCurrentCommand(); 149 killCurrentCommand();
150 } 150 }
151 151
152 void HgRunner::getPassword() 152 void HgRunner::getPassword()
153 { 153 {
169 QLineEdit::Password, QString(), &ok); 169 QLineEdit::Password, QString(), &ok);
170 if (ok) { 170 if (ok) {
171 m_procInput->write(QString("%1\n").arg(pwd).toUtf8()); 171 m_procInput->write(QString("%1\n").arg(pwd).toUtf8());
172 m_procInput->flush(); 172 m_procInput->flush();
173 return; 173 return;
174 } else {
175 DEBUG << "HgRunner::getPassword: user cancelled" << endl;
176 killCurrentCommand();
177 return;
174 } 178 }
175 } 179 }
176 // user cancelled or something went wrong 180 // user cancelled or something went wrong
181 DEBUG << "HgRunner::getPassword: something went wrong" << endl;
177 killCurrentCommand(); 182 killCurrentCommand();
178 } 183 }
179 184
180 void HgRunner::checkPrompts(QString chunk) 185 void HgRunner::checkPrompts(QString chunk)
181 { 186 {
237 242
238 if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) { 243 if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) {
239 DEBUG << "HgRunner::finished: Command completed successfully" << endl; 244 DEBUG << "HgRunner::finished: Command completed successfully" << endl;
240 emit commandCompleted(completedAction, m_stdout); 245 emit commandCompleted(completedAction, m_stdout);
241 } else { 246 } else {
242 DEBUG << "HgRunner::finished: Command failed" << endl; 247 DEBUG << "HgRunner::finished: Command failed, stderr follows" << endl;
248 DEBUG << m_stderr << endl;
243 emit commandFailed(completedAction, m_stderr); 249 emit commandFailed(completedAction, m_stderr);
244 } 250 }
245 251
246 checkQueue(); 252 checkQueue();
247 } 253 }
248 /*
249 bool HgRunner::isCommandRunning()
250 {
251 return m_isRunning;
252 }
253 */
254 254
255 void HgRunner::killCurrentCommand() 255 void HgRunner::killCurrentCommand()
256 { 256 {
257 if (m_isRunning) { 257 if (m_isRunning) {
258 m_proc -> kill(); 258 m_proc -> kill();
308 308
309 if (!action.workingDir.isEmpty()) { 309 if (!action.workingDir.isEmpty()) {
310 m_proc->setWorkingDirectory(action.workingDir); 310 m_proc->setWorkingDirectory(action.workingDir);
311 } 311 }
312 312
313 m_procInput = 0;
314 m_ptySlaveFilename = "";
315
316 #ifndef Q_OS_WIN32
317 if (interactive) { 313 if (interactive) {
318 char name[1024]; 314 openTerminal();
319 if (openpty(&m_ptyMasterFd, &m_ptySlaveFd, name, NULL, NULL)) { 315 if (m_ptySlaveFilename != "") {
320 perror("openpty failed");
321 } else {
322 DEBUG << "openpty succeeded: master " << m_ptyMasterFd
323 << " slave " << m_ptySlaveFd << " filename " << name << endl;
324 m_procInput = new QFile;
325 m_procInput->open(m_ptyMasterFd, QFile::WriteOnly);
326 m_ptySlaveFilename = name;
327 m_proc->setStandardInputFile(m_ptySlaveFilename); 316 m_proc->setStandardInputFile(m_ptySlaveFilename);
328 ::close(m_ptySlaveFd); 317 }
329 } 318 }
330 }
331 #endif
332 319
333 QString cmdline = executable; 320 QString cmdline = executable;
334 foreach (QString param, params) cmdline += " " + param; 321 foreach (QString param, params) cmdline += " " + param;
335 DEBUG << "HgRunner: starting: " << cmdline << " with cwd " 322 DEBUG << "HgRunner: starting: " << cmdline << " with cwd "
336 << action.workingDir << endl; 323 << action.workingDir << endl;
345 void HgRunner::closeProcInput() 332 void HgRunner::closeProcInput()
346 { 333 {
347 DEBUG << "closeProcInput" << endl; 334 DEBUG << "closeProcInput" << endl;
348 335
349 m_proc->closeWriteChannel(); 336 m_proc->closeWriteChannel();
337 }
338
339 void HgRunner::openTerminal()
340 {
341 #ifndef Q_OS_WIN32
342 if (m_ptySlaveFilename != "") return; // already open
343 DEBUG << "HgRunner::openTerminal: trying to open new pty" << endl;
344 int master = posix_openpt(O_RDWR | O_NOCTTY);
345 if (master < 0) {
346 DEBUG << "openpt failed" << endl;
347 perror("openpt failed");
348 return;
349 }
350 if (grantpt(master)) {
351 perror("grantpt failed");
352 }
353 if (unlockpt(master)) {
354 perror("unlockpt failed");
355 }
356 char *slave = ptsname(master);
357 if (!slave) {
358 perror("ptsname failed");
359 ::close(master);
360 return;
361 }
362 m_ptyMasterFd = master;
363 m_procInput = new QFile();
364 m_procInput->open(m_ptyMasterFd, QFile::WriteOnly);
365 m_ptySlaveFilename = slave;
366 DEBUG << "HgRunner::openTerminal: succeeded, slave is "
367 << m_ptySlaveFilename << endl;
368 #endif
369 }
370
371 void HgRunner::closeTerminal()
372 {
350 #ifndef Q_OS_WIN32 373 #ifndef Q_OS_WIN32
351 if (m_ptySlaveFilename != "") { 374 if (m_ptySlaveFilename != "") {
375 delete m_procInput;
376 m_procInput = 0;
352 ::close(m_ptyMasterFd); 377 ::close(m_ptyMasterFd);
353 m_ptySlaveFilename = ""; 378 m_ptySlaveFilename = "";
354 } 379 }
355 #endif 380 #endif
356 } 381 }
357