Plugins/VcsPlugins/vcsSubversion/subversion.py

changeset 3009
bf5ae5d7477d
parent 2963
745d38097b7f
child 3020
542e97d4ecb3
child 3057
10516539f238
equal deleted inserted replaced
3008:7848489bcb92 3009:bf5ae5d7477d
95 self.tagbranchList = None 95 self.tagbranchList = None
96 self.blame = None 96 self.blame = None
97 self.repoBrowser = None 97 self.repoBrowser = None
98 98
99 # regular expression object for evaluation of the status output 99 # regular expression object for evaluation of the status output
100 self.rx_status1 = QRegExp('(.{8})\\s+([0-9-]+)\\s+([0-9?]+)\\s+([\\w?]+)\\s+(.+)') 100 self.rx_status1 = QRegExp(
101 '(.{8})\\s+([0-9-]+)\\s+([0-9?]+)\\s+([\\w?]+)\\s+(.+)')
101 self.rx_status2 = QRegExp('(.{8})\\s+(.+)\\s*') 102 self.rx_status2 = QRegExp('(.{8})\\s+(.+)\\s*')
102 self.statusCache = {} 103 self.statusCache = {}
103 104
104 self.__commitData = {} 105 self.__commitData = {}
105 self.__commitDialog = None 106 self.__commitDialog = None
106 107
107 self.__wcng = True # assume new generation working copy metadata format 108 self.__wcng = True # assume new generation working copy
109 # metadata format
108 110
109 def getPlugin(self): 111 def getPlugin(self):
110 """ 112 """
111 Public method to get a reference to the plugin object. 113 Public method to get a reference to the plugin object.
112 114
137 139
138 def vcsExists(self): 140 def vcsExists(self):
139 """ 141 """
140 Public method used to test for the presence of the svn executable. 142 Public method used to test for the presence of the svn executable.
141 143
142 @return flag indicating the existance (boolean) and an error message (string) 144 @return flag indicating the existance (boolean) and an error message
145 (string)
143 """ 146 """
144 self.versionStr = '' 147 self.versionStr = ''
145 errMsg = "" 148 errMsg = ""
146 ioEncoding = Preferences.getSystem("IOEncoding") 149 ioEncoding = Preferences.getSystem("IOEncoding")
147 150
152 finished = process.waitForFinished(30000) 155 finished = process.waitForFinished(30000)
153 if finished and process.exitCode() == 0: 156 if finished and process.exitCode() == 0:
154 output = \ 157 output = \
155 str(process.readAllStandardOutput(), ioEncoding, 'replace') 158 str(process.readAllStandardOutput(), ioEncoding, 'replace')
156 self.versionStr = output.split()[2] 159 self.versionStr = output.split()[2]
157 v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?', self.versionStr).groups()) 160 v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?', self.versionStr)
161 .groups())
158 for i in range(3): 162 for i in range(3):
159 try: 163 try:
160 v[i] = int(v[i]) 164 v[i] = int(v[i])
161 except TypeError: 165 except TypeError:
162 v[i] = 0 166 v[i] = 0
164 v.append(0) 168 v.append(0)
165 self.version = tuple(v) 169 self.version = tuple(v)
166 return True, errMsg 170 return True, errMsg
167 else: 171 else:
168 if finished: 172 if finished:
169 errMsg = \ 173 errMsg = self.trUtf8(
170 self.trUtf8("The svn process finished with the exit code {0}")\ 174 "The svn process finished with the exit code {0}")\
171 .format(process.exitCode()) 175 .format(process.exitCode())
172 else: 176 else:
173 errMsg = self.trUtf8("The svn process did not finish within 30s.") 177 errMsg = self.trUtf8(
178 "The svn process did not finish within 30s.")
174 else: 179 else:
175 errMsg = self.trUtf8("Could not start the svn executable.") 180 errMsg = self.trUtf8("Could not start the svn executable.")
176 181
177 return False, errMsg 182 return False, errMsg
178 183
190 """ 195 """
191 return True 196 return True
192 197
193 def vcsConvertProject(self, vcsDataDict, project): 198 def vcsConvertProject(self, vcsDataDict, project):
194 """ 199 """
195 Public method to convert an uncontrolled project to a version controlled project. 200 Public method to convert an uncontrolled project to a version
201 controlled project.
196 202
197 @param vcsDataDict dictionary of data required for the conversion 203 @param vcsDataDict dictionary of data required for the conversion
198 @param project reference to the project object 204 @param project reference to the project object
199 """ 205 """
200 success = self.vcsImport(vcsDataDict, project.ppath)[0] 206 success = self.vcsImport(vcsDataDict, project.ppath)[0]
201 if not success: 207 if not success:
202 E5MessageBox.critical(self.__ui, 208 E5MessageBox.critical(self.__ui,
203 self.trUtf8("Create project in repository"), 209 self.trUtf8("Create project in repository"),
204 self.trUtf8("""The project could not be created in the repository.""" 210 self.trUtf8(
205 """ Maybe the given repository doesn't exist or the""" 211 """The project could not be created in the repository."""
206 """ repository server is down.""")) 212 """ Maybe the given repository doesn't exist or the"""
213 """ repository server is down."""))
207 else: 214 else:
208 cwdIsPpath = False 215 cwdIsPpath = False
209 if os.getcwd() == project.ppath: 216 if os.getcwd() == project.ppath:
210 os.chdir(os.path.dirname(project.ppath)) 217 os.chdir(os.path.dirname(project.ppath))
211 cwdIsPpath = True 218 cwdIsPpath = True
221 if not os.path.isfile(pfn): 228 if not os.path.isfile(pfn):
222 pfn += "z" 229 pfn += "z"
223 if not os.path.isfile(pfn): 230 if not os.path.isfile(pfn):
224 E5MessageBox.critical(self.__ui, 231 E5MessageBox.critical(self.__ui,
225 self.trUtf8("New project"), 232 self.trUtf8("New project"),
226 self.trUtf8("""The project could not be checked out of the""" 233 self.trUtf8(
227 """ repository.<br />""" 234 """The project could not be checked out of the"""
228 """Restoring the original contents.""")) 235 """ repository.<br />"""
236 """Restoring the original contents."""))
229 if os.getcwd() == project.ppath: 237 if os.getcwd() == project.ppath:
230 os.chdir(os.path.dirname(project.ppath)) 238 os.chdir(os.path.dirname(project.ppath))
231 cwdIsPpath = True 239 cwdIsPpath = True
232 else: 240 else:
233 cwdIsPpath = False 241 cwdIsPpath = False
243 project.closeProject(noSave=True) 251 project.closeProject(noSave=True)
244 project.openProject(pfn) 252 project.openProject(pfn)
245 253
246 def vcsImport(self, vcsDataDict, projectDir, noDialog=False): 254 def vcsImport(self, vcsDataDict, projectDir, noDialog=False):
247 """ 255 """
248 Public method used to import the project into the Subversion repository. 256 Public method used to import the project into the Subversion
257 repository.
249 258
250 @param vcsDataDict dictionary of data required for the import 259 @param vcsDataDict dictionary of data required for the import
251 @param projectDir project directory (string) 260 @param projectDir project directory (string)
252 @param noDialog flag indicating quiet operations 261 @param noDialog flag indicating quiet operations
253 @return flag indicating an execution without errors (boolean) 262 @return flag indicating an execution without errors (boolean)
272 os.makedirs(tmpDir) 281 os.makedirs(tmpDir)
273 if self.otherData["standardLayout"]: 282 if self.otherData["standardLayout"]:
274 os.mkdir(os.path.join(tmpDir, project)) 283 os.mkdir(os.path.join(tmpDir, project))
275 os.mkdir(os.path.join(tmpDir, project, 'branches')) 284 os.mkdir(os.path.join(tmpDir, project, 'branches'))
276 os.mkdir(os.path.join(tmpDir, project, 'tags')) 285 os.mkdir(os.path.join(tmpDir, project, 'tags'))
277 shutil.copytree(projectDir, os.path.join(tmpDir, project, 'trunk')) 286 shutil.copytree(
287 projectDir, os.path.join(tmpDir, project, 'trunk'))
278 else: 288 else:
279 shutil.copytree(projectDir, os.path.join(tmpDir, project)) 289 shutil.copytree(projectDir, os.path.join(tmpDir, project))
280 except OSError: 290 except OSError:
281 if os.path.isdir(tmpDir): 291 if os.path.isdir(tmpDir):
282 shutil.rmtree(tmpDir, True) 292 shutil.rmtree(tmpDir, True)
291 301
292 if noDialog: 302 if noDialog:
293 status = self.startSynchronizedProcess(QProcess(), "svn", args, 303 status = self.startSynchronizedProcess(QProcess(), "svn", args,
294 os.path.join(tmpDir, project)) 304 os.path.join(tmpDir, project))
295 else: 305 else:
296 dia = SvnDialog(self.trUtf8('Importing project into Subversion repository')) 306 dia = SvnDialog(
307 self.trUtf8('Importing project into Subversion repository'))
297 res = dia.startProcess(args, os.path.join(tmpDir, project)) 308 res = dia.startProcess(args, os.path.join(tmpDir, project))
298 if res: 309 if res:
299 dia.exec_() 310 dia.exec_()
300 status = dia.normalExit() 311 status = dia.normalExit()
301 312
302 shutil.rmtree(tmpDir, True) 313 shutil.rmtree(tmpDir, True)
303 return status, False 314 return status, False
304 315
305 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False): 316 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False):
306 """ 317 """
307 Public method used to check the project out of the Subversion repository. 318 Public method used to check the project out of the Subversion
319 repository.
308 320
309 @param vcsDataDict dictionary of data required for the checkout 321 @param vcsDataDict dictionary of data required for the checkout
310 @param projectDir project directory to create (string) 322 @param projectDir project directory to create (string)
311 @param noDialog flag indicating quiet operations 323 @param noDialog flag indicating quiet operations
312 @return flag indicating an execution without errors (boolean) 324 @return flag indicating an execution without errors (boolean)
324 336
325 if self.otherData["standardLayout"]: 337 if self.otherData["standardLayout"]:
326 if tag is None or tag == '': 338 if tag is None or tag == '':
327 svnUrl = '{0}/trunk'.format(vcsDir) 339 svnUrl = '{0}/trunk'.format(vcsDir)
328 else: 340 else:
329 if not tag.startswith('tags') and not tag.startswith('branches'): 341 if not tag.startswith('tags') and \
342 not tag.startswith('branches'):
330 type, ok = QInputDialog.getItem( 343 type, ok = QInputDialog.getItem(
331 None, 344 None,
332 self.trUtf8("Subversion Checkout"), 345 self.trUtf8("Subversion Checkout"),
333 self.trUtf8("The tag must be a normal tag (tags) or" 346 self.trUtf8("The tag must be a normal tag (tags) or"
334 " a branch tag (branches)." 347 " a branch tag (branches)."
350 args.append(projectDir) 363 args.append(projectDir)
351 364
352 if noDialog: 365 if noDialog:
353 return self.startSynchronizedProcess(QProcess(), 'svn', args) 366 return self.startSynchronizedProcess(QProcess(), 'svn', args)
354 else: 367 else:
355 dia = SvnDialog(self.trUtf8('Checking project out of Subversion repository')) 368 dia = SvnDialog(
369 self.trUtf8('Checking project out of Subversion repository'))
356 res = dia.startProcess(args) 370 res = dia.startProcess(args)
357 if res: 371 if res:
358 dia.exec_() 372 dia.exec_()
359 return dia.normalExit() 373 return dia.normalExit()
360 374
361 def vcsExport(self, vcsDataDict, projectDir): 375 def vcsExport(self, vcsDataDict, projectDir):
362 """ 376 """
363 Public method used to export a directory from the Subversion repository. 377 Public method used to export a directory from the Subversion
378 repository.
364 379
365 @param vcsDataDict dictionary of data required for the checkout 380 @param vcsDataDict dictionary of data required for the checkout
366 @param projectDir project directory to create (string) 381 @param projectDir project directory to create (string)
367 @return flag indicating an execution without errors (boolean) 382 @return flag indicating an execution without errors (boolean)
368 """ 383 """
376 391
377 if self.otherData["standardLayout"]: 392 if self.otherData["standardLayout"]:
378 if tag is None or tag == '': 393 if tag is None or tag == '':
379 svnUrl = '{0}/trunk'.format(vcsDir) 394 svnUrl = '{0}/trunk'.format(vcsDir)
380 else: 395 else:
381 if not tag.startswith('tags') and not tag.startswith('branches'): 396 if not tag.startswith('tags') and \
397 not tag.startswith('branches'):
382 type, ok = QInputDialog.getItem( 398 type, ok = QInputDialog.getItem(
383 None, 399 None,
384 self.trUtf8("Subversion Export"), 400 self.trUtf8("Subversion Export"),
385 self.trUtf8("The tag must be a normal tag (tags) or" 401 self.trUtf8("The tag must be a normal tag (tags) or"
386 " a branch tag (branches)." 402 " a branch tag (branches)."
399 self.addArguments(args, self.options['global']) 415 self.addArguments(args, self.options['global'])
400 args.append("--force") 416 args.append("--force")
401 args.append(self.__svnURL(svnUrl)) 417 args.append(self.__svnURL(svnUrl))
402 args.append(projectDir) 418 args.append(projectDir)
403 419
404 dia = SvnDialog(self.trUtf8('Exporting project from Subversion repository')) 420 dia = SvnDialog(
421 self.trUtf8('Exporting project from Subversion repository'))
405 res = dia.startProcess(args) 422 res = dia.startProcess(args)
406 if res: 423 if res:
407 dia.exec_() 424 dia.exec_()
408 return dia.normalExit() 425 return dia.normalExit()
409 426
410 def vcsCommit(self, name, message, noDialog=False): 427 def vcsCommit(self, name, message, noDialog=False):
411 """ 428 """
412 Public method used to make the change of a file/directory permanent in the 429 Public method used to make the change of a file/directory permanent
413 Subversion repository. 430 in the Subversion repository.
414 431
415 @param name file/directory name to be committed (string or list of strings) 432 @param name file/directory name to be committed (string or list of
433 strings)
416 @param message message for this operation (string) 434 @param message message for this operation (string)
417 @param noDialog flag indicating quiet operations 435 @param noDialog flag indicating quiet operations
418 """ 436 """
419 msg = message 437 msg = message
420 438
453 for nam in nameList: 471 for nam in nameList:
454 # check for commit of the project 472 # check for commit of the project
455 if os.path.isdir(nam): 473 if os.path.isdir(nam):
456 project = e5App().getObject("Project") 474 project = e5App().getObject("Project")
457 if nam == project.getProjectPath(): 475 if nam == project.getProjectPath():
458 ok &= project.checkAllScriptsDirty(reportSyntaxErrors=True) and \ 476 ok &= project.checkAllScriptsDirty(
459 project.checkDirty() 477 reportSyntaxErrors=True) and \
478 project.checkDirty()
460 continue 479 continue
461 elif os.path.isfile(nam): 480 elif os.path.isfile(nam):
462 editor = e5App().getObject("ViewManager").getOpenEditor(nam) 481 editor = e5App().getObject("ViewManager")\
482 .getOpenEditor(nam)
463 if editor: 483 if editor:
464 ok &= editor.checkDirty() 484 ok &= editor.checkDirty()
465 if not ok: 485 if not ok:
466 break 486 break
467 487
468 if not ok: 488 if not ok:
469 res = E5MessageBox.yesNo(self.__ui, 489 res = E5MessageBox.yesNo(self.__ui,
470 self.trUtf8("Commit Changes"), 490 self.trUtf8("Commit Changes"),
471 self.trUtf8("""The commit affects files, that have unsaved""" 491 self.trUtf8(
472 """ changes. Shall the commit be continued?"""), 492 """The commit affects files, that have unsaved"""
493 """ changes. Shall the commit be continued?"""),
473 icon=E5MessageBox.Warning) 494 icon=E5MessageBox.Warning)
474 if not res: 495 if not res:
475 return 496 return
476 497
477 if self.__commitDialog is not None: 498 if self.__commitDialog is not None:
478 msg = self.__commitDialog.logMessage() 499 msg = self.__commitDialog.logMessage()
479 if self.__commitDialog.hasChangelists(): 500 if self.__commitDialog.hasChangelists():
480 changelists, keepChangelists = self.__commitDialog.changelistsData() 501 changelists, keepChangelists = \
502 self.__commitDialog.changelistsData()
481 else: 503 else:
482 changelists, keepChangelists = [], False 504 changelists, keepChangelists = [], False
483 ## self.__commitDialog.accepted.disconnect(self.__vcsCommit_Step2)
484 self.__commitDialog.deleteLater() 505 self.__commitDialog.deleteLater()
485 self.__commitDialog = None 506 self.__commitDialog = None
486 else: 507 else:
487 changelists, keepChangelists = [], False 508 changelists, keepChangelists = [], False
488 509
512 noDialog = False 533 noDialog = False
513 534
514 if noDialog: 535 if noDialog:
515 self.startSynchronizedProcess(QProcess(), "svn", args, dname) 536 self.startSynchronizedProcess(QProcess(), "svn", args, dname)
516 else: 537 else:
517 dia = SvnDialog(self.trUtf8('Commiting changes to Subversion repository')) 538 dia = SvnDialog(
539 self.trUtf8('Commiting changes to Subversion repository'))
518 res = dia.startProcess(args, dname) 540 res = dia.startProcess(args, dname)
519 if res: 541 if res:
520 dia.exec_() 542 dia.exec_()
521 self.committed.emit() 543 self.committed.emit()
522 self.checkVCSStatus() 544 self.checkVCSStatus()
523 545
524 def vcsUpdate(self, name, noDialog=False): 546 def vcsUpdate(self, name, noDialog=False):
525 """ 547 """
526 Public method used to update a file/directory with the Subversion repository. 548 Public method used to update a file/directory with the Subversion
527 549 repository.
528 @param name file/directory name to be updated (string or list of strings) 550
551 @param name file/directory name to be updated (string or list of
552 strings)
529 @param noDialog flag indicating quiet operations (boolean) 553 @param noDialog flag indicating quiet operations (boolean)
530 @return flag indicating, that the update contained an add 554 @return flag indicating, that the update contained an add
531 or delete (boolean) 555 or delete (boolean)
532 """ 556 """
533 args = [] 557 args = []
546 570
547 if noDialog: 571 if noDialog:
548 self.startSynchronizedProcess(QProcess(), "svn", args, dname) 572 self.startSynchronizedProcess(QProcess(), "svn", args, dname)
549 res = False 573 res = False
550 else: 574 else:
551 dia = SvnDialog(self.trUtf8('Synchronizing with the Subversion repository')) 575 dia = SvnDialog(
576 self.trUtf8('Synchronizing with the Subversion repository'))
552 res = dia.startProcess(args, dname, True) 577 res = dia.startProcess(args, dname, True)
553 if res: 578 if res:
554 dia.exec_() 579 dia.exec_()
555 res = dia.hasAddOrDelete() 580 res = dia.hasAddOrDelete()
556 self.checkVCSStatus() 581 self.checkVCSStatus()
557 return res 582 return res
558 583
559 def vcsAdd(self, name, isDir=False, noDialog=False): 584 def vcsAdd(self, name, isDir=False, noDialog=False):
560 """ 585 """
561 Public method used to add a file/directory to the Subversion repository. 586 Public method used to add a file/directory to the Subversion
587 repository.
562 588
563 @param name file/directory name to be added (string) 589 @param name file/directory name to be added (string)
564 @param isDir flag indicating name is a directory (boolean) 590 @param isDir flag indicating name is a directory (boolean)
565 @param noDialog flag indicating quiet operations 591 @param noDialog flag indicating quiet operations
566 """ 592 """
589 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 615 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
590 repodir = os.path.dirname(repodir) 616 repodir = os.path.dirname(repodir)
591 if os.path.splitdrive(repodir)[1] == os.sep: 617 if os.path.splitdrive(repodir)[1] == os.sep:
592 return # oops, project is not version controlled 618 return # oops, project is not version controlled
593 while os.path.normcase(dname) != os.path.normcase(repodir) and \ 619 while os.path.normcase(dname) != os.path.normcase(repodir) and \
594 (os.path.normcase(dname) not in self.statusCache or \ 620 (os.path.normcase(dname) not in self.statusCache or \
595 self.statusCache[os.path.normcase(dname)] == self.canBeAdded): 621 self.statusCache[os.path.normcase(dname)] ==
596 # add directories recursively, if they aren't in the repository already 622 self.canBeAdded):
623 # add directories recursively, if they aren't in the
624 # repository already
597 tree.insert(-1, dname) 625 tree.insert(-1, dname)
598 dname = os.path.dirname(dname) 626 dname = os.path.dirname(dname)
599 wdir = dname 627 wdir = dname
600 else: 628 else:
601 while not os.path.exists(os.path.join(dname, self.adminDir)): 629 while not os.path.exists(os.path.join(dname, self.adminDir)):
602 # add directories recursively, if they aren't in the repository already 630 # add directories recursively, if they aren't in the
631 # repository already
603 tree.insert(-1, dname) 632 tree.insert(-1, dname)
604 dname = os.path.dirname(dname) 633 dname = os.path.dirname(dname)
605 wdir = dname 634 wdir = dname
606 self.addArguments(args, tree) 635 self.addArguments(args, tree)
607 636
609 tree2 = [] 638 tree2 = []
610 for n in name: 639 for n in name:
611 d = os.path.dirname(n) 640 d = os.path.dirname(n)
612 if self.__wcng: 641 if self.__wcng:
613 repodir = d 642 repodir = d
614 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 643 while not os.path.isdir(
644 os.path.join(repodir, self.adminDir)):
615 repodir = os.path.dirname(repodir) 645 repodir = os.path.dirname(repodir)
616 if os.path.splitdrive(repodir)[1] == os.sep: 646 if os.path.splitdrive(repodir)[1] == os.sep:
617 return # oops, project is not version controlled 647 return # oops, project is not version controlled
618 while os.path.normcase(d) != os.path.normcase(repodir) and \ 648 while os.path.normcase(d) != \
619 (d not in tree2 + tree) and \ 649 os.path.normcase(repodir) and \
620 (os.path.normcase(d) not in self.statusCache or \ 650 (d not in tree2 + tree) and \
621 self.statusCache[os.path.normcase(d)] == self.canBeAdded): 651 (os.path.normcase(d) not in self.statusCache or \
652 self.statusCache[os.path.normcase(d)] == \
653 self.canBeAdded):
622 tree2.append(d) 654 tree2.append(d)
623 d = os.path.dirname(d) 655 d = os.path.dirname(d)
624 else: 656 else:
625 while not os.path.exists(os.path.join(d, self.adminDir)): 657 while not os.path.exists(os.path.join(d, self.adminDir)):
626 if d in tree2 + tree: 658 if d in tree2 + tree:
635 667
636 if noDialog: 668 if noDialog:
637 self.startSynchronizedProcess(QProcess(), "svn", args, wdir) 669 self.startSynchronizedProcess(QProcess(), "svn", args, wdir)
638 else: 670 else:
639 dia = SvnDialog( 671 dia = SvnDialog(
640 self.trUtf8('Adding files/directories to the Subversion repository')) 672 self.trUtf8('Adding files/directories to the Subversion'
673 ' repository'))
641 res = dia.startProcess(args, wdir) 674 res = dia.startProcess(args, wdir)
642 if res: 675 if res:
643 dia.exec_() 676 dia.exec_()
644 677
645 def vcsAddBinary(self, name, isDir=False): 678 def vcsAddBinary(self, name, isDir=False):
652 """ 685 """
653 self.vcsAdd(name, isDir) 686 self.vcsAdd(name, isDir)
654 687
655 def vcsAddTree(self, path): 688 def vcsAddTree(self, path):
656 """ 689 """
657 Public method to add a directory tree rooted at path to the Subversion repository. 690 Public method to add a directory tree rooted at path to the Subversion
658 691 repository.
659 @param path root directory of the tree to be added (string or list of strings)) 692
693 @param path root directory of the tree to be added (string or list of
694 strings))
660 """ 695 """
661 args = [] 696 args = []
662 args.append('add') 697 args.append('add')
663 self.addArguments(args, self.options['global']) 698 self.addArguments(args, self.options['global'])
664 self.addArguments(args, self.options['add']) 699 self.addArguments(args, self.options['add'])
668 dname, fnames = self.splitPathList(path) 703 dname, fnames = self.splitPathList(path)
669 for n in path: 704 for n in path:
670 d = os.path.dirname(n) 705 d = os.path.dirname(n)
671 if self.__wcng: 706 if self.__wcng:
672 repodir = d 707 repodir = d
673 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 708 while not os.path.isdir(
709 os.path.join(repodir, self.adminDir)):
674 repodir = os.path.dirname(repodir) 710 repodir = os.path.dirname(repodir)
675 if os.path.splitdrive(repodir)[1] == os.sep: 711 if os.path.splitdrive(repodir)[1] == os.sep:
676 return # oops, project is not version controlled 712 return # oops, project is not version controlled
677 while os.path.normcase(d) != os.path.normcase(repodir) and \ 713 while os.path.normcase(d) != \
678 (d not in tree) and \ 714 os.path.normcase(repodir) and \
679 (os.path.normcase(d) not in self.statusCache or \ 715 (d not in tree) and \
680 self.statusCache[os.path.normcase(d)] == self.canBeAdded): 716 (os.path.normcase(d) not in self.statusCache or \
717 self.statusCache[os.path.normcase(d)] == \
718 self.canBeAdded):
681 tree.append(d) 719 tree.append(d)
682 d = os.path.dirname(d) 720 d = os.path.dirname(d)
683 else: 721 else:
684 while not os.path.exists(os.path.join(d, self.adminDir)): 722 while not os.path.exists(os.path.join(d, self.adminDir)):
685 # add directories recursively, 723 # add directories recursively,
695 repodir = dname 733 repodir = dname
696 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 734 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
697 repodir = os.path.dirname(repodir) 735 repodir = os.path.dirname(repodir)
698 if os.path.splitdrive(repodir)[1] == os.sep: 736 if os.path.splitdrive(repodir)[1] == os.sep:
699 return # oops, project is not version controlled 737 return # oops, project is not version controlled
700 while os.path.normcase(dname) != os.path.normcase(repodir) and \ 738 while os.path.normcase(dname) != \
701 (os.path.normcase(dname) not in self.statusCache or \ 739 os.path.normcase(repodir) and \
702 self.statusCache[os.path.normcase(dname)] == self.canBeAdded): 740 (os.path.normcase(dname) not in self.statusCache or \
703 # add directories recursively, if they aren't in the repository already 741 self.statusCache[os.path.normcase(dname)] == \
742 self.canBeAdded):
743 # add directories recursively, if they aren't in the
744 # repository already
704 tree.insert(-1, dname) 745 tree.insert(-1, dname)
705 dname = os.path.dirname(dname) 746 dname = os.path.dirname(dname)
706 else: 747 else:
707 while not os.path.exists(os.path.join(dname, self.adminDir)): 748 while not os.path.exists(os.path.join(dname, self.adminDir)):
708 # add directories recursively, 749 # add directories recursively,
723 if res: 764 if res:
724 dia.exec_() 765 dia.exec_()
725 766
726 def vcsRemove(self, name, project=False, noDialog=False): 767 def vcsRemove(self, name, project=False, noDialog=False):
727 """ 768 """
728 Public method used to remove a file/directory from the Subversion repository. 769 Public method used to remove a file/directory from the Subversion
770 repository.
729 771
730 The default operation is to remove the local copy as well. 772 The default operation is to remove the local copy as well.
731 773
732 @param name file/directory name to be removed (string or list of strings)) 774 @param name file/directory name to be removed (string or list of
733 @param project flag indicating deletion of a project tree (boolean) (not needed) 775 strings))
776 @param project flag indicating deletion of a project tree (boolean)
777 (not needed)
734 @param noDialog flag indicating quiet operations 778 @param noDialog flag indicating quiet operations
735 @return flag indicating successfull operation (boolean) 779 @return flag indicating successfull operation (boolean)
736 """ 780 """
737 args = [] 781 args = []
738 args.append('delete') 782 args.append('delete')
748 792
749 if noDialog: 793 if noDialog:
750 res = self.startSynchronizedProcess(QProcess(), "svn", args) 794 res = self.startSynchronizedProcess(QProcess(), "svn", args)
751 else: 795 else:
752 dia = SvnDialog( 796 dia = SvnDialog(
753 self.trUtf8('Removing files/directories from the Subversion repository')) 797 self.trUtf8('Removing files/directories from the Subversion'
798 ' repository'))
754 res = dia.startProcess(args) 799 res = dia.startProcess(args)
755 if res: 800 if res:
756 dia.exec_() 801 dia.exec_()
757 res = dia.normalExit() 802 res = dia.normalExit()
758 803
850 """ 895 """
851 Public method used to view the difference of a file/directory to the 896 Public method used to view the difference of a file/directory to the
852 Subversion repository. 897 Subversion repository.
853 898
854 If name is a directory and is the project directory, all project files 899 If name is a directory and is the project directory, all project files
855 are saved first. If name is a file (or list of files), which is/are being edited 900 are saved first. If name is a file (or list of files), which is/are
856 and has unsaved modification, they can be saved or the operation may be aborted. 901 being edited and has unsaved modification, they can be saved or the
902 operation may be aborted.
857 903
858 @param name file/directory name to be diffed (string) 904 @param name file/directory name to be diffed (string)
859 """ 905 """
860 if isinstance(name, list): 906 if isinstance(name, list):
861 names = name[:] 907 names = name[:]
900 946
901 reposURL = self.svnGetReposName(dname) 947 reposURL = self.svnGetReposName(dname)
902 if reposURL is None: 948 if reposURL is None:
903 E5MessageBox.critical(self.__ui, 949 E5MessageBox.critical(self.__ui,
904 self.trUtf8("Subversion Error"), 950 self.trUtf8("Subversion Error"),
905 self.trUtf8("""The URL of the project repository could not be""" 951 self.trUtf8(
906 """ retrieved from the working copy. The tag operation will""" 952 """The URL of the project repository could not be"""
907 """ be aborted""")) 953 """ retrieved from the working copy. The tag operation"""
954 """ will be aborted"""))
908 return 955 return
909 956
910 if self.otherData["standardLayout"]: 957 if self.otherData["standardLayout"]:
911 url = None 958 url = None
912 else: 959 else:
934 981
935 reposRoot = rx_base.cap(1) 982 reposRoot = rx_base.cap(1)
936 if tagOp in [1, 4]: 983 if tagOp in [1, 4]:
937 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag)) 984 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag))
938 elif tagOp in [2, 8]: 985 elif tagOp in [2, 8]:
939 url = '{0}/branches/{1}'.format(reposRoot, urllib.parse.quote(tag)) 986 url = '{0}/branches/{1}'.format(
987 reposRoot, urllib.parse.quote(tag))
940 else: 988 else:
941 url = self.__svnURL(tag) 989 url = self.__svnURL(tag)
942 990
943 args = [] 991 args = []
944 if tagOp in [1, 2]: 992 if tagOp in [1, 2]:
982 names = [name] 1030 names = [name]
983 1031
984 project = e5App().getObject("Project") 1032 project = e5App().getObject("Project")
985 names = [project.getRelativePath(nam) for nam in names] 1033 names = [project.getRelativePath(nam) for nam in names]
986 if names[0]: 1034 if names[0]:
987 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog 1035 from UI.DeleteFilesConfirmationDialog import \
1036 DeleteFilesConfirmationDialog
988 dlg = DeleteFilesConfirmationDialog(self.parent(), 1037 dlg = DeleteFilesConfirmationDialog(self.parent(),
989 self.trUtf8("Revert changes"), 1038 self.trUtf8("Revert changes"),
990 self.trUtf8("Do you really want to revert all changes to these files" 1039 self.trUtf8("Do you really want to revert all changes to"
991 " or directories?"), 1040 " these files or directories?"),
992 names) 1041 names)
993 yes = dlg.exec_() == QDialog.Accepted 1042 yes = dlg.exec_() == QDialog.Accepted
994 else: 1043 else:
995 yes = E5MessageBox.yesNo(None, 1044 yes = E5MessageBox.yesNo(None,
996 self.trUtf8("Revert changes"), 1045 self.trUtf8("Revert changes"),
1014 1063
1015 reposURL = self.svnGetReposName(dname) 1064 reposURL = self.svnGetReposName(dname)
1016 if reposURL is None: 1065 if reposURL is None:
1017 E5MessageBox.critical(self.__ui, 1066 E5MessageBox.critical(self.__ui,
1018 self.trUtf8("Subversion Error"), 1067 self.trUtf8("Subversion Error"),
1019 self.trUtf8("""The URL of the project repository could not be""" 1068 self.trUtf8(
1020 """ retrieved from the working copy. The switch operation will""" 1069 """The URL of the project repository could not be"""
1021 """ be aborted""")) 1070 """ retrieved from the working copy. The switch"""
1071 """ operation will be aborted"""))
1022 return False 1072 return False
1023 1073
1024 if self.otherData["standardLayout"]: 1074 if self.otherData["standardLayout"]:
1025 url = None 1075 url = None
1026 else: 1076 else:
1049 reposRoot = rx_base.cap(1) 1099 reposRoot = rx_base.cap(1)
1050 tn = tag 1100 tn = tag
1051 if tagType == 1: 1101 if tagType == 1:
1052 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1102 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag))
1053 elif tagType == 2: 1103 elif tagType == 2:
1054 url = '{0}/branches/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1104 url = '{0}/branches/{1}'.format(
1105 reposRoot, urllib.parse.quote(tag))
1055 elif tagType == 4: 1106 elif tagType == 4:
1056 url = '{0}/trunk'.format(reposRoot) 1107 url = '{0}/trunk'.format(reposRoot)
1057 tn = 'HEAD' 1108 tn = 'HEAD'
1058 else: 1109 else:
1059 url = self.__svnURL(tag) 1110 url = self.__svnURL(tag)
1088 force = '--force' in opts 1139 force = '--force' in opts
1089 if force: 1140 if force:
1090 del opts[opts.index('--force')] 1141 del opts[opts.index('--force')]
1091 1142
1092 from .SvnMergeDialog import SvnMergeDialog 1143 from .SvnMergeDialog import SvnMergeDialog
1093 dlg = SvnMergeDialog(self.mergeList[0], self.mergeList[1], self.mergeList[2], 1144 dlg = SvnMergeDialog(
1094 force) 1145 self.mergeList[0], self.mergeList[1], self.mergeList[2], force)
1095 if dlg.exec_() == QDialog.Accepted: 1146 if dlg.exec_() == QDialog.Accepted:
1096 urlrev1, urlrev2, target, force = dlg.getParameters() 1147 urlrev1, urlrev2, target, force = dlg.getParameters()
1097 else: 1148 else:
1098 return 1149 return
1099 1150
1151 1202
1152 def __vcsRegisteredState_wcng(self, name): 1203 def __vcsRegisteredState_wcng(self, name):
1153 """ 1204 """
1154 Private method used to get the registered state of a file in the vcs. 1205 Private method used to get the registered state of a file in the vcs.
1155 1206
1156 This is the variant for subversion installations using the new working copy 1207 This is the variant for subversion installations using the new
1157 meta-data format. 1208 working copy meta-data format.
1158 1209
1159 @param name filename to check (string) 1210 @param name filename to check (string)
1160 @return a combination of canBeCommited and canBeAdded 1211 @return a combination of canBeCommited and canBeAdded
1161 """ 1212 """
1162 if name.endswith(os.sep): 1213 if name.endswith(os.sep):
1178 else: 1229 else:
1179 return self.canBeAdded 1230 return self.canBeAdded
1180 1231
1181 def __vcsRegisteredState_wc(self, name): 1232 def __vcsRegisteredState_wc(self, name):
1182 """ 1233 """
1183 Private method used to get the registered state of a file in the vcs. 1234 Private method used to get the registered state of a file in the VCS.
1184 1235
1185 This is the variant for subversion installations using the old working copy 1236 This is the variant for subversion installations using the old working
1186 meta-data format. 1237 copy meta-data format.
1187 1238
1188 @param name filename to check (string) 1239 @param name filename to check (string)
1189 @return a combination of canBeCommited and canBeAdded 1240 @return a combination of canBeCommited and canBeAdded
1190 """ 1241 """
1191 dname, fname = self.splitPath(name) 1242 dname, fname = self.splitPath(name)
1204 else: 1255 else:
1205 return self.canBeAdded 1256 return self.canBeAdded
1206 1257
1207 def vcsAllRegisteredStates(self, names, dname, shortcut=True): 1258 def vcsAllRegisteredStates(self, names, dname, shortcut=True):
1208 """ 1259 """
1209 Public method used to get the registered states of a number of files in the vcs. 1260 Public method used to get the registered states of a number of files
1210 1261 in the VCS.
1211 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1262
1212 directory has been scanned already. If so, it is assumed, that the states for 1263 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1213 all files have been populated by the previous run. 1264 if the named directory has been scanned already. If so, it is assumed,
1265 that the states for all files have been populated by the previous run.
1214 1266
1215 @param names dictionary with all filenames to be checked as keys 1267 @param names dictionary with all filenames to be checked as keys
1216 @param dname directory to check in (string) 1268 @param dname directory to check in (string)
1217 @param shortcut flag indicating a shortcut should be taken (boolean) 1269 @param shortcut flag indicating a shortcut should be taken (boolean)
1218 @return the received dictionary completed with a combination of 1270 @return the received dictionary completed with a combination of
1223 else: 1275 else:
1224 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut) 1276 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut)
1225 1277
1226 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True): 1278 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True):
1227 """ 1279 """
1228 Private method used to get the registered states of a number of files in the vcs. 1280 Private method used to get the registered states of a number of files
1229 1281 in the VCS.
1230 This is the variant for subversion installations using the new working copy 1282
1231 meta-data format. 1283 This is the variant for subversion installations using the new working
1232 1284 copy meta-data format.
1233 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1285
1234 directory has been scanned already. If so, it is assumed, that the states for 1286 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1235 all files has been populated by the previous run. 1287 if the named directory has been scanned already. If so, it is assumed,
1288 that the states for all files has been populated by the previous run.
1236 1289
1237 @param names dictionary with all filenames to be checked as keys 1290 @param names dictionary with all filenames to be checked as keys
1238 @param dname directory to check in (string) 1291 @param dname directory to check in (string)
1239 @param shortcut flag indicating a shortcut should be taken (boolean) 1292 @param shortcut flag indicating a shortcut should be taken (boolean)
1240 @return the received dictionary completed with a combination of 1293 @return the received dictionary completed with a combination of
1268 process.start('svn', args) 1321 process.start('svn', args)
1269 procStarted = process.waitForStarted(5000) 1322 procStarted = process.waitForStarted(5000)
1270 if procStarted: 1323 if procStarted:
1271 finished = process.waitForFinished(30000) 1324 finished = process.waitForFinished(30000)
1272 if finished and process.exitCode() == 0: 1325 if finished and process.exitCode() == 0:
1273 output = \ 1326 output = str(process.readAllStandardOutput(), ioEncoding,
1274 str(process.readAllStandardOutput(), ioEncoding, 'replace') 1327 'replace')
1275 for line in output.splitlines(): 1328 for line in output.splitlines():
1276 if self.rx_status1.exactMatch(line): 1329 if self.rx_status1.exactMatch(line):
1277 flags = str(self.rx_status1.cap(1)) 1330 flags = str(self.rx_status1.cap(1))
1278 path = self.rx_status1.cap(5).strip() 1331 path = self.rx_status1.cap(5).strip()
1279 elif self.rx_status2.exactMatch(line): 1332 elif self.rx_status2.exactMatch(line):
1291 1344
1292 return names 1345 return names
1293 1346
1294 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True): 1347 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True):
1295 """ 1348 """
1296 Private method used to get the registered states of a number of files in the vcs. 1349 Private method used to get the registered states of a number of files
1297 1350 in the VCS.
1298 This is the variant for subversion installations using the old working copy 1351
1299 meta-data format. 1352 This is the variant for subversion installations using the old working
1300 1353 copy meta-data format.
1301 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1354
1302 directory has been scanned already. If so, it is assumed, that the states for 1355 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1303 all files has been populated by the previous run. 1356 if the named directory has been scanned already. If so, it is assumed,
1357 that the states for all files has been populated by the previous run.
1304 1358
1305 @param names dictionary with all filenames to be checked as keys 1359 @param names dictionary with all filenames to be checked as keys
1306 @param dname directory to check in (string) 1360 @param dname directory to check in (string)
1307 @param shortcut flag indicating a shortcut should be taken (boolean) 1361 @param shortcut flag indicating a shortcut should be taken (boolean)
1308 @return the received dictionary completed with a combination of 1362 @return the received dictionary completed with a combination of
1333 process.start('svn', args) 1387 process.start('svn', args)
1334 procStarted = process.waitForStarted(5000) 1388 procStarted = process.waitForStarted(5000)
1335 if procStarted: 1389 if procStarted:
1336 finished = process.waitForFinished(30000) 1390 finished = process.waitForFinished(30000)
1337 if finished and process.exitCode() == 0: 1391 if finished and process.exitCode() == 0:
1338 output = \ 1392 output = str(process.readAllStandardOutput(), ioEncoding,
1339 str(process.readAllStandardOutput(), ioEncoding, 'replace') 1393 'replace')
1340 for line in output.splitlines(): 1394 for line in output.splitlines():
1341 if self.rx_status1.exactMatch(line): 1395 if self.rx_status1.exactMatch(line):
1342 flags = self.rx_status1.cap(1) 1396 flags = self.rx_status1.cap(1)
1343 path = self.rx_status1.cap(5).strip() 1397 path = self.rx_status1.cap(5).strip()
1344 elif self.rx_status2.exactMatch(line): 1398 elif self.rx_status2.exactMatch(line):
1483 process.start('svn', args) 1537 process.start('svn', args)
1484 procStarted = process.waitForStarted(5000) 1538 procStarted = process.waitForStarted(5000)
1485 if procStarted: 1539 if procStarted:
1486 finished = process.waitForFinished(30000) 1540 finished = process.waitForFinished(30000)
1487 if finished and process.exitCode() == 0: 1541 if finished and process.exitCode() == 0:
1488 output = str(process.readAllStandardOutput(), ioEncoding, 'replace') 1542 output = str(process.readAllStandardOutput(), ioEncoding,
1543 'replace')
1489 entryFound = False 1544 entryFound = False
1490 commitFound = False 1545 commitFound = False
1491 for line in output.splitlines(): 1546 for line in output.splitlines():
1492 line = line.strip() 1547 line = line.strip()
1493 if line.startswith('<entry'): 1548 if line.startswith('<entry'):
1505 info['committed-rev'] = rev 1560 info['committed-rev'] = rev
1506 elif line.startswith('<url>'): 1561 elif line.startswith('<url>'):
1507 info['url'] = \ 1562 info['url'] = \
1508 line.replace('<url>', '').replace('</url>', '') 1563 line.replace('<url>', '').replace('</url>', '')
1509 elif line.startswith('<author>'): 1564 elif line.startswith('<author>'):
1510 info['last-author'] = \ 1565 info['last-author'] = line.replace('<author>', '')\
1511 line.replace('<author>', '').replace('</author>', '') 1566 .replace('</author>', '')
1512 elif line.startswith('<date>'): 1567 elif line.startswith('<date>'):
1513 value = line.replace('<date>', '').replace('</date>', '') 1568 value = line.replace('<date>', '')\
1569 .replace('</date>', '')
1514 date, time = value.split('T') 1570 date, time = value.split('T')
1515 info['committed-date'] = date 1571 info['committed-date'] = date
1516 info['committed-time'] = "{0}{1}".format( 1572 info['committed-time'] = "{0}{1}".format(
1517 time.split('.')[0], time[-1]) 1573 time.split('.')[0], time[-1])
1518 1574
1534 info['committed-rev'], 1590 info['committed-rev'],
1535 info['committed-date'], 1591 info['committed-date'],
1536 info['committed-time'], 1592 info['committed-time'],
1537 info['last-author']) 1593 info['last-author'])
1538 1594
1539 ############################################################################ 1595 ###########################################################################
1540 ## Public Subversion specific methods are below. 1596 ## Public Subversion specific methods are below.
1541 ############################################################################ 1597 ###########################################################################
1542 1598
1543 def svnGetReposName(self, path): 1599 def svnGetReposName(self, path):
1544 """ 1600 """
1545 Public method used to retrieve the URL of the subversion repository path. 1601 Public method used to retrieve the URL of the subversion repository
1602 path.
1546 1603
1547 @param path local path to get the svn repository path for (string) 1604 @param path local path to get the svn repository path for (string)
1548 @return string with the repository path URL 1605 @return string with the repository path URL
1549 """ 1606 """
1550 ioEncoding = Preferences.getSystem("IOEncoding") 1607 ioEncoding = Preferences.getSystem("IOEncoding")
1558 process.start('svn', args) 1615 process.start('svn', args)
1559 procStarted = process.waitForStarted(5000) 1616 procStarted = process.waitForStarted(5000)
1560 if procStarted: 1617 if procStarted:
1561 finished = process.waitForFinished(30000) 1618 finished = process.waitForFinished(30000)
1562 if finished and process.exitCode() == 0: 1619 if finished and process.exitCode() == 0:
1563 output = str(process.readAllStandardOutput(), ioEncoding, 'replace') 1620 output = str(process.readAllStandardOutput(), ioEncoding,
1621 'replace')
1564 for line in output.splitlines(): 1622 for line in output.splitlines():
1565 line = line.strip() 1623 line = line.strip()
1566 if line.startswith('<url>'): 1624 if line.startswith('<url>'):
1567 reposURL = line.replace('<url>', '').replace('</url>', '') 1625 reposURL = line.replace('<url>', '')\
1626 .replace('</url>', '')
1568 return reposURL 1627 return reposURL
1569 1628
1570 return "" 1629 return ""
1571 1630
1572 def svnResolve(self, name): 1631 def svnResolve(self, name):
1660 if dlg.exec_() == QDialog.Accepted: 1719 if dlg.exec_() == QDialog.Accepted:
1661 propName, fileFlag, propValue = dlg.getData() 1720 propName, fileFlag, propValue = dlg.getData()
1662 if not propName: 1721 if not propName:
1663 E5MessageBox.critical(self.__ui, 1722 E5MessageBox.critical(self.__ui,
1664 self.trUtf8("Subversion Set Property"), 1723 self.trUtf8("Subversion Set Property"),
1665 self.trUtf8("""You have to supply a property name. Aborting.""")) 1724 self.trUtf8("""You have to supply a property name."""
1725 """ Aborting."""))
1666 return 1726 return
1667 1727
1668 args = [] 1728 args = []
1669 args.append('propset') 1729 args.append('propset')
1670 self.addArguments(args, self.options['global']) 1730 self.addArguments(args, self.options['global'])
1703 return 1763 return
1704 1764
1705 if not propName: 1765 if not propName:
1706 E5MessageBox.critical(self.__ui, 1766 E5MessageBox.critical(self.__ui,
1707 self.trUtf8("Subversion Delete Property"), 1767 self.trUtf8("Subversion Delete Property"),
1708 self.trUtf8("""You have to supply a property name. Aborting.""")) 1768 self.trUtf8("""You have to supply a property name."""
1769 """ Aborting."""))
1709 return 1770 return
1710 1771
1711 args = [] 1772 args = []
1712 args.append('propdel') 1773 args.append('propdel')
1713 self.addArguments(args, self.options['global']) 1774 self.addArguments(args, self.options['global'])
1751 self.showedBranches = True 1812 self.showedBranches = True
1752 allTagsBranchesList = self.allTagsBranchesList 1813 allTagsBranchesList = self.allTagsBranchesList
1753 else: 1814 else:
1754 self.branchesList = [] 1815 self.branchesList = []
1755 allTagsBranchesList = None 1816 allTagsBranchesList = None
1756 self.tagbranchList.start(path, tags, 1817 self.tagbranchList.start(
1757 self.branchesList, self.allTagsBranchesList) 1818 path, tags, self.branchesList, self.allTagsBranchesList)
1758 1819
1759 def svnBlame(self, name): 1820 def svnBlame(self, name):
1760 """ 1821 """
1761 Public method to show the output of the svn blame command. 1822 Public method to show the output of the svn blame command.
1762 1823
1771 """ 1832 """
1772 Public method used to view the difference of a file/directory to the 1833 Public method used to view the difference of a file/directory to the
1773 Subversion repository. 1834 Subversion repository.
1774 1835
1775 If name is a directory and is the project directory, all project files 1836 If name is a directory and is the project directory, all project files
1776 are saved first. If name is a file (or list of files), which is/are being edited 1837 are saved first. If name is a file (or list of files), which is/are
1777 and has unsaved modification, they can be saved or the operation may be aborted. 1838 being edited and has unsaved modification, they can be saved or the
1839 operation may be aborted.
1778 1840
1779 This method gives the chance to enter the revisions to be compared. 1841 This method gives the chance to enter the revisions to be compared.
1780 1842
1781 @param name file/directory name to be diffed (string) 1843 @param name file/directory name to be diffed (string)
1782 """ 1844 """
1806 """ 1868 """
1807 Public method used to view the difference of a file/directory of two 1869 Public method used to view the difference of a file/directory of two
1808 repository URLs. 1870 repository URLs.
1809 1871
1810 If name is a directory and is the project directory, all project files 1872 If name is a directory and is the project directory, all project files
1811 are saved first. If name is a file (or list of files), which is/are being edited 1873 are saved first. If name is a file (or list of files), which is/are
1812 and has unsaved modification, they can be saved or the operation may be aborted. 1874 being edited and has unsaved modification, they can be saved or the
1875 operation may be aborted.
1813 1876
1814 This method gives the chance to enter the revisions to be compared. 1877 This method gives the chance to enter the revisions to be compared.
1815 1878
1816 @param name file/directory name to be diffed (string) 1879 @param name file/directory name to be diffed (string)
1817 """ 1880 """
1830 return 1893 return
1831 1894
1832 dname = self.splitPath(names[0])[0] 1895 dname = self.splitPath(names[0])[0]
1833 1896
1834 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog 1897 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog
1835 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList, dname) 1898 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList,
1899 dname)
1836 if dlg.exec_() == QDialog.Accepted: 1900 if dlg.exec_() == QDialog.Accepted:
1837 urls, summary = dlg.getURLs() 1901 urls, summary = dlg.getURLs()
1838 from .SvnDiffDialog import SvnDiffDialog 1902 from .SvnDiffDialog import SvnDiffDialog
1839 self.diff = SvnDiffDialog(self) 1903 self.diff = SvnDiffDialog(self)
1840 self.diff.show() 1904 self.diff.show()
1841 QApplication.processEvents() 1905 QApplication.processEvents()
1842 self.diff.start(name, urls=urls, summary=summary) 1906 self.diff.start(name, urls=urls, summary=summary)
1843 1907
1844 def __svnGetFileForRevision(self, name, rev=""): 1908 def __svnGetFileForRevision(self, name, rev=""):
1845 """ 1909 """
1846 Private method to get a file for a specific revision from the repository. 1910 Private method to get a file for a specific revision from the
1911 repository.
1847 1912
1848 @param name file name to get from the repository (string) 1913 @param name file name to get from the repository (string)
1849 @keyparam rev revision to retrieve (integer or string) 1914 @keyparam rev revision to retrieve (integer or string)
1850 @return contents of the file (string) and an error message (string) 1915 @return contents of the file (string) and an error message (string)
1851 """ 1916 """
1870 Preferences.getSystem("IOEncoding"), 'replace') 1935 Preferences.getSystem("IOEncoding"), 'replace')
1871 else: 1936 else:
1872 error = str(process.readAllStandardError(), 1937 error = str(process.readAllStandardError(),
1873 Preferences.getSystem("IOEncoding"), 'replace') 1938 Preferences.getSystem("IOEncoding"), 'replace')
1874 else: 1939 else:
1875 error = self.trUtf8("The svn process did not finish within 30s.") 1940 error = self.trUtf8(
1941 "The svn process did not finish within 30s.")
1876 else: 1942 else:
1877 error = self.trUtf8('The process {0} could not be started. ' 1943 error = self.trUtf8('The process {0} could not be started. '
1878 'Ensure, that it is in the search path.').format('svn') 1944 'Ensure, that it is in the search path.').format('svn')
1879 1945
1880 return output, error 1946 return output, error
1929 f1.close() 1995 f1.close()
1930 name2 = name 1996 name2 = name
1931 except IOError: 1997 except IOError:
1932 E5MessageBox.critical(self.__ui, 1998 E5MessageBox.critical(self.__ui,
1933 self.trUtf8("Subversion Side-by-Side Difference"), 1999 self.trUtf8("Subversion Side-by-Side Difference"),
1934 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""") 2000 self.trUtf8(
2001 """<p>The file <b>{0}</b> could not be read.</p>""")
1935 .format(name)) 2002 .format(name))
1936 return 2003 return
1937 2004
1938 if self.sbsDiff is None: 2005 if self.sbsDiff is None:
1939 from UI.CompareDialog import CompareDialog 2006 from UI.CompareDialog import CompareDialog
1956 2023
1957 def svnLock(self, name, stealIt=False, parent=None): 2024 def svnLock(self, name, stealIt=False, parent=None):
1958 """ 2025 """
1959 Public method used to lock a file in the Subversion repository. 2026 Public method used to lock a file in the Subversion repository.
1960 2027
1961 @param name file/directory name to be locked (string or list of strings) 2028 @param name file/directory name to be locked (string or list of
2029 strings)
1962 @param stealIt flag indicating a forced operation (boolean) 2030 @param stealIt flag indicating a forced operation (boolean)
1963 @param parent reference to the parent object of the subversion dialog (QWidget) 2031 @param parent reference to the parent object of the subversion dialog
2032 (QWidget)
1964 """ 2033 """
1965 args = [] 2034 args = []
1966 args.append('lock') 2035 args.append('lock')
1967 self.addArguments(args, self.options['global']) 2036 self.addArguments(args, self.options['global'])
1968 if stealIt: 2037 if stealIt:
1972 self.addArguments(args, fnames) 2041 self.addArguments(args, fnames)
1973 else: 2042 else:
1974 dname, fname = self.splitPath(name) 2043 dname, fname = self.splitPath(name)
1975 args.append(fname) 2044 args.append(fname)
1976 2045
1977 dia = SvnDialog(self.trUtf8('Locking in the Subversion repository'), parent) 2046 dia = SvnDialog(
2047 self.trUtf8('Locking in the Subversion repository'), parent)
1978 res = dia.startProcess(args, dname) 2048 res = dia.startProcess(args, dname)
1979 if res: 2049 if res:
1980 dia.exec_() 2050 dia.exec_()
1981 2051
1982 def svnUnlock(self, name, breakIt=False, parent=None): 2052 def svnUnlock(self, name, breakIt=False, parent=None):
1983 """ 2053 """
1984 Public method used to unlock a file in the Subversion repository. 2054 Public method used to unlock a file in the Subversion repository.
1985 2055
1986 @param name file/directory name to be unlocked (string or list of strings) 2056 @param name file/directory name to be unlocked (string or list of
2057 strings)
1987 @param breakIt flag indicating a forced operation (boolean) 2058 @param breakIt flag indicating a forced operation (boolean)
1988 @param parent reference to the parent object of the subversion dialog (QWidget) 2059 @param parent reference to the parent object of the subversion dialog
2060 (QWidget)
1989 """ 2061 """
1990 args = [] 2062 args = []
1991 args.append('unlock') 2063 args.append('unlock')
1992 self.addArguments(args, self.options['global']) 2064 self.addArguments(args, self.options['global'])
1993 if breakIt: 2065 if breakIt:
1997 self.addArguments(args, fnames) 2069 self.addArguments(args, fnames)
1998 else: 2070 else:
1999 dname, fname = self.splitPath(name) 2071 dname, fname = self.splitPath(name)
2000 args.append(fname) 2072 args.append(fname)
2001 2073
2002 dia = SvnDialog(self.trUtf8('Unlocking in the Subversion repository'), parent) 2074 dia = SvnDialog(
2075 self.trUtf8('Unlocking in the Subversion repository'), parent)
2003 res = dia.startProcess(args, dname) 2076 res = dia.startProcess(args, dname)
2004 if res: 2077 if res:
2005 dia.exec_() 2078 dia.exec_()
2006 2079
2007 def svnRelocate(self, projectPath): 2080 def svnRelocate(self, projectPath):
2162 if changelist not in changelists: 2235 if changelist not in changelists:
2163 changelists.append(changelist) 2236 changelists.append(changelist)
2164 2237
2165 return changelists 2238 return changelists
2166 2239
2167 ############################################################################ 2240 ###########################################################################
2168 ## Private Subversion specific methods are below. 2241 ## Private Subversion specific methods are below.
2169 ############################################################################ 2242 ###########################################################################
2170 2243
2171 def __svnURL(self, url): 2244 def __svnURL(self, url):
2172 """ 2245 """
2173 Private method to format a url for subversion. 2246 Private method to format a url for subversion.
2174 2247
2179 url = url.split(':', 2) 2252 url = url.split(':', 2)
2180 if len(url) == 3: 2253 if len(url) == 3:
2181 scheme = url[0] 2254 scheme = url[0]
2182 host = url[1] 2255 host = url[1]
2183 port, path = url[2].split("/", 1) 2256 port, path = url[2].split("/", 1)
2184 return "{0}:{1}:{2}/{3}".format(scheme, host, port, urllib.parse.quote(path)) 2257 return "{0}:{1}:{2}/{3}".format(
2258 scheme, host, port, urllib.parse.quote(path))
2185 else: 2259 else:
2186 scheme = url[0] 2260 scheme = url[0]
2187 if scheme == "file": 2261 if scheme == "file":
2188 return "{0}:{1}".format(scheme, urllib.parse.quote(url[1])) 2262 return "{0}:{1}".format(scheme, urllib.parse.quote(url[1]))
2189 else: 2263 else:
2190 try: 2264 try:
2191 host, path = url[1][2:].split("/", 1) 2265 host, path = url[1][2:].split("/", 1)
2192 except ValueError: 2266 except ValueError:
2193 host = url[1][2:] 2267 host = url[1][2:]
2194 path = "" 2268 path = ""
2195 return "{0}://{1}/{2}".format(scheme, host, urllib.parse.quote(path)) 2269 return "{0}://{1}/{2}".format(
2270 scheme, host, urllib.parse.quote(path))
2196 2271
2197 def svnNormalizeURL(self, url): 2272 def svnNormalizeURL(self, url):
2198 """ 2273 """
2199 Public method to normalize a url for subversion. 2274 Public method to normalize a url for subversion.
2200 2275
2211 url = url[:-1] 2286 url = url[:-1]
2212 if not url.startswith("/") and url[1] in [":", "|"]: 2287 if not url.startswith("/") and url[1] in [":", "|"]:
2213 url = "/{0}".format(url) 2288 url = "/{0}".format(url)
2214 return "{0}://{1}".format(protocol, url) 2289 return "{0}://{1}".format(protocol, url)
2215 2290
2216 ############################################################################ 2291 ###########################################################################
2217 ## Methods to get the helper objects are below. 2292 ## Methods to get the helper objects are below.
2218 ############################################################################ 2293 ###########################################################################
2219 2294
2220 def vcsGetProjectBrowserHelper(self, browser, project, isTranslationsBrowser=False): 2295 def vcsGetProjectBrowserHelper(self, browser, project,
2221 """ 2296 isTranslationsBrowser=False):
2222 Public method to instanciate a helper object for the different project browsers. 2297 """
2298 Public method to instanciate a helper object for the different
2299 project browsers.
2223 2300
2224 @param browser reference to the project browser object 2301 @param browser reference to the project browser object
2225 @param project reference to the project object 2302 @param project reference to the project object
2226 @param isTranslationsBrowser flag indicating, the helper is requested for the 2303 @param isTranslationsBrowser flag indicating, the helper is requested
2227 translations browser (this needs some special treatment) 2304 for the translations browser (this needs some special treatment)
2228 @return the project browser helper object 2305 @return the project browser helper object
2229 """ 2306 """
2230 from .ProjectBrowserHelper import SvnProjectBrowserHelper 2307 from .ProjectBrowserHelper import SvnProjectBrowserHelper
2231 return SvnProjectBrowserHelper(self, browser, project, isTranslationsBrowser) 2308 return SvnProjectBrowserHelper(self, browser, project,
2309 isTranslationsBrowser)
2232 2310
2233 def vcsGetProjectHelper(self, project): 2311 def vcsGetProjectHelper(self, project):
2234 """ 2312 """
2235 Public method to instanciate a helper object for the project. 2313 Public method to instanciate a helper object for the project.
2236 2314
2238 @return the project helper object 2316 @return the project helper object
2239 """ 2317 """
2240 helper = self.__plugin.getProjectHelper() 2318 helper = self.__plugin.getProjectHelper()
2241 helper.setObjects(self, project) 2319 helper.setObjects(self, project)
2242 self.__wcng = \ 2320 self.__wcng = \
2243 os.path.exists(os.path.join(project.getProjectPath(), ".svn", "format")) or \ 2321 os.path.exists(
2244 os.path.exists(os.path.join(project.getProjectPath(), "_svn", "format")) 2322 os.path.join(project.getProjectPath(), ".svn", "format")) or \
2323 os.path.exists(
2324 os.path.join(project.getProjectPath(), "_svn", "format"))
2245 return helper 2325 return helper
2246 2326
2247 ############################################################################ 2327 ###########################################################################
2248 ## Status Monitor Thread methods 2328 ## Status Monitor Thread methods
2249 ############################################################################ 2329 ###########################################################################
2250 2330
2251 def _createStatusMonitorThread(self, interval, project): 2331 def _createStatusMonitorThread(self, interval, project):
2252 """ 2332 """
2253 Protected method to create an instance of the VCS status monitor thread. 2333 Protected method to create an instance of the VCS status monitor
2254 2334 thread.
2255 @param interval check interval for the monitor thread in seconds (integer) 2335
2336 @param interval check interval for the monitor thread in seconds
2337 (integer)
2256 @param project reference to the project object 2338 @param project reference to the project object
2257 @return reference to the monitor thread (QThread) 2339 @return reference to the monitor thread (QThread)
2258 """ 2340 """
2259 from .SvnStatusMonitorThread import SvnStatusMonitorThread 2341 from .SvnStatusMonitorThread import SvnStatusMonitorThread
2260 return SvnStatusMonitorThread(interval, project, self) 2342 return SvnStatusMonitorThread(interval, project, self)

eric ide

mercurial