Plugins/VcsPlugins/vcsMercurial/hg.py

branch
Py2 comp.
changeset 3057
10516539f238
parent 2847
1843ef6e2656
parent 3008
7848489bcb92
child 3058
0a02c433f52d
equal deleted inserted replaced
3056:9986ec0e559a 3057:10516539f238
38 class Hg(VersionControl): 38 class Hg(VersionControl):
39 """ 39 """
40 Class implementing the version control systems interface to Mercurial. 40 Class implementing the version control systems interface to Mercurial.
41 41
42 @signal committed() emitted after the commit action has completed 42 @signal committed() emitted after the commit action has completed
43 @signal activeExtensionsChanged() emitted when the list of active extensions 43 @signal activeExtensionsChanged() emitted when the list of active
44 has changed 44 extensions has changed
45 """ 45 """
46 committed = pyqtSignal() 46 committed = pyqtSignal()
47 activeExtensionsChanged = pyqtSignal() 47 activeExtensionsChanged = pyqtSignal()
48 48
49 IgnoreFileName = ".hgignore" 49 IgnoreFileName = ".hgignore"
199 199
200 def vcsExists(self): 200 def vcsExists(self):
201 """ 201 """
202 Public method used to test for the presence of the hg executable. 202 Public method used to test for the presence of the hg executable.
203 203
204 @return flag indicating the existance (boolean) and an error message (string) 204 @return flag indicating the existance (boolean) and an error message
205 (string)
205 """ 206 """
206 self.versionStr = '' 207 self.versionStr = ''
207 errMsg = "" 208 errMsg = ""
208 ioEncoding = Preferences.getSystem("IOEncoding") 209 ioEncoding = Preferences.getSystem("IOEncoding")
209 210
228 self.version = tuple(v) 229 self.version = tuple(v)
229 self.__getExtensionsInfo() 230 self.__getExtensionsInfo()
230 return True, errMsg 231 return True, errMsg
231 else: 232 else:
232 if finished: 233 if finished:
233 errMsg = \ 234 errMsg = self.trUtf8(
234 self.trUtf8("The hg process finished with the exit code {0}")\ 235 "The hg process finished with the exit code {0}")\
235 .format(process.exitCode()) 236 .format(process.exitCode())
236 else: 237 else:
237 errMsg = self.trUtf8("The hg process did not finish within 30s.") 238 errMsg = self.trUtf8(
239 "The hg process did not finish within 30s.")
238 else: 240 else:
239 errMsg = self.trUtf8("Could not start the hg executable.") 241 errMsg = self.trUtf8("Could not start the hg executable.")
240 242
241 return False, errMsg 243 return False, errMsg
242 244
243 def vcsInit(self, vcsDir, noDialog=False): 245 def vcsInit(self, vcsDir, noDialog=False):
244 """ 246 """
245 Public method used to initialize the mercurial repository. 247 Public method used to initialize the mercurial repository.
246 248
247 The initialization is done, when a project is converted into a Mercurial 249 The initialization is done, when a project is converted into a
248 controlled project. Therefore we always return TRUE without doing anything. 250 Mercurial controlled project. Therefore we always return TRUE without
251 doing anything.
249 252
250 @param vcsDir name of the VCS directory (string) 253 @param vcsDir name of the VCS directory (string)
251 @param noDialog flag indicating quiet operations (boolean) 254 @param noDialog flag indicating quiet operations (boolean)
252 @return always TRUE 255 @return always TRUE
253 """ 256 """
254 return True 257 return True
255 258
256 def vcsConvertProject(self, vcsDataDict, project): 259 def vcsConvertProject(self, vcsDataDict, project):
257 """ 260 """
258 Public method to convert an uncontrolled project to a version controlled project. 261 Public method to convert an uncontrolled project to a version
262 controlled project.
259 263
260 @param vcsDataDict dictionary of data required for the conversion 264 @param vcsDataDict dictionary of data required for the conversion
261 @param project reference to the project object 265 @param project reference to the project object
262 """ 266 """
263 success = self.vcsImport(vcsDataDict, project.ppath)[0] 267 success = self.vcsImport(vcsDataDict, project.ppath)[0]
264 if not success: 268 if not success:
265 E5MessageBox.critical(self.__ui, 269 E5MessageBox.critical(self.__ui,
266 self.trUtf8("Create project repository"), 270 self.trUtf8("Create project repository"),
267 self.trUtf8("""The project repository could not be created.""")) 271 self.trUtf8(
272 """The project repository could not be created."""))
268 else: 273 else:
269 pfn = project.pfile 274 pfn = project.pfile
270 if not os.path.isfile(pfn): 275 if not os.path.isfile(pfn):
271 pfn += "z" 276 pfn += "z"
272 project.closeProject() 277 project.closeProject()
273 project.openProject(pfn) 278 project.openProject(pfn)
274 279
275 def vcsImport(self, vcsDataDict, projectDir, noDialog=False): 280 def vcsImport(self, vcsDataDict, projectDir, noDialog=False):
276 """ 281 """
277 Public method used to import the project into the Subversion repository. 282 Public method used to import the project into the Mercurial repository.
278 283
279 @param vcsDataDict dictionary of data required for the import 284 @param vcsDataDict dictionary of data required for the import
280 @param projectDir project directory (string) 285 @param projectDir project directory (string)
281 @param noDialog flag indicating quiet operations 286 @param noDialog flag indicating quiet operations
282 @return flag indicating an execution without errors (boolean) 287 @return flag indicating an execution without errors (boolean)
305 args = [] 310 args = []
306 args.append('commit') 311 args.append('commit')
307 args.append('--addremove') 312 args.append('--addremove')
308 args.append('--message') 313 args.append('--message')
309 args.append(msg) 314 args.append(msg)
310 dia = HgDialog(self.trUtf8('Initial commit to Mercurial repository'), 315 dia = HgDialog(
311 self) 316 self.trUtf8('Initial commit to Mercurial repository'),
317 self)
312 res = dia.startProcess(args, projectDir) 318 res = dia.startProcess(args, projectDir)
313 if res: 319 if res:
314 dia.exec_() 320 dia.exec_()
315 status = dia.normalExit() 321 status = dia.normalExit()
316 322
317 return status, False 323 return status, False
318 324
319 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False): 325 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False):
320 """ 326 """
321 Public method used to check the project out of a Mercurial repository (clone). 327 Public method used to check the project out of a Mercurial repository
328 (clone).
322 329
323 @param vcsDataDict dictionary of data required for the checkout 330 @param vcsDataDict dictionary of data required for the checkout
324 @param projectDir project directory to create (string) 331 @param projectDir project directory to create (string)
325 @param noDialog flag indicating quiet operations 332 @param noDialog flag indicating quiet operations
326 @return flag indicating an execution without errors (boolean) 333 @return flag indicating an execution without errors (boolean)
351 return self.startSynchronizedProcess(QProcess(), 'hg', args) 358 return self.startSynchronizedProcess(QProcess(), 'hg', args)
352 else: 359 else:
353 out, err = self.__client.runcommand(args) 360 out, err = self.__client.runcommand(args)
354 return err == "" 361 return err == ""
355 else: 362 else:
356 dia = HgDialog(self.trUtf8('Cloning project from a Mercurial repository'), 363 dia = HgDialog(
357 self) 364 self.trUtf8('Cloning project from a Mercurial repository'),
365 self)
358 res = dia.startProcess(args) 366 res = dia.startProcess(args)
359 if res: 367 if res:
360 dia.exec_() 368 dia.exec_()
361 return dia.normalExit() 369 return dia.normalExit()
362 370
363 def vcsExport(self, vcsDataDict, projectDir): 371 def vcsExport(self, vcsDataDict, projectDir):
364 """ 372 """
365 Public method used to export a directory from the Subversion repository. 373 Public method used to export a directory from the Mercurial repository.
366 374
367 @param vcsDataDict dictionary of data required for the checkout 375 @param vcsDataDict dictionary of data required for the checkout
368 @param projectDir project directory to create (string) 376 @param projectDir project directory to create (string)
369 @return flag indicating an execution without errors (boolean) 377 @return flag indicating an execution without errors (boolean)
370 """ 378 """
372 shutil.rmtree(os.path.join(projectDir, self.adminDir), True) 380 shutil.rmtree(os.path.join(projectDir, self.adminDir), True)
373 if os.path.exists(os.path.join(projectDir, '.hgignore')): 381 if os.path.exists(os.path.join(projectDir, '.hgignore')):
374 os.remove(os.path.join(projectDir, '.hgignore')) 382 os.remove(os.path.join(projectDir, '.hgignore'))
375 return status 383 return status
376 384
377 def vcsCommit(self, name, message, noDialog=False, closeBranch=False, mq=False): 385 def vcsCommit(self, name, message, noDialog=False, closeBranch=False,
378 """ 386 mq=False):
379 Public method used to make the change of a file/directory permanent in the 387 """
380 Mercurial repository. 388 Public method used to make the change of a file/directory permanent
381 389 in the Mercurial repository.
382 @param name file/directory name to be committed (string or list of strings) 390
391 @param name file/directory name to be committed (string or list of
392 strings)
383 @param message message for this operation (string) 393 @param message message for this operation (string)
384 @param noDialog flag indicating quiet operations 394 @param noDialog flag indicating quiet operations
385 @keyparam closeBranch flag indicating a close branch commit (boolean) 395 @keyparam closeBranch flag indicating a close branch commit (boolean)
386 @keyparam mq flag indicating a queue commit (boolean) 396 @keyparam mq flag indicating a queue commit (boolean)
387 """ 397 """
430 for nam in nameList: 440 for nam in nameList:
431 # check for commit of the project 441 # check for commit of the project
432 if os.path.isdir(nam): 442 if os.path.isdir(nam):
433 project = e5App().getObject("Project") 443 project = e5App().getObject("Project")
434 if nam == project.getProjectPath(): 444 if nam == project.getProjectPath():
435 ok &= project.checkAllScriptsDirty(reportSyntaxErrors=True) and \ 445 ok &= \
436 project.checkDirty() 446 project.checkAllScriptsDirty(
447 reportSyntaxErrors=True) and \
448 project.checkDirty()
437 continue 449 continue
438 elif os.path.isfile(nam): 450 elif os.path.isfile(nam):
439 editor = e5App().getObject("ViewManager").getOpenEditor(nam) 451 editor = \
452 e5App().getObject("ViewManager").getOpenEditor(nam)
440 if editor: 453 if editor:
441 ok &= editor.checkDirty() 454 ok &= editor.checkDirty()
442 if not ok: 455 if not ok:
443 break 456 break
444 457
445 if not ok: 458 if not ok:
446 res = E5MessageBox.yesNo(self.__ui, 459 res = E5MessageBox.yesNo(self.__ui,
447 self.trUtf8("Commit Changes"), 460 self.trUtf8("Commit Changes"),
448 self.trUtf8("""The commit affects files, that have unsaved""" 461 self.trUtf8(
449 """ changes. Shall the commit be continued?"""), 462 """The commit affects files, that have unsaved"""
463 """ changes. Shall the commit be continued?"""),
450 icon=E5MessageBox.Warning) 464 icon=E5MessageBox.Warning)
451 if not res: 465 if not res:
452 return 466 return
453 467
454 if self.__commitDialog is not None: 468 if self.__commitDialog is not None:
507 args.append(fname) 521 args.append(fname)
508 522
509 if noDialog: 523 if noDialog:
510 self.startSynchronizedProcess(QProcess(), "hg", args, dname) 524 self.startSynchronizedProcess(QProcess(), "hg", args, dname)
511 else: 525 else:
512 dia = HgDialog(self.trUtf8('Committing changes to Mercurial repository'), 526 dia = HgDialog(
513 self) 527 self.trUtf8('Committing changes to Mercurial repository'),
528 self)
514 res = dia.startProcess(args, dname) 529 res = dia.startProcess(args, dname)
515 if res: 530 if res:
516 dia.exec_() 531 dia.exec_()
517 self.committed.emit() 532 self.committed.emit()
518 if self.__forgotNames: 533 if self.__forgotNames:
522 self.__forgotNames = [] 537 self.__forgotNames = []
523 self.checkVCSStatus() 538 self.checkVCSStatus()
524 539
525 def vcsUpdate(self, name, noDialog=False, revision=None): 540 def vcsUpdate(self, name, noDialog=False, revision=None):
526 """ 541 """
527 Public method used to update a file/directory with the Mercurial repository. 542 Public method used to update a file/directory with the Mercurial
528 543 repository.
529 @param name file/directory name to be updated (string or list of strings) 544
545 @param name file/directory name to be updated (string or list of
546 strings)
530 @param noDialog flag indicating quiet operations (boolean) 547 @param noDialog flag indicating quiet operations (boolean)
531 @keyparam revision revision to update to (string) 548 @keyparam revision revision to update to (string)
532 @return flag indicating, that the update contained an add 549 @return flag indicating, that the update contained an add
533 or delete (boolean) 550 or delete (boolean)
534 """ 551 """
559 self.startSynchronizedProcess(QProcess(), 'hg', args, repodir) 576 self.startSynchronizedProcess(QProcess(), 'hg', args, repodir)
560 else: 577 else:
561 out, err = self.__client.runcommand(args) 578 out, err = self.__client.runcommand(args)
562 res = False 579 res = False
563 else: 580 else:
564 dia = HgDialog(self.trUtf8('Synchronizing with the Mercurial repository'), 581 dia = HgDialog(self.trUtf8(
565 self) 582 'Synchronizing with the Mercurial repository'),
583 self)
566 res = dia.startProcess(args, repodir) 584 res = dia.startProcess(args, repodir)
567 if res: 585 if res:
568 dia.exec_() 586 dia.exec_()
569 res = dia.hasAddOrDelete() 587 res = dia.hasAddOrDelete()
570 self.checkVCSStatus() 588 self.checkVCSStatus()
612 self.startSynchronizedProcess(QProcess(), 'hg', args, repodir) 630 self.startSynchronizedProcess(QProcess(), 'hg', args, repodir)
613 else: 631 else:
614 out, err = self.__client.runcommand(args) 632 out, err = self.__client.runcommand(args)
615 else: 633 else:
616 dia = HgDialog( 634 dia = HgDialog(
617 self.trUtf8('Adding files/directories to the Mercurial repository'), self) 635 self.trUtf8(
636 'Adding files/directories to the Mercurial repository'),
637 self)
618 res = dia.startProcess(args, repodir) 638 res = dia.startProcess(args, repodir)
619 if res: 639 if res:
620 dia.exec_() 640 dia.exec_()
621 641
622 def vcsAddBinary(self, name, isDir=False): 642 def vcsAddBinary(self, name, isDir=False):
629 """ 649 """
630 self.vcsAdd(name, isDir) 650 self.vcsAdd(name, isDir)
631 651
632 def vcsAddTree(self, path): 652 def vcsAddTree(self, path):
633 """ 653 """
634 Public method to add a directory tree rooted at path to the Mercurial repository. 654 Public method to add a directory tree rooted at path to the Mercurial
635 655 repository.
636 @param path root directory of the tree to be added (string or list of strings)) 656
657 @param path root directory of the tree to be added (string or list of
658 strings))
637 """ 659 """
638 self.vcsAdd(path, isDir=False) 660 self.vcsAdd(path, isDir=False)
639 661
640 def vcsRemove(self, name, project=False, noDialog=False): 662 def vcsRemove(self, name, project=False, noDialog=False):
641 """ 663 """
642 Public method used to remove a file/directory from the Mercurial repository. 664 Public method used to remove a file/directory from the Mercurial
665 repository.
643 666
644 The default operation is to remove the local copy as well. 667 The default operation is to remove the local copy as well.
645 668
646 @param name file/directory name to be removed (string or list of strings)) 669 @param name file/directory name to be removed (string or list of
647 @param project flag indicating deletion of a project tree (boolean) (not needed) 670 strings))
671 @param project flag indicating deletion of a project tree (boolean)
672 (not needed)
648 @param noDialog flag indicating quiet operations 673 @param noDialog flag indicating quiet operations
649 @return flag indicating successfull operation (boolean) 674 @return flag indicating successfull operation (boolean)
650 """ 675 """
651 args = [] 676 args = []
652 args.append('remove') 677 args.append('remove')
670 if os.path.splitdrive(repodir)[1] == os.sep: 695 if os.path.splitdrive(repodir)[1] == os.sep:
671 return False 696 return False
672 697
673 if noDialog: 698 if noDialog:
674 if self.__client is None: 699 if self.__client is None:
675 res = self.startSynchronizedProcess(QProcess(), 'hg', args, repodir) 700 res = self.startSynchronizedProcess(
701 QProcess(), 'hg', args, repodir)
676 else: 702 else:
677 out, err = self.__client.runcommand(args) 703 out, err = self.__client.runcommand(args)
678 res = err == "" 704 res = err == ""
679 else: 705 else:
680 dia = HgDialog( 706 dia = HgDialog(
681 self.trUtf8('Removing files/directories from the Mercurial repository'), 707 self.trUtf8(
708 'Removing files/directories from the Mercurial'
709 ' repository'),
682 self) 710 self)
683 res = dia.startProcess(args, repodir) 711 res = dia.startProcess(args, repodir)
684 if res: 712 if res:
685 dia.exec_() 713 dia.exec_()
686 res = dia.normalExitWithoutErrors() 714 res = dia.normalExitWithoutErrors()
733 repodir = os.path.dirname(repodir) 761 repodir = os.path.dirname(repodir)
734 if os.path.splitdrive(repodir)[1] == os.sep: 762 if os.path.splitdrive(repodir)[1] == os.sep:
735 return False 763 return False
736 764
737 if noDialog: 765 if noDialog:
738 res = self.startSynchronizedProcess(QProcess(), "hg", args, repodir)
739 if self.__client is None: 766 if self.__client is None:
740 res = self.startSynchronizedProcess(QProcess(), 'hg', args, repodir) 767 res = self.startSynchronizedProcess(
768 QProcess(), 'hg', args, repodir)
741 else: 769 else:
742 out, err = self.__client.runcommand(args) 770 out, err = self.__client.runcommand(args)
743 res = err == "" 771 res = err == ""
744 else: 772 else:
745 dia = HgDialog(self.trUtf8('Renaming {0}').format(name), self) 773 dia = HgDialog(self.trUtf8('Renaming {0}').format(name), self)
777 if os.path.splitdrive(repodir)[1] == os.sep: 805 if os.path.splitdrive(repodir)[1] == os.sep:
778 return 806 return
779 807
780 if self.isExtensionActive("bookmarks"): 808 if self.isExtensionActive("bookmarks"):
781 bookmarksList = \ 809 bookmarksList = \
782 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 810 self.getExtensionObject("bookmarks")\
811 .hgGetBookmarksList(repodir)
783 else: 812 else:
784 bookmarksList = None 813 bookmarksList = None
785 814
786 from .HgMultiRevisionSelectionDialog import HgMultiRevisionSelectionDialog 815 from .HgMultiRevisionSelectionDialog import \
816 HgMultiRevisionSelectionDialog
787 dlg = HgMultiRevisionSelectionDialog( 817 dlg = HgMultiRevisionSelectionDialog(
788 self.hgGetTagsList(repodir), 818 self.hgGetTagsList(repodir),
789 self.hgGetBranchesList(repodir), 819 self.hgGetBranchesList(repodir),
790 bookmarksList, 820 bookmarksList,
791 emptyRevsOk=True, 821 emptyRevsOk=True,
802 """ 832 """
803 Public method used to view the difference of a file/directory to the 833 Public method used to view the difference of a file/directory to the
804 Mercurial repository. 834 Mercurial repository.
805 835
806 If name is a directory and is the project directory, all project files 836 If name is a directory and is the project directory, all project files
807 are saved first. If name is a file (or list of files), which is/are being edited 837 are saved first. If name is a file (or list of files), which is/are
808 and has unsaved modification, they can be saved or the operation may be aborted. 838 being edited and has unsaved modification, they can be saved or the
839 operation may be aborted.
809 840
810 @param name file/directory name to be diffed (string) 841 @param name file/directory name to be diffed (string)
811 """ 842 """
812 if isinstance(name, list): 843 if isinstance(name, list):
813 names = name[:] 844 names = name[:]
849 @param mq flag indicating to show the queue status as well (boolean) 880 @param mq flag indicating to show the queue status as well (boolean)
850 """ 881 """
851 from .HgSummaryDialog import HgSummaryDialog 882 from .HgSummaryDialog import HgSummaryDialog
852 self.summary = HgSummaryDialog(self) 883 self.summary = HgSummaryDialog(self)
853 self.summary.show() 884 self.summary.show()
854 self.summary.start(self.__projectHelper.getProject().getProjectPath(), mq=mq) 885 self.summary.start(self.__projectHelper.getProject().getProjectPath(),
886 mq=mq)
855 887
856 def vcsTag(self, name): 888 def vcsTag(self, name):
857 """ 889 """
858 Public method used to set the tag in the Mercurial repository. 890 Public method used to set the tag in the Mercurial repository.
859 891
925 return False 957 return False
926 958
927 project = e5App().getObject("Project") 959 project = e5App().getObject("Project")
928 names = [project.getRelativePath(nam) for nam in names] 960 names = [project.getRelativePath(nam) for nam in names]
929 if names[0]: 961 if names[0]:
930 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog 962 from UI.DeleteFilesConfirmationDialog import \
963 DeleteFilesConfirmationDialog
931 dlg = DeleteFilesConfirmationDialog(self.parent(), 964 dlg = DeleteFilesConfirmationDialog(self.parent(),
932 self.trUtf8("Revert changes"), 965 self.trUtf8("Revert changes"),
933 self.trUtf8("Do you really want to revert all changes to these files" 966 self.trUtf8(
934 " or directories?"), 967 "Do you really want to revert all changes to these files"
968 " or directories?"),
935 names) 969 names)
936 yes = dlg.exec_() == QDialog.Accepted 970 yes = dlg.exec_() == QDialog.Accepted
937 else: 971 else:
938 yes = E5MessageBox.yesNo(None, 972 yes = E5MessageBox.yesNo(None,
939 self.trUtf8("Revert changes"), 973 self.trUtf8("Revert changes"),
971 if force: 1005 if force:
972 del opts[opts.index('--force')] 1006 del opts[opts.index('--force')]
973 1007
974 if self.isExtensionActive("bookmarks"): 1008 if self.isExtensionActive("bookmarks"):
975 bookmarksList = \ 1009 bookmarksList = \
976 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 1010 self.getExtensionObject("bookmarks")\
1011 .hgGetBookmarksList(repodir)
977 else: 1012 else:
978 bookmarksList = None 1013 bookmarksList = None
979 from .HgMergeDialog import HgMergeDialog 1014 from .HgMergeDialog import HgMergeDialog
980 dlg = HgMergeDialog(force, self.hgGetTagsList(repodir), 1015 dlg = HgMergeDialog(force, self.hgGetTagsList(repodir),
981 self.hgGetBranchesList(repodir), 1016 self.hgGetBranchesList(repodir),
1000 dia.exec_() 1035 dia.exec_()
1001 self.checkVCSStatus() 1036 self.checkVCSStatus()
1002 1037
1003 def vcsSwitch(self, name): 1038 def vcsSwitch(self, name):
1004 """ 1039 """
1005 Public method used to switch a working directory to a different revision. 1040 Public method used to switch a working directory to a different
1041 revision.
1006 1042
1007 @param name directory name to be switched (string) 1043 @param name directory name to be switched (string)
1008 @return flag indicating, that the switch contained an add 1044 @return flag indicating, that the switch contained an add
1009 or delete (boolean) 1045 or delete (boolean)
1010 """ 1046 """
1017 if os.path.splitdrive(repodir)[1] == os.sep: 1053 if os.path.splitdrive(repodir)[1] == os.sep:
1018 return False 1054 return False
1019 1055
1020 if self.isExtensionActive("bookmarks"): 1056 if self.isExtensionActive("bookmarks"):
1021 bookmarksList = \ 1057 bookmarksList = \
1022 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 1058 self.getExtensionObject("bookmarks")\
1059 .hgGetBookmarksList(repodir)
1023 else: 1060 else:
1024 bookmarksList = None 1061 bookmarksList = None
1025 from .HgRevisionSelectionDialog import HgRevisionSelectionDialog 1062 from .HgRevisionSelectionDialog import HgRevisionSelectionDialog
1026 dlg = HgRevisionSelectionDialog(self.hgGetTagsList(repodir), 1063 dlg = HgRevisionSelectionDialog(self.hgGetTagsList(repodir),
1027 self.hgGetBranchesList(repodir), 1064 self.hgGetBranchesList(repodir),
1094 1131
1095 return self.canBeAdded 1132 return self.canBeAdded
1096 1133
1097 def vcsAllRegisteredStates(self, names, dname, shortcut=True): 1134 def vcsAllRegisteredStates(self, names, dname, shortcut=True):
1098 """ 1135 """
1099 Public method used to get the registered states of a number of files in the vcs. 1136 Public method used to get the registered states of a number of files
1100 1137 in the vcs.
1101 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1138
1102 directory has been scanned already. If so, it is assumed, that the states for 1139 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1103 all files have been populated by the previous run. 1140 if the named directory has been scanned already. If so, it is assumed,
1141 that the states for all files have been populated by the previous run.
1104 1142
1105 @param names dictionary with all filenames to be checked as keys 1143 @param names dictionary with all filenames to be checked as keys
1106 @param dname directory to check in (string) 1144 @param dname directory to check in (string)
1107 @param shortcut flag indicating a shortcut should be taken (boolean) 1145 @param shortcut flag indicating a shortcut should be taken (boolean)
1108 @return the received dictionary completed with a combination of 1146 @return the received dictionary completed with a combination of
1258 """ 1296 """
1259 Public method to get a dialog to enter repository info. 1297 Public method to get a dialog to enter repository info.
1260 1298
1261 @param project reference to the project object 1299 @param project reference to the project object
1262 @param archive name of the project in the repository (string) 1300 @param archive name of the project in the repository (string)
1263 @param editable flag indicating that the project name is editable (boolean) 1301 @param editable flag indicating that the project name is editable
1302 (boolean)
1264 @param parent parent widget (QWidget) 1303 @param parent parent widget (QWidget)
1304 @return reference to the instantiated options dialog (HgOptionsDialog)
1265 """ 1305 """
1266 from .HgOptionsDialog import HgOptionsDialog 1306 from .HgOptionsDialog import HgOptionsDialog
1267 return HgOptionsDialog(self, project, parent) 1307 return HgOptionsDialog(self, project, parent)
1268 1308
1269 def vcsNewProjectOptionsDialog(self, parent=None): 1309 def vcsNewProjectOptionsDialog(self, parent=None):
1270 """ 1310 """
1271 Public method to get a dialog to enter repository info for getting a new project. 1311 Public method to get a dialog to enter repository info for getting a
1312 new project.
1272 1313
1273 @param parent parent widget (QWidget) 1314 @param parent parent widget (QWidget)
1315 @return reference to the instantiated options dialog
1316 (HgNewProjectOptionsDialog)
1274 """ 1317 """
1275 from .HgNewProjectOptionsDialog import HgNewProjectOptionsDialog 1318 from .HgNewProjectOptionsDialog import HgNewProjectOptionsDialog
1276 return HgNewProjectOptionsDialog(self, parent) 1319 return HgNewProjectOptionsDialog(self, parent)
1277 1320
1278 def vcsRepositoryInfos(self, ppath): 1321 def vcsRepositoryInfos(self, ppath):
1305 infoBlock = [] 1348 infoBlock = []
1306 if output: 1349 if output:
1307 index = 0 1350 index = 0
1308 for line in output.splitlines(): 1351 for line in output.splitlines():
1309 index += 1 1352 index += 1
1310 changeset, tags, author, date, branches, bookmarks = line.split("@@@") 1353 changeset, tags, author, date, branches, bookmarks = \
1354 line.split("@@@")
1311 cdate, ctime = date.split()[:2] 1355 cdate, ctime = date.split()[:2]
1312 info = [] 1356 info = []
1313 info.append(QApplication.translate("mercurial", 1357 info.append(QApplication.translate("mercurial",
1314 """<tr><td><b>Parent #{0}</b></td><td></td></tr>\n""" 1358 """<tr><td><b>Parent #{0}</b></td><td></td></tr>\n"""
1315 """<tr><td><b>Changeset</b></td><td>{1}</td></tr>""")\ 1359 """<tr><td><b>Changeset</b></td><td>{1}</td></tr>""")\
1368 """<tr><td><b>URL</b></td><td>{1}</td></tr>\n""" 1412 """<tr><td><b>URL</b></td><td>{1}</td></tr>\n"""
1369 """{2}""" 1413 """{2}"""
1370 """</table></p>\n""" 1414 """</table></p>\n"""
1371 ).format(self.versionStr, url, infoStr) 1415 ).format(self.versionStr, url, infoStr)
1372 1416
1373 ############################################################################ 1417 ###########################################################################
1374 ## Private Mercurial specific methods are below. 1418 ## Private Mercurial specific methods are below.
1375 ############################################################################ 1419 ###########################################################################
1376 1420
1377 def __hgURL(self, url): 1421 def __hgURL(self, url):
1378 """ 1422 """
1379 Private method to format a url for Mercurial. 1423 Private method to format a url for Mercurial.
1380 1424
1392 scheme, user, host, port, parse.quote(path)) 1436 scheme, user, host, port, parse.quote(path))
1393 elif len(url) == 3: 1437 elif len(url) == 3:
1394 scheme = url[0] 1438 scheme = url[0]
1395 host = url[1] 1439 host = url[1]
1396 port, path = url[2].split("/", 1) 1440 port, path = url[2].split("/", 1)
1397 return "{0}:{1}:{2}/{3}".format(scheme, host, port, parse.quote(path)) 1441 return "{0}:{1}:{2}/{3}".format(
1442 scheme, host, port, parse.quote(path))
1398 else: 1443 else:
1399 scheme = url[0] 1444 scheme = url[0]
1400 if scheme == "file": 1445 if scheme == "file":
1401 return "{0}:{1}".format(scheme, parse.quote(url[1])) 1446 return "{0}:{1}".format(scheme, parse.quote(url[1]))
1402 else: 1447 else:
1403 host, path = url[1][2:].split("/", 1) 1448 host, path = url[1][2:].split("/", 1)
1404 return "{0}://{1}/{2}".format(scheme, host, parse.quote(path)) 1449 return "{0}://{1}/{2}".format(
1450 scheme, host, parse.quote(path))
1405 1451
1406 def hgNormalizeURL(self, url): 1452 def hgNormalizeURL(self, url):
1407 """ 1453 """
1408 Public method to normalize a url for Mercurial. 1454 Public method to normalize a url for Mercurial.
1409 1455
1569 allTagsBranchesList = self.allTagsBranchesList 1615 allTagsBranchesList = self.allTagsBranchesList
1570 else: 1616 else:
1571 self.branchesList = [] 1617 self.branchesList = []
1572 allTagsBranchesList = None 1618 allTagsBranchesList = None
1573 self.tagbranchList.start(path, tags, 1619 self.tagbranchList.start(path, tags,
1574 self.branchesList, self.allTagsBranchesList) 1620 self.branchesList,
1621 self.allTagsBranchesList)
1575 1622
1576 def hgAnnotate(self, name): 1623 def hgAnnotate(self, name):
1577 """ 1624 """
1578 Public method to show the output of the hg annotate command. 1625 Public method to show the output of the hg annotate command.
1579 1626
1588 """ 1635 """
1589 Public method used to view the difference of a file/directory to the 1636 Public method used to view the difference of a file/directory to the
1590 Mercurial repository. 1637 Mercurial repository.
1591 1638
1592 If name is a directory and is the project directory, all project files 1639 If name is a directory and is the project directory, all project files
1593 are saved first. If name is a file (or list of files), which is/are being edited 1640 are saved first. If name is a file (or list of files), which is/are
1594 and has unsaved modification, they can be saved or the operation may be aborted. 1641 being edited and has unsaved modification, they can be saved or the
1642 operation may be aborted.
1595 1643
1596 This method gives the chance to enter the revisions to be compared. 1644 This method gives the chance to enter the revisions to be compared.
1597 1645
1598 @param name file/directory name to be diffed (string) 1646 @param name file/directory name to be diffed (string)
1599 """ 1647 """
1620 if os.path.splitdrive(repodir)[1] == os.sep: 1668 if os.path.splitdrive(repodir)[1] == os.sep:
1621 return 1669 return
1622 1670
1623 if self.isExtensionActive("bookmarks"): 1671 if self.isExtensionActive("bookmarks"):
1624 bookmarksList = \ 1672 bookmarksList = \
1625 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 1673 self.getExtensionObject("bookmarks")\
1674 .hgGetBookmarksList(repodir)
1626 else: 1675 else:
1627 bookmarksList = None 1676 bookmarksList = None
1628 from .HgRevisionsSelectionDialog import HgRevisionsSelectionDialog 1677 from .HgRevisionsSelectionDialog import HgRevisionsSelectionDialog
1629 dlg = HgRevisionsSelectionDialog(self.hgGetTagsList(repodir), 1678 dlg = HgRevisionsSelectionDialog(self.hgGetTagsList(repodir),
1630 self.hgGetBranchesList(repodir), 1679 self.hgGetBranchesList(repodir),
1636 self.diff.show() 1685 self.diff.show()
1637 self.diff.start(name, revisions) 1686 self.diff.start(name, revisions)
1638 1687
1639 def __hgGetFileForRevision(self, name, rev=""): 1688 def __hgGetFileForRevision(self, name, rev=""):
1640 """ 1689 """
1641 Private method to get a file for a specific revision from the repository. 1690 Private method to get a file for a specific revision from the
1691 repository.
1642 1692
1643 @param name file name to get from the repository (string) 1693 @param name file name to get from the repository (string)
1644 @keyparam rev revision to retrieve (string) 1694 @keyparam rev revision to retrieve (string)
1645 @return contents of the file (string) and an error message (string) 1695 @return contents of the file (string) and an error message (string)
1646 """ 1696 """
1674 Preferences.getSystem("IOEncoding"), 'replace') 1724 Preferences.getSystem("IOEncoding"), 'replace')
1675 else: 1725 else:
1676 error = str(process.readAllStandardError(), 1726 error = str(process.readAllStandardError(),
1677 Preferences.getSystem("IOEncoding"), 'replace') 1727 Preferences.getSystem("IOEncoding"), 'replace')
1678 else: 1728 else:
1679 error = self.trUtf8("The hg process did not finish within 30s.") 1729 error = self.trUtf8(
1730 "The hg process did not finish within 30s.")
1680 else: 1731 else:
1681 error = self.trUtf8('The process {0} could not be started. ' 1732 error = self.trUtf8('The process {0} could not be started. '
1682 'Ensure, that it is in the search path.').format('hg') 1733 'Ensure, that it is in the search path.').format('hg')
1683 else: 1734 else:
1684 output, error = self.__client.runcommand(args) 1735 output, error = self.__client.runcommand(args)
1685 1736
1686 return output, error 1737 return output, error
1687 1738
1688 def hgSbsDiff(self, name, extended=False, revisions=None): 1739 def hgSbsDiff(self, name, extended=False, revisions=None):
1689 """ 1740 """
1690 Public method used to view the difference of a file to the Mercurial repository 1741 Public method used to view the difference of a file to the Mercurial
1691 side-by-side. 1742 repository side-by-side.
1692 1743
1693 @param name file name to be diffed (string) 1744 @param name file name to be diffed (string)
1694 @keyparam extended flag indicating the extended variant (boolean) 1745 @keyparam extended flag indicating the extended variant (boolean)
1695 @keyparam revisions tuple of two revisions (tuple of strings) 1746 @keyparam revisions tuple of two revisions (tuple of strings)
1747 @exception ValueError raised to indicate an invalid name parameter
1696 """ 1748 """
1697 if isinstance(name, list): 1749 if isinstance(name, list):
1698 raise ValueError("Wrong parameter type") 1750 raise ValueError("Wrong parameter type")
1699 1751
1700 if extended: 1752 if extended:
1705 if os.path.splitdrive(repodir)[1] == os.sep: 1757 if os.path.splitdrive(repodir)[1] == os.sep:
1706 return 1758 return
1707 1759
1708 if self.isExtensionActive("bookmarks"): 1760 if self.isExtensionActive("bookmarks"):
1709 bookmarksList = \ 1761 bookmarksList = \
1710 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 1762 self.getExtensionObject("bookmarks")\
1763 .hgGetBookmarksList(repodir)
1711 else: 1764 else:
1712 bookmarksList = None 1765 bookmarksList = None
1713 1766
1714 from .HgRevisionsSelectionDialog import HgRevisionsSelectionDialog 1767 from .HgRevisionsSelectionDialog import HgRevisionsSelectionDialog
1715 dlg = HgRevisionsSelectionDialog(self.hgGetTagsList(repodir), 1768 dlg = HgRevisionsSelectionDialog(self.hgGetTagsList(repodir),
1745 f1.close() 1798 f1.close()
1746 name2 = name 1799 name2 = name
1747 except IOError: 1800 except IOError:
1748 E5MessageBox.critical(self.__ui, 1801 E5MessageBox.critical(self.__ui,
1749 self.trUtf8("Mercurial Side-by-Side Difference"), 1802 self.trUtf8("Mercurial Side-by-Side Difference"),
1750 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""") 1803 self.trUtf8(
1804 """<p>The file <b>{0}</b> could not be read.</p>""")
1751 .format(name)) 1805 .format(name))
1752 return 1806 return
1753 1807
1754 if self.sbsDiff is None: 1808 if self.sbsDiff is None:
1755 from UI.CompareDialog import CompareDialog 1809 from UI.CompareDialog import CompareDialog
1761 """ 1815 """
1762 Public method used to browse the log of a file/directory from the 1816 Public method used to browse the log of a file/directory from the
1763 Mercurial repository. 1817 Mercurial repository.
1764 1818
1765 @param path file/directory name to show the log of (string) 1819 @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) 1820 @keyparam isFile flag indicating log for a file is to be shown
1821 (boolean)
1767 """ 1822 """
1768 from .HgLogBrowserDialog import HgLogBrowserDialog 1823 from .HgLogBrowserDialog import HgLogBrowserDialog
1769 self.logBrowser = HgLogBrowserDialog(self, isFile=isFile) 1824 self.logBrowser = HgLogBrowserDialog(self, isFile=isFile)
1770 self.logBrowser.show() 1825 self.logBrowser.show()
1771 self.logBrowser.start(path) 1826 self.logBrowser.start(path)
1872 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 1927 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
1873 repodir = os.path.dirname(repodir) 1928 repodir = os.path.dirname(repodir)
1874 if os.path.splitdrive(repodir)[1] == os.sep: 1929 if os.path.splitdrive(repodir)[1] == os.sep:
1875 return 1930 return
1876 1931
1877 dia = HgDialog(self.trUtf8('Pushing to a remote Mercurial repository'), self) 1932 dia = HgDialog(
1933 self.trUtf8('Pushing to a remote Mercurial repository'), self)
1878 res = dia.startProcess(args, repodir) 1934 res = dia.startProcess(args, repodir)
1879 if res: 1935 if res:
1880 dia.exec_() 1936 dia.exec_()
1881 res = dia.hasAddOrDelete() 1937 res = dia.hasAddOrDelete()
1882 self.checkVCSStatus() 1938 self.checkVCSStatus()
1884 def hgInfo(self, ppath, mode="heads"): 1940 def hgInfo(self, ppath, mode="heads"):
1885 """ 1941 """
1886 Public method to show information about the heads of the repository. 1942 Public method to show information about the heads of the repository.
1887 1943
1888 @param ppath local path to get the repository infos (string) 1944 @param ppath local path to get the repository infos (string)
1889 @keyparam mode mode of the operation (string, one of heads, parents, tip) 1945 @keyparam mode mode of the operation (string, one of heads, parents,
1946 tip)
1890 """ 1947 """
1891 if mode not in ("heads", "parents", "tip"): 1948 if mode not in ("heads", "parents", "tip"):
1892 mode = "heads" 1949 mode = "heads"
1893 1950
1894 info = [] 1951 info = []
1989 # find the root of the repo 2046 # find the root of the repo
1990 repodir = dname 2047 repodir = dname
1991 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 2048 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
1992 repodir = os.path.dirname(repodir) 2049 repodir = os.path.dirname(repodir)
1993 if os.path.splitdrive(repodir)[1] == os.sep: 2050 if os.path.splitdrive(repodir)[1] == os.sep:
1994 return False 2051 return
1995 2052
1996 dia = HgDialog(self.trUtf8('Resolving files/directories'), self) 2053 dia = HgDialog(self.trUtf8('Resolving files/directories'), self)
1997 res = dia.startProcess(args, repodir) 2054 res = dia.startProcess(args, repodir)
1998 if res: 2055 if res:
1999 dia.exec_() 2056 dia.exec_()
2023 if ok and name: 2080 if ok and name:
2024 args = [] 2081 args = []
2025 args.append('branch') 2082 args.append('branch')
2026 args.append(name.strip().replace(" ", "_")) 2083 args.append(name.strip().replace(" ", "_"))
2027 2084
2028 dia = HgDialog(self.trUtf8('Creating branch in the Mercurial repository'), 2085 dia = HgDialog(
2029 self) 2086 self.trUtf8('Creating branch in the Mercurial repository'),
2087 self)
2030 res = dia.startProcess(args, repodir) 2088 res = dia.startProcess(args, repodir)
2031 if res: 2089 if res:
2032 dia.exec_() 2090 dia.exec_()
2033 2091
2034 def hgShowBranch(self, name): 2092 def hgShowBranch(self, name):
2061 from .HgUtilities import getConfigPath 2119 from .HgUtilities import getConfigPath
2062 cfgFile = getConfigPath() 2120 cfgFile = getConfigPath()
2063 if not os.path.exists(cfgFile): 2121 if not os.path.exists(cfgFile):
2064 try: 2122 try:
2065 f = open(cfgFile, "w") 2123 f = open(cfgFile, "w")
2066 f.write("[ui]\nusername = Firstname Lastname <email_address>\n") 2124 f.write("[ui]\nusername = Firstname Lastname"
2125 " <email_address>\n")
2067 f.close() 2126 f.close()
2068 except (IOError, OSError): 2127 except (IOError, OSError):
2069 # ignore these 2128 # ignore these
2070 pass 2129 pass
2071 self.userEditor = MiniEditor(cfgFile, "Properties") 2130 self.userEditor = MiniEditor(cfgFile, "Properties")
2113 return 2172 return
2114 2173
2115 args = [] 2174 args = []
2116 args.append('verify') 2175 args.append('verify')
2117 2176
2118 dia = HgDialog(self.trUtf8('Verifying the integrity of the Mercurial repository'), 2177 dia = HgDialog(
2119 self) 2178 self.trUtf8('Verifying the integrity of the Mercurial repository'),
2179 self)
2120 res = dia.startProcess(args, repodir) 2180 res = dia.startProcess(args, repodir)
2121 if res: 2181 if res:
2122 dia.exec_() 2182 dia.exec_()
2123 2183
2124 def hgShowConfig(self, name): 2184 def hgShowConfig(self, name):
2138 2198
2139 args = [] 2199 args = []
2140 args.append('showconfig') 2200 args.append('showconfig')
2141 args.append("--untrusted") 2201 args.append("--untrusted")
2142 2202
2143 dia = HgDialog(self.trUtf8('Showing the combined configuration settings'), self) 2203 dia = HgDialog(
2204 self.trUtf8('Showing the combined configuration settings'),
2205 self)
2144 res = dia.startProcess(args, repodir, False) 2206 res = dia.startProcess(args, repodir, False)
2145 if res: 2207 if res:
2146 dia.exec_() 2208 dia.exec_()
2147 2209
2148 def hgShowPaths(self, name): 2210 def hgShowPaths(self, name):
2161 return 2223 return
2162 2224
2163 args = [] 2225 args = []
2164 args.append('paths') 2226 args.append('paths')
2165 2227
2166 dia = HgDialog(self.trUtf8('Showing aliases for remote repositories'), self) 2228 dia = HgDialog(
2229 self.trUtf8('Showing aliases for remote repositories'),
2230 self)
2167 res = dia.startProcess(args, repodir, False) 2231 res = dia.startProcess(args, repodir, False)
2168 if res: 2232 if res:
2169 dia.exec_() 2233 dia.exec_()
2170 2234
2171 def hgRecover(self, name): 2235 def hgRecover(self, name):
2184 return 2248 return
2185 2249
2186 args = [] 2250 args = []
2187 args.append('recover') 2251 args.append('recover')
2188 2252
2189 dia = HgDialog(self.trUtf8('Recovering from interrupted transaction'), self) 2253 dia = HgDialog(
2254 self.trUtf8('Recovering from interrupted transaction'),
2255 self)
2190 res = dia.startProcess(args, repodir, False) 2256 res = dia.startProcess(args, repodir, False)
2191 if res: 2257 if res:
2192 dia.exec_() 2258 dia.exec_()
2193 2259
2194 def hgIdentify(self, name): 2260 def hgIdentify(self, name):
2285 if os.path.splitdrive(repodir)[1] == os.sep: 2351 if os.path.splitdrive(repodir)[1] == os.sep:
2286 return 2352 return
2287 2353
2288 if self.isExtensionActive("bookmarks"): 2354 if self.isExtensionActive("bookmarks"):
2289 bookmarksList = \ 2355 bookmarksList = \
2290 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 2356 self.getExtensionObject("bookmarks")\
2357 .hgGetBookmarksList(repodir)
2291 else: 2358 else:
2292 bookmarksList = None 2359 bookmarksList = None
2293 from .HgBundleDialog import HgBundleDialog 2360 from .HgBundleDialog import HgBundleDialog
2294 dlg = HgBundleDialog(self.hgGetTagsList(repodir), 2361 dlg = HgBundleDialog(self.hgGetTagsList(repodir),
2295 self.hgGetBranchesList(repodir), 2362 self.hgGetBranchesList(repodir),
2464 Public method to perform bisect commands. 2531 Public method to perform bisect commands.
2465 2532
2466 @param name file/directory name (string) 2533 @param name file/directory name (string)
2467 @param subcommand name of the subcommand (string, one of 'good', 'bad', 2534 @param subcommand name of the subcommand (string, one of 'good', 'bad',
2468 'skip' or 'reset') 2535 'skip' or 'reset')
2536 @exception ValueError raised to indicate an invalid bisect subcommand
2469 """ 2537 """
2470 if subcommand not in ("good", "bad", "skip", "reset"): 2538 if subcommand not in ("good", "bad", "skip", "reset"):
2471 raise ValueError( 2539 raise ValueError(
2472 self.trUtf8("Bisect subcommand ({0}) invalid.").format(subcommand)) 2540 self.trUtf8("Bisect subcommand ({0}) invalid.")
2541 .format(subcommand))
2473 2542
2474 dname, fname = self.splitPath(name) 2543 dname, fname = self.splitPath(name)
2475 2544
2476 # find the root of the repo 2545 # find the root of the repo
2477 repodir = dname 2546 repodir = dname
2482 2551
2483 rev = "" 2552 rev = ""
2484 if subcommand in ("good", "bad", "skip"): 2553 if subcommand in ("good", "bad", "skip"):
2485 if self.isExtensionActive("bookmarks"): 2554 if self.isExtensionActive("bookmarks"):
2486 bookmarksList = \ 2555 bookmarksList = \
2487 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 2556 self.getExtensionObject("bookmarks")\
2557 .hgGetBookmarksList(repodir)
2488 else: 2558 else:
2489 bookmarksList = None 2559 bookmarksList = None
2490 from .HgRevisionSelectionDialog import HgRevisionSelectionDialog 2560 from .HgRevisionSelectionDialog import HgRevisionSelectionDialog
2491 dlg = HgRevisionSelectionDialog(self.hgGetTagsList(repodir), 2561 dlg = HgRevisionSelectionDialog(self.hgGetTagsList(repodir),
2492 self.hgGetBranchesList(repodir), 2562 self.hgGetBranchesList(repodir),
2501 args.append("bisect") 2571 args.append("bisect")
2502 args.append("--{0}".format(subcommand)) 2572 args.append("--{0}".format(subcommand))
2503 if rev: 2573 if rev:
2504 args.append(rev) 2574 args.append(rev)
2505 2575
2506 dia = HgDialog(self.trUtf8('Mercurial Bisect ({0})').format(subcommand), self) 2576 dia = HgDialog(
2577 self.trUtf8('Mercurial Bisect ({0})').format(subcommand), self)
2507 res = dia.startProcess(args, repodir) 2578 res = dia.startProcess(args, repodir)
2508 if res: 2579 if res:
2509 dia.exec_() 2580 dia.exec_()
2510 2581
2511 def hgForget(self, name): 2582 def hgForget(self, name):
2512 """ 2583 """
2513 Public method used to remove a file from the Mercurial repository. 2584 Public method used to remove a file from the Mercurial repository.
2514 2585
2515 This will not remove the file from the project directory. 2586 This will not remove the file from the project directory.
2516 2587
2517 @param name file/directory name to be removed (string or list of strings)) 2588 @param name file/directory name to be removed (string or list of
2589 strings))
2518 """ 2590 """
2519 args = [] 2591 args = []
2520 args.append('forget') 2592 args.append('forget')
2521 self.addArguments(args, self.options['global']) 2593 self.addArguments(args, self.options['global'])
2522 args.append('-v') 2594 args.append('-v')
2534 repodir = os.path.dirname(repodir) 2606 repodir = os.path.dirname(repodir)
2535 if os.path.splitdrive(repodir)[1] == os.sep: 2607 if os.path.splitdrive(repodir)[1] == os.sep:
2536 return 2608 return
2537 2609
2538 dia = HgDialog( 2610 dia = HgDialog(
2539 self.trUtf8('Removing files from the Mercurial repository only'), self) 2611 self.trUtf8('Removing files from the Mercurial repository only'),
2612 self)
2540 res = dia.startProcess(args, repodir) 2613 res = dia.startProcess(args, repodir)
2541 if res: 2614 if res:
2542 dia.exec_() 2615 dia.exec_()
2543 if isinstance(name, list): 2616 if isinstance(name, list):
2544 self.__forgotNames.extend(name) 2617 self.__forgotNames.extend(name)
2545 else: 2618 else:
2546 self.__forgotNames.append(name) 2619 self.__forgotNames.append(name)
2547 2620
2548 def hgBackout(self, name): 2621 def hgBackout(self, name):
2549 """ 2622 """
2550 Public method used to backout an earlier changeset from the Mercurial repository. 2623 Public method used to backout an earlier changeset from the Mercurial
2624 repository.
2551 2625
2552 @param name directory name (string or list of strings) 2626 @param name directory name (string or list of strings)
2553 """ 2627 """
2554 dname, fname = self.splitPath(name) 2628 dname, fname = self.splitPath(name)
2555 2629
2560 if os.path.splitdrive(repodir)[1] == os.sep: 2634 if os.path.splitdrive(repodir)[1] == os.sep:
2561 return 2635 return
2562 2636
2563 if self.isExtensionActive("bookmarks"): 2637 if self.isExtensionActive("bookmarks"):
2564 bookmarksList = \ 2638 bookmarksList = \
2565 self.getExtensionObject("bookmarks").hgGetBookmarksList(repodir) 2639 self.getExtensionObject("bookmarks")\
2640 .hgGetBookmarksList(repodir)
2566 else: 2641 else:
2567 bookmarksList = None 2642 bookmarksList = None
2568 from .HgBackoutDialog import HgBackoutDialog 2643 from .HgBackoutDialog import HgBackoutDialog
2569 dlg = HgBackoutDialog(self.hgGetTagsList(repodir), 2644 dlg = HgBackoutDialog(self.hgGetTagsList(repodir),
2570 self.hgGetBranchesList(repodir), 2645 self.hgGetBranchesList(repodir),
2610 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 2685 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
2611 repodir = os.path.dirname(repodir) 2686 repodir = os.path.dirname(repodir)
2612 if os.path.splitdrive(repodir)[1] == os.sep: 2687 if os.path.splitdrive(repodir)[1] == os.sep:
2613 return 2688 return
2614 2689
2615 res = E5MessageBox.yesNo(None, 2690 res = E5MessageBox.yesNo(
2691 None,
2616 self.trUtf8("Rollback last transaction"), 2692 self.trUtf8("Rollback last transaction"),
2617 self.trUtf8("""Are you sure you want to rollback the last transaction?"""), 2693 self.trUtf8("""Are you sure you want to rollback the last"""
2694 """ transaction?"""),
2618 icon=E5MessageBox.Warning) 2695 icon=E5MessageBox.Warning)
2619 if res: 2696 if res:
2620 dia = HgDialog(self.trUtf8('Rollback last transaction'), self) 2697 dia = HgDialog(self.trUtf8('Rollback last transaction'), self)
2621 res = dia.startProcess(["rollback"], repodir) 2698 res = dia.startProcess(["rollback"], repodir)
2622 if res: 2699 if res:
2745 2822
2746 @param name directory name of the project to export from (string) 2823 @param name directory name of the project to export from (string)
2747 @param data tuple giving phase data (list of revisions, phase, flag 2824 @param data tuple giving phase data (list of revisions, phase, flag
2748 indicating a forced operation) (list of strings, string, boolean) 2825 indicating a forced operation) (list of strings, string, boolean)
2749 @return flag indicating success (boolean) 2826 @return flag indicating success (boolean)
2827 @exception ValueError raised to indicate an invalid phase
2750 """ 2828 """
2751 dname, fname = self.splitPath(name) 2829 dname, fname = self.splitPath(name)
2752 2830
2753 # find the root of the repo 2831 # find the root of the repo
2754 repodir = dname 2832 repodir = dname
2794 def hgGraft(self, path, revs=None): 2872 def hgGraft(self, path, revs=None):
2795 """ 2873 """
2796 Public method to copy changesets from another branch. 2874 Public method to copy changesets from another branch.
2797 2875
2798 @param path directory name of the project (string) 2876 @param path directory name of the project (string)
2799 @param revs list of revisions to show in the revisions pane (list of strings) 2877 @param revs list of revisions to show in the revisions pane (list of
2878 strings)
2800 @return flag indicating that the project should be reread (boolean) 2879 @return flag indicating that the project should be reread (boolean)
2801 """ 2880 """
2802 # find the root of the repo 2881 # find the root of the repo
2803 repodir = self.splitPath(path)[0] 2882 repodir = self.splitPath(path)[0]
2804 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 2883 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
2900 dia = HgDialog(self.trUtf8("Create Unversioned Archive"), self) 2979 dia = HgDialog(self.trUtf8("Create Unversioned Archive"), self)
2901 res = dia.startProcess(args, repodir) 2980 res = dia.startProcess(args, repodir)
2902 if res: 2981 if res:
2903 dia.exec_() 2982 dia.exec_()
2904 2983
2905 ############################################################################ 2984 ###########################################################################
2906 ## Methods to deal with subrepositories are below. 2985 ## Methods to deal with subrepositories are below.
2907 ############################################################################ 2986 ###########################################################################
2908 2987
2909 def getHgSubPath(self): 2988 def getHgSubPath(self):
2910 """ 2989 """
2911 Public method to get the path to the .hgsub file containing the definitions 2990 Public method to get the path to the .hgsub file containing the
2912 of sub-repositories. 2991 definitions of sub-repositories.
2913 2992
2914 @return full path of the .hgsub file (string) 2993 @return full path of the .hgsub file (string)
2915 """ 2994 """
2916 ppath = self.__projectHelper.getProject().getProjectPath() 2995 ppath = self.__projectHelper.getProject().getProjectPath()
2917 return os.path.join(ppath, ".hgsub") 2996 return os.path.join(ppath, ".hgsub")
2950 contents = f.readlines() 3029 contents = f.readlines()
2951 f.close() 3030 f.close()
2952 except IOError as err: 3031 except IOError as err:
2953 E5MessageBox.critical(self.__ui, 3032 E5MessageBox.critical(self.__ui,
2954 self.trUtf8("Add Sub-repository"), 3033 self.trUtf8("Add Sub-repository"),
2955 self.trUtf8("""<p>The sub-repositories file .hgsub could not""" 3034 self.trUtf8(
2956 """ be read.</p><p>Reason: {0}</p>""") 3035 """<p>The sub-repositories file .hgsub could not"""
2957 .format(str(err))) 3036 """ be read.</p><p>Reason: {0}</p>""")
3037 .format(str(err)))
2958 return 3038 return
2959 3039
2960 if entry in contents: 3040 if entry in contents:
2961 E5MessageBox.critical(self.__ui, 3041 E5MessageBox.critical(self.__ui,
2962 self.trUtf8("Add Sub-repository"), 3042 self.trUtf8("Add Sub-repository"),
2963 self.trUtf8("""<p>The sub-repositories file .hgsub already""" 3043 self.trUtf8(
2964 """ contains an entry <b>{0}</b>. Aborting...</p>""") 3044 """<p>The sub-repositories file .hgsub already"""
2965 .format(entry)) 3045 """ contains an entry <b>{0}</b>."""
3046 """ Aborting...</p>""").format(entry))
2966 return 3047 return
2967 else: 3048 else:
2968 needsAdd = True 3049 needsAdd = True
2969 3050
2970 if contents and not contents[-1].endswith("\n"): 3051 if contents and not contents[-1].endswith("\n"):
2975 f.writelines(contents) 3056 f.writelines(contents)
2976 f.close() 3057 f.close()
2977 except IOError as err: 3058 except IOError as err:
2978 E5MessageBox.critical(self.__ui, 3059 E5MessageBox.critical(self.__ui,
2979 self.trUtf8("Add Sub-repository"), 3060 self.trUtf8("Add Sub-repository"),
2980 self.trUtf8("""<p>The sub-repositories file .hgsub could not""" 3061 self.trUtf8(
2981 """ be written to.</p><p>Reason: {0}</p>""") 3062 """<p>The sub-repositories file .hgsub could not"""
2982 .format(str(err))) 3063 """ be written to.</p><p>Reason: {0}</p>""")
3064 .format(str(err)))
2983 return 3065 return
2984 3066
2985 if needsAdd: 3067 if needsAdd:
2986 self.vcsAdd(hgsub) 3068 self.vcsAdd(hgsub)
2987 self.__projectHelper.getProject().appendFile(hgsub) 3069 self.__projectHelper.getProject().appendFile(hgsub)
3010 self.trUtf8("""<p>The sub-repositories file .hgsub could not""" 3092 self.trUtf8("""<p>The sub-repositories file .hgsub could not"""
3011 """ be read.</p><p>Reason: {0}</p>""") 3093 """ be read.</p><p>Reason: {0}</p>""")
3012 .format(str(err))) 3094 .format(str(err)))
3013 return 3095 return
3014 3096
3015 from .HgRemoveSubrepositoriesDialog import HgRemoveSubrepositoriesDialog 3097 from .HgRemoveSubrepositoriesDialog import \
3098 HgRemoveSubrepositoriesDialog
3016 dlg = HgRemoveSubrepositoriesDialog(subrepositories) 3099 dlg = HgRemoveSubrepositoriesDialog(subrepositories)
3017 if dlg.exec_() == QDialog.Accepted: 3100 if dlg.exec_() == QDialog.Accepted:
3018 subrepositories, removedSubrepos, deleteSubrepos = dlg.getData() 3101 subrepositories, removedSubrepos, deleteSubrepos = dlg.getData()
3019 contents = "\n".join(subrepositories) + "\n" 3102 contents = "\n".join(subrepositories) + "\n"
3020 try: 3103 try:
3022 f.write(contents) 3105 f.write(contents)
3023 f.close() 3106 f.close()
3024 except IOError as err: 3107 except IOError as err:
3025 E5MessageBox.critical(self.__ui, 3108 E5MessageBox.critical(self.__ui,
3026 self.trUtf8("Remove Sub-repositories"), 3109 self.trUtf8("Remove Sub-repositories"),
3027 self.trUtf8("""<p>The sub-repositories file .hgsub could not""" 3110 self.trUtf8(
3028 """ be written to.</p><p>Reason: {0}</p>""") 3111 """<p>The sub-repositories file .hgsub could not"""
3029 .format(str(err))) 3112 """ be written to.</p><p>Reason: {0}</p>""")
3113 .format(str(err)))
3030 return 3114 return
3031 3115
3032 if deleteSubrepos: 3116 if deleteSubrepos:
3033 ppath = self.__projectHelper.getProject().getProjectPath() 3117 ppath = self.__projectHelper.getProject().getProjectPath()
3034 for removedSubrepo in removedSubrepos: 3118 for removedSubrepo in removedSubrepos:
3035 subrepoPath = removedSubrepo.split("=", 1)[0].strip() 3119 subrepoPath = removedSubrepo.split("=", 1)[0].strip()
3036 subrepoAbsPath = os.path.join(ppath, subrepoPath) 3120 subrepoAbsPath = os.path.join(ppath, subrepoPath)
3037 shutil.rmtree(subrepoAbsPath, True) 3121 shutil.rmtree(subrepoAbsPath, True)
3038 3122
3039 ############################################################################ 3123 ###########################################################################
3040 ## Methods to handle extensions are below. 3124 ## Methods to handle extensions are below.
3041 ############################################################################ 3125 ###########################################################################
3042 3126
3043 def __iniFileChanged(self, path): 3127 def __iniFileChanged(self, path):
3044 """ 3128 """
3045 Private slot to handle a change of the Mercurial configuration file. 3129 Private slot to handle a change of the Mercurial configuration file.
3046 3130
3051 if self.__client: 3135 if self.__client:
3052 ok, err = self.__client.restartServer() 3136 ok, err = self.__client.restartServer()
3053 if not ok: 3137 if not ok:
3054 E5MessageBox.warning(None, 3138 E5MessageBox.warning(None,
3055 self.trUtf8("Mercurial Command Server"), 3139 self.trUtf8("Mercurial Command Server"),
3056 self.trUtf8("""<p>The Mercurial Command Server could not be""" 3140 self.trUtf8(
3057 """ restarted.</p><p>Reason: {0}</p>""").format(err)) 3141 """<p>The Mercurial Command Server could not be"""
3142 """ restarted.</p><p>Reason: {0}</p>""").format(err))
3058 self.__client = None 3143 self.__client = None
3059 3144
3060 def __monitorRepoIniFile(self, name): 3145 def __monitorRepoIniFile(self, name):
3061 """ 3146 """
3062 Private slot to add a repository configuration file to the list of monitored 3147 Private slot to add a repository configuration file to the list of
3063 files. 3148 monitored files.
3064 3149
3065 @param name directory name pointing into the repository (string) 3150 @param name directory name pointing into the repository (string)
3066 """ 3151 """
3067 dname, fname = self.splitPath(name) 3152 dname, fname = self.splitPath(name)
3068 3153
3101 else: 3186 else:
3102 output, error = self.__client.runcommand(args) 3187 output, error = self.__client.runcommand(args)
3103 3188
3104 if output: 3189 if output:
3105 for line in output.splitlines(): 3190 for line in output.splitlines():
3106 extensionName = line.split("=", 1)[0].strip().split(".")[-1].strip() 3191 extensionName = \
3192 line.split("=", 1)[0].strip().split(".")[-1].strip()
3107 self.__activeExtensions.append(extensionName) 3193 self.__activeExtensions.append(extensionName)
3108 3194
3109 if self.version >= (1, 8): 3195 if self.version >= (1, 8):
3110 if "bookmarks" not in self.__activeExtensions: 3196 if "bookmarks" not in self.__activeExtensions:
3111 self.__activeExtensions.append("bookmarks") 3197 self.__activeExtensions.append("bookmarks")
3120 @param extensionName name of the extension to check for (string) 3206 @param extensionName name of the extension to check for (string)
3121 @return flag indicating an active extension (boolean) 3207 @return flag indicating an active extension (boolean)
3122 """ 3208 """
3123 extensionName = extensionName.strip() 3209 extensionName = extensionName.strip()
3124 isActive = extensionName in self.__activeExtensions 3210 isActive = extensionName in self.__activeExtensions
3125 if isActive and extensionName == "transplant" and self.version >= (2, 3): 3211 if isActive and \
3212 extensionName == "transplant" and \
3213 self.version >= (2, 3):
3126 # transplant extension is deprecated as of Mercurial 2.3.0 3214 # transplant extension is deprecated as of Mercurial 2.3.0
3127 isActive = False 3215 isActive = False
3128 3216
3129 return isActive 3217 return isActive
3130 3218
3135 @param extensionName name of the extension (string) 3223 @param extensionName name of the extension (string)
3136 @return reference to the extension object (boolean) 3224 @return reference to the extension object (boolean)
3137 """ 3225 """
3138 return self.__extensions[extensionName] 3226 return self.__extensions[extensionName]
3139 3227
3140 ############################################################################ 3228 ###########################################################################
3141 ## Methods to get the helper objects are below. 3229 ## Methods to get the helper objects are below.
3142 ############################################################################ 3230 ###########################################################################
3143 3231
3144 def vcsGetProjectBrowserHelper(self, browser, project, isTranslationsBrowser=False): 3232 def vcsGetProjectBrowserHelper(self, browser, project,
3145 """ 3233 isTranslationsBrowser=False):
3146 Public method to instantiate a helper object for the different project browsers. 3234 """
3235 Public method to instantiate a helper object for the different
3236 project browsers.
3147 3237
3148 @param browser reference to the project browser object 3238 @param browser reference to the project browser object
3149 @param project reference to the project object 3239 @param project reference to the project object
3150 @param isTranslationsBrowser flag indicating, the helper is requested for the 3240 @param isTranslationsBrowser flag indicating, the helper is requested
3151 translations browser (this needs some special treatment) 3241 for the translations browser (this needs some special treatment)
3152 @return the project browser helper object 3242 @return the project browser helper object
3153 """ 3243 """
3154 from .ProjectBrowserHelper import HgProjectBrowserHelper 3244 from .ProjectBrowserHelper import HgProjectBrowserHelper
3155 return HgProjectBrowserHelper(self, browser, project, isTranslationsBrowser) 3245 return HgProjectBrowserHelper(self, browser, project,
3246 isTranslationsBrowser)
3156 3247
3157 def vcsGetProjectHelper(self, project): 3248 def vcsGetProjectHelper(self, project):
3158 """ 3249 """
3159 Public method to instantiate a helper object for the project. 3250 Public method to instantiate a helper object for the project.
3160 3251
3180 if ok: 3271 if ok:
3181 self.__client = client 3272 self.__client = client
3182 else: 3273 else:
3183 E5MessageBox.warning(None, 3274 E5MessageBox.warning(None,
3184 self.trUtf8("Mercurial Command Server"), 3275 self.trUtf8("Mercurial Command Server"),
3185 self.trUtf8("""<p>The Mercurial Command Server could not be""" 3276 self.trUtf8(
3186 """ started.</p><p>Reason: {0}</p>""").format(err)) 3277 """<p>The Mercurial Command Server could not be"""
3278 """ started.</p><p>Reason: {0}</p>""").format(err))
3187 3279
3188 return self.__projectHelper 3280 return self.__projectHelper
3189 3281
3190 ############################################################################ 3282 ###########################################################################
3191 ## Status Monitor Thread methods 3283 ## Status Monitor Thread methods
3192 ############################################################################ 3284 ###########################################################################
3193 3285
3194 def _createStatusMonitorThread(self, interval, project): 3286 def _createStatusMonitorThread(self, interval, project):
3195 """ 3287 """
3196 Protected method to create an instance of the VCS status monitor thread. 3288 Protected method to create an instance of the VCS status monitor
3197 3289 thread.
3290
3291 @param interval check interval for the monitor thread in seconds
3292 (integer)
3198 @param project reference to the project object (Project) 3293 @param project reference to the project object (Project)
3199 @param interval check interval for the monitor thread in seconds (integer)
3200 @return reference to the monitor thread (QThread) 3294 @return reference to the monitor thread (QThread)
3201 """ 3295 """
3202 from .HgStatusMonitorThread import HgStatusMonitorThread 3296 from .HgStatusMonitorThread import HgStatusMonitorThread
3203 return HgStatusMonitorThread(interval, project, self) 3297 return HgStatusMonitorThread(interval, project, self)

eric ide

mercurial