Plugins/VcsPlugins/vcsSubversion/subversion.py

branch
Py2 comp.
changeset 3057
10516539f238
parent 2847
1843ef6e2656
parent 3009
bf5ae5d7477d
child 3058
0a02c433f52d
equal deleted inserted replaced
3056:9986ec0e559a 3057:10516539f238
101 self.tagbranchList = None 101 self.tagbranchList = None
102 self.blame = None 102 self.blame = None
103 self.repoBrowser = None 103 self.repoBrowser = None
104 104
105 # regular expression object for evaluation of the status output 105 # regular expression object for evaluation of the status output
106 self.rx_status1 = QRegExp('(.{8})\\s+([0-9-]+)\\s+([0-9?]+)\\s+([\\w?]+)\\s+(.+)') 106 self.rx_status1 = QRegExp(
107 '(.{8})\\s+([0-9-]+)\\s+([0-9?]+)\\s+([\\w?]+)\\s+(.+)')
107 self.rx_status2 = QRegExp('(.{8})\\s+(.+)\\s*') 108 self.rx_status2 = QRegExp('(.{8})\\s+(.+)\\s*')
108 self.statusCache = {} 109 self.statusCache = {}
109 110
110 self.__commitData = {} 111 self.__commitData = {}
111 self.__commitDialog = None 112 self.__commitDialog = None
112 113
113 self.__wcng = True # assume new generation working copy metadata format 114 self.__wcng = True # assume new generation working copy
115 # metadata format
114 116
115 def getPlugin(self): 117 def getPlugin(self):
116 """ 118 """
117 Public method to get a reference to the plugin object. 119 Public method to get a reference to the plugin object.
118 120
143 145
144 def vcsExists(self): 146 def vcsExists(self):
145 """ 147 """
146 Public method used to test for the presence of the svn executable. 148 Public method used to test for the presence of the svn executable.
147 149
148 @return flag indicating the existance (boolean) and an error message (string) 150 @return flag indicating the existance (boolean) and an error message
151 (string)
149 """ 152 """
150 self.versionStr = '' 153 self.versionStr = ''
151 errMsg = "" 154 errMsg = ""
152 ioEncoding = Preferences.getSystem("IOEncoding") 155 ioEncoding = Preferences.getSystem("IOEncoding")
153 156
158 finished = process.waitForFinished(30000) 161 finished = process.waitForFinished(30000)
159 if finished and process.exitCode() == 0: 162 if finished and process.exitCode() == 0:
160 output = \ 163 output = \
161 str(process.readAllStandardOutput(), ioEncoding, 'replace') 164 str(process.readAllStandardOutput(), ioEncoding, 'replace')
162 self.versionStr = output.split()[2] 165 self.versionStr = output.split()[2]
163 v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?', self.versionStr).groups()) 166 v = list(re.match(r'.*?(\d+)\.(\d+)\.?(\d+)?', self.versionStr)
167 .groups())
164 for i in range(3): 168 for i in range(3):
165 try: 169 try:
166 v[i] = int(v[i]) 170 v[i] = int(v[i])
167 except TypeError: 171 except TypeError:
168 v[i] = 0 172 v[i] = 0
170 v.append(0) 174 v.append(0)
171 self.version = tuple(v) 175 self.version = tuple(v)
172 return True, errMsg 176 return True, errMsg
173 else: 177 else:
174 if finished: 178 if finished:
175 errMsg = \ 179 errMsg = self.trUtf8(
176 self.trUtf8("The svn process finished with the exit code {0}")\ 180 "The svn process finished with the exit code {0}")\
177 .format(process.exitCode()) 181 .format(process.exitCode())
178 else: 182 else:
179 errMsg = self.trUtf8("The svn process did not finish within 30s.") 183 errMsg = self.trUtf8(
184 "The svn process did not finish within 30s.")
180 else: 185 else:
181 errMsg = self.trUtf8("Could not start the svn executable.") 186 errMsg = self.trUtf8("Could not start the svn executable.")
182 187
183 return False, errMsg 188 return False, errMsg
184 189
196 """ 201 """
197 return True 202 return True
198 203
199 def vcsConvertProject(self, vcsDataDict, project): 204 def vcsConvertProject(self, vcsDataDict, project):
200 """ 205 """
201 Public method to convert an uncontrolled project to a version controlled project. 206 Public method to convert an uncontrolled project to a version
207 controlled project.
202 208
203 @param vcsDataDict dictionary of data required for the conversion 209 @param vcsDataDict dictionary of data required for the conversion
204 @param project reference to the project object 210 @param project reference to the project object
205 """ 211 """
206 success = self.vcsImport(vcsDataDict, project.ppath)[0] 212 success = self.vcsImport(vcsDataDict, project.ppath)[0]
207 if not success: 213 if not success:
208 E5MessageBox.critical(self.__ui, 214 E5MessageBox.critical(self.__ui,
209 self.trUtf8("Create project in repository"), 215 self.trUtf8("Create project in repository"),
210 self.trUtf8("""The project could not be created in the repository.""" 216 self.trUtf8(
211 """ Maybe the given repository doesn't exist or the""" 217 """The project could not be created in the repository."""
212 """ repository server is down.""")) 218 """ Maybe the given repository doesn't exist or the"""
219 """ repository server is down."""))
213 else: 220 else:
214 cwdIsPpath = False 221 cwdIsPpath = False
215 if os.getcwd() == project.ppath: 222 if os.getcwd() == project.ppath:
216 os.chdir(os.path.dirname(project.ppath)) 223 os.chdir(os.path.dirname(project.ppath))
217 cwdIsPpath = True 224 cwdIsPpath = True
227 if not os.path.isfile(pfn): 234 if not os.path.isfile(pfn):
228 pfn += "z" 235 pfn += "z"
229 if not os.path.isfile(pfn): 236 if not os.path.isfile(pfn):
230 E5MessageBox.critical(self.__ui, 237 E5MessageBox.critical(self.__ui,
231 self.trUtf8("New project"), 238 self.trUtf8("New project"),
232 self.trUtf8("""The project could not be checked out of the""" 239 self.trUtf8(
233 """ repository.<br />""" 240 """The project could not be checked out of the"""
234 """Restoring the original contents.""")) 241 """ repository.<br />"""
242 """Restoring the original contents."""))
235 if os.getcwd() == project.ppath: 243 if os.getcwd() == project.ppath:
236 os.chdir(os.path.dirname(project.ppath)) 244 os.chdir(os.path.dirname(project.ppath))
237 cwdIsPpath = True 245 cwdIsPpath = True
238 else: 246 else:
239 cwdIsPpath = False 247 cwdIsPpath = False
249 project.closeProject(noSave=True) 257 project.closeProject(noSave=True)
250 project.openProject(pfn) 258 project.openProject(pfn)
251 259
252 def vcsImport(self, vcsDataDict, projectDir, noDialog=False): 260 def vcsImport(self, vcsDataDict, projectDir, noDialog=False):
253 """ 261 """
254 Public method used to import the project into the Subversion repository. 262 Public method used to import the project into the Subversion
263 repository.
255 264
256 @param vcsDataDict dictionary of data required for the import 265 @param vcsDataDict dictionary of data required for the import
257 @param projectDir project directory (string) 266 @param projectDir project directory (string)
258 @param noDialog flag indicating quiet operations 267 @param noDialog flag indicating quiet operations
259 @return flag indicating an execution without errors (boolean) 268 @return flag indicating an execution without errors (boolean)
278 os.makedirs(tmpDir) 287 os.makedirs(tmpDir)
279 if self.otherData["standardLayout"]: 288 if self.otherData["standardLayout"]:
280 os.mkdir(os.path.join(tmpDir, project)) 289 os.mkdir(os.path.join(tmpDir, project))
281 os.mkdir(os.path.join(tmpDir, project, 'branches')) 290 os.mkdir(os.path.join(tmpDir, project, 'branches'))
282 os.mkdir(os.path.join(tmpDir, project, 'tags')) 291 os.mkdir(os.path.join(tmpDir, project, 'tags'))
283 shutil.copytree(projectDir, os.path.join(tmpDir, project, 'trunk')) 292 shutil.copytree(
293 projectDir, os.path.join(tmpDir, project, 'trunk'))
284 else: 294 else:
285 shutil.copytree(projectDir, os.path.join(tmpDir, project)) 295 shutil.copytree(projectDir, os.path.join(tmpDir, project))
286 except OSError: 296 except OSError:
287 if os.path.isdir(tmpDir): 297 if os.path.isdir(tmpDir):
288 shutil.rmtree(tmpDir, True) 298 shutil.rmtree(tmpDir, True)
297 307
298 if noDialog: 308 if noDialog:
299 status = self.startSynchronizedProcess(QProcess(), "svn", args, 309 status = self.startSynchronizedProcess(QProcess(), "svn", args,
300 os.path.join(tmpDir, project)) 310 os.path.join(tmpDir, project))
301 else: 311 else:
302 dia = SvnDialog(self.trUtf8('Importing project into Subversion repository')) 312 dia = SvnDialog(
313 self.trUtf8('Importing project into Subversion repository'))
303 res = dia.startProcess(args, os.path.join(tmpDir, project)) 314 res = dia.startProcess(args, os.path.join(tmpDir, project))
304 if res: 315 if res:
305 dia.exec_() 316 dia.exec_()
306 status = dia.normalExit() 317 status = dia.normalExit()
307 318
308 shutil.rmtree(tmpDir, True) 319 shutil.rmtree(tmpDir, True)
309 return status, False 320 return status, False
310 321
311 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False): 322 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False):
312 """ 323 """
313 Public method used to check the project out of the Subversion repository. 324 Public method used to check the project out of the Subversion
325 repository.
314 326
315 @param vcsDataDict dictionary of data required for the checkout 327 @param vcsDataDict dictionary of data required for the checkout
316 @param projectDir project directory to create (string) 328 @param projectDir project directory to create (string)
317 @param noDialog flag indicating quiet operations 329 @param noDialog flag indicating quiet operations
318 @return flag indicating an execution without errors (boolean) 330 @return flag indicating an execution without errors (boolean)
330 342
331 if self.otherData["standardLayout"]: 343 if self.otherData["standardLayout"]:
332 if tag is None or tag == '': 344 if tag is None or tag == '':
333 svnUrl = '{0}/trunk'.format(vcsDir) 345 svnUrl = '{0}/trunk'.format(vcsDir)
334 else: 346 else:
335 if not tag.startswith('tags') and not tag.startswith('branches'): 347 if not tag.startswith('tags') and \
348 not tag.startswith('branches'):
336 type, ok = QInputDialog.getItem( 349 type, ok = QInputDialog.getItem(
337 None, 350 None,
338 self.trUtf8("Subversion Checkout"), 351 self.trUtf8("Subversion Checkout"),
339 self.trUtf8("The tag must be a normal tag (tags) or" 352 self.trUtf8("The tag must be a normal tag (tags) or"
340 " a branch tag (branches)." 353 " a branch tag (branches)."
356 args.append(projectDir) 369 args.append(projectDir)
357 370
358 if noDialog: 371 if noDialog:
359 return self.startSynchronizedProcess(QProcess(), 'svn', args) 372 return self.startSynchronizedProcess(QProcess(), 'svn', args)
360 else: 373 else:
361 dia = SvnDialog(self.trUtf8('Checking project out of Subversion repository')) 374 dia = SvnDialog(
375 self.trUtf8('Checking project out of Subversion repository'))
362 res = dia.startProcess(args) 376 res = dia.startProcess(args)
363 if res: 377 if res:
364 dia.exec_() 378 dia.exec_()
365 return dia.normalExit() 379 return dia.normalExit()
366 380
367 def vcsExport(self, vcsDataDict, projectDir): 381 def vcsExport(self, vcsDataDict, projectDir):
368 """ 382 """
369 Public method used to export a directory from the Subversion repository. 383 Public method used to export a directory from the Subversion
384 repository.
370 385
371 @param vcsDataDict dictionary of data required for the checkout 386 @param vcsDataDict dictionary of data required for the checkout
372 @param projectDir project directory to create (string) 387 @param projectDir project directory to create (string)
373 @return flag indicating an execution without errors (boolean) 388 @return flag indicating an execution without errors (boolean)
374 """ 389 """
382 397
383 if self.otherData["standardLayout"]: 398 if self.otherData["standardLayout"]:
384 if tag is None or tag == '': 399 if tag is None or tag == '':
385 svnUrl = '{0}/trunk'.format(vcsDir) 400 svnUrl = '{0}/trunk'.format(vcsDir)
386 else: 401 else:
387 if not tag.startswith('tags') and not tag.startswith('branches'): 402 if not tag.startswith('tags') and \
403 not tag.startswith('branches'):
388 type, ok = QInputDialog.getItem( 404 type, ok = QInputDialog.getItem(
389 None, 405 None,
390 self.trUtf8("Subversion Export"), 406 self.trUtf8("Subversion Export"),
391 self.trUtf8("The tag must be a normal tag (tags) or" 407 self.trUtf8("The tag must be a normal tag (tags) or"
392 " a branch tag (branches)." 408 " a branch tag (branches)."
405 self.addArguments(args, self.options['global']) 421 self.addArguments(args, self.options['global'])
406 args.append("--force") 422 args.append("--force")
407 args.append(self.__svnURL(svnUrl)) 423 args.append(self.__svnURL(svnUrl))
408 args.append(projectDir) 424 args.append(projectDir)
409 425
410 dia = SvnDialog(self.trUtf8('Exporting project from Subversion repository')) 426 dia = SvnDialog(
427 self.trUtf8('Exporting project from Subversion repository'))
411 res = dia.startProcess(args) 428 res = dia.startProcess(args)
412 if res: 429 if res:
413 dia.exec_() 430 dia.exec_()
414 return dia.normalExit() 431 return dia.normalExit()
415 432
416 def vcsCommit(self, name, message, noDialog=False): 433 def vcsCommit(self, name, message, noDialog=False):
417 """ 434 """
418 Public method used to make the change of a file/directory permanent in the 435 Public method used to make the change of a file/directory permanent
419 Subversion repository. 436 in the Subversion repository.
420 437
421 @param name file/directory name to be committed (string or list of strings) 438 @param name file/directory name to be committed (string or list of
439 strings)
422 @param message message for this operation (string) 440 @param message message for this operation (string)
423 @param noDialog flag indicating quiet operations 441 @param noDialog flag indicating quiet operations
424 """ 442 """
425 msg = message 443 msg = message
426 444
459 for nam in nameList: 477 for nam in nameList:
460 # check for commit of the project 478 # check for commit of the project
461 if os.path.isdir(nam): 479 if os.path.isdir(nam):
462 project = e5App().getObject("Project") 480 project = e5App().getObject("Project")
463 if nam == project.getProjectPath(): 481 if nam == project.getProjectPath():
464 ok &= project.checkAllScriptsDirty(reportSyntaxErrors=True) and \ 482 ok &= project.checkAllScriptsDirty(
465 project.checkDirty() 483 reportSyntaxErrors=True) and \
484 project.checkDirty()
466 continue 485 continue
467 elif os.path.isfile(nam): 486 elif os.path.isfile(nam):
468 editor = e5App().getObject("ViewManager").getOpenEditor(nam) 487 editor = e5App().getObject("ViewManager")\
488 .getOpenEditor(nam)
469 if editor: 489 if editor:
470 ok &= editor.checkDirty() 490 ok &= editor.checkDirty()
471 if not ok: 491 if not ok:
472 break 492 break
473 493
474 if not ok: 494 if not ok:
475 res = E5MessageBox.yesNo(self.__ui, 495 res = E5MessageBox.yesNo(self.__ui,
476 self.trUtf8("Commit Changes"), 496 self.trUtf8("Commit Changes"),
477 self.trUtf8("""The commit affects files, that have unsaved""" 497 self.trUtf8(
478 """ changes. Shall the commit be continued?"""), 498 """The commit affects files, that have unsaved"""
499 """ changes. Shall the commit be continued?"""),
479 icon=E5MessageBox.Warning) 500 icon=E5MessageBox.Warning)
480 if not res: 501 if not res:
481 return 502 return
482 503
483 if self.__commitDialog is not None: 504 if self.__commitDialog is not None:
484 msg = self.__commitDialog.logMessage() 505 msg = self.__commitDialog.logMessage()
485 if self.__commitDialog.hasChangelists(): 506 if self.__commitDialog.hasChangelists():
486 changelists, keepChangelists = self.__commitDialog.changelistsData() 507 changelists, keepChangelists = \
508 self.__commitDialog.changelistsData()
487 else: 509 else:
488 changelists, keepChangelists = [], False 510 changelists, keepChangelists = [], False
489 ## self.__commitDialog.accepted.disconnect(self.__vcsCommit_Step2)
490 self.__commitDialog.deleteLater() 511 self.__commitDialog.deleteLater()
491 self.__commitDialog = None 512 self.__commitDialog = None
492 else: 513 else:
493 changelists, keepChangelists = [], False 514 changelists, keepChangelists = [], False
494 515
518 noDialog = False 539 noDialog = False
519 540
520 if noDialog: 541 if noDialog:
521 self.startSynchronizedProcess(QProcess(), "svn", args, dname) 542 self.startSynchronizedProcess(QProcess(), "svn", args, dname)
522 else: 543 else:
523 dia = SvnDialog(self.trUtf8('Commiting changes to Subversion repository')) 544 dia = SvnDialog(
545 self.trUtf8('Commiting changes to Subversion repository'))
524 res = dia.startProcess(args, dname) 546 res = dia.startProcess(args, dname)
525 if res: 547 if res:
526 dia.exec_() 548 dia.exec_()
527 self.committed.emit() 549 self.committed.emit()
528 self.checkVCSStatus() 550 self.checkVCSStatus()
529 551
530 def vcsUpdate(self, name, noDialog=False): 552 def vcsUpdate(self, name, noDialog=False):
531 """ 553 """
532 Public method used to update a file/directory with the Subversion repository. 554 Public method used to update a file/directory with the Subversion
533 555 repository.
534 @param name file/directory name to be updated (string or list of strings) 556
557 @param name file/directory name to be updated (string or list of
558 strings)
535 @param noDialog flag indicating quiet operations (boolean) 559 @param noDialog flag indicating quiet operations (boolean)
536 @return flag indicating, that the update contained an add 560 @return flag indicating, that the update contained an add
537 or delete (boolean) 561 or delete (boolean)
538 """ 562 """
539 args = [] 563 args = []
552 576
553 if noDialog: 577 if noDialog:
554 self.startSynchronizedProcess(QProcess(), "svn", args, dname) 578 self.startSynchronizedProcess(QProcess(), "svn", args, dname)
555 res = False 579 res = False
556 else: 580 else:
557 dia = SvnDialog(self.trUtf8('Synchronizing with the Subversion repository')) 581 dia = SvnDialog(
582 self.trUtf8('Synchronizing with the Subversion repository'))
558 res = dia.startProcess(args, dname, True) 583 res = dia.startProcess(args, dname, True)
559 if res: 584 if res:
560 dia.exec_() 585 dia.exec_()
561 res = dia.hasAddOrDelete() 586 res = dia.hasAddOrDelete()
562 self.checkVCSStatus() 587 self.checkVCSStatus()
563 return res 588 return res
564 589
565 def vcsAdd(self, name, isDir=False, noDialog=False): 590 def vcsAdd(self, name, isDir=False, noDialog=False):
566 """ 591 """
567 Public method used to add a file/directory to the Subversion repository. 592 Public method used to add a file/directory to the Subversion
593 repository.
568 594
569 @param name file/directory name to be added (string) 595 @param name file/directory name to be added (string)
570 @param isDir flag indicating name is a directory (boolean) 596 @param isDir flag indicating name is a directory (boolean)
571 @param noDialog flag indicating quiet operations 597 @param noDialog flag indicating quiet operations
572 """ 598 """
595 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 621 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
596 repodir = os.path.dirname(repodir) 622 repodir = os.path.dirname(repodir)
597 if os.path.splitdrive(repodir)[1] == os.sep: 623 if os.path.splitdrive(repodir)[1] == os.sep:
598 return # oops, project is not version controlled 624 return # oops, project is not version controlled
599 while os.path.normcase(dname) != os.path.normcase(repodir) and \ 625 while os.path.normcase(dname) != os.path.normcase(repodir) and \
600 (os.path.normcase(dname) not in self.statusCache or \ 626 (os.path.normcase(dname) not in self.statusCache or \
601 self.statusCache[os.path.normcase(dname)] == self.canBeAdded): 627 self.statusCache[os.path.normcase(dname)] ==
602 # add directories recursively, if they aren't in the repository already 628 self.canBeAdded):
629 # add directories recursively, if they aren't in the
630 # repository already
603 tree.insert(-1, dname) 631 tree.insert(-1, dname)
604 dname = os.path.dirname(dname) 632 dname = os.path.dirname(dname)
605 wdir = dname 633 wdir = dname
606 else: 634 else:
607 while not os.path.exists(os.path.join(dname, self.adminDir)): 635 while not os.path.exists(os.path.join(dname, self.adminDir)):
608 # add directories recursively, if they aren't in the repository already 636 # add directories recursively, if they aren't in the
637 # repository already
609 tree.insert(-1, dname) 638 tree.insert(-1, dname)
610 dname = os.path.dirname(dname) 639 dname = os.path.dirname(dname)
611 wdir = dname 640 wdir = dname
612 self.addArguments(args, tree) 641 self.addArguments(args, tree)
613 642
615 tree2 = [] 644 tree2 = []
616 for n in name: 645 for n in name:
617 d = os.path.dirname(n) 646 d = os.path.dirname(n)
618 if self.__wcng: 647 if self.__wcng:
619 repodir = d 648 repodir = d
620 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 649 while not os.path.isdir(
650 os.path.join(repodir, self.adminDir)):
621 repodir = os.path.dirname(repodir) 651 repodir = os.path.dirname(repodir)
622 if os.path.splitdrive(repodir)[1] == os.sep: 652 if os.path.splitdrive(repodir)[1] == os.sep:
623 return # oops, project is not version controlled 653 return # oops, project is not version controlled
624 while os.path.normcase(d) != os.path.normcase(repodir) and \ 654 while os.path.normcase(d) != \
625 (d not in tree2 + tree) and \ 655 os.path.normcase(repodir) and \
626 (os.path.normcase(d) not in self.statusCache or \ 656 (d not in tree2 + tree) and \
627 self.statusCache[os.path.normcase(d)] == self.canBeAdded): 657 (os.path.normcase(d) not in self.statusCache or \
658 self.statusCache[os.path.normcase(d)] == \
659 self.canBeAdded):
628 tree2.append(d) 660 tree2.append(d)
629 d = os.path.dirname(d) 661 d = os.path.dirname(d)
630 else: 662 else:
631 while not os.path.exists(os.path.join(d, self.adminDir)): 663 while not os.path.exists(os.path.join(d, self.adminDir)):
632 if d in tree2 + tree: 664 if d in tree2 + tree:
641 673
642 if noDialog: 674 if noDialog:
643 self.startSynchronizedProcess(QProcess(), "svn", args, wdir) 675 self.startSynchronizedProcess(QProcess(), "svn", args, wdir)
644 else: 676 else:
645 dia = SvnDialog( 677 dia = SvnDialog(
646 self.trUtf8('Adding files/directories to the Subversion repository')) 678 self.trUtf8('Adding files/directories to the Subversion'
679 ' repository'))
647 res = dia.startProcess(args, wdir) 680 res = dia.startProcess(args, wdir)
648 if res: 681 if res:
649 dia.exec_() 682 dia.exec_()
650 683
651 def vcsAddBinary(self, name, isDir=False): 684 def vcsAddBinary(self, name, isDir=False):
658 """ 691 """
659 self.vcsAdd(name, isDir) 692 self.vcsAdd(name, isDir)
660 693
661 def vcsAddTree(self, path): 694 def vcsAddTree(self, path):
662 """ 695 """
663 Public method to add a directory tree rooted at path to the Subversion repository. 696 Public method to add a directory tree rooted at path to the Subversion
664 697 repository.
665 @param path root directory of the tree to be added (string or list of strings)) 698
699 @param path root directory of the tree to be added (string or list of
700 strings))
666 """ 701 """
667 args = [] 702 args = []
668 args.append('add') 703 args.append('add')
669 self.addArguments(args, self.options['global']) 704 self.addArguments(args, self.options['global'])
670 self.addArguments(args, self.options['add']) 705 self.addArguments(args, self.options['add'])
674 dname, fnames = self.splitPathList(path) 709 dname, fnames = self.splitPathList(path)
675 for n in path: 710 for n in path:
676 d = os.path.dirname(n) 711 d = os.path.dirname(n)
677 if self.__wcng: 712 if self.__wcng:
678 repodir = d 713 repodir = d
679 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 714 while not os.path.isdir(
715 os.path.join(repodir, self.adminDir)):
680 repodir = os.path.dirname(repodir) 716 repodir = os.path.dirname(repodir)
681 if os.path.splitdrive(repodir)[1] == os.sep: 717 if os.path.splitdrive(repodir)[1] == os.sep:
682 return # oops, project is not version controlled 718 return # oops, project is not version controlled
683 while os.path.normcase(d) != os.path.normcase(repodir) and \ 719 while os.path.normcase(d) != \
684 (d not in tree) and \ 720 os.path.normcase(repodir) and \
685 (os.path.normcase(d) not in self.statusCache or \ 721 (d not in tree) and \
686 self.statusCache[os.path.normcase(d)] == self.canBeAdded): 722 (os.path.normcase(d) not in self.statusCache or \
723 self.statusCache[os.path.normcase(d)] == \
724 self.canBeAdded):
687 tree.append(d) 725 tree.append(d)
688 d = os.path.dirname(d) 726 d = os.path.dirname(d)
689 else: 727 else:
690 while not os.path.exists(os.path.join(d, self.adminDir)): 728 while not os.path.exists(os.path.join(d, self.adminDir)):
691 # add directories recursively, 729 # add directories recursively,
701 repodir = dname 739 repodir = dname
702 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 740 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
703 repodir = os.path.dirname(repodir) 741 repodir = os.path.dirname(repodir)
704 if os.path.splitdrive(repodir)[1] == os.sep: 742 if os.path.splitdrive(repodir)[1] == os.sep:
705 return # oops, project is not version controlled 743 return # oops, project is not version controlled
706 while os.path.normcase(dname) != os.path.normcase(repodir) and \ 744 while os.path.normcase(dname) != \
707 (os.path.normcase(dname) not in self.statusCache or \ 745 os.path.normcase(repodir) and \
708 self.statusCache[os.path.normcase(dname)] == self.canBeAdded): 746 (os.path.normcase(dname) not in self.statusCache or \
709 # add directories recursively, if they aren't in the repository already 747 self.statusCache[os.path.normcase(dname)] == \
748 self.canBeAdded):
749 # add directories recursively, if they aren't in the
750 # repository already
710 tree.insert(-1, dname) 751 tree.insert(-1, dname)
711 dname = os.path.dirname(dname) 752 dname = os.path.dirname(dname)
712 else: 753 else:
713 while not os.path.exists(os.path.join(dname, self.adminDir)): 754 while not os.path.exists(os.path.join(dname, self.adminDir)):
714 # add directories recursively, 755 # add directories recursively,
729 if res: 770 if res:
730 dia.exec_() 771 dia.exec_()
731 772
732 def vcsRemove(self, name, project=False, noDialog=False): 773 def vcsRemove(self, name, project=False, noDialog=False):
733 """ 774 """
734 Public method used to remove a file/directory from the Subversion repository. 775 Public method used to remove a file/directory from the Subversion
776 repository.
735 777
736 The default operation is to remove the local copy as well. 778 The default operation is to remove the local copy as well.
737 779
738 @param name file/directory name to be removed (string or list of strings)) 780 @param name file/directory name to be removed (string or list of
739 @param project flag indicating deletion of a project tree (boolean) (not needed) 781 strings))
782 @param project flag indicating deletion of a project tree (boolean)
783 (not needed)
740 @param noDialog flag indicating quiet operations 784 @param noDialog flag indicating quiet operations
741 @return flag indicating successfull operation (boolean) 785 @return flag indicating successfull operation (boolean)
742 """ 786 """
743 args = [] 787 args = []
744 args.append('delete') 788 args.append('delete')
754 798
755 if noDialog: 799 if noDialog:
756 res = self.startSynchronizedProcess(QProcess(), "svn", args) 800 res = self.startSynchronizedProcess(QProcess(), "svn", args)
757 else: 801 else:
758 dia = SvnDialog( 802 dia = SvnDialog(
759 self.trUtf8('Removing files/directories from the Subversion repository')) 803 self.trUtf8('Removing files/directories from the Subversion'
804 ' repository'))
760 res = dia.startProcess(args) 805 res = dia.startProcess(args)
761 if res: 806 if res:
762 dia.exec_() 807 dia.exec_()
763 res = dia.normalExit() 808 res = dia.normalExit()
764 809
856 """ 901 """
857 Public method used to view the difference of a file/directory to the 902 Public method used to view the difference of a file/directory to the
858 Subversion repository. 903 Subversion repository.
859 904
860 If name is a directory and is the project directory, all project files 905 If name is a directory and is the project directory, all project files
861 are saved first. If name is a file (or list of files), which is/are being edited 906 are saved first. If name is a file (or list of files), which is/are
862 and has unsaved modification, they can be saved or the operation may be aborted. 907 being edited and has unsaved modification, they can be saved or the
908 operation may be aborted.
863 909
864 @param name file/directory name to be diffed (string) 910 @param name file/directory name to be diffed (string)
865 """ 911 """
866 if isinstance(name, list): 912 if isinstance(name, list):
867 names = name[:] 913 names = name[:]
906 952
907 reposURL = self.svnGetReposName(dname) 953 reposURL = self.svnGetReposName(dname)
908 if reposURL is None: 954 if reposURL is None:
909 E5MessageBox.critical(self.__ui, 955 E5MessageBox.critical(self.__ui,
910 self.trUtf8("Subversion Error"), 956 self.trUtf8("Subversion Error"),
911 self.trUtf8("""The URL of the project repository could not be""" 957 self.trUtf8(
912 """ retrieved from the working copy. The tag operation will""" 958 """The URL of the project repository could not be"""
913 """ be aborted""")) 959 """ retrieved from the working copy. The tag operation"""
960 """ will be aborted"""))
914 return 961 return
915 962
916 if self.otherData["standardLayout"]: 963 if self.otherData["standardLayout"]:
917 url = None 964 url = None
918 else: 965 else:
940 987
941 reposRoot = rx_base.cap(1) 988 reposRoot = rx_base.cap(1)
942 if tagOp in [1, 4]: 989 if tagOp in [1, 4]:
943 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag)) 990 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag))
944 elif tagOp in [2, 8]: 991 elif tagOp in [2, 8]:
945 url = '{0}/branches/{1}'.format(reposRoot, urllib.parse.quote(tag)) 992 url = '{0}/branches/{1}'.format(
993 reposRoot, urllib.parse.quote(tag))
946 else: 994 else:
947 url = self.__svnURL(tag) 995 url = self.__svnURL(tag)
948 996
949 args = [] 997 args = []
950 if tagOp in [1, 2]: 998 if tagOp in [1, 2]:
988 names = [name] 1036 names = [name]
989 1037
990 project = e5App().getObject("Project") 1038 project = e5App().getObject("Project")
991 names = [project.getRelativePath(nam) for nam in names] 1039 names = [project.getRelativePath(nam) for nam in names]
992 if names[0]: 1040 if names[0]:
993 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog 1041 from UI.DeleteFilesConfirmationDialog import \
1042 DeleteFilesConfirmationDialog
994 dlg = DeleteFilesConfirmationDialog(self.parent(), 1043 dlg = DeleteFilesConfirmationDialog(self.parent(),
995 self.trUtf8("Revert changes"), 1044 self.trUtf8("Revert changes"),
996 self.trUtf8("Do you really want to revert all changes to these files" 1045 self.trUtf8("Do you really want to revert all changes to"
997 " or directories?"), 1046 " these files or directories?"),
998 names) 1047 names)
999 yes = dlg.exec_() == QDialog.Accepted 1048 yes = dlg.exec_() == QDialog.Accepted
1000 else: 1049 else:
1001 yes = E5MessageBox.yesNo(None, 1050 yes = E5MessageBox.yesNo(None,
1002 self.trUtf8("Revert changes"), 1051 self.trUtf8("Revert changes"),
1012 def vcsSwitch(self, name): 1061 def vcsSwitch(self, name):
1013 """ 1062 """
1014 Public method used to switch a directory to a different tag/branch. 1063 Public method used to switch a directory to a different tag/branch.
1015 1064
1016 @param name directory name to be switched (string) 1065 @param name directory name to be switched (string)
1066 @return flag indicating added or changed files (boolean)
1017 """ 1067 """
1018 dname, fname = self.splitPath(name) 1068 dname, fname = self.splitPath(name)
1019 1069
1020 reposURL = self.svnGetReposName(dname) 1070 reposURL = self.svnGetReposName(dname)
1021 if reposURL is None: 1071 if reposURL is None:
1022 E5MessageBox.critical(self.__ui, 1072 E5MessageBox.critical(self.__ui,
1023 self.trUtf8("Subversion Error"), 1073 self.trUtf8("Subversion Error"),
1024 self.trUtf8("""The URL of the project repository could not be""" 1074 self.trUtf8(
1025 """ retrieved from the working copy. The switch operation will""" 1075 """The URL of the project repository could not be"""
1026 """ be aborted""")) 1076 """ retrieved from the working copy. The switch"""
1077 """ operation will be aborted"""))
1027 return False 1078 return False
1028 1079
1029 if self.otherData["standardLayout"]: 1080 if self.otherData["standardLayout"]:
1030 url = None 1081 url = None
1031 else: 1082 else:
1054 reposRoot = rx_base.cap(1) 1105 reposRoot = rx_base.cap(1)
1055 tn = tag 1106 tn = tag
1056 if tagType == 1: 1107 if tagType == 1:
1057 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1108 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag))
1058 elif tagType == 2: 1109 elif tagType == 2:
1059 url = '{0}/branches/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1110 url = '{0}/branches/{1}'.format(
1111 reposRoot, urllib.parse.quote(tag))
1060 elif tagType == 4: 1112 elif tagType == 4:
1061 url = '{0}/trunk'.format(reposRoot) 1113 url = '{0}/trunk'.format(reposRoot)
1062 tn = 'HEAD' 1114 tn = 'HEAD'
1063 else: 1115 else:
1064 url = self.__svnURL(tag) 1116 url = self.__svnURL(tag)
1093 force = '--force' in opts 1145 force = '--force' in opts
1094 if force: 1146 if force:
1095 del opts[opts.index('--force')] 1147 del opts[opts.index('--force')]
1096 1148
1097 from .SvnMergeDialog import SvnMergeDialog 1149 from .SvnMergeDialog import SvnMergeDialog
1098 dlg = SvnMergeDialog(self.mergeList[0], self.mergeList[1], self.mergeList[2], 1150 dlg = SvnMergeDialog(
1099 force) 1151 self.mergeList[0], self.mergeList[1], self.mergeList[2], force)
1100 if dlg.exec_() == QDialog.Accepted: 1152 if dlg.exec_() == QDialog.Accepted:
1101 urlrev1, urlrev2, target, force = dlg.getParameters() 1153 urlrev1, urlrev2, target, force = dlg.getParameters()
1102 else: 1154 else:
1103 return 1155 return
1104 1156
1156 1208
1157 def __vcsRegisteredState_wcng(self, name): 1209 def __vcsRegisteredState_wcng(self, name):
1158 """ 1210 """
1159 Private method used to get the registered state of a file in the vcs. 1211 Private method used to get the registered state of a file in the vcs.
1160 1212
1161 This is the variant for subversion installations using the new working copy 1213 This is the variant for subversion installations using the new
1162 meta-data format. 1214 working copy meta-data format.
1163 1215
1164 @param name filename to check (string) 1216 @param name filename to check (string)
1165 @return a combination of canBeCommited and canBeAdded 1217 @return a combination of canBeCommited and canBeAdded
1166 """ 1218 """
1167 if name.endswith(os.sep): 1219 if name.endswith(os.sep):
1183 else: 1235 else:
1184 return self.canBeAdded 1236 return self.canBeAdded
1185 1237
1186 def __vcsRegisteredState_wc(self, name): 1238 def __vcsRegisteredState_wc(self, name):
1187 """ 1239 """
1188 Private method used to get the registered state of a file in the vcs. 1240 Private method used to get the registered state of a file in the VCS.
1189 1241
1190 This is the variant for subversion installations using the old working copy 1242 This is the variant for subversion installations using the old working
1191 meta-data format. 1243 copy meta-data format.
1192 1244
1193 @param name filename to check (string) 1245 @param name filename to check (string)
1194 @return a combination of canBeCommited and canBeAdded 1246 @return a combination of canBeCommited and canBeAdded
1195 """ 1247 """
1196 dname, fname = self.splitPath(name) 1248 dname, fname = self.splitPath(name)
1209 else: 1261 else:
1210 return self.canBeAdded 1262 return self.canBeAdded
1211 1263
1212 def vcsAllRegisteredStates(self, names, dname, shortcut=True): 1264 def vcsAllRegisteredStates(self, names, dname, shortcut=True):
1213 """ 1265 """
1214 Public method used to get the registered states of a number of files in the vcs. 1266 Public method used to get the registered states of a number of files
1215 1267 in the VCS.
1216 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1268
1217 directory has been scanned already. If so, it is assumed, that the states for 1269 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1218 all files have been populated by the previous run. 1270 if the named directory has been scanned already. If so, it is assumed,
1271 that the states for all files have been populated by the previous run.
1219 1272
1220 @param names dictionary with all filenames to be checked as keys 1273 @param names dictionary with all filenames to be checked as keys
1221 @param dname directory to check in (string) 1274 @param dname directory to check in (string)
1222 @param shortcut flag indicating a shortcut should be taken (boolean) 1275 @param shortcut flag indicating a shortcut should be taken (boolean)
1223 @return the received dictionary completed with a combination of 1276 @return the received dictionary completed with a combination of
1228 else: 1281 else:
1229 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut) 1282 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut)
1230 1283
1231 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True): 1284 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True):
1232 """ 1285 """
1233 Private method used to get the registered states of a number of files in the vcs. 1286 Private method used to get the registered states of a number of files
1234 1287 in the VCS.
1235 This is the variant for subversion installations using the new working copy 1288
1236 meta-data format. 1289 This is the variant for subversion installations using the new working
1237 1290 copy meta-data format.
1238 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1291
1239 directory has been scanned already. If so, it is assumed, that the states for 1292 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1240 all files has been populated by the previous run. 1293 if the named directory has been scanned already. If so, it is assumed,
1294 that the states for all files has been populated by the previous run.
1241 1295
1242 @param names dictionary with all filenames to be checked as keys 1296 @param names dictionary with all filenames to be checked as keys
1243 @param dname directory to check in (string) 1297 @param dname directory to check in (string)
1244 @param shortcut flag indicating a shortcut should be taken (boolean) 1298 @param shortcut flag indicating a shortcut should be taken (boolean)
1245 @return the received dictionary completed with a combination of 1299 @return the received dictionary completed with a combination of
1273 process.start('svn', args) 1327 process.start('svn', args)
1274 procStarted = process.waitForStarted(5000) 1328 procStarted = process.waitForStarted(5000)
1275 if procStarted: 1329 if procStarted:
1276 finished = process.waitForFinished(30000) 1330 finished = process.waitForFinished(30000)
1277 if finished and process.exitCode() == 0: 1331 if finished and process.exitCode() == 0:
1278 output = \ 1332 output = str(process.readAllStandardOutput(), ioEncoding,
1279 str(process.readAllStandardOutput(), ioEncoding, 'replace') 1333 'replace')
1280 for line in output.splitlines(): 1334 for line in output.splitlines():
1281 if self.rx_status1.exactMatch(line): 1335 if self.rx_status1.exactMatch(line):
1282 flags = str(self.rx_status1.cap(1)) 1336 flags = str(self.rx_status1.cap(1))
1283 path = self.rx_status1.cap(5).strip() 1337 path = self.rx_status1.cap(5).strip()
1284 elif self.rx_status2.exactMatch(line): 1338 elif self.rx_status2.exactMatch(line):
1296 1350
1297 return names 1351 return names
1298 1352
1299 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True): 1353 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True):
1300 """ 1354 """
1301 Private method used to get the registered states of a number of files in the vcs. 1355 Private method used to get the registered states of a number of files
1302 1356 in the VCS.
1303 This is the variant for subversion installations using the old working copy 1357
1304 meta-data format. 1358 This is the variant for subversion installations using the old working
1305 1359 copy meta-data format.
1306 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1360
1307 directory has been scanned already. If so, it is assumed, that the states for 1361 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1308 all files has been populated by the previous run. 1362 if the named directory has been scanned already. If so, it is assumed,
1363 that the states for all files has been populated by the previous run.
1309 1364
1310 @param names dictionary with all filenames to be checked as keys 1365 @param names dictionary with all filenames to be checked as keys
1311 @param dname directory to check in (string) 1366 @param dname directory to check in (string)
1312 @param shortcut flag indicating a shortcut should be taken (boolean) 1367 @param shortcut flag indicating a shortcut should be taken (boolean)
1313 @return the received dictionary completed with a combination of 1368 @return the received dictionary completed with a combination of
1338 process.start('svn', args) 1393 process.start('svn', args)
1339 procStarted = process.waitForStarted(5000) 1394 procStarted = process.waitForStarted(5000)
1340 if procStarted: 1395 if procStarted:
1341 finished = process.waitForFinished(30000) 1396 finished = process.waitForFinished(30000)
1342 if finished and process.exitCode() == 0: 1397 if finished and process.exitCode() == 0:
1343 output = \ 1398 output = str(process.readAllStandardOutput(), ioEncoding,
1344 str(process.readAllStandardOutput(), ioEncoding, 'replace') 1399 'replace')
1345 for line in output.splitlines(): 1400 for line in output.splitlines():
1346 if self.rx_status1.exactMatch(line): 1401 if self.rx_status1.exactMatch(line):
1347 flags = self.rx_status1.cap(1) 1402 flags = self.rx_status1.cap(1)
1348 path = self.rx_status1.cap(5).strip() 1403 path = self.rx_status1.cap(5).strip()
1349 elif self.rx_status2.exactMatch(line): 1404 elif self.rx_status2.exactMatch(line):
1439 """ 1494 """
1440 Public method to get a dialog to enter repository info. 1495 Public method to get a dialog to enter repository info.
1441 1496
1442 @param project reference to the project object 1497 @param project reference to the project object
1443 @param archive name of the project in the repository (string) 1498 @param archive name of the project in the repository (string)
1444 @param editable flag indicating that the project name is editable (boolean) 1499 @param editable flag indicating that the project name is editable
1500 (boolean)
1445 @param parent parent widget (QWidget) 1501 @param parent parent widget (QWidget)
1502 @return reference to the instantiated options dialog (SvnOptionsDialog)
1446 """ 1503 """
1447 from .SvnOptionsDialog import SvnOptionsDialog 1504 from .SvnOptionsDialog import SvnOptionsDialog
1448 return SvnOptionsDialog(self, project, parent) 1505 return SvnOptionsDialog(self, project, parent)
1449 1506
1450 def vcsNewProjectOptionsDialog(self, parent=None): 1507 def vcsNewProjectOptionsDialog(self, parent=None):
1451 """ 1508 """
1452 Public method to get a dialog to enter repository info for getting a new project. 1509 Public method to get a dialog to enter repository info for getting
1510 a new project.
1453 1511
1454 @param parent parent widget (QWidget) 1512 @param parent parent widget (QWidget)
1513 @return reference to the instantiated options dialog
1514 (SvnNewProjectOptionsDialog)
1455 """ 1515 """
1456 from .SvnNewProjectOptionsDialog import SvnNewProjectOptionsDialog 1516 from .SvnNewProjectOptionsDialog import SvnNewProjectOptionsDialog
1457 return SvnNewProjectOptionsDialog(self, parent) 1517 return SvnNewProjectOptionsDialog(self, parent)
1458 1518
1459 def vcsRepositoryInfos(self, ppath): 1519 def vcsRepositoryInfos(self, ppath):
1483 process.start('svn', args) 1543 process.start('svn', args)
1484 procStarted = process.waitForStarted(5000) 1544 procStarted = process.waitForStarted(5000)
1485 if procStarted: 1545 if procStarted:
1486 finished = process.waitForFinished(30000) 1546 finished = process.waitForFinished(30000)
1487 if finished and process.exitCode() == 0: 1547 if finished and process.exitCode() == 0:
1488 output = str(process.readAllStandardOutput(), ioEncoding, 'replace') 1548 output = str(process.readAllStandardOutput(), ioEncoding,
1549 'replace')
1489 entryFound = False 1550 entryFound = False
1490 commitFound = False 1551 commitFound = False
1491 for line in output.splitlines(): 1552 for line in output.splitlines():
1492 line = line.strip() 1553 line = line.strip()
1493 if line.startswith('<entry'): 1554 if line.startswith('<entry'):
1505 info['committed-rev'] = rev 1566 info['committed-rev'] = rev
1506 elif line.startswith('<url>'): 1567 elif line.startswith('<url>'):
1507 info['url'] = \ 1568 info['url'] = \
1508 line.replace('<url>', '').replace('</url>', '') 1569 line.replace('<url>', '').replace('</url>', '')
1509 elif line.startswith('<author>'): 1570 elif line.startswith('<author>'):
1510 info['last-author'] = \ 1571 info['last-author'] = line.replace('<author>', '')\
1511 line.replace('<author>', '').replace('</author>', '') 1572 .replace('</author>', '')
1512 elif line.startswith('<date>'): 1573 elif line.startswith('<date>'):
1513 value = line.replace('<date>', '').replace('</date>', '') 1574 value = line.replace('<date>', '')\
1575 .replace('</date>', '')
1514 date, time = value.split('T') 1576 date, time = value.split('T')
1515 info['committed-date'] = date 1577 info['committed-date'] = date
1516 info['committed-time'] = "{0}{1}".format( 1578 info['committed-time'] = "{0}{1}".format(
1517 time.split('.')[0], time[-1]) 1579 time.split('.')[0], time[-1])
1518 1580
1534 info['committed-rev'], 1596 info['committed-rev'],
1535 info['committed-date'], 1597 info['committed-date'],
1536 info['committed-time'], 1598 info['committed-time'],
1537 info['last-author']) 1599 info['last-author'])
1538 1600
1539 ############################################################################ 1601 ###########################################################################
1540 ## Public Subversion specific methods are below. 1602 ## Public Subversion specific methods are below.
1541 ############################################################################ 1603 ###########################################################################
1542 1604
1543 def svnGetReposName(self, path): 1605 def svnGetReposName(self, path):
1544 """ 1606 """
1545 Public method used to retrieve the URL of the subversion repository path. 1607 Public method used to retrieve the URL of the subversion repository
1608 path.
1546 1609
1547 @param path local path to get the svn repository path for (string) 1610 @param path local path to get the svn repository path for (string)
1548 @return string with the repository path URL 1611 @return string with the repository path URL
1549 """ 1612 """
1550 ioEncoding = Preferences.getSystem("IOEncoding") 1613 ioEncoding = Preferences.getSystem("IOEncoding")
1558 process.start('svn', args) 1621 process.start('svn', args)
1559 procStarted = process.waitForStarted(5000) 1622 procStarted = process.waitForStarted(5000)
1560 if procStarted: 1623 if procStarted:
1561 finished = process.waitForFinished(30000) 1624 finished = process.waitForFinished(30000)
1562 if finished and process.exitCode() == 0: 1625 if finished and process.exitCode() == 0:
1563 output = str(process.readAllStandardOutput(), ioEncoding, 'replace') 1626 output = str(process.readAllStandardOutput(), ioEncoding,
1627 'replace')
1564 for line in output.splitlines(): 1628 for line in output.splitlines():
1565 line = line.strip() 1629 line = line.strip()
1566 if line.startswith('<url>'): 1630 if line.startswith('<url>'):
1567 reposURL = line.replace('<url>', '').replace('</url>', '') 1631 reposURL = line.replace('<url>', '')\
1632 .replace('</url>', '')
1568 return reposURL 1633 return reposURL
1569 1634
1570 return "" 1635 return ""
1571 1636
1572 def svnResolve(self, name): 1637 def svnResolve(self, name):
1660 if dlg.exec_() == QDialog.Accepted: 1725 if dlg.exec_() == QDialog.Accepted:
1661 propName, fileFlag, propValue = dlg.getData() 1726 propName, fileFlag, propValue = dlg.getData()
1662 if not propName: 1727 if not propName:
1663 E5MessageBox.critical(self.__ui, 1728 E5MessageBox.critical(self.__ui,
1664 self.trUtf8("Subversion Set Property"), 1729 self.trUtf8("Subversion Set Property"),
1665 self.trUtf8("""You have to supply a property name. Aborting.""")) 1730 self.trUtf8("""You have to supply a property name."""
1731 """ Aborting."""))
1666 return 1732 return
1667 1733
1668 args = [] 1734 args = []
1669 args.append('propset') 1735 args.append('propset')
1670 self.addArguments(args, self.options['global']) 1736 self.addArguments(args, self.options['global'])
1703 return 1769 return
1704 1770
1705 if not propName: 1771 if not propName:
1706 E5MessageBox.critical(self.__ui, 1772 E5MessageBox.critical(self.__ui,
1707 self.trUtf8("Subversion Delete Property"), 1773 self.trUtf8("Subversion Delete Property"),
1708 self.trUtf8("""You have to supply a property name. Aborting.""")) 1774 self.trUtf8("""You have to supply a property name."""
1775 """ Aborting."""))
1709 return 1776 return
1710 1777
1711 args = [] 1778 args = []
1712 args.append('propdel') 1779 args.append('propdel')
1713 self.addArguments(args, self.options['global']) 1780 self.addArguments(args, self.options['global'])
1751 self.showedBranches = True 1818 self.showedBranches = True
1752 allTagsBranchesList = self.allTagsBranchesList 1819 allTagsBranchesList = self.allTagsBranchesList
1753 else: 1820 else:
1754 self.branchesList = [] 1821 self.branchesList = []
1755 allTagsBranchesList = None 1822 allTagsBranchesList = None
1756 self.tagbranchList.start(path, tags, 1823 self.tagbranchList.start(
1757 self.branchesList, self.allTagsBranchesList) 1824 path, tags, self.branchesList, self.allTagsBranchesList)
1758 1825
1759 def svnBlame(self, name): 1826 def svnBlame(self, name):
1760 """ 1827 """
1761 Public method to show the output of the svn blame command. 1828 Public method to show the output of the svn blame command.
1762 1829
1771 """ 1838 """
1772 Public method used to view the difference of a file/directory to the 1839 Public method used to view the difference of a file/directory to the
1773 Subversion repository. 1840 Subversion repository.
1774 1841
1775 If name is a directory and is the project directory, all project files 1842 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 1843 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. 1844 being edited and has unsaved modification, they can be saved or the
1845 operation may be aborted.
1778 1846
1779 This method gives the chance to enter the revisions to be compared. 1847 This method gives the chance to enter the revisions to be compared.
1780 1848
1781 @param name file/directory name to be diffed (string) 1849 @param name file/directory name to be diffed (string)
1782 """ 1850 """
1806 """ 1874 """
1807 Public method used to view the difference of a file/directory of two 1875 Public method used to view the difference of a file/directory of two
1808 repository URLs. 1876 repository URLs.
1809 1877
1810 If name is a directory and is the project directory, all project files 1878 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 1879 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. 1880 being edited and has unsaved modification, they can be saved or the
1881 operation may be aborted.
1813 1882
1814 This method gives the chance to enter the revisions to be compared. 1883 This method gives the chance to enter the revisions to be compared.
1815 1884
1816 @param name file/directory name to be diffed (string) 1885 @param name file/directory name to be diffed (string)
1817 """ 1886 """
1830 return 1899 return
1831 1900
1832 dname = self.splitPath(names[0])[0] 1901 dname = self.splitPath(names[0])[0]
1833 1902
1834 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog 1903 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog
1835 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList, dname) 1904 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList,
1905 dname)
1836 if dlg.exec_() == QDialog.Accepted: 1906 if dlg.exec_() == QDialog.Accepted:
1837 urls, summary = dlg.getURLs() 1907 urls, summary = dlg.getURLs()
1838 from .SvnDiffDialog import SvnDiffDialog 1908 from .SvnDiffDialog import SvnDiffDialog
1839 self.diff = SvnDiffDialog(self) 1909 self.diff = SvnDiffDialog(self)
1840 self.diff.show() 1910 self.diff.show()
1841 QApplication.processEvents() 1911 QApplication.processEvents()
1842 self.diff.start(name, urls=urls, summary=summary) 1912 self.diff.start(name, urls=urls, summary=summary)
1843 1913
1844 def __svnGetFileForRevision(self, name, rev=""): 1914 def __svnGetFileForRevision(self, name, rev=""):
1845 """ 1915 """
1846 Private method to get a file for a specific revision from the repository. 1916 Private method to get a file for a specific revision from the
1917 repository.
1847 1918
1848 @param name file name to get from the repository (string) 1919 @param name file name to get from the repository (string)
1849 @keyparam rev revision to retrieve (integer or string) 1920 @keyparam rev revision to retrieve (integer or string)
1850 @return contents of the file (string) and an error message (string) 1921 @return contents of the file (string) and an error message (string)
1851 """ 1922 """
1870 Preferences.getSystem("IOEncoding"), 'replace') 1941 Preferences.getSystem("IOEncoding"), 'replace')
1871 else: 1942 else:
1872 error = str(process.readAllStandardError(), 1943 error = str(process.readAllStandardError(),
1873 Preferences.getSystem("IOEncoding"), 'replace') 1944 Preferences.getSystem("IOEncoding"), 'replace')
1874 else: 1945 else:
1875 error = self.trUtf8("The svn process did not finish within 30s.") 1946 error = self.trUtf8(
1947 "The svn process did not finish within 30s.")
1876 else: 1948 else:
1877 error = self.trUtf8('The process {0} could not be started. ' 1949 error = self.trUtf8('The process {0} could not be started. '
1878 'Ensure, that it is in the search path.').format('svn') 1950 'Ensure, that it is in the search path.').format('svn')
1879 1951
1880 return output, error 1952 return output, error
1881 1953
1882 def svnSbsDiff(self, name, extended=False, revisions=None): 1954 def svnSbsDiff(self, name, extended=False, revisions=None):
1883 """ 1955 """
1884 Public method used to view the difference of a file to the Mercurial repository 1956 Public method used to view the difference of a file to the Mercurial
1885 side-by-side. 1957 repository side-by-side.
1886 1958
1887 @param name file name to be diffed (string) 1959 @param name file name to be diffed (string)
1888 @keyparam extended flag indicating the extended variant (boolean) 1960 @keyparam extended flag indicating the extended variant (boolean)
1889 @keyparam revisions tuple of two revisions (tuple of strings) 1961 @keyparam revisions tuple of two revisions (tuple of strings)
1962 @exception ValueError raised to indicate an illegal name parameter type
1890 """ 1963 """
1891 if isinstance(name, list): 1964 if isinstance(name, list):
1892 raise ValueError("Wrong parameter type") 1965 raise ValueError("Wrong parameter type")
1893 1966
1894 if extended: 1967 if extended:
1928 f1.close() 2001 f1.close()
1929 name2 = name 2002 name2 = name
1930 except IOError: 2003 except IOError:
1931 E5MessageBox.critical(self.__ui, 2004 E5MessageBox.critical(self.__ui,
1932 self.trUtf8("Subversion Side-by-Side Difference"), 2005 self.trUtf8("Subversion Side-by-Side Difference"),
1933 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""") 2006 self.trUtf8(
2007 """<p>The file <b>{0}</b> could not be read.</p>""")
1934 .format(name)) 2008 .format(name))
1935 return 2009 return
1936 2010
1937 if self.sbsDiff is None: 2011 if self.sbsDiff is None:
1938 from UI.CompareDialog import CompareDialog 2012 from UI.CompareDialog import CompareDialog
1955 2029
1956 def svnLock(self, name, stealIt=False, parent=None): 2030 def svnLock(self, name, stealIt=False, parent=None):
1957 """ 2031 """
1958 Public method used to lock a file in the Subversion repository. 2032 Public method used to lock a file in the Subversion repository.
1959 2033
1960 @param name file/directory name to be locked (string or list of strings) 2034 @param name file/directory name to be locked (string or list of
2035 strings)
1961 @param stealIt flag indicating a forced operation (boolean) 2036 @param stealIt flag indicating a forced operation (boolean)
1962 @param parent reference to the parent object of the subversion dialog (QWidget) 2037 @param parent reference to the parent object of the subversion dialog
2038 (QWidget)
1963 """ 2039 """
1964 args = [] 2040 args = []
1965 args.append('lock') 2041 args.append('lock')
1966 self.addArguments(args, self.options['global']) 2042 self.addArguments(args, self.options['global'])
1967 if stealIt: 2043 if stealIt:
1971 self.addArguments(args, fnames) 2047 self.addArguments(args, fnames)
1972 else: 2048 else:
1973 dname, fname = self.splitPath(name) 2049 dname, fname = self.splitPath(name)
1974 args.append(fname) 2050 args.append(fname)
1975 2051
1976 dia = SvnDialog(self.trUtf8('Locking in the Subversion repository'), parent) 2052 dia = SvnDialog(
2053 self.trUtf8('Locking in the Subversion repository'), parent)
1977 res = dia.startProcess(args, dname) 2054 res = dia.startProcess(args, dname)
1978 if res: 2055 if res:
1979 dia.exec_() 2056 dia.exec_()
1980 2057
1981 def svnUnlock(self, name, breakIt=False, parent=None): 2058 def svnUnlock(self, name, breakIt=False, parent=None):
1982 """ 2059 """
1983 Public method used to unlock a file in the Subversion repository. 2060 Public method used to unlock a file in the Subversion repository.
1984 2061
1985 @param name file/directory name to be unlocked (string or list of strings) 2062 @param name file/directory name to be unlocked (string or list of
2063 strings)
1986 @param breakIt flag indicating a forced operation (boolean) 2064 @param breakIt flag indicating a forced operation (boolean)
1987 @param parent reference to the parent object of the subversion dialog (QWidget) 2065 @param parent reference to the parent object of the subversion dialog
2066 (QWidget)
1988 """ 2067 """
1989 args = [] 2068 args = []
1990 args.append('unlock') 2069 args.append('unlock')
1991 self.addArguments(args, self.options['global']) 2070 self.addArguments(args, self.options['global'])
1992 if breakIt: 2071 if breakIt:
1996 self.addArguments(args, fnames) 2075 self.addArguments(args, fnames)
1997 else: 2076 else:
1998 dname, fname = self.splitPath(name) 2077 dname, fname = self.splitPath(name)
1999 args.append(fname) 2078 args.append(fname)
2000 2079
2001 dia = SvnDialog(self.trUtf8('Unlocking in the Subversion repository'), parent) 2080 dia = SvnDialog(
2081 self.trUtf8('Unlocking in the Subversion repository'), parent)
2002 res = dia.startProcess(args, dname) 2082 res = dia.startProcess(args, dname)
2003 if res: 2083 if res:
2004 dia.exec_() 2084 dia.exec_()
2005 2085
2006 def svnRelocate(self, projectPath): 2086 def svnRelocate(self, projectPath):
2161 if changelist not in changelists: 2241 if changelist not in changelists:
2162 changelists.append(changelist) 2242 changelists.append(changelist)
2163 2243
2164 return changelists 2244 return changelists
2165 2245
2166 ############################################################################ 2246 ###########################################################################
2167 ## Private Subversion specific methods are below. 2247 ## Private Subversion specific methods are below.
2168 ############################################################################ 2248 ###########################################################################
2169 2249
2170 def __svnURL(self, url): 2250 def __svnURL(self, url):
2171 """ 2251 """
2172 Private method to format a url for subversion. 2252 Private method to format a url for subversion.
2173 2253
2178 url = url.split(':', 2) 2258 url = url.split(':', 2)
2179 if len(url) == 3: 2259 if len(url) == 3:
2180 scheme = url[0] 2260 scheme = url[0]
2181 host = url[1] 2261 host = url[1]
2182 port, path = url[2].split("/", 1) 2262 port, path = url[2].split("/", 1)
2183 return "{0}:{1}:{2}/{3}".format(scheme, host, port, urllib.parse.quote(path)) 2263 return "{0}:{1}:{2}/{3}".format(
2264 scheme, host, port, urllib.parse.quote(path))
2184 else: 2265 else:
2185 scheme = url[0] 2266 scheme = url[0]
2186 if scheme == "file": 2267 if scheme == "file":
2187 return "{0}:{1}".format(scheme, urllib.parse.quote(url[1])) 2268 return "{0}:{1}".format(scheme, urllib.parse.quote(url[1]))
2188 else: 2269 else:
2189 try: 2270 try:
2190 host, path = url[1][2:].split("/", 1) 2271 host, path = url[1][2:].split("/", 1)
2191 except ValueError: 2272 except ValueError:
2192 host = url[1][2:] 2273 host = url[1][2:]
2193 path = "" 2274 path = ""
2194 return "{0}://{1}/{2}".format(scheme, host, urllib.parse.quote(path)) 2275 return "{0}://{1}/{2}".format(
2276 scheme, host, urllib.parse.quote(path))
2195 2277
2196 def svnNormalizeURL(self, url): 2278 def svnNormalizeURL(self, url):
2197 """ 2279 """
2198 Public method to normalize a url for subversion. 2280 Public method to normalize a url for subversion.
2199 2281
2210 url = url[:-1] 2292 url = url[:-1]
2211 if not url.startswith("/") and url[1] in [":", "|"]: 2293 if not url.startswith("/") and url[1] in [":", "|"]:
2212 url = "/{0}".format(url) 2294 url = "/{0}".format(url)
2213 return "{0}://{1}".format(protocol, url) 2295 return "{0}://{1}".format(protocol, url)
2214 2296
2215 ############################################################################ 2297 ###########################################################################
2216 ## Methods to get the helper objects are below. 2298 ## Methods to get the helper objects are below.
2217 ############################################################################ 2299 ###########################################################################
2218 2300
2219 def vcsGetProjectBrowserHelper(self, browser, project, isTranslationsBrowser=False): 2301 def vcsGetProjectBrowserHelper(self, browser, project,
2220 """ 2302 isTranslationsBrowser=False):
2221 Public method to instanciate a helper object for the different project browsers. 2303 """
2304 Public method to instanciate a helper object for the different
2305 project browsers.
2222 2306
2223 @param browser reference to the project browser object 2307 @param browser reference to the project browser object
2224 @param project reference to the project object 2308 @param project reference to the project object
2225 @param isTranslationsBrowser flag indicating, the helper is requested for the 2309 @param isTranslationsBrowser flag indicating, the helper is requested
2226 translations browser (this needs some special treatment) 2310 for the translations browser (this needs some special treatment)
2227 @return the project browser helper object 2311 @return the project browser helper object
2228 """ 2312 """
2229 from .ProjectBrowserHelper import SvnProjectBrowserHelper 2313 from .ProjectBrowserHelper import SvnProjectBrowserHelper
2230 return SvnProjectBrowserHelper(self, browser, project, isTranslationsBrowser) 2314 return SvnProjectBrowserHelper(self, browser, project,
2315 isTranslationsBrowser)
2231 2316
2232 def vcsGetProjectHelper(self, project): 2317 def vcsGetProjectHelper(self, project):
2233 """ 2318 """
2234 Public method to instanciate a helper object for the project. 2319 Public method to instanciate a helper object for the project.
2235 2320
2237 @return the project helper object 2322 @return the project helper object
2238 """ 2323 """
2239 helper = self.__plugin.getProjectHelper() 2324 helper = self.__plugin.getProjectHelper()
2240 helper.setObjects(self, project) 2325 helper.setObjects(self, project)
2241 self.__wcng = \ 2326 self.__wcng = \
2242 os.path.exists(os.path.join(project.getProjectPath(), ".svn", "format")) or \ 2327 os.path.exists(
2243 os.path.exists(os.path.join(project.getProjectPath(), "_svn", "format")) 2328 os.path.join(project.getProjectPath(), ".svn", "format")) or \
2329 os.path.exists(
2330 os.path.join(project.getProjectPath(), "_svn", "format"))
2244 return helper 2331 return helper
2245 2332
2246 ############################################################################ 2333 ###########################################################################
2247 ## Status Monitor Thread methods 2334 ## Status Monitor Thread methods
2248 ############################################################################ 2335 ###########################################################################
2249 2336
2250 def _createStatusMonitorThread(self, interval, project): 2337 def _createStatusMonitorThread(self, interval, project):
2251 """ 2338 """
2252 Protected method to create an instance of the VCS status monitor thread. 2339 Protected method to create an instance of the VCS status monitor
2253 2340 thread.
2341
2342 @param interval check interval for the monitor thread in seconds
2343 (integer)
2254 @param project reference to the project object 2344 @param project reference to the project object
2255 @param interval check interval for the monitor thread in seconds (integer)
2256 @return reference to the monitor thread (QThread) 2345 @return reference to the monitor thread (QThread)
2257 """ 2346 """
2258 from .SvnStatusMonitorThread import SvnStatusMonitorThread 2347 from .SvnStatusMonitorThread import SvnStatusMonitorThread
2259 return SvnStatusMonitorThread(interval, project, self) 2348 return SvnStatusMonitorThread(interval, project, self)

eric ide

mercurial