Plugins/VcsPlugins/vcsMercurial/hg.py

branch
Py2 comp.
changeset 2847
1843ef6e2656
parent 2791
a9577f248f04
parent 2844
a61ee61b1c2c
child 3057
10516539f238
equal deleted inserted replaced
2846:b852fe4d153a 2847:1843ef6e2656
95 self.adminDir = '.hg' 95 self.adminDir = '.hg'
96 96
97 self.log = None 97 self.log = None
98 self.logBrowser = None 98 self.logBrowser = None
99 self.diff = None 99 self.diff = None
100 self.sbsDiff = None
100 self.status = None 101 self.status = None
102 self.summary = None
101 self.tagbranchList = None 103 self.tagbranchList = None
102 self.annotate = None 104 self.annotate = None
103 self.repoEditor = None 105 self.repoEditor = None
104 self.userEditor = None 106 self.userEditor = None
105 self.serveDlg = None 107 self.serveDlg = None
159 self.log.close() 161 self.log.close()
160 if self.logBrowser is not None: 162 if self.logBrowser is not None:
161 self.logBrowser.close() 163 self.logBrowser.close()
162 if self.diff is not None: 164 if self.diff is not None:
163 self.diff.close() 165 self.diff.close()
166 if self.sbsDiff is not None:
167 self.sbsDiff.close()
164 if self.status is not None: 168 if self.status is not None:
165 self.status.close() 169 self.status.close()
170 if self.summary is not None:
171 self.summary.close()
166 if self.tagbranchList is not None: 172 if self.tagbranchList is not None:
167 self.tagbranchList.close() 173 self.tagbranchList.close()
168 if self.annotate is not None: 174 if self.annotate is not None:
169 self.annotate.close() 175 self.annotate.close()
170 if self.serveDlg is not None: 176 if self.serveDlg is not None:
366 shutil.rmtree(os.path.join(projectDir, self.adminDir), True) 372 shutil.rmtree(os.path.join(projectDir, self.adminDir), True)
367 if os.path.exists(os.path.join(projectDir, '.hgignore')): 373 if os.path.exists(os.path.join(projectDir, '.hgignore')):
368 os.remove(os.path.join(projectDir, '.hgignore')) 374 os.remove(os.path.join(projectDir, '.hgignore'))
369 return status 375 return status
370 376
371 def vcsCommit(self, name, message, noDialog=False, closeBranch=False): 377 def vcsCommit(self, name, message, noDialog=False, closeBranch=False, mq=False):
372 """ 378 """
373 Public method used to make the change of a file/directory permanent in the 379 Public method used to make the change of a file/directory permanent in the
374 Mercurial repository. 380 Mercurial repository.
375 381
376 @param name file/directory name to be committed (string or list of strings) 382 @param name file/directory name to be committed (string or list of strings)
377 @param message message for this operation (string) 383 @param message message for this operation (string)
378 @param noDialog flag indicating quiet operations 384 @param noDialog flag indicating quiet operations
379 @keyparam closeBranch flag indicating a close branch commit (boolean) 385 @keyparam closeBranch flag indicating a close branch commit (boolean)
386 @keyparam mq flag indicating a queue commit (boolean)
380 """ 387 """
381 msg = message 388 msg = message
389
390 if mq:
391 # ensure dialog is shown for a queue commit
392 noDialog = False
382 393
383 if not noDialog and not msg: 394 if not noDialog and not msg:
384 # call CommitDialog and get message from there 395 # call CommitDialog and get message from there
385 if self.__commitDialog is None: 396 if self.__commitDialog is None:
386 from .HgCommitDialog import HgCommitDialog 397 from .HgCommitDialog import HgCommitDialog
387 self.__commitDialog = HgCommitDialog(self, self.__ui) 398 self.__commitDialog = HgCommitDialog(self, mq, self.__ui)
388 self.__commitDialog.accepted.connect(self.__vcsCommit_Step2) 399 self.__commitDialog.accepted.connect(self.__vcsCommit_Step2)
389 self.__commitDialog.show() 400 self.__commitDialog.show()
390 self.__commitDialog.raise_() 401 self.__commitDialog.raise_()
391 self.__commitDialog.activateWindow() 402 self.__commitDialog.activateWindow()
392 403
393 self.__commitData["name"] = name 404 self.__commitData["name"] = name
394 self.__commitData["msg"] = msg 405 self.__commitData["msg"] = msg
395 self.__commitData["noDialog"] = noDialog 406 self.__commitData["noDialog"] = noDialog
396 self.__commitData["closeBranch"] = closeBranch 407 self.__commitData["closeBranch"] = closeBranch
408 self.__commitData["mq"] = mq
397 409
398 if noDialog: 410 if noDialog:
399 self.__vcsCommit_Step2() 411 self.__vcsCommit_Step2()
400 412
401 def __vcsCommit_Step2(self): 413 def __vcsCommit_Step2(self):
404 """ 416 """
405 name = self.__commitData["name"] 417 name = self.__commitData["name"]
406 msg = self.__commitData["msg"] 418 msg = self.__commitData["msg"]
407 noDialog = self.__commitData["noDialog"] 419 noDialog = self.__commitData["noDialog"]
408 closeBranch = self.__commitData["closeBranch"] 420 closeBranch = self.__commitData["closeBranch"]
421 mq = self.__commitData["mq"]
409 422
410 if not noDialog: 423 if not noDialog:
411 # check, if there are unsaved changes, that should be committed 424 # check, if there are unsaved changes, that should be committed
412 if isinstance(name, list): 425 if isinstance(name, list):
413 nameList = name 426 nameList = name
440 453
441 if self.__commitDialog is not None: 454 if self.__commitDialog is not None:
442 msg = self.__commitDialog.logMessage() 455 msg = self.__commitDialog.logMessage()
443 amend = self.__commitDialog.amend() 456 amend = self.__commitDialog.amend()
444 commitSubrepositories = self.__commitDialog.commitSubrepositories() 457 commitSubrepositories = self.__commitDialog.commitSubrepositories()
445 ## self.__commitDialog.accepted.disconnect(self.__vcsCommit_Step2)
446 self.__commitDialog.deleteLater() 458 self.__commitDialog.deleteLater()
447 self.__commitDialog = None 459 self.__commitDialog = None
448 else: 460 else:
449 amend = False 461 amend = False
450 commitSubrepositories = False 462 commitSubrepositories = False
455 args = [] 467 args = []
456 args.append('commit') 468 args.append('commit')
457 self.addArguments(args, self.options['global']) 469 self.addArguments(args, self.options['global'])
458 self.addArguments(args, self.options['commit']) 470 self.addArguments(args, self.options['commit'])
459 args.append("-v") 471 args.append("-v")
460 if closeBranch: 472 if mq:
461 args.append("--close-branch") 473 args.append("--mq")
462 if amend: 474 else:
463 args.append("--amend") 475 if closeBranch:
464 if commitSubrepositories: 476 args.append("--close-branch")
465 args.append("--subrepos") 477 if amend:
478 args.append("--amend")
479 if commitSubrepositories:
480 args.append("--subrepos")
466 if msg: 481 if msg:
467 args.append("--message") 482 args.append("--message")
468 args.append(msg) 483 args.append(msg)
469 if isinstance(name, list): 484 if isinstance(name, list):
470 dname, fnames = self.splitPathList(name) 485 dname, fnames = self.splitPathList(name)
751 Mercurial repository. 766 Mercurial repository.
752 767
753 @param name file/directory name to show the log of (string) 768 @param name file/directory name to show the log of (string)
754 """ 769 """
755 dname, fname = self.splitPath(name) 770 dname, fname = self.splitPath(name)
771 isFile = os.path.isfile(name)
756 772
757 # find the root of the repo 773 # find the root of the repo
758 repodir = dname 774 repodir = dname
759 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 775 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
760 repodir = os.path.dirname(repodir) 776 repodir = os.path.dirname(repodir)
776 showLimit=True, 792 showLimit=True,
777 limitDefault=self.getPlugin().getPreferences("LogLimit")) 793 limitDefault=self.getPlugin().getPreferences("LogLimit"))
778 if dlg.exec_() == QDialog.Accepted: 794 if dlg.exec_() == QDialog.Accepted:
779 revs, noEntries = dlg.getRevisions() 795 revs, noEntries = dlg.getRevisions()
780 from .HgLogDialog import HgLogDialog 796 from .HgLogDialog import HgLogDialog
781 self.log = HgLogDialog(self) 797 self.log = HgLogDialog(self, isFile=isFile)
782 self.log.show() 798 self.log.show()
783 self.log.start(name, noEntries=noEntries, revisions=revs) 799 self.log.start(name, noEntries=noEntries, revisions=revs)
784 800
785 def vcsDiff(self, name): 801 def vcsDiff(self, name):
786 """ 802 """
822 """ 838 """
823 from .HgStatusDialog import HgStatusDialog 839 from .HgStatusDialog import HgStatusDialog
824 self.status = HgStatusDialog(self) 840 self.status = HgStatusDialog(self)
825 self.status.show() 841 self.status.show()
826 self.status.start(name) 842 self.status.start(name)
843
844 def hgSummary(self, mq=False):
845 """
846 Public method used to show some summary information of the
847 working directory state.
848
849 @param mq flag indicating to show the queue status as well (boolean)
850 """
851 from .HgSummaryDialog import HgSummaryDialog
852 self.summary = HgSummaryDialog(self)
853 self.summary.show()
854 self.summary.start(self.__projectHelper.getProject().getProjectPath(), mq=mq)
827 855
828 def vcsTag(self, name): 856 def vcsTag(self, name):
829 """ 857 """
830 Public method used to set the tag in the Mercurial repository. 858 Public method used to set the tag in the Mercurial repository.
831 859
1252 Public method to retrieve information about the repository. 1280 Public method to retrieve information about the repository.
1253 1281
1254 @param ppath local path to get the repository infos (string) 1282 @param ppath local path to get the repository infos (string)
1255 @return string with ready formated info for display (string) 1283 @return string with ready formated info for display (string)
1256 """ 1284 """
1257 info = []
1258
1259 args = [] 1285 args = []
1260 args.append('parents') 1286 args.append('parents')
1261 args.append('--template') 1287 args.append('--template')
1262 args.append('{rev}:{node|short}@@@{tags}@@@{author|xmlescape}@@@' 1288 args.append('{rev}:{node|short}@@@{tags}@@@{author|xmlescape}@@@'
1263 '{date|isodate}@@@{branches}@@@{bookmarks}\n') 1289 '{date|isodate}@@@{branches}@@@{bookmarks}\n')
1274 output = str(process.readAllStandardOutput(), 1300 output = str(process.readAllStandardOutput(),
1275 Preferences.getSystem("IOEncoding"), 'replace') 1301 Preferences.getSystem("IOEncoding"), 'replace')
1276 else: 1302 else:
1277 output, error = self.__client.runcommand(args) 1303 output, error = self.__client.runcommand(args)
1278 1304
1305 infoBlock = []
1279 if output: 1306 if output:
1280 index = 0 1307 index = 0
1281 for line in output.splitlines(): 1308 for line in output.splitlines():
1282 index += 1 1309 index += 1
1283 changeset, tags, author, date, branches, bookmarks = line.split("@@@") 1310 changeset, tags, author, date, branches, bookmarks = line.split("@@@")
1284 cdate, ctime = date.split()[:2] 1311 cdate, ctime = date.split()[:2]
1285 info.append("""<p><table>""") 1312 info = []
1286 info.append(QApplication.translate("mercurial", 1313 info.append(QApplication.translate("mercurial",
1287 """<tr><td><b>Parent #{0}</b></td><td></td></tr>\n""" 1314 """<tr><td><b>Parent #{0}</b></td><td></td></tr>\n"""
1288 """<tr><td><b>Changeset</b></td><td>{1}</td></tr>""")\ 1315 """<tr><td><b>Changeset</b></td><td>{1}</td></tr>""")\
1289 .format(index, changeset)) 1316 .format(index, changeset))
1290 if tags: 1317 if tags:
1302 info.append(QApplication.translate("mercurial", 1329 info.append(QApplication.translate("mercurial",
1303 """<tr><td><b>Last author</b></td><td>{0}</td></tr>\n""" 1330 """<tr><td><b>Last author</b></td><td>{0}</td></tr>\n"""
1304 """<tr><td><b>Committed date</b></td><td>{1}</td></tr>\n""" 1331 """<tr><td><b>Committed date</b></td><td>{1}</td></tr>\n"""
1305 """<tr><td><b>Committed time</b></td><td>{2}</td></tr>""")\ 1332 """<tr><td><b>Committed time</b></td><td>{2}</td></tr>""")\
1306 .format(author, cdate, ctime)) 1333 .format(author, cdate, ctime))
1307 info.append("""</table></p>""") 1334 infoBlock.append("\n".join(info))
1335 if infoBlock:
1336 infoStr = """<tr></tr>{0}""".format("<tr></tr>".join(infoBlock))
1337 else:
1338 infoStr = ""
1308 1339
1309 url = "" 1340 url = ""
1310 args = [] 1341 args = []
1311 args.append('showconfig') 1342 args.append('showconfig')
1312 args.append('paths.default') 1343 args.append('paths.default')
1333 """<h3>Repository information</h3>\n""" 1364 """<h3>Repository information</h3>\n"""
1334 """<p><table>\n""" 1365 """<p><table>\n"""
1335 """<tr><td><b>Mercurial V.</b></td><td>{0}</td></tr>\n""" 1366 """<tr><td><b>Mercurial V.</b></td><td>{0}</td></tr>\n"""
1336 """<tr></tr>\n""" 1367 """<tr></tr>\n"""
1337 """<tr><td><b>URL</b></td><td>{1}</td></tr>\n""" 1368 """<tr><td><b>URL</b></td><td>{1}</td></tr>\n"""
1369 """{2}"""
1338 """</table></p>\n""" 1370 """</table></p>\n"""
1339 """{2}""" 1371 ).format(self.versionStr, url, infoStr)
1340 ).format(self.versionStr, url, "\n".join(info))
1341 1372
1342 ############################################################################ 1373 ############################################################################
1343 ## Private Mercurial specific methods are below. 1374 ## Private Mercurial specific methods are below.
1344 ############################################################################ 1375 ############################################################################
1345 1376
1603 from .HgDiffDialog import HgDiffDialog 1634 from .HgDiffDialog import HgDiffDialog
1604 self.diff = HgDiffDialog(self) 1635 self.diff = HgDiffDialog(self)
1605 self.diff.show() 1636 self.diff.show()
1606 self.diff.start(name, revisions) 1637 self.diff.start(name, revisions)
1607 1638
1608 def hgLogBrowser(self, path): 1639 def __hgGetFileForRevision(self, name, rev=""):
1640 """
1641 Private method to get a file for a specific revision from the repository.
1642
1643 @param name file name to get from the repository (string)
1644 @keyparam rev revision to retrieve (string)
1645 @return contents of the file (string) and an error message (string)
1646 """
1647 args = []
1648 args.append("cat")
1649 if rev:
1650 args.append("--rev")
1651 args.append(rev)
1652 args.append(name)
1653
1654 if self.__client is None:
1655 output = ""
1656 error = ""
1657
1658 # find the root of the repo
1659 repodir = self.splitPath(name)[0]
1660 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
1661 repodir = os.path.dirname(repodir)
1662 if os.path.splitdrive(repodir)[1] == os.sep:
1663 return
1664
1665 process = QProcess()
1666 process.setWorkingDirectory(repodir)
1667 process.start('hg', args)
1668 procStarted = process.waitForStarted(5000)
1669 if procStarted:
1670 finished = process.waitForFinished(30000)
1671 if finished:
1672 if process.exitCode() == 0:
1673 output = str(process.readAllStandardOutput(),
1674 Preferences.getSystem("IOEncoding"), 'replace')
1675 else:
1676 error = str(process.readAllStandardError(),
1677 Preferences.getSystem("IOEncoding"), 'replace')
1678 else:
1679 error = self.trUtf8("The hg process did not finish within 30s.")
1680 else:
1681 error = self.trUtf8('The process {0} could not be started. '
1682 'Ensure, that it is in the search path.').format('hg')
1683 else:
1684 output, error = self.__client.runcommand(args)
1685
1686 return output, error
1687
1688 def hgSbsDiff(self, name, extended=False, revisions=None):
1689 """
1690 Public method used to view the difference of a file to the Mercurial repository
1691 side-by-side.
1692
1693 @param name file name to be diffed (string)
1694 @keyparam extended flag indicating the extended variant (boolean)
1695 @keyparam revisions tuple of two revisions (tuple of strings)
1696 """
1697 if isinstance(name, list):
1698 raise ValueError("Wrong parameter type")
1699
1700 if extended:
1701 # find the root of the repo
1702 repodir = self.splitPath(name)[0]
1703 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
1704 repodir = os.path.dirname(repodir)
1705 if os.path.splitdrive(repodir)[1] == os.sep:
1706 return
1707
1708 if self.isExtensionActive("bookmarks"):
1709 bookmarksList = \
1710 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir)
1711 else:
1712 bookmarksList = None
1713
1714 from .HgRevisionsSelectionDialog import HgRevisionsSelectionDialog
1715 dlg = HgRevisionsSelectionDialog(self.hgGetTagsList(repodir),
1716 self.hgGetBranchesList(repodir),
1717 bookmarksList)
1718 if dlg.exec_() == QDialog.Accepted:
1719 rev1, rev2 = dlg.getRevisions()
1720 elif revisions:
1721 rev1, rev2 = revisions[0], revisions[1]
1722 else:
1723 rev1, rev2 = "", ""
1724
1725 output1, error = self.__hgGetFileForRevision(name, rev=rev1)
1726 if error:
1727 E5MessageBox.critical(self.__ui,
1728 self.trUtf8("Mercurial Side-by-Side Difference"),
1729 error)
1730 return
1731 name1 = "{0} (rev. {1})".format(name, rev1 and rev1 or ".")
1732
1733 if rev2:
1734 output2, error = self.__hgGetFileForRevision(name, rev=rev2)
1735 if error:
1736 E5MessageBox.critical(self.__ui,
1737 self.trUtf8("Mercurial Side-by-Side Difference"),
1738 error)
1739 return
1740 name2 = "{0} (rev. {1})".format(name, rev2)
1741 else:
1742 try:
1743 f1 = open(name, "r", encoding="utf-8")
1744 output2 = f1.read()
1745 f1.close()
1746 name2 = name
1747 except IOError:
1748 E5MessageBox.critical(self.__ui,
1749 self.trUtf8("Mercurial Side-by-Side Difference"),
1750 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""")
1751 .format(name))
1752 return
1753
1754 if self.sbsDiff is None:
1755 from UI.CompareDialog import CompareDialog
1756 self.sbsDiff = CompareDialog()
1757 self.sbsDiff.show()
1758 self.sbsDiff.compare(output1, output2, name1, name2)
1759
1760 def hgLogBrowser(self, path, isFile=False):
1609 """ 1761 """
1610 Public method used to browse the log of a file/directory from the 1762 Public method used to browse the log of a file/directory from the
1611 Mercurial repository. 1763 Mercurial repository.
1612 1764
1613 @param path file/directory name to show the log of (string) 1765 @param path file/directory name to show the log of (string)
1766 @keyparam isFile flag indicating log for a file is to be shown (boolean)
1614 """ 1767 """
1615 from .HgLogBrowserDialog import HgLogBrowserDialog 1768 from .HgLogBrowserDialog import HgLogBrowserDialog
1616 self.logBrowser = HgLogBrowserDialog(self) 1769 self.logBrowser = HgLogBrowserDialog(self, isFile=isFile)
1617 self.logBrowser.show() 1770 self.logBrowser.show()
1618 self.logBrowser.start(path) 1771 self.logBrowser.start(path)
1619 1772
1620 def hgIncoming(self, name): 1773 def hgIncoming(self, name):
1621 """ 1774 """
2714 dia.exec_() 2867 dia.exec_()
2715 res = dia.hasAddOrDelete() 2868 res = dia.hasAddOrDelete()
2716 self.checkVCSStatus() 2869 self.checkVCSStatus()
2717 return res 2870 return res
2718 2871
2872 def hgArchive(self):
2873 """
2874 Public method to create an unversioned archive from the repository.
2875 """
2876 # find the root of the repo
2877 repodir = self.__projectHelper.getProject().getProjectPath()
2878 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
2879 repodir = os.path.dirname(repodir)
2880 if os.path.splitdrive(repodir)[1] == os.sep:
2881 return
2882
2883 from .HgArchiveDialog import HgArchiveDialog
2884 dlg = HgArchiveDialog(self)
2885 if dlg.exec_() == QDialog.Accepted:
2886 archive, type_, prefix, subrepos = dlg.getData()
2887
2888 args = []
2889 args.append("archive")
2890 if type_:
2891 args.append("--type")
2892 args.append(type_)
2893 if prefix:
2894 args.append("--prefix")
2895 args.append(prefix)
2896 if subrepos:
2897 args.append("--subrepos")
2898 args.append(archive)
2899
2900 dia = HgDialog(self.trUtf8("Create Unversioned Archive"), self)
2901 res = dia.startProcess(args, repodir)
2902 if res:
2903 dia.exec_()
2904
2719 ############################################################################ 2905 ############################################################################
2720 ## Methods to deal with subrepositories are below. 2906 ## Methods to deal with subrepositories are below.
2721 ############################################################################ 2907 ############################################################################
2722 2908
2723 def getHgSubPath(self): 2909 def getHgSubPath(self):

eric ide

mercurial