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