Mercurial > hg > easyhg
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 |