comparison hgrunner.cpp @ 84:8a4e26dc3182

* Make all of the "Open" options do something sensible
author Chris Cannam
date Mon, 22 Nov 2010 17:27:59 +0000
parents 32fa40c3d174
children dfb7a274b90f
comparison
equal deleted inserted replaced
83:af7cf6f7282c 84:8a4e26dc3182
40 #endif 40 #endif
41 #endif 41 #endif
42 42
43 HgRunner::HgRunner(QWidget * parent): QProgressBar(parent) 43 HgRunner::HgRunner(QWidget * parent): QProgressBar(parent)
44 { 44 {
45 proc = new QProcess(this); 45 m_proc = new QProcess(this);
46 46
47 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 47 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
48 env.insert("LANG", "en_US.utf8"); 48 env.insert("LANG", "en_US.utf8");
49 env.insert("LC_ALL", "en_US.utf8"); 49 env.insert("LC_ALL", "en_US.utf8");
50 proc->setProcessEnvironment(env); 50 m_proc->setProcessEnvironment(env);
51
52 m_proc->setProcessChannelMode(QProcess::MergedChannels);
51 53
52 setTextVisible(false); 54 setTextVisible(false);
53 setVisible(false); 55 setVisible(false);
54 isRunning = false; 56 m_isRunning = false;
55 57
56 stdOut.clear(); 58 m_output.clear();
57 stdErr.clear(); 59
58 60 connect(m_proc, SIGNAL(started()), this, SLOT(started()));
59 procInput = 0; 61 connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)),
60 #ifndef Q_OS_WIN32
61 char name[1024];
62 if (openpty(&ptyMasterFd, &ptySlaveFd, name, NULL, NULL)) {
63 perror("openpty failed");
64 } else {
65 DEBUG << "openpty succeeded: master " << ptyMasterFd
66 << " slave " << ptySlaveFd << " filename " << name << endl;
67 procInput = new QFile;
68 procInput->open(ptyMasterFd, QFile::WriteOnly);
69 ptySlaveFilename = name;
70 proc->setStandardInputFile(ptySlaveFilename);
71 ::close(ptySlaveFd);
72 }
73 #endif
74 connect(proc, SIGNAL(started()), this, SLOT(started()));
75 connect(proc, SIGNAL(finished(int, QProcess::ExitStatus)),
76 this, SLOT(finished(int, QProcess::ExitStatus))); 62 this, SLOT(finished(int, QProcess::ExitStatus)));
77 connect(proc, SIGNAL(readyReadStandardOutput()), 63 connect(m_proc, SIGNAL(readyRead()), this, SLOT(dataReady()));
78 this, SLOT(stdOutReady()));
79 connect(proc, SIGNAL(readyReadStandardError()),
80 this, SLOT(stdErrReady()));
81
82 reportErrors = false;
83 } 64 }
84 65
85 HgRunner::~HgRunner() 66 HgRunner::~HgRunner()
86 { 67 {
87 if (ptySlaveFilename != "") { 68 if (m_ptySlaveFilename != "") {
88 ::close(ptyMasterFd); 69 ::close(m_ptyMasterFd);
89 // ::close(ptySlaveFd); 70 }
90 } 71 delete m_proc;
91 delete proc;
92 } 72 }
93 73
94 QString HgRunner::getHgBinaryName() 74 QString HgRunner::getHgBinaryName()
95 { 75 {
96 QSettings settings; 76 QSettings settings;
115 } 95 }
116 proc -> closeWriteChannel(); 96 proc -> closeWriteChannel();
117 */ 97 */
118 } 98 }
119 99
120 void HgRunner::saveOutput()
121 {
122 stdOut += QString::fromUtf8(proc -> readAllStandardOutput());
123 stdErr += QString::fromUtf8(proc -> readAllStandardError());
124
125 DEBUG << "saveOutput: " << stdOut.split("\n").size() << " line(s) of stdout, " << stdErr.split("\n").size() << " line(s) of stderr" << endl;
126
127 // std::cerr << "stdout was " << stdOut.toStdString() << std::endl;
128 }
129
130 void HgRunner::setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus) 100 void HgRunner::setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus)
131 { 101 {
132 exitCode = procExitCode; 102 m_exitCode = procExitCode;
133 exitStatus = procExitStatus; 103 m_exitStatus = procExitStatus;
134 } 104 }
135 105
136 QString HgRunner::getLastCommandLine() 106 QString HgRunner::getLastCommandLine()
137 { 107 {
138 return QString("Command line: " + lastHgCommand + " " + lastParams); 108 return QString("Command line: " + m_lastHgCommand + " " + m_lastParams);
139 } 109 }
140 110
141 void HgRunner::stdOutReady() 111 void HgRunner::noteUsername(QString name)
142 { 112 {
143 DEBUG << "stdOutReady" << endl; 113 m_userName = name;
144 QString chunk = QString::fromUtf8(proc->readAllStandardOutput()); 114 }
145 //DEBUG << "stdout was " << chunk << endl; 115
146 stdOut += chunk; 116 void HgRunner::noteRealm(QString realm)
147 } 117 {
148 118 m_realm = realm;
149 void HgRunner::stdErrReady() 119 }
150 { 120
151 DEBUG << "stdErrReady" << endl; 121 void HgRunner::getUsername()
152 QString chunk = QString::fromUtf8(proc->readAllStandardError()); 122 {
153 //DEBUG << "stderr was " << chunk << endl; 123 if (m_procInput) {
154 stdErr += chunk; 124 bool ok = false;
155 if (procInput) { 125 QString prompt = tr("User name:");
156 if (chunk.toLower().trimmed() == "password:") { 126 if (m_realm != "") {
157 bool ok = false; 127 prompt = tr("User name for \"%1\":").arg(m_realm);
158 QString pwd = QInputDialog::getText 128 }
159 (qobject_cast<QWidget *>(parent()), 129 QString pwd = QInputDialog::getText
160 tr("Enter password"), tr("Password (but for what user name and repository??"), 130 (qobject_cast<QWidget *>(parent()),
161 QLineEdit::Password, QString(), &ok); 131 tr("Enter user name"), prompt,
162 if (ok) { 132 QLineEdit::Normal, QString(), &ok);
163 procInput->write(QString("%1\n").arg(pwd).toUtf8()); 133 if (ok) {
164 procInput->flush(); 134 m_procInput->write(QString("%1\n").arg(pwd).toUtf8());
135 m_procInput->flush();
136 return;
137 }
138 }
139 // user cancelled or something went wrong
140 killCurrentCommand();
141 }
142
143 void HgRunner::getPassword()
144 {
145 if (m_procInput) {
146 bool ok = false;
147 QString prompt = tr("Password:");
148 if (m_userName != "") {
149 if (m_realm != "") {
150 prompt = tr("Password for \"%1\" at \"%2\":")
151 .arg(m_userName).arg(m_realm);
165 } else { 152 } else {
166 //!!! do what? close the terminal? 153 prompt = tr("Password for user \"%1\":")
154 .arg(m_userName);
167 } 155 }
168 } 156 }
169 } 157 QString pwd = QInputDialog::getText
158 (qobject_cast<QWidget *>(parent()),
159 tr("Enter password"), prompt,
160 QLineEdit::Password, QString(), &ok);
161 if (ok) {
162 m_procInput->write(QString("%1\n").arg(pwd).toUtf8());
163 m_procInput->flush();
164 return;
165 }
166 }
167 // user cancelled or something went wrong
168 killCurrentCommand();
169 }
170
171 void HgRunner::checkPrompts(QString chunk)
172 {
173 DEBUG << "checkPrompts: " << chunk << endl;
174
175 QString text = chunk.trimmed();
176 QString lower = text.toLower();
177 if (lower.endsWith("password:")) {
178 getPassword();
179 return;
180 }
181 if (lower.endsWith("user:")) {
182 getUsername();
183 return;
184 }
185 QRegExp userRe("\\buser:\\s*([^\\s]+)");
186 if (userRe.indexIn(text) >= 0) {
187 noteUsername(userRe.cap(1));
188 }
189 QRegExp realmRe("\\brealmr:\\s*([^\\s]+)");
190 if (realmRe.indexIn(text) >= 0) {
191 noteRealm(realmRe.cap(1));
192 }
193 }
194
195 void HgRunner::dataReady()
196 {
197 DEBUG << "dataReady" << endl;
198 QString chunk = QString::fromUtf8(m_proc->readAll());
199 m_output += chunk;
200 checkPrompts(chunk);
170 } 201 }
171 202
172 void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus) 203 void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus)
173 { 204 {
174 setProcExitInfo(procExitCode, procExitStatus); 205 setProcExitInfo(procExitCode, procExitStatus);
175 saveOutput(); 206 m_isRunning = false;
176 isRunning = false; 207
208 closeProcInput();
177 209
178 if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) { 210 if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) {
179 DEBUG << "HgRunner::finished: Command completed successfully: stderr says: " << stdErr << endl; 211 DEBUG << "HgRunner::finished: Command completed successfully" << endl;
180 emit commandCompleted(); 212 emit commandCompleted();
181 } else { 213 } else {
182 DEBUG << "HgRunner::finished: Command failed: stderr says: " << stdErr << endl; 214 DEBUG << "HgRunner::finished: Command failed" << endl;
183 emit commandFailed(); 215 emit commandFailed();
184 } 216 }
185 } 217 }
186 218
187 bool HgRunner::isCommandRunning() 219 bool HgRunner::isCommandRunning()
188 { 220 {
189 return isRunning; 221 return m_isRunning;
190 } 222 }
191 223
192 void HgRunner::killCurrentCommand() 224 void HgRunner::killCurrentCommand()
193 { 225 {
194 if (isCommandRunning()) { 226 if (isCommandRunning()) {
195 proc -> kill(); 227 m_proc -> kill();
196 } 228 }
197 } 229 }
198 230
199 void HgRunner::startHgCommand(QString workingDir, QStringList params) 231 void HgRunner::startHgCommand(QString workingDir, QStringList params)
200 { 232 {
201 startCommand(getHgBinaryName(), workingDir, params); 233 startCommand(getHgBinaryName(), workingDir, params);
202 } 234 }
203 235
204 void HgRunner::startCommand(QString command, QString workingDir, QStringList params) 236 void HgRunner::startCommand(QString command, QString workingDir, QStringList params)
205 { 237 {
206 isRunning = true; 238 m_isRunning = true;
207 setRange(0, 0); 239 setRange(0, 0);
208 setVisible(true); 240 setVisible(true);
209 stdOut.clear(); 241 m_output.clear();
210 stdErr.clear(); 242 m_exitCode = 0;
211 exitCode = 0; 243 m_exitStatus = QProcess::NormalExit;
212 exitStatus = QProcess::NormalExit; 244 m_realm = "";
213 245 m_userName = "";
214 if (!workingDir.isEmpty()) 246
215 { 247 if (!workingDir.isEmpty()) {
216 proc -> setWorkingDirectory(workingDir); 248 m_proc->setWorkingDirectory(workingDir);
217 } 249 }
218 250
219 lastHgCommand = command; 251 m_procInput = 0;
220 lastParams = params.join(" "); 252 #ifndef Q_OS_WIN32
253 char name[1024];
254 if (openpty(&m_ptyMasterFd, &m_ptySlaveFd, name, NULL, NULL)) {
255 perror("openpty failed");
256 } else {
257 DEBUG << "openpty succeeded: master " << m_ptyMasterFd
258 << " slave " << m_ptySlaveFd << " filename " << name << endl;
259 m_procInput = new QFile;
260 m_procInput->open(m_ptyMasterFd, QFile::WriteOnly);
261 m_ptySlaveFilename = name;
262 m_proc->setStandardInputFile(m_ptySlaveFilename);
263 ::close(m_ptySlaveFd);
264 }
265 #endif
266
267 m_lastHgCommand = command;
268 m_lastParams = params.join(" ");
221 269
222 QString cmdline = command; 270 QString cmdline = command;
223 foreach (QString param, params) cmdline += " " + param; 271 foreach (QString param, params) cmdline += " " + param;
224 DEBUG << "HgRunner: starting: " << cmdline << " with cwd " 272 DEBUG << "HgRunner: starting: " << cmdline << " with cwd "
225 << workingDir << endl; 273 << workingDir << endl;
226 274
227 proc -> start(command, params); 275 m_proc->start(command, params);
276 }
277
278 void HgRunner::closeProcInput()
279 {
280 DEBUG << "closeProcInput" << endl;
281
282 m_proc->closeWriteChannel();
283 #ifndef Q_OS_WIN32
284 if (m_ptySlaveFilename != "") {
285 ::close(m_ptyMasterFd);
286 m_ptySlaveFilename = "";
287 }
288 #endif
228 } 289 }
229 290
230 int HgRunner::getExitCode() 291 int HgRunner::getExitCode()
231 { 292 {
232 return exitCode; 293 return m_exitCode;
233 } 294 }
234 295
235 QString HgRunner::getStdOut() 296 QString HgRunner::getOutput()
236 { 297 {
237 return stdOut; 298 return m_output;
238 } 299 }
239 300
240 void HgRunner::hideProgBar() 301 void HgRunner::hideProgBar()
241 { 302 {
242 setVisible(false); 303 setVisible(false);