comparison hgrunner.cpp @ 109:1721c580c10e

* Add a queueing mechanism for Hg actions, instead of refusing to start an action if something else is already happening. This is essential now that actions can be prompted by asynchronous events (e.g. filesystem watcher). * Make Revert behave sensibly
author Chris Cannam
date Fri, 26 Nov 2010 12:48:29 +0000
parents fdca34c989c0
children 0f039d3cc38e
comparison
equal deleted inserted replaced
108:8ae3b44c0073 109:1721c580c10e
70 ::close(m_ptyMasterFd); 70 ::close(m_ptyMasterFd);
71 } 71 }
72 delete m_proc; 72 delete m_proc;
73 } 73 }
74 74
75 void HgRunner::requestAction(HgAction action)
76 {
77 DEBUG << "requestAction " << action.action << endl;
78 bool pushIt = true;
79 if (m_queue.empty()) {
80 if (action == m_currentAction) {
81 // this request is identical to the thing we're executing
82 DEBUG << "requestAction: we're already handling this one, ignoring identical request" << endl;
83 pushIt = false;
84 }
85 } else {
86 HgAction last = m_queue.back();
87 if (action == last) {
88 // this request is identical to the previous thing we
89 // queued which we haven't executed yet
90 DEBUG << "requestAction: we're already queueing this one, ignoring identical request" << endl;
91 pushIt = false;
92 }
93 }
94 if (pushIt) m_queue.push_back(action);
95 checkQueue();
96 }
97
75 QString HgRunner::getHgBinaryName() 98 QString HgRunner::getHgBinaryName()
76 { 99 {
77 QSettings settings; 100 QSettings settings;
78 QString hg = settings.value("hgbinary", "").toString(); 101 QString hg = settings.value("hgbinary", "").toString();
79 if (hg == "") { 102 if (hg == "") {
91 /* 114 /*
92 m_proc->write("blah\n"); 115 m_proc->write("blah\n");
93 m_proc->write("blah\n"); 116 m_proc->write("blah\n");
94 m_proc -> closeWriteChannel(); 117 m_proc -> closeWriteChannel();
95 */ 118 */
96 }
97
98 void HgRunner::setProcExitInfo(int procExitCode, QProcess::ExitStatus procExitStatus)
99 {
100 m_exitCode = procExitCode;
101 m_exitStatus = procExitStatus;
102 }
103
104 QString HgRunner::getLastCommandLine()
105 {
106 return QString("Command line: " + m_lastHgCommand + " " + m_lastParams);
107 } 119 }
108 120
109 void HgRunner::noteUsername(QString name) 121 void HgRunner::noteUsername(QString name)
110 { 122 {
111 m_userName = name; 123 m_userName = name;
198 checkPrompts(chunk); 210 checkPrompts(chunk);
199 } 211 }
200 212
201 void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus) 213 void HgRunner::finished(int procExitCode, QProcess::ExitStatus procExitStatus)
202 { 214 {
203 setProcExitInfo(procExitCode, procExitStatus); 215 // Save the current action and reset m_currentAction before we
216 // emit a signal to mark the completion; otherwise we may be
217 // resetting the action after a slot has already tried to set it
218 // to something else to start a new action
219
220 HgAction completedAction = m_currentAction;
221
204 m_isRunning = false; 222 m_isRunning = false;
223 m_currentAction = HgAction();
205 224
206 closeProcInput(); 225 closeProcInput();
226
227 if (completedAction.action == ACT_NONE) {
228 DEBUG << "HgRunner::finished: WARNING: completed action is ACT_NONE" << endl;
229 }
207 230
208 if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) { 231 if (procExitCode == 0 && procExitStatus == QProcess::NormalExit) {
209 DEBUG << "HgRunner::finished: Command completed successfully" << endl; 232 DEBUG << "HgRunner::finished: Command completed successfully" << endl;
210 emit commandCompleted(); 233 //!!! NB this is all output not stdout as it should be
234 emit commandCompleted(completedAction, m_output);
211 } else { 235 } else {
212 DEBUG << "HgRunner::finished: Command failed" << endl; 236 DEBUG << "HgRunner::finished: Command failed" << endl;
213 emit commandFailed(); 237 //!!! NB this is all output not stderr as it should be
214 } 238 emit commandFailed(completedAction, m_output);
215 } 239 }
216 240
241 checkQueue();
242 }
243 /*
217 bool HgRunner::isCommandRunning() 244 bool HgRunner::isCommandRunning()
218 { 245 {
219 return m_isRunning; 246 return m_isRunning;
220 } 247 }
248 */
221 249
222 void HgRunner::killCurrentCommand() 250 void HgRunner::killCurrentCommand()
223 { 251 {
224 if (isCommandRunning()) { 252 if (m_isRunning) {
225 m_proc -> kill(); 253 m_proc -> kill();
226 } 254 }
227 } 255 }
228 256
229 void HgRunner::startHgCommand(QString workingDir, QStringList params, bool interactive) 257 void HgRunner::checkQueue()
230 { 258 {
259 if (m_isRunning) {
260 return;
261 }
262 if (m_queue.empty()) {
263 hide();
264 return;
265 }
266 HgAction toRun = m_queue.front();
267 m_queue.pop_front();
268 DEBUG << "checkQueue: have action: running " << toRun.action << endl;
269 startCommand(toRun);
270 }
271
272 void HgRunner::startCommand(HgAction action)
273 {
274 QString executable = action.executable;
275 bool interactive = false;
276 QStringList params = action.params;
277
278 if (executable == "") {
279 // This is a Hg command
280 executable = getHgBinaryName();
231 #ifdef Q_OS_WIN32 281 #ifdef Q_OS_WIN32
232 // This at least means we won't block on the non-working password prompt 282 // This at least means we won't block on the non-working password prompt
233 params.push_front("ui.interactive=false"); 283 params.push_front("--noninteractive");
234 #else 284 #else
235 // password prompt should work here 285 // password prompt should work here
236 if (interactive) { 286 if (action.mayBeInteractive()) {
237 params.push_front("ui.interactive=true"); 287 params.push_front("ui.interactive=true");
238 } else { 288 params.push_front("--config");
239 params.push_front("ui.interactive=false"); 289 interactive = true;
240 } 290 } else {
241 #endif 291 params.push_front("--noninteractive");
242 params.push_front("--config"); 292 }
243 startCommand(getHgBinaryName(), workingDir, params, interactive); 293 }
244 } 294 #endif
245 295
246 void HgRunner::startCommand(QString command, QString workingDir, QStringList params,
247 bool interactive)
248 {
249 m_isRunning = true; 296 m_isRunning = true;
250 setRange(0, 0); 297 setRange(0, 0);
251 setVisible(true); 298 show();
252 m_output.clear(); 299 m_output.clear();
253 m_exitCode = 0;
254 m_exitStatus = QProcess::NormalExit;
255 m_realm = ""; 300 m_realm = "";
256 m_userName = ""; 301 m_userName = "";
257 302
258 if (!workingDir.isEmpty()) { 303 if (!action.workingDir.isEmpty()) {
259 m_proc->setWorkingDirectory(workingDir); 304 m_proc->setWorkingDirectory(action.workingDir);
260 } 305 }
261 306
262 m_procInput = 0; 307 m_procInput = 0;
263 m_ptySlaveFilename = ""; 308 m_ptySlaveFilename = "";
264 309
277 ::close(m_ptySlaveFd); 322 ::close(m_ptySlaveFd);
278 } 323 }
279 } 324 }
280 #endif 325 #endif
281 326
282 m_lastHgCommand = command; 327 QString cmdline = executable;
283 m_lastParams = params.join(" ");
284
285 QString cmdline = command;
286 foreach (QString param, params) cmdline += " " + param; 328 foreach (QString param, params) cmdline += " " + param;
287 DEBUG << "HgRunner: starting: " << cmdline << " with cwd " 329 DEBUG << "HgRunner: starting: " << cmdline << " with cwd "
288 << workingDir << endl; 330 << action.workingDir << endl;
289 331
290 m_proc->start(command, params); 332 m_currentAction = action;
333
334 DEBUG << "set current action to " << m_currentAction.action << endl;
335
336 m_proc->start(executable, params);
291 } 337 }
292 338
293 void HgRunner::closeProcInput() 339 void HgRunner::closeProcInput()
294 { 340 {
295 DEBUG << "closeProcInput" << endl; 341 DEBUG << "closeProcInput" << endl;
301 m_ptySlaveFilename = ""; 347 m_ptySlaveFilename = "";
302 } 348 }
303 #endif 349 #endif
304 } 350 }
305 351
306 int HgRunner::getExitCode()
307 {
308 return m_exitCode;
309 }
310
311 QString HgRunner::getOutput()
312 {
313 return m_output;
314 }
315
316 void HgRunner::hideProgBar()
317 {
318 setVisible(false);
319 }
320
321