Plugins/VcsPlugins/vcsMercurial/HgLogDialog.py

branch
Py2 comp.
changeset 3484
645c12de6b0c
parent 3178
f25fc1364c88
parent 3330
955e15f0ecce
child 3532
86ac124f322c
equal deleted inserted replaced
3456:96232974dcdb 3484:645c12de6b0c
7 Module implementing a dialog to show the output of the hg log command process. 7 Module implementing a dialog to show the output of the hg log command process.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 try: 11 try:
12 str = unicode # __IGNORE_WARNING__ 12 str = unicode
13 except (NameError): 13 except NameError:
14 pass 14 pass
15 15
16 import os 16 import os
17 17
18 from PyQt4.QtCore import pyqtSlot, QProcess, QTimer, QUrl, QByteArray 18 from PyQt4.QtCore import pyqtSlot, QProcess, QTimer, QUrl, QByteArray
23 from E5Gui import E5MessageBox 23 from E5Gui import E5MessageBox
24 24
25 from .Ui_HgLogDialog import Ui_HgLogDialog 25 from .Ui_HgLogDialog import Ui_HgLogDialog
26 26
27 import Utilities 27 import Utilities
28 import Preferences
29 28
30 29
31 class HgLogDialog(QWidget, Ui_HgLogDialog): 30 class HgLogDialog(QWidget, Ui_HgLogDialog):
32 """ 31 """
33 Class implementing a dialog to show the output of the hg log command 32 Class implementing a dialog to show the output of the hg log command
60 self.mode = "log" 59 self.mode = "log"
61 self.bundle = bundle 60 self.bundle = bundle
62 self.__hgClient = self.vcs.getClient() 61 self.__hgClient = self.vcs.getClient()
63 62
64 self.contents.setHtml( 63 self.contents.setHtml(
65 self.trUtf8('<b>Processing your request, please wait...</b>')) 64 self.tr('<b>Processing your request, please wait...</b>'))
66 65
67 self.process.finished.connect(self.__procFinished) 66 self.process.finished.connect(self.__procFinished)
68 self.process.readyReadStandardOutput.connect(self.__readStdout) 67 self.process.readyReadStandardOutput.connect(self.__readStdout)
69 self.process.readyReadStandardError.connect(self.__readStderr) 68 self.process.readyReadStandardError.connect(self.__readStderr)
70 69
71 self.contents.anchorClicked.connect(self.__sourceChanged) 70 self.contents.anchorClicked.connect(self.__sourceChanged)
72 71
73 self.revisions = [] # stack of remembered revisions 72 self.revisions = [] # stack of remembered revisions
74 self.revString = self.trUtf8('Revision') 73 self.revString = self.tr('Revision')
75 self.projectMode = False 74 self.projectMode = False
76 75
77 self.logEntries = [] # list of log entries 76 self.logEntries = [] # list of log entries
78 self.lastLogEntry = {} 77 self.lastLogEntry = {}
79 self.fileCopies = {} 78 self.fileCopies = {}
128 self.projectMode = (self.fname == "." and self.dname == self.repodir) 127 self.projectMode = (self.fname == "." and self.dname == self.repodir)
129 128
130 self.activateWindow() 129 self.activateWindow()
131 self.raise_() 130 self.raise_()
132 131
133 args = [] 132 preargs = []
134 args.append(self.mode) 133 args = self.vcs.initCommand(self.mode)
135 self.vcs.addArguments(args, self.vcs.options['global'])
136 self.vcs.addArguments(args, self.vcs.options['log'])
137 if noEntries and self.mode == "log": 134 if noEntries and self.mode == "log":
138 args.append('--limit') 135 args.append('--limit')
139 args.append(str(noEntries)) 136 args.append(str(noEntries))
140 if self.mode in ("incoming", "outgoing"): 137 if self.mode in ("incoming", "outgoing"):
141 args.append("--newest-first") 138 args.append("--newest-first")
158 args.append(self.bundle) 155 args.append(self.bundle)
159 elif not self.vcs.hasSubrepositories(): 156 elif not self.vcs.hasSubrepositories():
160 project = e5App().getObject("Project") 157 project = e5App().getObject("Project")
161 self.vcs.bundleFile = os.path.join( 158 self.vcs.bundleFile = os.path.join(
162 project.getProjectManagementDir(), "hg-bundle.hg") 159 project.getProjectManagementDir(), "hg-bundle.hg")
163 args.append('--bundle') 160 if os.path.exists(self.vcs.bundleFile):
161 os.remove(self.vcs.bundleFile)
162 preargs = args[:]
163 preargs.append("--quiet")
164 preargs.append('--bundle')
165 preargs.append(self.vcs.bundleFile)
164 args.append(self.vcs.bundleFile) 166 args.append(self.vcs.bundleFile)
165 if revisions: 167 if revisions:
166 for rev in revisions: 168 for rev in revisions:
167 args.append("--rev") 169 args.append("--rev")
168 args.append(rev) 170 args.append(rev)
171 173
172 if self.__hgClient: 174 if self.__hgClient:
173 self.inputGroup.setEnabled(False) 175 self.inputGroup.setEnabled(False)
174 self.inputGroup.hide() 176 self.inputGroup.hide()
175 177
176 out, err = self.__hgClient.runcommand(args) 178 if preargs:
177 179 out, err = self.__hgClient.runcommand(preargs)
180 else:
181 err = ""
178 if err: 182 if err:
179 self.__showError(err) 183 self.__showError(err)
180 if out and self.isVisible(): 184 elif self.mode != "incoming" or \
181 for line in out.splitlines(True): 185 (self.vcs.bundleFile and
182 self.__processOutputLine(line) 186 os.path.exists(self.vcs.bundleFile)) or \
183 if self.__hgClient.wasCanceled(): 187 self.bundle:
184 break 188 out, err = self.__hgClient.runcommand(args)
185 189 if err:
190 self.__showError(err)
191 if out and self.isVisible():
192 for line in out.splitlines(True):
193 self.__processOutputLine(line)
194 if self.__hgClient.wasCanceled():
195 break
186 self.__finish() 196 self.__finish()
187 else: 197 else:
188 self.process.kill() 198 self.process.kill()
189 199
190 self.process.setWorkingDirectory(self.repodir) 200 self.process.setWorkingDirectory(self.repodir)
191 201
192 self.process.start('hg', args) 202 if preargs:
193 procStarted = self.process.waitForStarted(5000) 203 process = QProcess()
194 if not procStarted: 204 process.setWorkingDirectory(self.repodir)
195 self.inputGroup.setEnabled(False) 205 process.start('hg', args)
196 self.inputGroup.hide() 206 procStarted = process.waitForStarted(5000)
197 E5MessageBox.critical( 207 if procStarted:
198 self, 208 process.waitForFinished(30000)
199 self.trUtf8('Process Generation Error'), 209
200 self.trUtf8( 210 if self.mode != "incoming" or \
201 'The process {0} could not be started. ' 211 (self.vcs.bundleFile and
202 'Ensure, that it is in the search path.' 212 os.path.exists(self.vcs.bundleFile)) or \
203 ).format('hg')) 213 self.bundle:
214 self.process.start('hg', args)
215 procStarted = self.process.waitForStarted(5000)
216 if not procStarted:
217 self.inputGroup.setEnabled(False)
218 self.inputGroup.hide()
219 E5MessageBox.critical(
220 self,
221 self.tr('Process Generation Error'),
222 self.tr(
223 'The process {0} could not be started. '
224 'Ensure, that it is in the search path.'
225 ).format('hg'))
226 else:
227 self.__finish()
204 228
205 def __getParents(self, rev): 229 def __getParents(self, rev):
206 """ 230 """
207 Private method to get the parents of the currently viewed 231 Private method to get the parents of the currently viewed
208 file/directory. 232 file/directory.
212 """ 236 """
213 errMsg = "" 237 errMsg = ""
214 parents = [] 238 parents = []
215 239
216 if int(rev) > 0: 240 if int(rev) > 0:
217 args = [] 241 args = self.vcs.initCommand("parents")
218 args.append("parents")
219 if self.mode == "incoming": 242 if self.mode == "incoming":
220 if self.bundle: 243 if self.bundle:
221 args.append("--repository") 244 args.append("--repository")
222 args.append(self.bundle) 245 args.append(self.bundle)
223 elif self.vcs.bundleFile and \ 246 elif self.vcs.bundleFile and \
240 process.start('hg', args) 263 process.start('hg', args)
241 procStarted = process.waitForStarted(5000) 264 procStarted = process.waitForStarted(5000)
242 if procStarted: 265 if procStarted:
243 finished = process.waitForFinished(30000) 266 finished = process.waitForFinished(30000)
244 if finished and process.exitCode() == 0: 267 if finished and process.exitCode() == 0:
245 output = \ 268 output = str(process.readAllStandardOutput(),
246 str(process.readAllStandardOutput(), 269 self.vcs.getEncoding(), 'replace')
247 Preferences.getSystem("IOEncoding"),
248 'replace')
249 else: 270 else:
250 if not finished: 271 if not finished:
251 errMsg = self.trUtf8( 272 errMsg = self.tr(
252 "The hg process did not finish within 30s.") 273 "The hg process did not finish within 30s.")
253 else: 274 else:
254 errMsg = self.trUtf8("Could not start the hg executable.") 275 errMsg = self.tr("Could not start the hg executable.")
255 276
256 if errMsg: 277 if errMsg:
257 E5MessageBox.critical( 278 E5MessageBox.critical(
258 self, 279 self,
259 self.trUtf8("Mercurial Error"), 280 self.tr("Mercurial Error"),
260 errMsg) 281 errMsg)
261 282
262 if output: 283 if output:
263 parents = [p for p in output.strip().splitlines()] 284 parents = [p for p in output.strip().splitlines()]
264 285
282 self.inputGroup.hide() 303 self.inputGroup.hide()
283 304
284 self.contents.clear() 305 self.contents.clear()
285 306
286 if not self.logEntries: 307 if not self.logEntries:
287 self.errors.append(self.trUtf8("No log available for '{0}'") 308 self.errors.append(self.tr("No log available for '{0}'")
288 .format(self.filename)) 309 .format(self.filename))
289 self.errorGroup.show() 310 self.errorGroup.show()
290 return 311 return
291 312
292 html = "" 313 html = ""
318 query.append(parent.split(":")[0]).append('_').append(rev) 339 query.append(parent.split(":")[0]).append('_').append(rev)
319 url.setEncodedQuery(query) 340 url.setEncodedQuery(query)
320 dstr += ' [<a href="{0}" name="{1}" id="{1}">{2}</a>]'.format( 341 dstr += ' [<a href="{0}" name="{1}" id="{1}">{2}</a>]'.format(
321 url.toString(), 342 url.toString(),
322 str(query, encoding="ascii"), 343 str(query, encoding="ascii"),
323 self.trUtf8('diff to {0}').format(parent), 344 self.tr('diff to {0}').format(parent),
324 ) 345 )
325 dstr += '<br />\n' 346 dstr += '<br />\n'
326 html += dstr 347 html += dstr
327 348
328 if "phase" in entry: 349 if "phase" in entry:
329 html += self.trUtf8("Phase: {0}<br />\n")\ 350 html += self.tr("Phase: {0}<br />\n")\
330 .format(entry["phase"]) 351 .format(entry["phase"])
331 352
332 html += self.trUtf8("Branches: {0}<br />\n")\ 353 html += self.tr("Branches: {0}<br />\n")\
333 .format(entry["branches"]) 354 .format(entry["branches"])
334 355
335 html += self.trUtf8("Tags: {0}<br />\n").format(entry["tags"]) 356 html += self.tr("Tags: {0}<br />\n").format(entry["tags"])
336 357
337 if "bookmarks" in entry: 358 if "bookmarks" in entry:
338 html += self.trUtf8("Bookmarks: {0}<br />\n")\ 359 html += self.tr("Bookmarks: {0}<br />\n")\
339 .format(entry["bookmarks"]) 360 .format(entry["bookmarks"])
340 361
341 html += self.trUtf8("Parents: {0}<br />\n")\ 362 html += self.tr("Parents: {0}<br />\n")\
342 .format(entry["parents"]) 363 .format(entry["parents"])
343 364
344 html += self.trUtf8('<i>Author: {0}</i><br />\n')\ 365 html += self.tr('<i>Author: {0}</i><br />\n')\
345 .format(entry["user"]) 366 .format(entry["user"])
346 367
347 date, time = entry["date"].split()[:2] 368 date, time = entry["date"].split()[:2]
348 html += self.trUtf8('<i>Date: {0}, {1}</i><br />\n')\ 369 html += self.tr('<i>Date: {0}, {1}</i><br />\n')\
349 .format(date, time) 370 .format(date, time)
350 371
351 for line in entry["description"]: 372 for line in entry["description"]:
352 html += Utilities.html_encode(line.strip()) 373 html += Utilities.html_encode(line.strip())
353 html += '<br />\n' 374 html += '<br />\n'
354 375
355 if entry["file_adds"]: 376 if entry["file_adds"]:
356 html += '<br />\n' 377 html += '<br />\n'
357 for f in entry["file_adds"].strip().split(", "): 378 for f in entry["file_adds"].strip().split(", "):
358 if f in fileCopies: 379 if f in fileCopies:
359 html += self.trUtf8( 380 html += self.tr(
360 'Added {0} (copied from {1})<br />\n')\ 381 'Added {0} (copied from {1})<br />\n')\
361 .format(Utilities.html_encode(f), 382 .format(Utilities.html_encode(f),
362 Utilities.html_encode(fileCopies[f])) 383 Utilities.html_encode(fileCopies[f]))
363 else: 384 else:
364 html += self.trUtf8('Added {0}<br />\n')\ 385 html += self.tr('Added {0}<br />\n')\
365 .format(Utilities.html_encode(f)) 386 .format(Utilities.html_encode(f))
366 387
367 if entry["files_mods"]: 388 if entry["files_mods"]:
368 html += '<br />\n' 389 html += '<br />\n'
369 for f in entry["files_mods"].strip().split(", "): 390 for f in entry["files_mods"].strip().split(", "):
370 html += self.trUtf8('Modified {0}<br />\n')\ 391 html += self.tr('Modified {0}<br />\n')\
371 .format(Utilities.html_encode(f)) 392 .format(Utilities.html_encode(f))
372 393
373 if entry["file_dels"]: 394 if entry["file_dels"]:
374 html += '<br />\n' 395 html += '<br />\n'
375 for f in entry["file_dels"].strip().split(", "): 396 for f in entry["file_dels"].strip().split(", "):
376 html += self.trUtf8('Deleted {0}<br />\n')\ 397 html += self.tr('Deleted {0}<br />\n')\
377 .format(Utilities.html_encode(f)) 398 .format(Utilities.html_encode(f))
378 399
379 html += '</p>{0}<br/>\n'.format(80 * "=") 400 html += '</p>{0}<br/>\n'.format(80 * "=")
380 401
381 self.contents.setHtml(html) 402 self.contents.setHtml(html)
391 It reads the output of the process and inserts it into a buffer. 412 It reads the output of the process and inserts it into a buffer.
392 """ 413 """
393 self.process.setReadChannel(QProcess.StandardOutput) 414 self.process.setReadChannel(QProcess.StandardOutput)
394 415
395 while self.process.canReadLine(): 416 while self.process.canReadLine():
396 s = str(self.process.readLine(), 417 s = str(self.process.readLine(), self.vcs.getEncoding(), 'replace')
397 Preferences.getSystem("IOEncoding"),
398 'replace')
399 self.__processOutputLine(s) 418 self.__processOutputLine(s)
400 419
401 def __processOutputLine(self, line): 420 def __processOutputLine(self, line):
402 """ 421 """
403 Private method to process the lines of output. 422 Private method to process the lines of output.
414 except ValueError: 433 except ValueError:
415 key = "" 434 key = ""
416 value = line 435 value = line
417 if key == "change": 436 if key == "change":
418 self.endInitialText = True 437 self.endInitialText = True
419 if key in ("change", "branches", "tags", "parents", "user", 438 if key in ("change", "tags", "parents", "user", "date",
420 "date", "file_copies", "file_adds", "files_mods", 439 "file_copies", "file_adds", "files_mods", "file_dels",
421 "file_dels", "bookmarks", "phase"): 440 "bookmarks", "phase"):
422 self.lastLogEntry[key] = value.strip() 441 self.lastLogEntry[key] = value.strip()
442 elif key == "branches":
443 if value.strip():
444 self.lastLogEntry[key] = value.strip()
445 else:
446 self.lastLogEntry[key] = "default"
423 elif key == "description": 447 elif key == "description":
424 self.lastLogEntry[key] = [value.strip()] 448 self.lastLogEntry[key] = [value.strip()]
425 else: 449 else:
426 if self.endInitialText: 450 if self.endInitialText:
427 self.lastLogEntry["description"].append(value.strip()) 451 self.lastLogEntry["description"].append(value.strip())
435 It reads the error output of the process and inserts it into the 459 It reads the error output of the process and inserts it into the
436 error pane. 460 error pane.
437 """ 461 """
438 if self.process is not None: 462 if self.process is not None:
439 s = str(self.process.readAllStandardError(), 463 s = str(self.process.readAllStandardError(),
440 Preferences.getSystem("IOEncoding"), 464 self.vcs.getEncoding(), 'replace')
441 'replace')
442 self.__showError(s) 465 self.__showError(s)
443 466
444 def __showError(self, out): 467 def __showError(self, out):
445 """ 468 """
446 Private slot to show some error. 469 Private slot to show some error.

eric ide

mercurial