Plugins/VcsPlugins/vcsPySvn/subversion.py

changeset 3009
bf5ae5d7477d
parent 2963
745d38097b7f
child 3020
542e97d4ecb3
child 3057
10516539f238
equal deleted inserted replaced
3008:7848489bcb92 3009:bf5ae5d7477d
81 ] 81 ]
82 82
83 self.commandHistory = [] 83 self.commandHistory = []
84 self.wdHistory = [] 84 self.wdHistory = []
85 85
86 if pysvn.version >= (1, 4, 3, 0) and "SVN_ASP_DOT_NET_HACK" in os.environ: 86 if pysvn.version >= (1, 4, 3, 0) and \
87 "SVN_ASP_DOT_NET_HACK" in os.environ:
87 self.adminDir = '_svn' 88 self.adminDir = '_svn'
88 else: 89 else:
89 self.adminDir = '.svn' 90 self.adminDir = '.svn'
90 91
91 self.log = None 92 self.log = None
101 self.statusCache = {} 102 self.statusCache = {}
102 103
103 self.__commitData = {} 104 self.__commitData = {}
104 self.__commitDialog = None 105 self.__commitDialog = None
105 106
106 self.__wcng = True # assume new generation working copy metadata format 107 self.__wcng = True # assume new generation working copy
108 # metadata format
107 109
108 def getPlugin(self): 110 def getPlugin(self):
109 """ 111 """
110 Public method to get a reference to the plugin object. 112 Public method to get a reference to the plugin object.
111 113
131 client.exception_style = 1 133 client.exception_style = 1
132 client.set_auth_cache(authCache) 134 client.set_auth_cache(authCache)
133 135
134 return client 136 return client
135 137
136 ############################################################################ 138 ###########################################################################
137 ## Methods of the VCS interface 139 ## Methods of the VCS interface
138 ############################################################################ 140 ###########################################################################
139 141
140 def vcsShutdown(self): 142 def vcsShutdown(self):
141 """ 143 """
142 Public method used to shutdown the Subversion interface. 144 Public method used to shutdown the Subversion interface.
143 """ 145 """
162 164
163 def vcsExists(self): 165 def vcsExists(self):
164 """ 166 """
165 Public method used to test for the presence of the svn executable. 167 Public method used to test for the presence of the svn executable.
166 168
167 @return flag indicating the existance (boolean) and an error message (string) 169 @return flag indicating the existance (boolean) and an error message
170 (string)
168 """ 171 """
169 self.versionStr = ".".join([str(v) for v in pysvn.svn_version[:-1]]) 172 self.versionStr = ".".join([str(v) for v in pysvn.svn_version[:-1]])
170 self.version = pysvn.svn_version[:-1] 173 self.version = pysvn.svn_version[:-1]
171 return True, "" 174 return True, ""
172 175
184 """ 187 """
185 return True 188 return True
186 189
187 def vcsConvertProject(self, vcsDataDict, project): 190 def vcsConvertProject(self, vcsDataDict, project):
188 """ 191 """
189 Public method to convert an uncontrolled project to a version controlled project. 192 Public method to convert an uncontrolled project to a version
193 controlled project.
190 194
191 @param vcsDataDict dictionary of data required for the conversion 195 @param vcsDataDict dictionary of data required for the conversion
192 @param project reference to the project object 196 @param project reference to the project object
193 """ 197 """
194 success = self.vcsImport(vcsDataDict, project.ppath)[0] 198 success = self.vcsImport(vcsDataDict, project.ppath)[0]
195 if not success: 199 if not success:
196 E5MessageBox.critical(self.__ui, 200 E5MessageBox.critical(self.__ui,
197 self.trUtf8("Create project in repository"), 201 self.trUtf8("Create project in repository"),
198 self.trUtf8("""The project could not be created in the repository.""" 202 self.trUtf8(
199 """ Maybe the given repository doesn't exist or the""" 203 """The project could not be created in the repository."""
200 """ repository server is down.""")) 204 """ Maybe the given repository doesn't exist or the"""
205 """ repository server is down."""))
201 else: 206 else:
202 cwdIsPpath = False 207 cwdIsPpath = False
203 if os.getcwd() == project.ppath: 208 if os.getcwd() == project.ppath:
204 os.chdir(os.path.dirname(project.ppath)) 209 os.chdir(os.path.dirname(project.ppath))
205 cwdIsPpath = True 210 cwdIsPpath = True
215 if not os.path.isfile(pfn): 220 if not os.path.isfile(pfn):
216 pfn += "z" 221 pfn += "z"
217 if not os.path.isfile(pfn): 222 if not os.path.isfile(pfn):
218 E5MessageBox.critical(self.__ui, 223 E5MessageBox.critical(self.__ui,
219 self.trUtf8("New project"), 224 self.trUtf8("New project"),
220 self.trUtf8("""The project could not be checked out of the""" 225 self.trUtf8(
221 """ repository.<br />""" 226 """The project could not be checked out of the"""
222 """Restoring the original contents.""")) 227 """ repository.<br />"""
228 """Restoring the original contents."""))
223 if os.getcwd() == project.ppath: 229 if os.getcwd() == project.ppath:
224 os.chdir(os.path.dirname(project.ppath)) 230 os.chdir(os.path.dirname(project.ppath))
225 cwdIsPpath = True 231 cwdIsPpath = True
226 else: 232 else:
227 cwdIsPpath = False 233 cwdIsPpath = False
237 project.closeProject(noSave=True) 243 project.closeProject(noSave=True)
238 project.openProject(pfn) 244 project.openProject(pfn)
239 245
240 def vcsImport(self, vcsDataDict, projectDir, noDialog=False): 246 def vcsImport(self, vcsDataDict, projectDir, noDialog=False):
241 """ 247 """
242 Public method used to import the project into the Subversion repository. 248 Public method used to import the project into the Subversion
249 repository.
243 250
244 @param vcsDataDict dictionary of data required for the import 251 @param vcsDataDict dictionary of data required for the import
245 @param projectDir project directory (string) 252 @param projectDir project directory (string)
246 @param noDialog flag indicating quiet operations 253 @param noDialog flag indicating quiet operations
247 @return flag indicating an execution without errors (boolean) 254 @return flag indicating an execution without errors (boolean)
266 os.makedirs(tmpDir) 273 os.makedirs(tmpDir)
267 if self.otherData["standardLayout"]: 274 if self.otherData["standardLayout"]:
268 os.mkdir(os.path.join(tmpDir, project)) 275 os.mkdir(os.path.join(tmpDir, project))
269 os.mkdir(os.path.join(tmpDir, project, 'branches')) 276 os.mkdir(os.path.join(tmpDir, project, 'branches'))
270 os.mkdir(os.path.join(tmpDir, project, 'tags')) 277 os.mkdir(os.path.join(tmpDir, project, 'tags'))
271 shutil.copytree(projectDir, os.path.join(tmpDir, project, 'trunk')) 278 shutil.copytree(
279 projectDir, os.path.join(tmpDir, project, 'trunk'))
272 else: 280 else:
273 shutil.copytree(projectDir, os.path.join(tmpDir, project)) 281 shutil.copytree(projectDir, os.path.join(tmpDir, project))
274 except OSError as e: 282 except OSError as e:
275 if os.path.isdir(tmpDir): 283 if os.path.isdir(tmpDir):
276 shutil.rmtree(tmpDir, True) 284 shutil.rmtree(tmpDir, True)
282 opts = self.options['global'] 290 opts = self.options['global']
283 recurse = "--non-recursive" not in opts 291 recurse = "--non-recursive" not in opts
284 url = self.__svnURL(vcsDir) 292 url = self.__svnURL(vcsDir)
285 client = self.getClient() 293 client = self.getClient()
286 if not noDialog: 294 if not noDialog:
287 dlg = \ 295 dlg = SvnDialog(
288 SvnDialog(self.trUtf8('Importing project into Subversion repository'), 296 self.trUtf8('Importing project into Subversion repository'),
289 "import{0} --message {1} .".format( 297 "import{0} --message {1} .".format(
290 (not recurse) and " --non-recursive" or "", 298 (not recurse) and " --non-recursive" or "", msg),
291 msg), 299 client)
292 client)
293 QApplication.processEvents() 300 QApplication.processEvents()
294 try: 301 try:
295 rev = client.import_(".", url, msg, recurse, ignore=True) 302 rev = client.import_(".", url, msg, recurse, ignore=True)
296 status = True 303 status = True
297 except pysvn.ClientError as e: 304 except pysvn.ClientError as e:
310 shutil.rmtree(tmpDir, True) 317 shutil.rmtree(tmpDir, True)
311 return status, False 318 return status, False
312 319
313 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False): 320 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False):
314 """ 321 """
315 Public method used to check the project out of the Subversion repository. 322 Public method used to check the project out of the Subversion
323 repository.
316 324
317 @param vcsDataDict dictionary of data required for the checkout 325 @param vcsDataDict dictionary of data required for the checkout
318 @param projectDir project directory to create (string) 326 @param projectDir project directory to create (string)
319 @param noDialog flag indicating quiet operations 327 @param noDialog flag indicating quiet operations
320 @return flag indicating an execution without errors (boolean) 328 @return flag indicating an execution without errors (boolean)
332 340
333 if self.otherData["standardLayout"]: 341 if self.otherData["standardLayout"]:
334 if tag is None or tag == '': 342 if tag is None or tag == '':
335 svnUrl = '{0}/trunk'.format(vcsDir) 343 svnUrl = '{0}/trunk'.format(vcsDir)
336 else: 344 else:
337 if not tag.startswith('tags') and not tag.startswith('branches'): 345 if not tag.startswith('tags') and \
346 not tag.startswith('branches'):
338 type_, ok = QInputDialog.getItem( 347 type_, ok = QInputDialog.getItem(
339 None, 348 None,
340 self.trUtf8("Subversion Checkout"), 349 self.trUtf8("Subversion Checkout"),
341 self.trUtf8("The tag must be a normal tag (tags) or" 350 self.trUtf8("The tag must be a normal tag (tags) or"
342 " a branch tag (branches)." 351 " a branch tag (branches)."
353 opts = self.options['global'] + self.options['checkout'] 362 opts = self.options['global'] + self.options['checkout']
354 recurse = "--non-recursive" not in opts 363 recurse = "--non-recursive" not in opts
355 url = self.__svnURL(svnUrl) 364 url = self.__svnURL(svnUrl)
356 client = self.getClient() 365 client = self.getClient()
357 if not noDialog: 366 if not noDialog:
358 dlg = \ 367 dlg = SvnDialog(
359 SvnDialog(self.trUtf8('Checking project out of Subversion repository'), 368 self.trUtf8('Checking project out of Subversion repository'),
360 "checkout{0} {1} {2}".format( 369 "checkout{0} {1} {2}".format(
361 (not recurse) and " --non-recursive" or "", 370 (not recurse) and " --non-recursive" or "",
362 url, projectDir), 371 url, projectDir),
363 client) 372 client)
364 QApplication.processEvents() 373 QApplication.processEvents()
365 locker = QMutexLocker(self.vcsExecutionMutex) 374 locker = QMutexLocker(self.vcsExecutionMutex)
366 try: 375 try:
367 client.checkout(url, projectDir, recurse) 376 client.checkout(url, projectDir, recurse)
368 status = True 377 status = True
376 dlg.exec_() 385 dlg.exec_()
377 return status 386 return status
378 387
379 def vcsExport(self, vcsDataDict, projectDir): 388 def vcsExport(self, vcsDataDict, projectDir):
380 """ 389 """
381 Public method used to export a directory from the Subversion repository. 390 Public method used to export a directory from the Subversion
391 repository.
382 392
383 @param vcsDataDict dictionary of data required for the checkout 393 @param vcsDataDict dictionary of data required for the checkout
384 @param projectDir project directory to create (string) 394 @param projectDir project directory to create (string)
385 @return flag indicating an execution without errors (boolean) 395 @return flag indicating an execution without errors (boolean)
386 """ 396 """
394 404
395 if self.otherData["standardLayout"]: 405 if self.otherData["standardLayout"]:
396 if tag is None or tag == '': 406 if tag is None or tag == '':
397 svnUrl = '{0}/trunk'.format(vcsDir) 407 svnUrl = '{0}/trunk'.format(vcsDir)
398 else: 408 else:
399 if not tag.startswith('tags') and not tag.startswith('branches'): 409 if not tag.startswith('tags') and \
410 not tag.startswith('branches'):
400 type_, ok = QInputDialog.getItem( 411 type_, ok = QInputDialog.getItem(
401 None, 412 None,
402 self.trUtf8("Subversion Export"), 413 self.trUtf8("Subversion Export"),
403 self.trUtf8("The tag must be a normal tag (tags) or" 414 self.trUtf8("The tag must be a normal tag (tags) or"
404 " a branch tag (branches)." 415 " a branch tag (branches)."
414 425
415 opts = self.options['global'] 426 opts = self.options['global']
416 recurse = "--non-recursive" not in opts 427 recurse = "--non-recursive" not in opts
417 url = self.__svnURL(svnUrl) 428 url = self.__svnURL(svnUrl)
418 client = self.getClient() 429 client = self.getClient()
419 dlg = \ 430 dlg = SvnDialog(
420 SvnDialog(self.trUtf8('Exporting project from Subversion repository'), 431 self.trUtf8('Exporting project from Subversion repository'),
421 "export --force{0} {1} {2}".format( 432 "export --force{0} {1} {2}".format(
422 (not recurse) and " --non-recursive" or "", 433 (not recurse) and " --non-recursive" or "",
423 url, projectDir), 434 url, projectDir),
424 client) 435 client)
425 QApplication.processEvents() 436 QApplication.processEvents()
426 locker = QMutexLocker(self.vcsExecutionMutex) 437 locker = QMutexLocker(self.vcsExecutionMutex)
427 try: 438 try:
428 client.export(url, projectDir, force=True, recurse=recurse) 439 client.export(url, projectDir, force=True, recurse=recurse)
429 status = True 440 status = True
435 dlg.exec_() 446 dlg.exec_()
436 return status 447 return status
437 448
438 def vcsCommit(self, name, message, noDialog=False): 449 def vcsCommit(self, name, message, noDialog=False):
439 """ 450 """
440 Public method used to make the change of a file/directory permanent in the 451 Public method used to make the change of a file/directory permanent
441 Subversion repository. 452 in the Subversion repository.
442 453
443 @param name file/directory name to be committed (string or list of strings) 454 @param name file/directory name to be committed (string or
455 list of strings)
444 @param message message for this operation (string) 456 @param message message for this operation (string)
445 @param noDialog flag indicating quiet operations 457 @param noDialog flag indicating quiet operations
446 """ 458 """
447 if not noDialog and not message: 459 if not noDialog and not message:
448 # call CommitDialog and get message from there 460 # call CommitDialog and get message from there
449 if self.__commitDialog is None: 461 if self.__commitDialog is None:
450 from .SvnCommitDialog import SvnCommitDialog 462 from .SvnCommitDialog import SvnCommitDialog
451 self.__commitDialog = SvnCommitDialog(self.svnGetChangelists(), self.__ui) 463 self.__commitDialog = SvnCommitDialog(
464 self.svnGetChangelists(), self.__ui)
452 self.__commitDialog.accepted.connect(self.__vcsCommit_Step2) 465 self.__commitDialog.accepted.connect(self.__vcsCommit_Step2)
453 self.__commitDialog.show() 466 self.__commitDialog.show()
454 self.__commitDialog.raise_() 467 self.__commitDialog.raise_()
455 self.__commitDialog.activateWindow() 468 self.__commitDialog.activateWindow()
456 469
479 for nam in nameList: 492 for nam in nameList:
480 # check for commit of the project 493 # check for commit of the project
481 if os.path.isdir(nam): 494 if os.path.isdir(nam):
482 project = e5App().getObject("Project") 495 project = e5App().getObject("Project")
483 if nam == project.getProjectPath(): 496 if nam == project.getProjectPath():
484 ok &= project.checkAllScriptsDirty(reportSyntaxErrors=True) and \ 497 ok &= project.checkAllScriptsDirty(
498 reportSyntaxErrors=True) and \
485 project.checkDirty() 499 project.checkDirty()
486 continue 500 continue
487 elif os.path.isfile(nam): 501 elif os.path.isfile(nam):
488 editor = e5App().getObject("ViewManager").getOpenEditor(nam) 502 editor = e5App().getObject("ViewManager")\
503 .getOpenEditor(nam)
489 if editor: 504 if editor:
490 ok &= editor.checkDirty() 505 ok &= editor.checkDirty()
491 if not ok: 506 if not ok:
492 break 507 break
493 508
494 if not ok: 509 if not ok:
495 res = E5MessageBox.yesNo(self.__ui, 510 res = E5MessageBox.yesNo(self.__ui,
496 self.trUtf8("Commit Changes"), 511 self.trUtf8("Commit Changes"),
497 self.trUtf8("""The commit affects files, that have unsaved""" 512 self.trUtf8(
498 """ changes. Shall the commit be continued?"""), 513 """The commit affects files, that have unsaved"""
514 """ changes. Shall the commit be continued?"""),
499 icon=E5MessageBox.Warning) 515 icon=E5MessageBox.Warning)
500 if not res: 516 if not res:
501 return 517 return
502 518
503 if self.__commitDialog is not None: 519 if self.__commitDialog is not None:
504 msg = self.__commitDialog.logMessage() 520 msg = self.__commitDialog.logMessage()
505 if self.__commitDialog.hasChangelists(): 521 if self.__commitDialog.hasChangelists():
506 changelists, keepChangelists = self.__commitDialog.changelistsData() 522 changelists, keepChangelists = \
523 self.__commitDialog.changelistsData()
507 else: 524 else:
508 changelists, keepChangelists = [], False 525 changelists, keepChangelists = [], False
509 ## self.__commitDialog.accepted.disconnect(self.__vcsCommit_Step2)
510 self.__commitDialog.deleteLater() 526 self.__commitDialog.deleteLater()
511 self.__commitDialog = None 527 self.__commitDialog = None
512 else: 528 else:
513 changelists, keepChangelists = [], False 529 changelists, keepChangelists = [], False
514 530
531 opts = self.options['global'] + self.options['commit'] 547 opts = self.options['global'] + self.options['commit']
532 recurse = "--non-recursive" not in opts 548 recurse = "--non-recursive" not in opts
533 keeplocks = "--keep-locks" in opts 549 keeplocks = "--keep-locks" in opts
534 client = self.getClient() 550 client = self.getClient()
535 if not noDialog: 551 if not noDialog:
536 dlg = \ 552 dlg = SvnDialog(
537 SvnDialog(self.trUtf8('Commiting changes to Subversion repository'), 553 self.trUtf8('Commiting changes to Subversion repository'),
538 "commit{0}{1}{2}{3} --message {4} {5}".format( 554 "commit{0}{1}{2}{3} --message {4} {5}".format(
539 (not recurse) and " --non-recursive" or "", 555 (not recurse) and " --non-recursive" or "",
540 keeplocks and " --keep-locks" or "", 556 keeplocks and " --keep-locks" or "",
541 keepChangelists and " --keep-changelists" or "", 557 keepChangelists and " --keep-changelists" or "",
542 changelists and \ 558 changelists and \
543 " --changelist ".join([""] + changelists) or "", 559 " --changelist ".join([""] + changelists) or "",
544 msg, " ".join(fnames)), 560 msg, " ".join(fnames)),
545 client) 561 client)
546 QApplication.processEvents() 562 QApplication.processEvents()
547 try: 563 try:
548 if changelists: 564 if changelists:
549 rev = client.checkin(fnames, msg, 565 rev = client.checkin(fnames, msg,
550 recurse=recurse, keep_locks=keeplocks, 566 recurse=recurse, keep_locks=keeplocks,
567 self.committed.emit() 583 self.committed.emit()
568 self.checkVCSStatus() 584 self.checkVCSStatus()
569 585
570 def vcsUpdate(self, name, noDialog=False): 586 def vcsUpdate(self, name, noDialog=False):
571 """ 587 """
572 Public method used to update a file/directory with the Subversion repository. 588 Public method used to update a file/directory with the Subversion
573 589 repository.
574 @param name file/directory name to be updated (string or list of strings) 590
591 @param name file/directory name to be updated (string or list of
592 strings)
575 @param noDialog flag indicating quiet operations (boolean) 593 @param noDialog flag indicating quiet operations (boolean)
576 @return flag indicating, that the update contained an add 594 @return flag indicating, that the update contained an add
577 or delete (boolean) 595 or delete (boolean)
578 """ 596 """
579 if isinstance(name, list): 597 if isinstance(name, list):
587 os.chdir(dname) 605 os.chdir(dname)
588 opts = self.options['global'] + self.options['update'] 606 opts = self.options['global'] + self.options['update']
589 recurse = "--non-recursive" not in opts 607 recurse = "--non-recursive" not in opts
590 client = self.getClient() 608 client = self.getClient()
591 if not noDialog: 609 if not noDialog:
592 dlg = \ 610 dlg = SvnDialog(
593 SvnDialog(self.trUtf8('Synchronizing with the Subversion repository'), 611 self.trUtf8('Synchronizing with the Subversion repository'),
594 "update{0} {1}".format( 612 "update{0} {1}".format(
595 (not recurse) and " --non-recursive" or "", 613 (not recurse) and " --non-recursive" or "",
596 " ".join(fnames)), 614 " ".join(fnames)),
597 client) 615 client)
598 QApplication.processEvents() 616 QApplication.processEvents()
599 try: 617 try:
600 client.update(fnames, recurse) 618 client.update(fnames, recurse)
601 except pysvn.ClientError as e: 619 except pysvn.ClientError as e:
602 dlg.showError(e.args[0]) 620 dlg.showError(e.args[0])
611 self.checkVCSStatus() 629 self.checkVCSStatus()
612 return res 630 return res
613 631
614 def vcsAdd(self, name, isDir=False, noDialog=False): 632 def vcsAdd(self, name, isDir=False, noDialog=False):
615 """ 633 """
616 Public method used to add a file/directory to the Subversion repository. 634 Public method used to add a file/directory to the Subversion
635 repository.
617 636
618 @param name file/directory name to be added (string) 637 @param name file/directory name to be added (string)
619 @param isDir flag indicating name is a directory (boolean) 638 @param isDir flag indicating name is a directory (boolean)
620 @param noDialog flag indicating quiet operations (boolean) 639 @param noDialog flag indicating quiet operations (boolean)
621 """ 640 """
638 repodir = os.path.dirname(repodir) 657 repodir = os.path.dirname(repodir)
639 if os.path.splitdrive(repodir)[1] == os.sep: 658 if os.path.splitdrive(repodir)[1] == os.sep:
640 return # oops, project is not version controlled 659 return # oops, project is not version controlled
641 while os.path.normcase(dname) != os.path.normcase(repodir) and \ 660 while os.path.normcase(dname) != os.path.normcase(repodir) and \
642 (os.path.normcase(dname) not in self.statusCache or \ 661 (os.path.normcase(dname) not in self.statusCache or \
643 self.statusCache[os.path.normcase(dname)] == self.canBeAdded): 662 self.statusCache[os.path.normcase(dname)] ==
644 # add directories recursively, if they aren't in the repository already 663 self.canBeAdded):
664 # add directories recursively, if they aren't in the
665 # repository already
645 tree.insert(-1, dname) 666 tree.insert(-1, dname)
646 dname = os.path.dirname(dname) 667 dname = os.path.dirname(dname)
647 wdir = dname 668 wdir = dname
648 else: 669 else:
649 while not os.path.exists(os.path.join(dname, self.adminDir)): 670 while not os.path.exists(os.path.join(dname, self.adminDir)):
650 # add directories recursively, if they aren't in the repository already 671 # add directories recursively, if they aren't in the
672 # repository already
651 tree.insert(-1, dname) 673 tree.insert(-1, dname)
652 dname = os.path.dirname(dname) 674 dname = os.path.dirname(dname)
653 wdir = dname 675 wdir = dname
654 names.extend(tree) 676 names.extend(tree)
655 677
657 tree2 = [] 679 tree2 = []
658 for n in name: 680 for n in name:
659 d = os.path.dirname(n) 681 d = os.path.dirname(n)
660 if self.__wcng: 682 if self.__wcng:
661 repodir = d 683 repodir = d
662 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 684 while not os.path.isdir(
685 os.path.join(repodir, self.adminDir)):
663 repodir = os.path.dirname(repodir) 686 repodir = os.path.dirname(repodir)
664 if os.path.splitdrive(repodir)[1] == os.sep: 687 if os.path.splitdrive(repodir)[1] == os.sep:
665 return # oops, project is not version controlled 688 return # oops, project is not version controlled
666 while os.path.normcase(d) != os.path.normcase(repodir) and \ 689 while os.path.normcase(d) != \
690 os.path.normcase(repodir) and \
667 (d not in tree2 + tree) and \ 691 (d not in tree2 + tree) and \
668 (os.path.normcase(d) not in self.statusCache or \ 692 (os.path.normcase(d) not in self.statusCache or \
669 self.statusCache[os.path.normcase(d)] == self.canBeAdded): 693 self.statusCache[os.path.normcase(d)] ==
694 self.canBeAdded):
670 tree2.append(d) 695 tree2.append(d)
671 d = os.path.dirname(d) 696 d = os.path.dirname(d)
672 else: 697 else:
673 while not os.path.exists(os.path.join(d, self.adminDir)): 698 while not os.path.exists(os.path.join(d, self.adminDir)):
674 if d in tree2 + tree: 699 if d in tree2 + tree:
688 recurse = False 713 recurse = False
689 force = "--force" in opts or noDialog 714 force = "--force" in opts or noDialog
690 noignore = "--no-ignore" in opts 715 noignore = "--no-ignore" in opts
691 client = self.getClient() 716 client = self.getClient()
692 if not noDialog: 717 if not noDialog:
693 dlg = \ 718 dlg = SvnDialog(
694 SvnDialog( 719 self.trUtf8('Adding files/directories to the Subversion'
695 self.trUtf8('Adding files/directories to the Subversion repository'), 720 ' repository'),
696 "add --non-recursive{0}{1} {2}".format( 721 "add --non-recursive{0}{1} {2}".format(
697 force and " --force" or "", 722 force and " --force" or "",
698 noignore and " --no-ignore" or "", 723 noignore and " --no-ignore" or "",
699 " ".join(names)), 724 " ".join(names)),
700 client) 725 client)
701 QApplication.processEvents() 726 QApplication.processEvents()
702 try: 727 try:
703 client.add(names, recurse=recurse, force=force, ignore=not noignore) 728 client.add(names, recurse=recurse, force=force,
729 ignore=not noignore)
704 except pysvn.ClientError as e: 730 except pysvn.ClientError as e:
705 if not noDialog: 731 if not noDialog:
706 dlg.showError(e.args[0]) 732 dlg.showError(e.args[0])
707 locker.unlock() 733 locker.unlock()
708 if not noDialog: 734 if not noDialog:
720 """ 746 """
721 self.vcsAdd(name, isDir) 747 self.vcsAdd(name, isDir)
722 748
723 def vcsAddTree(self, path): 749 def vcsAddTree(self, path):
724 """ 750 """
725 Public method to add a directory tree rooted at path to the Subversion repository. 751 Public method to add a directory tree rooted at path to the Subversion
726 752 repository.
727 @param path root directory of the tree to be added (string or list of strings)) 753
754 @param path root directory of the tree to be added (string or list of
755 strings))
728 """ 756 """
729 tree = [] 757 tree = []
730 if isinstance(path, list): 758 if isinstance(path, list):
731 dname, fnames = self.splitPathList(path) 759 dname, fnames = self.splitPathList(path)
732 for n in path: 760 for n in path:
733 d = os.path.dirname(n) 761 d = os.path.dirname(n)
734 if self.__wcng: 762 if self.__wcng:
735 repodir = d 763 repodir = d
736 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 764 while not os.path.isdir(
765 os.path.join(repodir, self.adminDir)):
737 repodir = os.path.dirname(repodir) 766 repodir = os.path.dirname(repodir)
738 if os.path.splitdrive(repodir)[1] == os.sep: 767 if os.path.splitdrive(repodir)[1] == os.sep:
739 return # oops, project is not version controlled 768 return # oops, project is not version controlled
740 while os.path.normcase(d) != os.path.normcase(repodir) and \ 769 while os.path.normcase(d) != \
770 os.path.normcase(repodir) and \
741 (d not in tree) and \ 771 (d not in tree) and \
742 (os.path.normcase(d) not in self.statusCache or \ 772 (os.path.normcase(d) not in self.statusCache or \
743 self.statusCache[os.path.normcase(d)] == self.canBeAdded): 773 self.statusCache[os.path.normcase(d)] ==
774 self.canBeAdded):
744 tree.append(d) 775 tree.append(d)
745 d = os.path.dirname(d) 776 d = os.path.dirname(d)
746 else: 777 else:
747 while not os.path.exists(os.path.join(d, self.adminDir)): 778 while not os.path.exists(os.path.join(d, self.adminDir)):
748 # add directories recursively, 779 # add directories recursively,
758 repodir = dname 789 repodir = dname
759 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 790 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
760 repodir = os.path.dirname(repodir) 791 repodir = os.path.dirname(repodir)
761 if os.path.splitdrive(repodir)[1] == os.sep: 792 if os.path.splitdrive(repodir)[1] == os.sep:
762 return # oops, project is not version controlled 793 return # oops, project is not version controlled
763 while os.path.normcase(dname) != os.path.normcase(repodir) and \ 794 while os.path.normcase(dname) != \
795 os.path.normcase(repodir) and \
764 (os.path.normcase(dname) not in self.statusCache or \ 796 (os.path.normcase(dname) not in self.statusCache or \
765 self.statusCache[os.path.normcase(dname)] == self.canBeAdded): 797 self.statusCache[os.path.normcase(dname)] ==
766 # add directories recursively, if they aren't in the repository already 798 self.canBeAdded):
799 # add directories recursively, if they aren't in the
800 # repository already
767 tree.insert(-1, dname) 801 tree.insert(-1, dname)
768 dname = os.path.dirname(dname) 802 dname = os.path.dirname(dname)
769 else: 803 else:
770 while not os.path.exists(os.path.join(dname, self.adminDir)): 804 while not os.path.exists(os.path.join(dname, self.adminDir)):
771 # add directories recursively, 805 # add directories recursively,
787 opts = self.options['global'] + self.options['add'] 821 opts = self.options['global'] + self.options['add']
788 recurse = True 822 recurse = True
789 force = "--force" in opts 823 force = "--force" in opts
790 ignore = "--ignore" in opts 824 ignore = "--ignore" in opts
791 client = self.getClient() 825 client = self.getClient()
792 dlg = \ 826 dlg = SvnDialog(
793 SvnDialog( 827 self.trUtf8('Adding directory trees to the Subversion repository'),
794 self.trUtf8('Adding directory trees to the Subversion repository'), 828 "add{0}{1} {2}".format(
795 "add{0}{1} {2}".format( 829 force and " --force" or "",
796 force and " --force" or "", 830 ignore and " --ignore" or "",
797 ignore and " --ignore" or "", 831 " ".join(names)),
798 " ".join(names)), 832 client)
799 client)
800 QApplication.processEvents() 833 QApplication.processEvents()
801 try: 834 try:
802 client.add(names, recurse=recurse, force=force, ignore=ignore) 835 client.add(names, recurse=recurse, force=force, ignore=ignore)
803 except pysvn.ClientError as e: 836 except pysvn.ClientError as e:
804 dlg.showError(e.args[0]) 837 dlg.showError(e.args[0])
807 dlg.exec_() 840 dlg.exec_()
808 os.chdir(cwd) 841 os.chdir(cwd)
809 842
810 def vcsRemove(self, name, project=False, noDialog=False): 843 def vcsRemove(self, name, project=False, noDialog=False):
811 """ 844 """
812 Public method used to remove a file/directory from the Subversion repository. 845 Public method used to remove a file/directory from the Subversion
846 repository.
813 847
814 The default operation is to remove the local copy as well. 848 The default operation is to remove the local copy as well.
815 849
816 @param name file/directory name to be removed (string or list of strings)) 850 @param name file/directory name to be removed (string or list of
817 @param project flag indicating deletion of a project tree (boolean) (not needed) 851 strings))
852 @param project flag indicating deletion of a project tree (boolean)
853 (not needed)
818 @param noDialog flag indicating quiet operations 854 @param noDialog flag indicating quiet operations
819 @return flag indicating successfull operation (boolean) 855 @return flag indicating successfull operation (boolean)
820 """ 856 """
821 if not isinstance(name, list): 857 if not isinstance(name, list):
822 name = [name] 858 name = [name]
823 opts = self.options['global'] + self.options['remove'] 859 opts = self.options['global'] + self.options['remove']
824 force = "--force" in opts or noDialog 860 force = "--force" in opts or noDialog
825 client = self.getClient() 861 client = self.getClient()
826 if not noDialog: 862 if not noDialog:
827 dlg = \ 863 dlg = SvnDialog(
828 SvnDialog( 864 self.trUtf8('Removing files/directories from the Subversion'
829 self.trUtf8('Removing files/directories from the Subversion repository'), 865 ' repository'),
830 "remove{0} {1}".format( 866 "remove{0} {1}".format(
831 force and " --force" or "", 867 force and " --force" or "",
832 " ".join(name)), 868 " ".join(name)),
833 client) 869 client)
834 QApplication.processEvents() 870 QApplication.processEvents()
835 locker = QMutexLocker(self.vcsExecutionMutex) 871 locker = QMutexLocker(self.vcsExecutionMutex)
836 try: 872 try:
837 client.remove(name, force=force) 873 client.remove(name, force=force)
838 res = True 874 res = True
945 """ 981 """
946 Public method used to view the difference of a file/directory to the 982 Public method used to view the difference of a file/directory to the
947 Subversion repository. 983 Subversion repository.
948 984
949 If name is a directory and is the project directory, all project files 985 If name is a directory and is the project directory, all project files
950 are saved first. If name is a file (or list of files), which is/are being edited 986 are saved first. If name is a file (or list of files), which is/are
951 and has unsaved modification, they can be saved or the operation may be aborted. 987 being edited and has unsaved modification, they can be saved or the
988 operation may be aborted.
952 989
953 @param name file/directory name to be diffed (string) 990 @param name file/directory name to be diffed (string)
954 """ 991 """
955 if isinstance(name, list): 992 if isinstance(name, list):
956 names = name[:] 993 names = name[:]
996 1033
997 reposURL = self.svnGetReposName(dname) 1034 reposURL = self.svnGetReposName(dname)
998 if reposURL is None: 1035 if reposURL is None:
999 E5MessageBox.critical(self.__ui, 1036 E5MessageBox.critical(self.__ui,
1000 self.trUtf8("Subversion Error"), 1037 self.trUtf8("Subversion Error"),
1001 self.trUtf8("""The URL of the project repository could not be""" 1038 self.trUtf8(
1002 """ retrieved from the working copy. The tag operation will""" 1039 """The URL of the project repository could not be"""
1003 """ be aborted""")) 1040 """ retrieved from the working copy. The tag operation"""
1041 """ will be aborted"""))
1004 return 1042 return
1005 1043
1006 if self.otherData["standardLayout"]: 1044 if self.otherData["standardLayout"]:
1007 url = None 1045 url = None
1008 else: 1046 else:
1030 1068
1031 reposRoot = rx_base.cap(1) 1069 reposRoot = rx_base.cap(1)
1032 if tagOp in [1, 4]: 1070 if tagOp in [1, 4]:
1033 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1071 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag))
1034 elif tagOp in [2, 8]: 1072 elif tagOp in [2, 8]:
1035 url = '{0}/branches/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1073 url = '{0}/branches/{1}'.format(
1074 reposRoot, urllib.parse.quote(tag))
1036 else: 1075 else:
1037 url = self.__svnURL(tag) 1076 url = self.__svnURL(tag)
1038 1077
1039 self.tagName = tag 1078 self.tagName = tag
1040 client = self.getClient() 1079 client = self.getClient()
1041 rev = None 1080 rev = None
1042 if tagOp in [1, 2]: 1081 if tagOp in [1, 2]:
1043 log = 'Created tag <{0}>'.format(self.tagName) 1082 log = 'Created tag <{0}>'.format(self.tagName)
1044 dlg = \ 1083 dlg = SvnDialog(
1045 SvnDialog( 1084 self.trUtf8('Tagging {0} in the Subversion repository')
1046 self.trUtf8('Tagging {0} in the Subversion repository').format(name), 1085 .format(name),
1047 "copy --message {0} {1} {2}".format(log, reposURL, url), 1086 "copy --message {0} {1} {2}".format(log, reposURL, url),
1048 client, log=log) 1087 client, log=log)
1049 QApplication.processEvents() 1088 QApplication.processEvents()
1050 locker = QMutexLocker(self.vcsExecutionMutex) 1089 locker = QMutexLocker(self.vcsExecutionMutex)
1051 try: 1090 try:
1052 rev = client.copy(reposURL, url) 1091 rev = client.copy(reposURL, url)
1053 except pysvn.ClientError as e: 1092 except pysvn.ClientError as e:
1054 dlg.showError(e.args[0]) 1093 dlg.showError(e.args[0])
1055 locker.unlock() 1094 locker.unlock()
1056 else: 1095 else:
1057 log = 'Deleted tag <{0}>'.format(self.tagName) 1096 log = 'Deleted tag <{0}>'.format(self.tagName)
1058 dlg = \ 1097 dlg = SvnDialog(
1059 SvnDialog( 1098 self.trUtf8('Tagging {0} in the Subversion repository')
1060 self.trUtf8('Tagging {0} in the Subversion repository').format(name), 1099 .format(name),
1061 "remove --message {0} {1}".format(log, url), 1100 "remove --message {0} {1}".format(log, url),
1062 client, log=log) 1101 client, log=log)
1063 QApplication.processEvents() 1102 QApplication.processEvents()
1064 locker = QMutexLocker(self.vcsExecutionMutex) 1103 locker = QMutexLocker(self.vcsExecutionMutex)
1065 try: 1104 try:
1066 rev = client.remove(url) 1105 rev = client.remove(url)
1067 except pysvn.ClientError as e: 1106 except pysvn.ClientError as e:
1085 recurse = True 1124 recurse = True
1086 1125
1087 project = e5App().getObject("Project") 1126 project = e5App().getObject("Project")
1088 names = [project.getRelativePath(nam) for nam in name] 1127 names = [project.getRelativePath(nam) for nam in name]
1089 if names[0]: 1128 if names[0]:
1090 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog 1129 from UI.DeleteFilesConfirmationDialog import \
1130 DeleteFilesConfirmationDialog
1091 dia = DeleteFilesConfirmationDialog(self.parent(), 1131 dia = DeleteFilesConfirmationDialog(self.parent(),
1092 self.trUtf8("Revert changes"), 1132 self.trUtf8("Revert changes"),
1093 self.trUtf8("Do you really want to revert all changes to these files" 1133 self.trUtf8(
1094 " or directories?"), 1134 "Do you really want to revert all changes to these files"
1135 " or directories?"),
1095 name) 1136 name)
1096 yes = dia.exec_() == QDialog.Accepted 1137 yes = dia.exec_() == QDialog.Accepted
1097 else: 1138 else:
1098 yes = E5MessageBox.yesNo(None, 1139 yes = E5MessageBox.yesNo(None,
1099 self.trUtf8("Revert changes"), 1140 self.trUtf8("Revert changes"),
1100 self.trUtf8("""Do you really want to revert all changes of""" 1141 self.trUtf8("""Do you really want to revert all changes of"""
1101 """ the project?""")) 1142 """ the project?"""))
1102 if yes: 1143 if yes:
1103 client = self.getClient() 1144 client = self.getClient()
1104 dlg = \ 1145 dlg = SvnDialog(
1105 SvnDialog(self.trUtf8('Reverting changes'), 1146 self.trUtf8('Reverting changes'),
1106 "revert {0} {1}".format((not recurse) and " --non-recursive" or "", 1147 "revert {0} {1}".format(
1107 " ".join(name)), 1148 (not recurse) and " --non-recursive" or "",
1108 client) 1149 " ".join(name)),
1150 client)
1109 QApplication.processEvents() 1151 QApplication.processEvents()
1110 locker = QMutexLocker(self.vcsExecutionMutex) 1152 locker = QMutexLocker(self.vcsExecutionMutex)
1111 try: 1153 try:
1112 client.revert(name, recurse) 1154 client.revert(name, recurse)
1113 except pysvn.ClientError as e: 1155 except pysvn.ClientError as e:
1129 1171
1130 reposURL = self.svnGetReposName(dname) 1172 reposURL = self.svnGetReposName(dname)
1131 if reposURL is None: 1173 if reposURL is None:
1132 E5MessageBox.critical(self.__ui, 1174 E5MessageBox.critical(self.__ui,
1133 self.trUtf8("Subversion Error"), 1175 self.trUtf8("Subversion Error"),
1134 self.trUtf8("""The URL of the project repository could not be""" 1176 self.trUtf8(
1135 """ retrieved from the working copy. The switch operation will""" 1177 """The URL of the project repository could not be"""
1136 """ be aborted""")) 1178 """ retrieved from the working copy. The switch"""
1179 """ operation will be aborted"""))
1137 return False 1180 return False
1138 1181
1139 if self.otherData["standardLayout"]: 1182 if self.otherData["standardLayout"]:
1140 url = None 1183 url = None
1141 else: 1184 else:
1164 reposRoot = rx_base.cap(1) 1207 reposRoot = rx_base.cap(1)
1165 tn = tag 1208 tn = tag
1166 if tagType == 1: 1209 if tagType == 1:
1167 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1210 url = '{0}/tags/{1}'.format(reposRoot, urllib.parse.quote(tag))
1168 elif tagType == 2: 1211 elif tagType == 2:
1169 url = '{0}/branches/{1}'.format(reposRoot, urllib.parse.quote(tag)) 1212 url = '{0}/branches/{1}'.format(
1213 reposRoot, urllib.parse.quote(tag))
1170 elif tagType == 4: 1214 elif tagType == 4:
1171 url = '{0}/trunk'.format(reposRoot) 1215 url = '{0}/trunk'.format(reposRoot)
1172 tn = 'HEAD' 1216 tn = 'HEAD'
1173 else: 1217 else:
1174 url = self.__svnURL(tag) 1218 url = self.__svnURL(tag)
1201 """ 1245 """
1202 dname, fname = self.splitPath(name) 1246 dname, fname = self.splitPath(name)
1203 1247
1204 opts = self.options['global'] 1248 opts = self.options['global']
1205 from .SvnMergeDialog import SvnMergeDialog 1249 from .SvnMergeDialog import SvnMergeDialog
1206 dlg = SvnMergeDialog(self.mergeList[0], self.mergeList[1], self.mergeList[2], 1250 dlg = SvnMergeDialog(self.mergeList[0], self.mergeList[1],
1207 "--force" in opts) 1251 self.mergeList[2], "--force" in opts)
1208 if dlg.exec_() == QDialog.Accepted: 1252 if dlg.exec_() == QDialog.Accepted:
1209 urlrev1, urlrev2, target, force = dlg.getParameters() 1253 urlrev1, urlrev2, target, force = dlg.getParameters()
1210 else: 1254 else:
1211 return 1255 return
1212 1256
1227 if rx_rev.exactMatch(urlrev1): 1271 if rx_rev.exactMatch(urlrev1):
1228 if urlrev1 in ["HEAD", "head"]: 1272 if urlrev1 in ["HEAD", "head"]:
1229 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head) 1273 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head)
1230 rev1 = "HEAD" 1274 rev1 = "HEAD"
1231 else: 1275 else:
1232 revision1 = \ 1276 revision1 = pysvn.Revision(
1233 pysvn.Revision(pysvn.opt_revision_kind.number, int(urlrev1)) 1277 pysvn.opt_revision_kind.number, int(urlrev1))
1234 rev1 = urlrev1 1278 rev1 = urlrev1
1235 if urlrev2 in ["HEAD", "head"]: 1279 if urlrev2 in ["HEAD", "head"]:
1236 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head) 1280 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head)
1237 rev2 = "HEAD" 1281 rev2 = "HEAD"
1238 else: 1282 else:
1239 revision2 = \ 1283 revision2 = pysvn.Revision(
1240 pysvn.Revision(pysvn.opt_revision_kind.number, int(urlrev2)) 1284 pysvn.opt_revision_kind.number, int(urlrev2))
1241 rev2 = urlrev2 1285 rev2 = urlrev2
1242 if not target: 1286 if not target:
1243 url1 = name 1287 url1 = name
1244 url2 = name 1288 url2 = name
1245 else: 1289 else:
1255 url1, rev = urlrev1.split("@") 1299 url1, rev = urlrev1.split("@")
1256 if rev in ["HEAD", "head"]: 1300 if rev in ["HEAD", "head"]:
1257 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head) 1301 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head)
1258 rev1 = "HEAD" 1302 rev1 = "HEAD"
1259 else: 1303 else:
1260 revision1 = \ 1304 revision1 = pysvn.Revision(
1261 pysvn.Revision(pysvn.opt_revision_kind.number, int(rev)) 1305 pysvn.opt_revision_kind.number, int(rev))
1262 rev1 = rev 1306 rev1 = rev
1263 else: 1307 else:
1264 url1 = urlrev1 1308 url1 = urlrev1
1265 revision1 = pysvn.Revision(pysvn.opt_revision_kind.unspecified) 1309 revision1 = pysvn.Revision(pysvn.opt_revision_kind.unspecified)
1266 rev1 = "" 1310 rev1 = ""
1268 url2, rev = urlrev2.split("@") 1312 url2, rev = urlrev2.split("@")
1269 if rev in ["HEAD", "head"]: 1313 if rev in ["HEAD", "head"]:
1270 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head) 1314 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head)
1271 rev2 = "HEAD" 1315 rev2 = "HEAD"
1272 else: 1316 else:
1273 revision2 = \ 1317 revision2 = pysvn.Revision(
1274 pysvn.Revision(pysvn.opt_revision_kind.number, int(rev)) 1318 pysvn.opt_revision_kind.number, int(rev))
1275 rev2 = rev 1319 rev2 = rev
1276 else: 1320 else:
1277 url2 = urlrev2 1321 url2 = urlrev2
1278 revision2 = pysvn.Revision(pysvn.opt_revision_kind.unspecified) 1322 revision2 = pysvn.Revision(pysvn.opt_revision_kind.unspecified)
1279 rev2 = "" 1323 rev2 = ""
1313 1357
1314 def __vcsRegisteredState_wcng(self, name): 1358 def __vcsRegisteredState_wcng(self, name):
1315 """ 1359 """
1316 Private method used to get the registered state of a file in the vcs. 1360 Private method used to get the registered state of a file in the vcs.
1317 1361
1318 This is the variant for subversion installations using the new working copy 1362 This is the variant for subversion installations using the new
1319 meta-data format. 1363 working copy meta-data format.
1320 1364
1321 @param name filename to check (string) 1365 @param name filename to check (string)
1322 @return a combination of canBeCommited and canBeAdded 1366 @return a combination of canBeCommited and canBeAdded
1323 """ 1367 """
1324 if name.endswith(os.sep): 1368 if name.endswith(os.sep):
1342 1386
1343 def __vcsRegisteredState_wc(self, name): 1387 def __vcsRegisteredState_wc(self, name):
1344 """ 1388 """
1345 Private method used to get the registered state of a file in the vcs. 1389 Private method used to get the registered state of a file in the vcs.
1346 1390
1347 This is the variant for subversion installations using the old working copy 1391 This is the variant for subversion installations using the old working
1348 meta-data format. 1392 copy meta-data format.
1349 1393
1350 @param name filename to check (string) 1394 @param name filename to check (string)
1351 @return a combination of canBeCommited and canBeAdded 1395 @return a combination of canBeCommited and canBeAdded
1352 """ 1396 """
1353 dname, fname = self.splitPath(name) 1397 dname, fname = self.splitPath(name)
1366 else: 1410 else:
1367 return self.canBeAdded 1411 return self.canBeAdded
1368 1412
1369 def vcsAllRegisteredStates(self, names, dname, shortcut=True): 1413 def vcsAllRegisteredStates(self, names, dname, shortcut=True):
1370 """ 1414 """
1371 Public method used to get the registered states of a number of files in the vcs. 1415 Public method used to get the registered states of a number of files
1372 1416 in the vcs.
1373 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1417
1374 directory has been scanned already. If so, it is assumed, that the states for 1418 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1375 all files has been populated by the previous run. 1419 if the named directory has been scanned already. If so, it is assumed,
1420 that the states for all files has been populated by the previous run.
1376 1421
1377 @param names dictionary with all filenames to be checked as keys 1422 @param names dictionary with all filenames to be checked as keys
1378 @param dname directory to check in (string) 1423 @param dname directory to check in (string)
1379 @param shortcut flag indicating a shortcut should be taken (boolean) 1424 @param shortcut flag indicating a shortcut should be taken (boolean)
1380 @return the received dictionary completed with a combination of 1425 @return the received dictionary completed with a combination of
1385 else: 1430 else:
1386 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut) 1431 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut)
1387 1432
1388 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True): 1433 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True):
1389 """ 1434 """
1390 Private method used to get the registered states of a number of files in the vcs. 1435 Private method used to get the registered states of a number of files
1391 1436 in the vcs.
1392 This is the variant for subversion installations using the new working copy 1437
1393 meta-data format. 1438 This is the variant for subversion installations using the new working
1394 1439 copy meta-data format.
1395 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1440
1396 directory has been scanned already. If so, it is assumed, that the states for 1441 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1397 all files has been populated by the previous run. 1442 if the named directory has been scanned already. If so, it is assumed,
1443 that the states for all files has been populated by the previous run.
1398 1444
1399 @param names dictionary with all filenames to be checked as keys 1445 @param names dictionary with all filenames to be checked as keys
1400 @param dname directory to check in (string) 1446 @param dname directory to check in (string)
1401 @param shortcut flag indicating a shortcut should be taken (boolean) 1447 @param shortcut flag indicating a shortcut should be taken (boolean)
1402 @return the received dictionary completed with a combination of 1448 @return the received dictionary completed with a combination of
1462 1508
1463 return names 1509 return names
1464 1510
1465 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True): 1511 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True):
1466 """ 1512 """
1467 Private method used to get the registered states of a number of files in the vcs. 1513 Private method used to get the registered states of a number of files
1468 1514 in the VCS.
1469 This is the variant for subversion installations using the old working copy 1515
1470 meta-data format. 1516 This is the variant for subversion installations using the old working
1471 1517 copy meta-data format.
1472 <b>Note:</b> If a shortcut is to be taken, the code will only check, if the named 1518
1473 directory has been scanned already. If so, it is assumed, that the states for 1519 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1474 all files has been populated by the previous run. 1520 if the named directory has been scanned already. If so, it is assumed,
1521 that the states for all files has been populated by the previous run.
1475 1522
1476 @param names dictionary with all filenames to be checked as keys 1523 @param names dictionary with all filenames to be checked as keys
1477 @param dname directory to check in (string) 1524 @param dname directory to check in (string)
1478 @param shortcut flag indicating a shortcut should be taken (boolean) 1525 @param shortcut flag indicating a shortcut should be taken (boolean)
1479 @return the received dictionary completed with a combination of 1526 @return the received dictionary completed with a combination of
1528 1575
1529 def vcsInitConfig(self, project): 1576 def vcsInitConfig(self, project):
1530 """ 1577 """
1531 Public method to initialize the VCS configuration. 1578 Public method to initialize the VCS configuration.
1532 1579
1533 This method ensures, that eric specific files and directories are ignored. 1580 This method ensures, that eric specific files and directories are
1581 ignored.
1534 1582
1535 @param project reference to the project (Project) 1583 @param project reference to the project (Project)
1536 """ 1584 """
1537 configPath = getConfigPath() 1585 configPath = getConfigPath()
1538 if os.path.exists(configPath): 1586 if os.path.exists(configPath):
1662 ".".join([str(v) for v in pysvn.svn_version[:3]]), 1710 ".".join([str(v) for v in pysvn.svn_version[:3]]),
1663 apiVersion, 1711 apiVersion,
1664 entry.url, 1712 entry.url,
1665 entry.revision.number, 1713 entry.revision.number,
1666 entry.commit_revision.number, 1714 entry.commit_revision.number,
1667 time.strftime("%Y-%m-%d", time.localtime(entry.commit_time)), 1715 time.strftime(
1668 time.strftime("%H:%M:%S %Z", time.localtime(entry.commit_time)), 1716 "%Y-%m-%d", time.localtime(entry.commit_time)),
1717 time.strftime(
1718 "%H:%M:%S %Z", time.localtime(entry.commit_time)),
1669 entry.commit_author 1719 entry.commit_author
1670 ) 1720 )
1671 1721
1672 ############################################################################ 1722 ###########################################################################
1673 ## Public Subversion specific methods are below. 1723 ## Public Subversion specific methods are below.
1674 ############################################################################ 1724 ###########################################################################
1675 1725
1676 def svnGetReposName(self, path): 1726 def svnGetReposName(self, path):
1677 """ 1727 """
1678 Public method used to retrieve the URL of the subversion repository path. 1728 Public method used to retrieve the URL of the subversion repository
1729 path.
1679 1730
1680 @param path local path to get the svn repository path for (string) 1731 @param path local path to get the svn repository path for (string)
1681 @return string with the repository path URL 1732 @return string with the repository path URL
1682 """ 1733 """
1683 client = pysvn.Client() 1734 client = pysvn.Client()
1800 if dlg.exec_() == QDialog.Accepted: 1851 if dlg.exec_() == QDialog.Accepted:
1801 propName, propValue, recurse = dlg.getData() 1852 propName, propValue, recurse = dlg.getData()
1802 if not propName: 1853 if not propName:
1803 E5MessageBox.critical(self.__ui, 1854 E5MessageBox.critical(self.__ui,
1804 self.trUtf8("Subversion Set Property"), 1855 self.trUtf8("Subversion Set Property"),
1805 self.trUtf8("""You have to supply a property name. Aborting.""")) 1856 self.trUtf8(
1857 """You have to supply a property name. Aborting."""))
1806 return 1858 return
1807 1859
1808 if isinstance(name, list): 1860 if isinstance(name, list):
1809 dname, fnames = self.splitPathList(name) 1861 dname, fnames = self.splitPathList(name)
1810 else: 1862 else:
1852 propName, recurse = dlg.getData() 1904 propName, recurse = dlg.getData()
1853 1905
1854 if not propName: 1906 if not propName:
1855 E5MessageBox.critical(self.__ui, 1907 E5MessageBox.critical(self.__ui,
1856 self.trUtf8("Subversion Delete Property"), 1908 self.trUtf8("Subversion Delete Property"),
1857 self.trUtf8("""You have to supply a property name. Aborting.""")) 1909 self.trUtf8(
1910 """You have to supply a property name. Aborting."""))
1858 return 1911 return
1859 1912
1860 if isinstance(name, list): 1913 if isinstance(name, list):
1861 dname, fnames = self.splitPathList(name) 1914 dname, fnames = self.splitPathList(name)
1862 else: 1915 else:
1905 res = self.tagbranchList.start(path, tags) 1958 res = self.tagbranchList.start(path, tags)
1906 if res: 1959 if res:
1907 if tags: 1960 if tags:
1908 self.tagsList = self.tagbranchList.getTagList() 1961 self.tagsList = self.tagbranchList.getTagList()
1909 if not self.showedTags: 1962 if not self.showedTags:
1910 self.allTagsBranchesList = self.allTagsBranchesList + self.tagsList 1963 self.allTagsBranchesList = \
1964 self.allTagsBranchesList + self.tagsList
1911 self.showedTags = True 1965 self.showedTags = True
1912 elif not tags: 1966 elif not tags:
1913 self.branchesList = self.tagbranchList.getTagList() 1967 self.branchesList = self.tagbranchList.getTagList()
1914 if not self.showedBranches: 1968 if not self.showedBranches:
1915 self.allTagsBranchesList = self.allTagsBranchesList + self.branchesList 1969 self.allTagsBranchesList = \
1970 self.allTagsBranchesList + self.branchesList
1916 self.showedBranches = True 1971 self.showedBranches = True
1917 1972
1918 def svnBlame(self, name): 1973 def svnBlame(self, name):
1919 """ 1974 """
1920 Public method to show the output of the svn blame command. 1975 Public method to show the output of the svn blame command.
1931 """ 1986 """
1932 Public method used to view the difference of a file/directory to the 1987 Public method used to view the difference of a file/directory to the
1933 Subversion repository. 1988 Subversion repository.
1934 1989
1935 If name is a directory and is the project directory, all project files 1990 If name is a directory and is the project directory, all project files
1936 are saved first. If name is a file (or list of files), which is/are being edited 1991 are saved first. If name is a file (or list of files), which is/are
1937 and has unsaved modification, they can be saved or the operation may be aborted. 1992 being edited and has unsaved modification, they can be saved or the
1993 operation may be aborted.
1938 1994
1939 This method gives the chance to enter the revisions to be compared. 1995 This method gives the chance to enter the revisions to be compared.
1940 1996
1941 @param name file/directory name to be diffed (string) 1997 @param name file/directory name to be diffed (string)
1942 """ 1998 """
1967 """ 2023 """
1968 Public method used to view the difference of a file/directory of two 2024 Public method used to view the difference of a file/directory of two
1969 repository URLs. 2025 repository URLs.
1970 2026
1971 If name is a directory and is the project directory, all project files 2027 If name is a directory and is the project directory, all project files
1972 are saved first. If name is a file (or list of files), which is/are being edited 2028 are saved first. If name is a file (or list of files), which is/are
1973 and has unsaved modification, they can be saved or the operation may be aborted. 2029 being edited and has unsaved modification, they can be saved or the
2030 operation may be aborted.
1974 2031
1975 This method gives the chance to enter the revisions to be compared. 2032 This method gives the chance to enter the revisions to be compared.
1976 2033
1977 @param name file/directory name to be diffed (string) 2034 @param name file/directory name to be diffed (string)
1978 """ 2035 """
1991 return 2048 return
1992 2049
1993 dname = self.splitPath(names[0])[0] 2050 dname = self.splitPath(names[0])[0]
1994 2051
1995 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog 2052 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog
1996 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList, dname) 2053 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList,
2054 dname)
1997 if dlg.exec_() == QDialog.Accepted: 2055 if dlg.exec_() == QDialog.Accepted:
1998 urls, summary = dlg.getURLs() 2056 urls, summary = dlg.getURLs()
1999 from .SvnDiffDialog import SvnDiffDialog 2057 from .SvnDiffDialog import SvnDiffDialog
2000 self.diff = SvnDiffDialog(self) 2058 self.diff = SvnDiffDialog(self)
2001 self.diff.show() 2059 self.diff.show()
2002 QApplication.processEvents() 2060 QApplication.processEvents()
2003 self.diff.start(name, urls=urls, summary=summary) 2061 self.diff.start(name, urls=urls, summary=summary)
2004 2062
2005 def __svnGetFileForRevision(self, name, rev=""): 2063 def __svnGetFileForRevision(self, name, rev=""):
2006 """ 2064 """
2007 Private method to get a file for a specific revision from the repository. 2065 Private method to get a file for a specific revision from the
2066 repository.
2008 2067
2009 @param name file name to get from the repository (string) 2068 @param name file name to get from the repository (string)
2010 @keyparam rev revision to retrieve (integer or string) 2069 @keyparam rev revision to retrieve (integer or string)
2011 @return contents of the file (string) and an error message (string) 2070 @return contents of the file (string) and an error message (string)
2012 """ 2071 """
2015 2074
2016 client = self.getClient() 2075 client = self.getClient()
2017 try: 2076 try:
2018 if rev: 2077 if rev:
2019 if isinstance(rev, int) or rev.isdecimal(): 2078 if isinstance(rev, int) or rev.isdecimal():
2020 rev = pysvn.Revision(pysvn.opt_revision_kind.number, int(rev)) 2079 rev = pysvn.Revision(
2080 pysvn.opt_revision_kind.number, int(rev))
2021 elif rev.startswith("{"): 2081 elif rev.startswith("{"):
2022 dateStr = rev[1:-1] 2082 dateStr = rev[1:-1]
2023 secs = QDateTime.fromString(dateStr, Qt.ISODate).toTime_t() 2083 secs = QDateTime.fromString(dateStr, Qt.ISODate).toTime_t()
2024 rev = pysvn.Revision(pysvn.opt_revision_kind.date, secs) 2084 rev = pysvn.Revision(pysvn.opt_revision_kind.date, secs)
2025 elif rev == "HEAD": 2085 elif rev == "HEAD":
2093 f1.close() 2153 f1.close()
2094 name2 = name 2154 name2 = name
2095 except IOError: 2155 except IOError:
2096 E5MessageBox.critical(self.__ui, 2156 E5MessageBox.critical(self.__ui,
2097 self.trUtf8("Subversion Side-by-Side Difference"), 2157 self.trUtf8("Subversion Side-by-Side Difference"),
2098 self.trUtf8("""<p>The file <b>{0}</b> could not be read.</p>""") 2158 self.trUtf8(
2159 """<p>The file <b>{0}</b> could not be read.</p>""")
2099 .format(name)) 2160 .format(name))
2100 return 2161 return
2101 2162
2102 if self.sbsDiff is None: 2163 if self.sbsDiff is None:
2103 from UI.CompareDialog import CompareDialog 2164 from UI.CompareDialog import CompareDialog
2121 2182
2122 def svnLock(self, name, stealIt=False, parent=None): 2183 def svnLock(self, name, stealIt=False, parent=None):
2123 """ 2184 """
2124 Public method used to lock a file in the Subversion repository. 2185 Public method used to lock a file in the Subversion repository.
2125 2186
2126 @param name file/directory name to be locked (string or list of strings) 2187 @param name file/directory name to be locked (string or list of
2188 strings)
2127 @param stealIt flag indicating a forced operation (boolean) 2189 @param stealIt flag indicating a forced operation (boolean)
2128 @param parent reference to the parent object of the subversion dialog (QWidget) 2190 @param parent reference to the parent object of the subversion dialog
2191 (QWidget)
2129 """ 2192 """
2130 comment, ok = QInputDialog.getText( 2193 comment, ok = QInputDialog.getText(
2131 None, 2194 None,
2132 self.trUtf8("Subversion Lock"), 2195 self.trUtf8("Subversion Lock"),
2133 self.trUtf8("Enter lock comment"), 2196 self.trUtf8("Enter lock comment"),
2168 2231
2169 def svnUnlock(self, name, breakIt=False, parent=None): 2232 def svnUnlock(self, name, breakIt=False, parent=None):
2170 """ 2233 """
2171 Public method used to unlock a file in the Subversion repository. 2234 Public method used to unlock a file in the Subversion repository.
2172 2235
2173 @param name file/directory name to be unlocked (string or list of strings) 2236 @param name file/directory name to be unlocked (string or list of
2237 strings)
2174 @param breakIt flag indicating a forced operation (boolean) 2238 @param breakIt flag indicating a forced operation (boolean)
2175 @param parent reference to the parent object of the subversion dialog (QWidget) 2239 @param parent reference to the parent object of the subversion dialog
2240 (QWidget)
2176 """ 2241 """
2177 if isinstance(name, list): 2242 if isinstance(name, list):
2178 dname, fnames = self.splitPathList(name) 2243 dname, fnames = self.splitPathList(name)
2179 else: 2244 else:
2180 dname, fname = self.splitPath(name) 2245 dname, fname = self.splitPath(name)
2227 if dlg.exec_() == QDialog.Accepted: 2292 if dlg.exec_() == QDialog.Accepted:
2228 newUrl, inside = dlg.getData() 2293 newUrl, inside = dlg.getData()
2229 if inside: 2294 if inside:
2230 msg = "switch {0} {1}".format(newUrl, projectPath) 2295 msg = "switch {0} {1}".format(newUrl, projectPath)
2231 else: 2296 else:
2232 msg = "relocate {0} {1} {2}".format(currUrl, newUrl, projectPath) 2297 msg = "relocate {0} {1} {2}".format(currUrl, newUrl,
2298 projectPath)
2233 client = self.getClient() 2299 client = self.getClient()
2234 dlg = \ 2300 dlg = \
2235 SvnDialog(self.trUtf8('Relocating'), msg, client) 2301 SvnDialog(self.trUtf8('Relocating'), msg, client)
2236 QApplication.processEvents() 2302 QApplication.processEvents()
2237 locker = QMutexLocker(self.vcsExecutionMutex) 2303 locker = QMutexLocker(self.vcsExecutionMutex)
2325 client) 2391 client)
2326 QApplication.processEvents() 2392 QApplication.processEvents()
2327 locker = QMutexLocker(self.vcsExecutionMutex) 2393 locker = QMutexLocker(self.vcsExecutionMutex)
2328 try: 2394 try:
2329 for name in names: 2395 for name in names:
2330 client.add_to_changelist(name, clname, depth=pysvn.depth.infinity) 2396 client.add_to_changelist(name, clname,
2397 depth=pysvn.depth.infinity)
2331 except pysvn.ClientError as e: 2398 except pysvn.ClientError as e:
2332 dlg.showError(e.args[0]) 2399 dlg.showError(e.args[0])
2333 locker.unlock() 2400 locker.unlock()
2334 dlg.finish() 2401 dlg.finish()
2335 dlg.exec_() 2402 dlg.exec_()
2356 client = self.getClient() 2423 client = self.getClient()
2357 if hasattr(client, 'get_changelist'): 2424 if hasattr(client, 'get_changelist'):
2358 ppath = e5App().getObject("Project").getProjectPath() 2425 ppath = e5App().getObject("Project").getProjectPath()
2359 locker = QMutexLocker(self.vcsExecutionMutex) 2426 locker = QMutexLocker(self.vcsExecutionMutex)
2360 try: 2427 try:
2361 entries = client.get_changelist(ppath, depth=pysvn.depth.infinity) 2428 entries = client.get_changelist(ppath,
2429 depth=pysvn.depth.infinity)
2362 for entry in entries: 2430 for entry in entries:
2363 changelist = entry[1] 2431 changelist = entry[1]
2364 if changelist not in changelists: 2432 if changelist not in changelists:
2365 changelists.append(changelist) 2433 changelists.append(changelist)
2366 except pysvn.ClientError: 2434 except pysvn.ClientError:
2367 pass 2435 pass
2368 locker.unlock() 2436 locker.unlock()
2369 2437
2370 return changelists 2438 return changelists
2371 2439
2372 ############################################################################ 2440 ###########################################################################
2373 ## Private Subversion specific methods are below. 2441 ## Private Subversion specific methods are below.
2374 ############################################################################ 2442 ###########################################################################
2375 2443
2376 def __svnURL(self, url): 2444 def __svnURL(self, url):
2377 """ 2445 """
2378 Private method to format a url for subversion. 2446 Private method to format a url for subversion.
2379 2447
2384 url = url.split(':', 2) 2452 url = url.split(':', 2)
2385 if len(url) == 3: 2453 if len(url) == 3:
2386 scheme = url[0] 2454 scheme = url[0]
2387 host = url[1] 2455 host = url[1]
2388 port, path = url[2].split("/", 1) 2456 port, path = url[2].split("/", 1)
2389 return "{0}:{1}:{2}/{3}".format(scheme, host, port, urllib.parse.quote(path)) 2457 return "{0}:{1}:{2}/{3}".format(scheme, host, port,
2458 urllib.parse.quote(path))
2390 else: 2459 else:
2391 scheme = url[0] 2460 scheme = url[0]
2392 if scheme == "file": 2461 if scheme == "file":
2393 return "{0}:{1}".format(scheme, urllib.parse.quote(url[1])) 2462 return "{0}:{1}".format(scheme, urllib.parse.quote(url[1]))
2394 else: 2463 else:
2395 try: 2464 try:
2396 host, path = url[1][2:].split("/", 1) 2465 host, path = url[1][2:].split("/", 1)
2397 except ValueError: 2466 except ValueError:
2398 host = url[1][2:] 2467 host = url[1][2:]
2399 path = "" 2468 path = ""
2400 return "{0}://{1}/{2}".format(scheme, host, urllib.parse.quote(path)) 2469 return "{0}://{1}/{2}".format(scheme, host,
2470 urllib.parse.quote(path))
2401 2471
2402 def svnNormalizeURL(self, url): 2472 def svnNormalizeURL(self, url):
2403 """ 2473 """
2404 Public method to normalize a url for subversion. 2474 Public method to normalize a url for subversion.
2405 2475
2418 url = url[:-1] 2488 url = url[:-1]
2419 if not url.startswith("/") and url[1] in [":", "|"]: 2489 if not url.startswith("/") and url[1] in [":", "|"]:
2420 url = "/{0}".format(url) 2490 url = "/{0}".format(url)
2421 return "{0}://{1}".format(protocol, url) 2491 return "{0}://{1}".format(protocol, url)
2422 2492
2423 ############################################################################ 2493 ###########################################################################
2424 ## Methods to get the helper objects are below. 2494 ## Methods to get the helper objects are below.
2425 ############################################################################ 2495 ###########################################################################
2426 2496
2427 def vcsGetProjectBrowserHelper(self, browser, project, isTranslationsBrowser=False): 2497 def vcsGetProjectBrowserHelper(self, browser, project,
2428 """ 2498 isTranslationsBrowser=False):
2429 Public method to instanciate a helper object for the different project browsers. 2499 """
2500 Public method to instanciate a helper object for the different
2501 project browsers.
2430 2502
2431 @param browser reference to the project browser object 2503 @param browser reference to the project browser object
2432 @param project reference to the project object 2504 @param project reference to the project object
2433 @param isTranslationsBrowser flag indicating, the helper is requested for the 2505 @param isTranslationsBrowser flag indicating, the helper is requested
2434 translations browser (this needs some special treatment) 2506 for the translations browser (this needs some special treatment)
2435 @return the project browser helper object 2507 @return the project browser helper object
2436 """ 2508 """
2437 from .ProjectBrowserHelper import SvnProjectBrowserHelper 2509 from .ProjectBrowserHelper import SvnProjectBrowserHelper
2438 return SvnProjectBrowserHelper(self, browser, project, isTranslationsBrowser) 2510 return SvnProjectBrowserHelper(self, browser, project,
2511 isTranslationsBrowser)
2439 2512
2440 def vcsGetProjectHelper(self, project): 2513 def vcsGetProjectHelper(self, project):
2441 """ 2514 """
2442 Public method to instanciate a helper object for the project. 2515 Public method to instanciate a helper object for the project.
2443 2516
2445 @return the project helper object 2518 @return the project helper object
2446 """ 2519 """
2447 helper = self.__plugin.getProjectHelper() 2520 helper = self.__plugin.getProjectHelper()
2448 helper.setObjects(self, project) 2521 helper.setObjects(self, project)
2449 self.__wcng = \ 2522 self.__wcng = \
2450 os.path.exists(os.path.join(project.getProjectPath(), ".svn", "format")) or \ 2523 os.path.exists(
2451 os.path.exists(os.path.join(project.getProjectPath(), "_svn", "format")) 2524 os.path.join(project.getProjectPath(), ".svn", "format")) or \
2525 os.path.exists(
2526 os.path.join(project.getProjectPath(), "_svn", "format"))
2452 return helper 2527 return helper
2453 2528
2454 ############################################################################ 2529 ###########################################################################
2455 ## Status Monitor Thread methods 2530 ## Status Monitor Thread methods
2456 ############################################################################ 2531 ###########################################################################
2457 2532
2458 def _createStatusMonitorThread(self, interval, project): 2533 def _createStatusMonitorThread(self, interval, project):
2459 """ 2534 """
2460 Protected method to create an instance of the VCS status monitor 2535 Protected method to create an instance of the VCS status monitor
2461 thread. 2536 thread.

eric ide

mercurial