src/eric7/Plugins/VcsPlugins/vcsPySvn/subversion.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9278
36448ca469c2
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
34 34
35 35
36 class Subversion(VersionControl): 36 class Subversion(VersionControl):
37 """ 37 """
38 Class implementing the version control systems interface to Subversion. 38 Class implementing the version control systems interface to Subversion.
39 39
40 @signal committed() emitted after the commit action has completed 40 @signal committed() emitted after the commit action has completed
41 """ 41 """
42
42 committed = pyqtSignal() 43 committed = pyqtSignal()
43 44
44 def __init__(self, plugin, parent=None, name=None): 45 def __init__(self, plugin, parent=None, name=None):
45 """ 46 """
46 Constructor 47 Constructor
47 48
48 @param plugin reference to the plugin object 49 @param plugin reference to the plugin object
49 @param parent parent widget (QWidget) 50 @param parent parent widget (QWidget)
50 @param name name of this object (string) 51 @param name name of this object (string)
51 """ 52 """
52 VersionControl.__init__(self, parent, name) 53 VersionControl.__init__(self, parent, name)
53 self.defaultOptions = { 54 self.defaultOptions = {
54 'global': [''], 55 "global": [""],
55 'commit': [''], 56 "commit": [""],
56 'checkout': [''], 57 "checkout": [""],
57 'update': [''], 58 "update": [""],
58 'add': [''], 59 "add": [""],
59 'remove': [''], 60 "remove": [""],
60 'diff': [''], 61 "diff": [""],
61 'log': [''], 62 "log": [""],
62 'history': [''], 63 "history": [""],
63 'status': [''], 64 "status": [""],
64 'tag': [''], 65 "tag": [""],
65 'export': [''] 66 "export": [""],
66 } 67 }
67 self.interestingDataKeys = [ 68 self.interestingDataKeys = [
68 "standardLayout", 69 "standardLayout",
69 ] 70 ]
70 71
71 self.__plugin = plugin 72 self.__plugin = plugin
72 self.__ui = parent 73 self.__ui = parent
73 74
74 self.options = self.defaultOptions 75 self.options = self.defaultOptions
75 self.otherData["standardLayout"] = True 76 self.otherData["standardLayout"] = True
76 self.tagsList = [] 77 self.tagsList = []
77 self.branchesList = [] 78 self.branchesList = []
78 self.allTagsBranchesList = [] 79 self.allTagsBranchesList = []
79 self.mergeList = [[], [], []] 80 self.mergeList = [[], [], []]
80 self.showedTags = False 81 self.showedTags = False
81 self.showedBranches = False 82 self.showedBranches = False
82 83
83 self.tagTypeList = [ 84 self.tagTypeList = ["tags", "branches"]
84 'tags', 85
85 'branches'
86 ]
87
88 self.commandHistory = [] 86 self.commandHistory = []
89 self.wdHistory = [] 87 self.wdHistory = []
90 88
91 if ( 89 if pysvn.version >= (1, 4, 3, 0) and "SVN_ASP_DOT_NET_HACK" in os.environ:
92 pysvn.version >= (1, 4, 3, 0) and 90 self.adminDir = "_svn"
93 "SVN_ASP_DOT_NET_HACK" in os.environ 91 else:
94 ): 92 self.adminDir = ".svn"
95 self.adminDir = '_svn' 93
96 else:
97 self.adminDir = '.svn'
98
99 self.log = None 94 self.log = None
100 self.diff = None 95 self.diff = None
101 self.sbsDiff = None 96 self.sbsDiff = None
102 self.status = None 97 self.status = None
103 self.propList = None 98 self.propList = None
104 self.tagbranchList = None 99 self.tagbranchList = None
105 self.blame = None 100 self.blame = None
106 self.repoBrowser = None 101 self.repoBrowser = None
107 self.logBrowser = None 102 self.logBrowser = None
108 103
109 self.statusCache = {} 104 self.statusCache = {}
110 105
111 self.__commitData = {} 106 self.__commitData = {}
112 self.__commitDialog = None 107 self.__commitDialog = None
113 108
114 self.__wcng = True 109 self.__wcng = True
115 # assume new generation working copy metadata format 110 # assume new generation working copy metadata format
116 111
117 def getPlugin(self): 112 def getPlugin(self):
118 """ 113 """
119 Public method to get a reference to the plugin object. 114 Public method to get a reference to the plugin object.
120 115
121 @return reference to the plugin object (VcsPySvnPlugin) 116 @return reference to the plugin object (VcsPySvnPlugin)
122 """ 117 """
123 return self.__plugin 118 return self.__plugin
124 119
125 def getClient(self): 120 def getClient(self):
126 """ 121 """
127 Public method to create and initialize the pysvn client object. 122 Public method to create and initialize the pysvn client object.
128 123
129 @return the pysvn client object (pysvn.Client) 124 @return the pysvn client object (pysvn.Client)
130 """ 125 """
131 configDir = "" 126 configDir = ""
132 authCache = True 127 authCache = True
133 for arg in self.options['global']: 128 for arg in self.options["global"]:
134 if arg.startswith("--config-dir"): 129 if arg.startswith("--config-dir"):
135 configDir = arg.split("=", 1)[1] 130 configDir = arg.split("=", 1)[1]
136 if arg.startswith("--no-auth-cache"): 131 if arg.startswith("--no-auth-cache"):
137 authCache = False 132 authCache = False
138 133
139 client = pysvn.Client(configDir) 134 client = pysvn.Client(configDir)
140 client.exception_style = 1 135 client.exception_style = 1
141 client.set_auth_cache(authCache) 136 client.set_auth_cache(authCache)
142 137
143 return client 138 return client
144 139
145 ########################################################################### 140 ###########################################################################
146 ## Methods of the VCS interface 141 ## Methods of the VCS interface
147 ########################################################################### 142 ###########################################################################
148 143
149 def vcsShutdown(self): 144 def vcsShutdown(self):
150 """ 145 """
151 Public method used to shutdown the Subversion interface. 146 Public method used to shutdown the Subversion interface.
152 """ 147 """
153 if self.log is not None: 148 if self.log is not None:
166 self.blame.close() 161 self.blame.close()
167 if self.repoBrowser is not None: 162 if self.repoBrowser is not None:
168 self.repoBrowser.close() 163 self.repoBrowser.close()
169 if self.logBrowser is not None: 164 if self.logBrowser is not None:
170 self.logBrowser.close() 165 self.logBrowser.close()
171 166
172 def vcsExists(self): 167 def vcsExists(self):
173 """ 168 """
174 Public method used to test for the presence of the svn executable. 169 Public method used to test for the presence of the svn executable.
175 170
176 @return flag indicating the existance (boolean) and an error message 171 @return flag indicating the existance (boolean) and an error message
177 (string) 172 (string)
178 """ 173 """
179 self.versionStr = ".".join([str(v) for v in pysvn.svn_version[:-1]]) 174 self.versionStr = ".".join([str(v) for v in pysvn.svn_version[:-1]])
180 self.version = pysvn.svn_version[:-1] 175 self.version = pysvn.svn_version[:-1]
181 return True, "" 176 return True, ""
182 177
183 def vcsInit(self, vcsDir, noDialog=False): 178 def vcsInit(self, vcsDir, noDialog=False):
184 """ 179 """
185 Public method used to initialize the subversion repository. 180 Public method used to initialize the subversion repository.
186 181
187 The subversion repository has to be initialized from outside eric 182 The subversion repository has to be initialized from outside eric
188 because the respective command always works locally. Therefore we 183 because the respective command always works locally. Therefore we
189 always return TRUE without doing anything. 184 always return TRUE without doing anything.
190 185
191 @param vcsDir name of the VCS directory (string) 186 @param vcsDir name of the VCS directory (string)
192 @param noDialog flag indicating quiet operations (boolean) 187 @param noDialog flag indicating quiet operations (boolean)
193 @return always TRUE 188 @return always TRUE
194 """ 189 """
195 return True 190 return True
196 191
197 def vcsConvertProject(self, vcsDataDict, project, addAll=True): 192 def vcsConvertProject(self, vcsDataDict, project, addAll=True):
198 """ 193 """
199 Public method to convert an uncontrolled project to a version 194 Public method to convert an uncontrolled project to a version
200 controlled project. 195 controlled project.
201 196
202 @param vcsDataDict dictionary of data required for the conversion 197 @param vcsDataDict dictionary of data required for the conversion
203 @type dict 198 @type dict
204 @param project reference to the project object 199 @param project reference to the project object
205 @type Project 200 @type Project
206 @param addAll flag indicating to add all files to the repository 201 @param addAll flag indicating to add all files to the repository
212 self.__ui, 207 self.__ui,
213 self.tr("Create project in repository"), 208 self.tr("Create project in repository"),
214 self.tr( 209 self.tr(
215 """The project could not be created in the repository.""" 210 """The project could not be created in the repository."""
216 """ Maybe the given repository doesn't exist or the""" 211 """ Maybe the given repository doesn't exist or the"""
217 """ repository server is down.""")) 212 """ repository server is down."""
213 ),
214 )
218 else: 215 else:
219 cwdIsPpath = False 216 cwdIsPpath = False
220 if os.getcwd() == project.ppath: 217 if os.getcwd() == project.ppath:
221 os.chdir(os.path.dirname(project.ppath)) 218 os.chdir(os.path.dirname(project.ppath))
222 cwdIsPpath = True 219 cwdIsPpath = True
236 self.__ui, 233 self.__ui,
237 self.tr("New project"), 234 self.tr("New project"),
238 self.tr( 235 self.tr(
239 """The project could not be checked out of the""" 236 """The project could not be checked out of the"""
240 """ repository.<br />""" 237 """ repository.<br />"""
241 """Restoring the original contents.""")) 238 """Restoring the original contents."""
239 ),
240 )
242 if os.getcwd() == project.ppath: 241 if os.getcwd() == project.ppath:
243 os.chdir(os.path.dirname(project.ppath)) 242 os.chdir(os.path.dirname(project.ppath))
244 cwdIsPpath = True 243 cwdIsPpath = True
245 else: 244 else:
246 cwdIsPpath = False 245 cwdIsPpath = False
247 shutil.rmtree(project.ppath, True) 246 shutil.rmtree(project.ppath, True)
248 os.rename(tmpProjectDir, project.ppath) 247 os.rename(tmpProjectDir, project.ppath)
249 project.pdata["VCS"] = 'None' 248 project.pdata["VCS"] = "None"
250 project.vcs = None 249 project.vcs = None
251 project.setDirty(True) 250 project.setDirty(True)
252 project.saveProject() 251 project.saveProject()
253 project.closeProject() 252 project.closeProject()
254 return 253 return
255 shutil.rmtree(tmpProjectDir, True) 254 shutil.rmtree(tmpProjectDir, True)
256 project.closeProject(noSave=True) 255 project.closeProject(noSave=True)
257 project.openProject(pfn) 256 project.openProject(pfn)
258 257
259 def vcsImport(self, vcsDataDict, projectDir, noDialog=False, addAll=True): 258 def vcsImport(self, vcsDataDict, projectDir, noDialog=False, addAll=True):
260 """ 259 """
261 Public method used to import the project into the Subversion 260 Public method used to import the project into the Subversion
262 repository. 261 repository.
263 262
264 @param vcsDataDict dictionary of data required for the import 263 @param vcsDataDict dictionary of data required for the import
265 @type dict 264 @type dict
266 @param projectDir project directory (string) 265 @param projectDir project directory (string)
267 @type str 266 @type str
268 @param noDialog flag indicating quiet operations 267 @param noDialog flag indicating quiet operations
274 @rtype tuple of (bool, bool) 273 @rtype tuple of (bool, bool)
275 """ 274 """
276 noDialog = False 275 noDialog = False
277 msg = vcsDataDict["message"] 276 msg = vcsDataDict["message"]
278 if not msg: 277 if not msg:
279 msg = '***' 278 msg = "***"
280 279
281 vcsDir = self.svnNormalizeURL(vcsDataDict["url"]) 280 vcsDir = self.svnNormalizeURL(vcsDataDict["url"])
282 if vcsDir.startswith('/'): 281 if vcsDir.startswith("/"):
283 vcsDir = 'file://{0}'.format(vcsDir) 282 vcsDir = "file://{0}".format(vcsDir)
284 elif vcsDir[1] in ['|', ':']: 283 elif vcsDir[1] in ["|", ":"]:
285 vcsDir = 'file:///{0}'.format(vcsDir) 284 vcsDir = "file:///{0}".format(vcsDir)
286 285
287 project = vcsDir[vcsDir.rfind('/') + 1:] 286 project = vcsDir[vcsDir.rfind("/") + 1 :]
288 287
289 # create the dir structure to be imported into the repository 288 # create the dir structure to be imported into the repository
290 tmpDir = '{0}_tmp'.format(projectDir) 289 tmpDir = "{0}_tmp".format(projectDir)
291 try: 290 try:
292 os.makedirs(tmpDir) 291 os.makedirs(tmpDir)
293 if self.otherData["standardLayout"]: 292 if self.otherData["standardLayout"]:
294 os.mkdir(os.path.join(tmpDir, project)) 293 os.mkdir(os.path.join(tmpDir, project))
295 os.mkdir(os.path.join(tmpDir, project, 'branches')) 294 os.mkdir(os.path.join(tmpDir, project, "branches"))
296 os.mkdir(os.path.join(tmpDir, project, 'tags')) 295 os.mkdir(os.path.join(tmpDir, project, "tags"))
297 shutil.copytree( 296 shutil.copytree(projectDir, os.path.join(tmpDir, project, "trunk"))
298 projectDir, os.path.join(tmpDir, project, 'trunk'))
299 else: 297 else:
300 shutil.copytree(projectDir, os.path.join(tmpDir, project)) 298 shutil.copytree(projectDir, os.path.join(tmpDir, project))
301 except OSError: 299 except OSError:
302 if os.path.isdir(tmpDir): 300 if os.path.isdir(tmpDir):
303 shutil.rmtree(tmpDir, True) 301 shutil.rmtree(tmpDir, True)
304 return False, False 302 return False, False
305 303
306 cwd = os.getcwd() 304 cwd = os.getcwd()
307 os.chdir(os.path.join(tmpDir, project)) 305 os.chdir(os.path.join(tmpDir, project))
308 opts = self.options['global'] 306 opts = self.options["global"]
309 recurse = "--non-recursive" not in opts 307 recurse = "--non-recursive" not in opts
310 url = self.__svnURL(vcsDir) 308 url = self.__svnURL(vcsDir)
311 client = self.getClient() 309 client = self.getClient()
312 if not noDialog: 310 if not noDialog:
313 dlg = SvnDialog( 311 dlg = SvnDialog(
314 self.tr('Importing project into Subversion repository'), 312 self.tr("Importing project into Subversion repository"),
315 "import{0} --message {1} .".format( 313 "import{0} --message {1} .".format(
316 (not recurse) and " --non-recursive" or "", msg), 314 (not recurse) and " --non-recursive" or "", msg
317 client) 315 ),
316 client,
317 )
318 QApplication.processEvents() 318 QApplication.processEvents()
319 try: 319 try:
320 with EricMutexLocker(self.vcsExecutionMutex): 320 with EricMutexLocker(self.vcsExecutionMutex):
321 rev = client.import_(".", url, msg, recurse, ignore=True) 321 rev = client.import_(".", url, msg, recurse, ignore=True)
322 status = True 322 status = True
324 status = False 324 status = False
325 rev = None 325 rev = None
326 if not noDialog: 326 if not noDialog:
327 dlg.showError(e.args[0]) 327 dlg.showError(e.args[0])
328 if not noDialog: 328 if not noDialog:
329 rev and dlg.showMessage(self.tr("Imported revision {0}.\n") 329 rev and dlg.showMessage(
330 .format(rev.number)) 330 self.tr("Imported revision {0}.\n").format(rev.number)
331 )
331 dlg.finish() 332 dlg.finish()
332 dlg.exec() 333 dlg.exec()
333 os.chdir(cwd) 334 os.chdir(cwd)
334 335
335 shutil.rmtree(tmpDir, True) 336 shutil.rmtree(tmpDir, True)
336 return status, False 337 return status, False
337 338
338 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False): 339 def vcsCheckout(self, vcsDataDict, projectDir, noDialog=False):
339 """ 340 """
340 Public method used to check the project out of the Subversion 341 Public method used to check the project out of the Subversion
341 repository. 342 repository.
342 343
343 @param vcsDataDict dictionary of data required for the checkout 344 @param vcsDataDict dictionary of data required for the checkout
344 @param projectDir project directory to create (string) 345 @param projectDir project directory to create (string)
345 @param noDialog flag indicating quiet operations 346 @param noDialog flag indicating quiet operations
346 @return flag indicating an execution without errors (boolean) 347 @return flag indicating an execution without errors (boolean)
347 """ 348 """
349 try: 350 try:
350 tag = vcsDataDict["tag"] 351 tag = vcsDataDict["tag"]
351 except KeyError: 352 except KeyError:
352 tag = None 353 tag = None
353 vcsDir = self.svnNormalizeURL(vcsDataDict["url"]) 354 vcsDir = self.svnNormalizeURL(vcsDataDict["url"])
354 if vcsDir.startswith('/'): 355 if vcsDir.startswith("/"):
355 vcsDir = 'file://{0}'.format(vcsDir) 356 vcsDir = "file://{0}".format(vcsDir)
356 elif vcsDir[1] in ['|', ':']: 357 elif vcsDir[1] in ["|", ":"]:
357 vcsDir = 'file:///{0}'.format(vcsDir) 358 vcsDir = "file:///{0}".format(vcsDir)
358 359
359 if self.otherData["standardLayout"]: 360 if self.otherData["standardLayout"]:
360 if tag is None or tag == '': 361 if tag is None or tag == "":
361 svnUrl = '{0}/trunk'.format(vcsDir) 362 svnUrl = "{0}/trunk".format(vcsDir)
362 else: 363 else:
363 if ( 364 if not tag.startswith("tags") and not tag.startswith("branches"):
364 not tag.startswith('tags') and
365 not tag.startswith('branches')
366 ):
367 type_, ok = QInputDialog.getItem( 365 type_, ok = QInputDialog.getItem(
368 None, 366 None,
369 self.tr("Subversion Checkout"), 367 self.tr("Subversion Checkout"),
370 self.tr( 368 self.tr(
371 "The tag must be a normal tag (tags) or" 369 "The tag must be a normal tag (tags) or"
372 " a branch tag (branches)." 370 " a branch tag (branches)."
373 " Please select from the list."), 371 " Please select from the list."
372 ),
374 self.tagTypeList, 373 self.tagTypeList,
375 0, False) 374 0,
375 False,
376 )
376 if not ok: 377 if not ok:
377 return False 378 return False
378 tag = '{0}/{1}'.format(type_, tag) 379 tag = "{0}/{1}".format(type_, tag)
379 svnUrl = '{0}/{1}'.format(vcsDir, tag) 380 svnUrl = "{0}/{1}".format(vcsDir, tag)
380 else: 381 else:
381 svnUrl = vcsDir 382 svnUrl = vcsDir
382 383
383 opts = self.options['global'] + self.options['checkout'] 384 opts = self.options["global"] + self.options["checkout"]
384 recurse = "--non-recursive" not in opts 385 recurse = "--non-recursive" not in opts
385 url = self.__svnURL(svnUrl) 386 url = self.__svnURL(svnUrl)
386 client = self.getClient() 387 client = self.getClient()
387 if not noDialog: 388 if not noDialog:
388 dlg = SvnDialog( 389 dlg = SvnDialog(
389 self.tr('Checking project out of Subversion repository'), 390 self.tr("Checking project out of Subversion repository"),
390 "checkout{0} {1} {2}".format( 391 "checkout{0} {1} {2}".format(
391 (not recurse) and " --non-recursive" or "", 392 (not recurse) and " --non-recursive" or "", url, projectDir
392 url, projectDir), 393 ),
393 client) 394 client,
395 )
394 QApplication.processEvents() 396 QApplication.processEvents()
395 try: 397 try:
396 with EricMutexLocker(self.vcsExecutionMutex): 398 with EricMutexLocker(self.vcsExecutionMutex):
397 client.checkout(url, projectDir, recurse) 399 client.checkout(url, projectDir, recurse)
398 status = True 400 status = True
402 dlg.showError(e.args[0]) 404 dlg.showError(e.args[0])
403 if not noDialog: 405 if not noDialog:
404 dlg.finish() 406 dlg.finish()
405 dlg.exec() 407 dlg.exec()
406 return status 408 return status
407 409
408 def vcsExport(self, vcsDataDict, projectDir): 410 def vcsExport(self, vcsDataDict, projectDir):
409 """ 411 """
410 Public method used to export a directory from the Subversion 412 Public method used to export a directory from the Subversion
411 repository. 413 repository.
412 414
413 @param vcsDataDict dictionary of data required for the checkout 415 @param vcsDataDict dictionary of data required for the checkout
414 @param projectDir project directory to create (string) 416 @param projectDir project directory to create (string)
415 @return flag indicating an execution without errors (boolean) 417 @return flag indicating an execution without errors (boolean)
416 """ 418 """
417 try: 419 try:
418 tag = vcsDataDict["tag"] 420 tag = vcsDataDict["tag"]
419 except KeyError: 421 except KeyError:
420 tag = None 422 tag = None
421 vcsDir = self.svnNormalizeURL(vcsDataDict["url"]) 423 vcsDir = self.svnNormalizeURL(vcsDataDict["url"])
422 if vcsDir.startswith('/') or vcsDir[1] == '|': 424 if vcsDir.startswith("/") or vcsDir[1] == "|":
423 vcsDir = 'file://{0}'.format(vcsDir) 425 vcsDir = "file://{0}".format(vcsDir)
424 426
425 if self.otherData["standardLayout"]: 427 if self.otherData["standardLayout"]:
426 if tag is None or tag == '': 428 if tag is None or tag == "":
427 svnUrl = '{0}/trunk'.format(vcsDir) 429 svnUrl = "{0}/trunk".format(vcsDir)
428 else: 430 else:
429 if ( 431 if not tag.startswith("tags") and not tag.startswith("branches"):
430 not tag.startswith('tags') and
431 not tag.startswith('branches')
432 ):
433 type_, ok = QInputDialog.getItem( 432 type_, ok = QInputDialog.getItem(
434 None, 433 None,
435 self.tr("Subversion Export"), 434 self.tr("Subversion Export"),
436 self.tr( 435 self.tr(
437 "The tag must be a normal tag (tags) or" 436 "The tag must be a normal tag (tags) or"
438 " a branch tag (branches)." 437 " a branch tag (branches)."
439 " Please select from the list."), 438 " Please select from the list."
439 ),
440 self.tagTypeList, 440 self.tagTypeList,
441 0, False) 441 0,
442 False,
443 )
442 if not ok: 444 if not ok:
443 return False 445 return False
444 tag = '{0}/{1}'.format(type_, tag) 446 tag = "{0}/{1}".format(type_, tag)
445 svnUrl = '{0}/{1}'.format(vcsDir, tag) 447 svnUrl = "{0}/{1}".format(vcsDir, tag)
446 else: 448 else:
447 svnUrl = vcsDir 449 svnUrl = vcsDir
448 450
449 opts = self.options['global'] 451 opts = self.options["global"]
450 recurse = "--non-recursive" not in opts 452 recurse = "--non-recursive" not in opts
451 url = self.__svnURL(svnUrl) 453 url = self.__svnURL(svnUrl)
452 client = self.getClient() 454 client = self.getClient()
453 dlg = SvnDialog( 455 dlg = SvnDialog(
454 self.tr('Exporting project from Subversion repository'), 456 self.tr("Exporting project from Subversion repository"),
455 "export --force{0} {1} {2}".format( 457 "export --force{0} {1} {2}".format(
456 (not recurse) and " --non-recursive" or "", 458 (not recurse) and " --non-recursive" or "", url, projectDir
457 url, projectDir), 459 ),
458 client) 460 client,
461 )
459 QApplication.processEvents() 462 QApplication.processEvents()
460 try: 463 try:
461 with EricMutexLocker(self.vcsExecutionMutex): 464 with EricMutexLocker(self.vcsExecutionMutex):
462 client.export(url, projectDir, force=True, recurse=recurse) 465 client.export(url, projectDir, force=True, recurse=recurse)
463 status = True 466 status = True
465 status = False 468 status = False
466 dlg.showError(e.args[0]) 469 dlg.showError(e.args[0])
467 dlg.finish() 470 dlg.finish()
468 dlg.exec() 471 dlg.exec()
469 return status 472 return status
470 473
471 def vcsCommit(self, name, message, noDialog=False): 474 def vcsCommit(self, name, message, noDialog=False):
472 """ 475 """
473 Public method used to make the change of a file/directory permanent 476 Public method used to make the change of a file/directory permanent
474 in the Subversion repository. 477 in the Subversion repository.
475 478
476 @param name file/directory name to be committed (string or 479 @param name file/directory name to be committed (string or
477 list of strings) 480 list of strings)
478 @param message message for this operation (string) 481 @param message message for this operation (string)
479 @param noDialog flag indicating quiet operations 482 @param noDialog flag indicating quiet operations
480 """ 483 """
481 if not noDialog and not message: 484 if not noDialog and not message:
482 # call CommitDialog and get message from there 485 # call CommitDialog and get message from there
483 if self.__commitDialog is None: 486 if self.__commitDialog is None:
484 from .SvnCommitDialog import SvnCommitDialog 487 from .SvnCommitDialog import SvnCommitDialog
488
485 self.__commitDialog = SvnCommitDialog(self, self.__ui) 489 self.__commitDialog = SvnCommitDialog(self, self.__ui)
486 self.__commitDialog.accepted.connect(self.__vcsCommit_Step2) 490 self.__commitDialog.accepted.connect(self.__vcsCommit_Step2)
487 self.__commitDialog.show() 491 self.__commitDialog.show()
488 self.__commitDialog.raise_() 492 self.__commitDialog.raise_()
489 self.__commitDialog.activateWindow() 493 self.__commitDialog.activateWindow()
490 494
491 self.__commitData["name"] = name 495 self.__commitData["name"] = name
492 self.__commitData["msg"] = message 496 self.__commitData["msg"] = message
493 self.__commitData["noDialog"] = noDialog 497 self.__commitData["noDialog"] = noDialog
494 498
495 if noDialog: 499 if noDialog:
496 self.__vcsCommit_Step2() 500 self.__vcsCommit_Step2()
497 501
498 def __vcsCommit_Step2(self): 502 def __vcsCommit_Step2(self):
499 """ 503 """
500 Private slot performing the second step of the commit action. 504 Private slot performing the second step of the commit action.
501 """ 505 """
502 name = self.__commitData["name"] 506 name = self.__commitData["name"]
503 msg = self.__commitData["msg"] 507 msg = self.__commitData["msg"]
504 noDialog = self.__commitData["noDialog"] 508 noDialog = self.__commitData["noDialog"]
505 509
506 if not noDialog: 510 if not noDialog:
507 # check, if there are unsaved changes, that should be committed 511 # check, if there are unsaved changes, that should be committed
508 if isinstance(name, list): 512 if isinstance(name, list):
509 nameList = name 513 nameList = name
510 else: 514 else:
513 for nam in nameList: 517 for nam in nameList:
514 # check for commit of the project 518 # check for commit of the project
515 if os.path.isdir(nam): 519 if os.path.isdir(nam):
516 project = ericApp().getObject("Project") 520 project = ericApp().getObject("Project")
517 if nam == project.getProjectPath(): 521 if nam == project.getProjectPath():
518 ok &= project.checkAllScriptsDirty( 522 ok &= (
519 reportSyntaxErrors=True) and project.checkDirty() 523 project.checkAllScriptsDirty(reportSyntaxErrors=True)
524 and project.checkDirty()
525 )
520 continue 526 continue
521 elif os.path.isfile(nam): 527 elif os.path.isfile(nam):
522 editor = ericApp().getObject("ViewManager").getOpenEditor( 528 editor = ericApp().getObject("ViewManager").getOpenEditor(nam)
523 nam)
524 if editor: 529 if editor:
525 ok &= editor.checkDirty() 530 ok &= editor.checkDirty()
526 if not ok: 531 if not ok:
527 break 532 break
528 533
529 if not ok: 534 if not ok:
530 res = EricMessageBox.yesNo( 535 res = EricMessageBox.yesNo(
531 self.__ui, 536 self.__ui,
532 self.tr("Commit Changes"), 537 self.tr("Commit Changes"),
533 self.tr( 538 self.tr(
534 """The commit affects files, that have unsaved""" 539 """The commit affects files, that have unsaved"""
535 """ changes. Shall the commit be continued?"""), 540 """ changes. Shall the commit be continued?"""
536 icon=EricMessageBox.Warning) 541 ),
542 icon=EricMessageBox.Warning,
543 )
537 if not res: 544 if not res:
538 return 545 return
539 546
540 if self.__commitDialog is not None: 547 if self.__commitDialog is not None:
541 msg = self.__commitDialog.logMessage() 548 msg = self.__commitDialog.logMessage()
542 if self.__commitDialog.hasChangelists(): 549 if self.__commitDialog.hasChangelists():
543 changelists, keepChangelists = ( 550 changelists, keepChangelists = self.__commitDialog.changelistsData()
544 self.__commitDialog.changelistsData()
545 )
546 else: 551 else:
547 changelists, keepChangelists = [], False 552 changelists, keepChangelists = [], False
548 self.__commitDialog.deleteLater() 553 self.__commitDialog.deleteLater()
549 self.__commitDialog = None 554 self.__commitDialog = None
550 else: 555 else:
551 changelists, keepChangelists = [], False 556 changelists, keepChangelists = [], False
552 557
553 if not msg: 558 if not msg:
554 msg = '***' 559 msg = "***"
555 560
556 if isinstance(name, list): 561 if isinstance(name, list):
557 dname, fnames = self.splitPathList(name) 562 dname, fnames = self.splitPathList(name)
558 else: 563 else:
559 dname, fname = self.splitPath(name) 564 dname, fname = self.splitPath(name)
560 fnames = [fname] 565 fnames = [fname]
561 566
562 if ( 567 if self.svnGetReposName(dname).startswith("http") or self.svnGetReposName(
563 self.svnGetReposName(dname).startswith('http') or 568 dname
564 self.svnGetReposName(dname).startswith('svn') 569 ).startswith("svn"):
565 ):
566 noDialog = False 570 noDialog = False
567 571
568 cwd = os.getcwd() 572 cwd = os.getcwd()
569 os.chdir(dname) 573 os.chdir(dname)
570 opts = self.options['global'] + self.options['commit'] 574 opts = self.options["global"] + self.options["commit"]
571 recurse = "--non-recursive" not in opts 575 recurse = "--non-recursive" not in opts
572 keeplocks = "--keep-locks" in opts 576 keeplocks = "--keep-locks" in opts
573 client = self.getClient() 577 client = self.getClient()
574 if not noDialog: 578 if not noDialog:
575 dlg = SvnDialog( 579 dlg = SvnDialog(
576 self.tr('Commiting changes to Subversion repository'), 580 self.tr("Commiting changes to Subversion repository"),
577 "commit{0}{1}{2}{3} --message {4} {5}".format( 581 "commit{0}{1}{2}{3} --message {4} {5}".format(
578 (not recurse) and " --non-recursive" or "", 582 (not recurse) and " --non-recursive" or "",
579 keeplocks and " --keep-locks" or "", 583 keeplocks and " --keep-locks" or "",
580 keepChangelists and " --keep-changelists" or "", 584 keepChangelists and " --keep-changelists" or "",
581 changelists and 585 changelists and " --changelist ".join([""] + changelists) or "",
582 " --changelist ".join([""] + changelists) or "", 586 msg,
583 msg, " ".join(fnames)), 587 " ".join(fnames),
584 client) 588 ),
589 client,
590 )
585 QApplication.processEvents() 591 QApplication.processEvents()
586 try: 592 try:
587 with EricMutexLocker(self.vcsExecutionMutex): 593 with EricMutexLocker(self.vcsExecutionMutex):
588 rev = ( 594 rev = (
589 client.checkin( 595 client.checkin(
590 fnames, msg, recurse=recurse, keep_locks=keeplocks, 596 fnames,
597 msg,
598 recurse=recurse,
599 keep_locks=keeplocks,
591 keep_changelist=keepChangelists, 600 keep_changelist=keepChangelists,
592 changelists=changelists) 601 changelists=changelists,
593 if changelists else 602 )
594 client.checkin( 603 if changelists
595 fnames, msg, recurse=recurse, keep_locks=keeplocks) 604 else client.checkin(
605 fnames, msg, recurse=recurse, keep_locks=keeplocks
606 )
596 ) 607 )
597 except pysvn.ClientError as e: 608 except pysvn.ClientError as e:
598 rev = None 609 rev = None
599 if not noDialog: 610 if not noDialog:
600 dlg.showError(e.args[0]) 611 dlg.showError(e.args[0])
601 if not noDialog: 612 if not noDialog:
602 rev and dlg.showMessage(self.tr("Committed revision {0}.") 613 rev and dlg.showMessage(
603 .format(rev.number)) 614 self.tr("Committed revision {0}.").format(rev.number)
615 )
604 dlg.finish() 616 dlg.finish()
605 dlg.exec() 617 dlg.exec()
606 os.chdir(cwd) 618 os.chdir(cwd)
607 self.committed.emit() 619 self.committed.emit()
608 self.checkVCSStatus() 620 self.checkVCSStatus()
609 621
610 def vcsCommitMessages(self): 622 def vcsCommitMessages(self):
611 """ 623 """
612 Public method to get the list of saved commit messages. 624 Public method to get the list of saved commit messages.
613 625
614 @return list of saved commit messages 626 @return list of saved commit messages
615 @rtype list of str 627 @rtype list of str
616 """ 628 """
617 # try per project commit history first 629 # try per project commit history first
618 messages = self._vcsProjectCommitMessages() 630 messages = self._vcsProjectCommitMessages()
619 if not messages: 631 if not messages:
620 # empty list returned, try the vcs specific one 632 # empty list returned, try the vcs specific one
621 messages = self.getPlugin().getPreferences("Commits") 633 messages = self.getPlugin().getPreferences("Commits")
622 634
623 return messages 635 return messages
624 636
625 def vcsAddCommitMessage(self, message): 637 def vcsAddCommitMessage(self, message):
626 """ 638 """
627 Public method to add a commit message to the list of saved messages. 639 Public method to add a commit message to the list of saved messages.
628 640
629 @param message message to be added 641 @param message message to be added
630 @type str 642 @type str
631 """ 643 """
632 if not self._vcsAddProjectCommitMessage(message): 644 if not self._vcsAddProjectCommitMessage(message):
633 commitMessages = self.vcsCommitMessages() 645 commitMessages = self.vcsCommitMessages()
635 commitMessages.remove(message) 647 commitMessages.remove(message)
636 commitMessages.insert(0, message) 648 commitMessages.insert(0, message)
637 no = Preferences.getVCS("CommitMessages") 649 no = Preferences.getVCS("CommitMessages")
638 del commitMessages[no:] 650 del commitMessages[no:]
639 self.getPlugin().setPreferences("Commits", commitMessages) 651 self.getPlugin().setPreferences("Commits", commitMessages)
640 652
641 def vcsClearCommitMessages(self): 653 def vcsClearCommitMessages(self):
642 """ 654 """
643 Public method to clear the list of saved messages. 655 Public method to clear the list of saved messages.
644 """ 656 """
645 if not self._vcsClearProjectCommitMessages(): 657 if not self._vcsClearProjectCommitMessages():
646 self.getPlugin().setPreferences('Commits', []) 658 self.getPlugin().setPreferences("Commits", [])
647 659
648 def vcsUpdate(self, name, noDialog=False): 660 def vcsUpdate(self, name, noDialog=False):
649 """ 661 """
650 Public method used to update a file/directory with the Subversion 662 Public method used to update a file/directory with the Subversion
651 repository. 663 repository.
652 664
653 @param name file/directory name to be updated (string or list of 665 @param name file/directory name to be updated (string or list of
654 strings) 666 strings)
655 @param noDialog flag indicating quiet operations (boolean) 667 @param noDialog flag indicating quiet operations (boolean)
656 @return flag indicating, that the update contained an add 668 @return flag indicating, that the update contained an add
657 or delete (boolean) 669 or delete (boolean)
659 if isinstance(name, list): 671 if isinstance(name, list):
660 dname, fnames = self.splitPathList(name) 672 dname, fnames = self.splitPathList(name)
661 else: 673 else:
662 dname, fname = self.splitPath(name) 674 dname, fname = self.splitPath(name)
663 fnames = [fname] 675 fnames = [fname]
664 676
665 cwd = os.getcwd() 677 cwd = os.getcwd()
666 os.chdir(dname) 678 os.chdir(dname)
667 opts = self.options['global'] + self.options['update'] 679 opts = self.options["global"] + self.options["update"]
668 recurse = "--non-recursive" not in opts 680 recurse = "--non-recursive" not in opts
669 client = self.getClient() 681 client = self.getClient()
670 if not noDialog: 682 if not noDialog:
671 dlg = SvnDialog( 683 dlg = SvnDialog(
672 self.tr('Synchronizing with the Subversion repository'), 684 self.tr("Synchronizing with the Subversion repository"),
673 "update{0} {1}".format( 685 "update{0} {1}".format(
674 (not recurse) and " --non-recursive" or "", 686 (not recurse) and " --non-recursive" or "", " ".join(fnames)
675 " ".join(fnames)), 687 ),
676 client) 688 client,
689 )
677 QApplication.processEvents() 690 QApplication.processEvents()
678 try: 691 try:
679 with EricMutexLocker(self.vcsExecutionMutex): 692 with EricMutexLocker(self.vcsExecutionMutex):
680 client.update(fnames, recurse) 693 client.update(fnames, recurse)
681 except pysvn.ClientError as e: 694 except pysvn.ClientError as e:
687 else: 700 else:
688 res = False 701 res = False
689 os.chdir(cwd) 702 os.chdir(cwd)
690 self.checkVCSStatus() 703 self.checkVCSStatus()
691 return res 704 return res
692 705
693 def vcsAdd(self, name, isDir=False, noDialog=False): 706 def vcsAdd(self, name, isDir=False, noDialog=False):
694 """ 707 """
695 Public method used to add a file/directory to the Subversion 708 Public method used to add a file/directory to the Subversion
696 repository. 709 repository.
697 710
698 @param name file/directory name to be added (string) 711 @param name file/directory name to be added (string)
699 @param isDir flag indicating name is a directory (boolean) 712 @param isDir flag indicating name is a directory (boolean)
700 @param noDialog flag indicating quiet operations (boolean) 713 @param noDialog flag indicating quiet operations (boolean)
701 """ 714 """
702 if isinstance(name, list): 715 if isinstance(name, list):
716 repodir = dname 729 repodir = dname
717 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 730 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
718 repodir = os.path.dirname(repodir) 731 repodir = os.path.dirname(repodir)
719 if os.path.splitdrive(repodir)[1] == os.sep: 732 if os.path.splitdrive(repodir)[1] == os.sep:
720 return # oops, project is not version controlled 733 return # oops, project is not version controlled
721 while ( 734 while os.path.normcase(dname) != os.path.normcase(repodir) and (
722 os.path.normcase(dname) != os.path.normcase(repodir) and 735 os.path.normcase(dname) not in self.statusCache
723 (os.path.normcase(dname) not in self.statusCache or 736 or self.statusCache[os.path.normcase(dname)] == self.canBeAdded
724 self.statusCache[os.path.normcase(dname)] ==
725 self.canBeAdded)
726 ): 737 ):
727 # add directories recursively, if they aren't in the 738 # add directories recursively, if they aren't in the
728 # repository already 739 # repository already
729 tree.insert(-1, dname) 740 tree.insert(-1, dname)
730 dname = os.path.dirname(dname) 741 dname = os.path.dirname(dname)
735 # repository already 746 # repository already
736 tree.insert(-1, dname) 747 tree.insert(-1, dname)
737 dname = os.path.dirname(dname) 748 dname = os.path.dirname(dname)
738 wdir = dname 749 wdir = dname
739 names.extend(tree) 750 names.extend(tree)
740 751
741 if isinstance(name, list): 752 if isinstance(name, list):
742 tree2 = [] 753 tree2 = []
743 for n in name: 754 for n in name:
744 d = os.path.dirname(n) 755 d = os.path.dirname(n)
745 if self.__wcng: 756 if self.__wcng:
746 repodir = d 757 repodir = d
747 while not os.path.isdir( 758 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
748 os.path.join(repodir, self.adminDir)):
749 repodir = os.path.dirname(repodir) 759 repodir = os.path.dirname(repodir)
750 if os.path.splitdrive(repodir)[1] == os.sep: 760 if os.path.splitdrive(repodir)[1] == os.sep:
751 return # oops, project is not version controlled 761 return # oops, project is not version controlled
752 while ( 762 while (
753 (os.path.normcase(d) != os.path.normcase(repodir)) and 763 (os.path.normcase(d) != os.path.normcase(repodir))
754 (d not in tree2 + tree) and 764 and (d not in tree2 + tree)
755 (os.path.normcase(d) not in self.statusCache or 765 and (
756 self.statusCache[os.path.normcase(d)] == 766 os.path.normcase(d) not in self.statusCache
757 self.canBeAdded) 767 or self.statusCache[os.path.normcase(d)] == self.canBeAdded
768 )
758 ): 769 ):
759 tree2.append(d) 770 tree2.append(d)
760 d = os.path.dirname(d) 771 d = os.path.dirname(d)
761 else: 772 else:
762 while not os.path.exists(os.path.join(d, self.adminDir)): 773 while not os.path.exists(os.path.join(d, self.adminDir)):
767 tree2.reverse() 778 tree2.reverse()
768 names.extend(tree2) 779 names.extend(tree2)
769 names.extend(name) 780 names.extend(name)
770 else: 781 else:
771 names.append(name) 782 names.append(name)
772 783
773 cwd = os.getcwd() 784 cwd = os.getcwd()
774 os.chdir(wdir) 785 os.chdir(wdir)
775 opts = self.options['global'] + self.options['add'] 786 opts = self.options["global"] + self.options["add"]
776 recurse = False 787 recurse = False
777 force = "--force" in opts or noDialog 788 force = "--force" in opts or noDialog
778 noignore = "--no-ignore" in opts 789 noignore = "--no-ignore" in opts
779 client = self.getClient() 790 client = self.getClient()
780 if not noDialog: 791 if not noDialog:
781 dlg = SvnDialog( 792 dlg = SvnDialog(
782 self.tr('Adding files/directories to the Subversion' 793 self.tr("Adding files/directories to the Subversion" " repository"),
783 ' repository'),
784 "add --non-recursive{0}{1} {2}".format( 794 "add --non-recursive{0}{1} {2}".format(
785 force and " --force" or "", 795 force and " --force" or "",
786 noignore and " --no-ignore" or "", 796 noignore and " --no-ignore" or "",
787 " ".join(names)), 797 " ".join(names),
788 client) 798 ),
799 client,
800 )
789 QApplication.processEvents() 801 QApplication.processEvents()
790 try: 802 try:
791 with EricMutexLocker(self.vcsExecutionMutex): 803 with EricMutexLocker(self.vcsExecutionMutex):
792 client.add(names, recurse=recurse, force=force, 804 client.add(names, recurse=recurse, force=force, ignore=not noignore)
793 ignore=not noignore)
794 except pysvn.ClientError as e: 805 except pysvn.ClientError as e:
795 if not noDialog: 806 if not noDialog:
796 dlg.showError(e.args[0]) 807 dlg.showError(e.args[0])
797 if not noDialog: 808 if not noDialog:
798 dlg.finish() 809 dlg.finish()
799 dlg.exec() 810 dlg.exec()
800 os.chdir(cwd) 811 os.chdir(cwd)
801 812
802 def vcsAddBinary(self, name, isDir=False): 813 def vcsAddBinary(self, name, isDir=False):
803 """ 814 """
804 Public method used to add a file/directory in binary mode to the 815 Public method used to add a file/directory in binary mode to the
805 Subversion repository. 816 Subversion repository.
806 817
807 @param name file/directory name to be added (string) 818 @param name file/directory name to be added (string)
808 @param isDir flag indicating name is a directory (boolean) 819 @param isDir flag indicating name is a directory (boolean)
809 """ 820 """
810 self.vcsAdd(name, isDir) 821 self.vcsAdd(name, isDir)
811 822
812 def vcsAddTree(self, path): 823 def vcsAddTree(self, path):
813 """ 824 """
814 Public method to add a directory tree rooted at path to the Subversion 825 Public method to add a directory tree rooted at path to the Subversion
815 repository. 826 repository.
816 827
817 @param path root directory of the tree to be added (string or list of 828 @param path root directory of the tree to be added (string or list of
818 strings)) 829 strings))
819 """ 830 """
820 tree = [] 831 tree = []
821 if isinstance(path, list): 832 if isinstance(path, list):
822 dname, fnames = self.splitPathList(path) 833 dname, fnames = self.splitPathList(path)
823 for n in path: 834 for n in path:
824 d = os.path.dirname(n) 835 d = os.path.dirname(n)
825 if self.__wcng: 836 if self.__wcng:
826 repodir = d 837 repodir = d
827 while not os.path.isdir( 838 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
828 os.path.join(repodir, self.adminDir)):
829 repodir = os.path.dirname(repodir) 839 repodir = os.path.dirname(repodir)
830 if os.path.splitdrive(repodir)[1] == os.sep: 840 if os.path.splitdrive(repodir)[1] == os.sep:
831 return # oops, project is not version controlled 841 return # oops, project is not version controlled
832 while ( 842 while (
833 (os.path.normcase(d) != os.path.normcase(repodir)) and 843 (os.path.normcase(d) != os.path.normcase(repodir))
834 (d not in tree) and 844 and (d not in tree)
835 (os.path.normcase(d) not in self.statusCache or 845 and (
836 self.statusCache[os.path.normcase(d)] == 846 os.path.normcase(d) not in self.statusCache
837 self.canBeAdded) 847 or self.statusCache[os.path.normcase(d)] == self.canBeAdded
848 )
838 ): 849 ):
839 tree.append(d) 850 tree.append(d)
840 d = os.path.dirname(d) 851 d = os.path.dirname(d)
841 else: 852 else:
842 while not os.path.exists(os.path.join(d, self.adminDir)): 853 while not os.path.exists(os.path.join(d, self.adminDir)):
853 repodir = dname 864 repodir = dname
854 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 865 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
855 repodir = os.path.dirname(repodir) 866 repodir = os.path.dirname(repodir)
856 if os.path.splitdrive(repodir)[1] == os.sep: 867 if os.path.splitdrive(repodir)[1] == os.sep:
857 return # oops, project is not version controlled 868 return # oops, project is not version controlled
858 while ( 869 while (os.path.normcase(dname) != os.path.normcase(repodir)) and (
859 (os.path.normcase(dname) != os.path.normcase(repodir)) and 870 os.path.normcase(dname) not in self.statusCache
860 (os.path.normcase(dname) not in self.statusCache or 871 or self.statusCache[os.path.normcase(dname)] == self.canBeAdded
861 self.statusCache[os.path.normcase(dname)] ==
862 self.canBeAdded)
863 ): 872 ):
864 # add directories recursively, if they aren't in the 873 # add directories recursively, if they aren't in the
865 # repository already 874 # repository already
866 tree.insert(-1, dname) 875 tree.insert(-1, dname)
867 dname = os.path.dirname(dname) 876 dname = os.path.dirname(dname)
871 # if they aren't in the repository already 880 # if they aren't in the repository already
872 tree.insert(-1, dname) 881 tree.insert(-1, dname)
873 dname = os.path.dirname(dname) 882 dname = os.path.dirname(dname)
874 if tree: 883 if tree:
875 self.vcsAdd(tree, True) 884 self.vcsAdd(tree, True)
876 885
877 names = [] 886 names = []
878 if isinstance(path, list): 887 if isinstance(path, list):
879 names.extend(path) 888 names.extend(path)
880 else: 889 else:
881 names.append(path) 890 names.append(path)
882 891
883 cwd = os.getcwd() 892 cwd = os.getcwd()
884 os.chdir(dname) 893 os.chdir(dname)
885 opts = self.options['global'] + self.options['add'] 894 opts = self.options["global"] + self.options["add"]
886 recurse = True 895 recurse = True
887 force = "--force" in opts 896 force = "--force" in opts
888 ignore = "--ignore" in opts 897 ignore = "--ignore" in opts
889 client = self.getClient() 898 client = self.getClient()
890 dlg = SvnDialog( 899 dlg = SvnDialog(
891 self.tr('Adding directory trees to the Subversion repository'), 900 self.tr("Adding directory trees to the Subversion repository"),
892 "add{0}{1} {2}".format( 901 "add{0}{1} {2}".format(
893 force and " --force" or "", 902 force and " --force" or "",
894 ignore and " --ignore" or "", 903 ignore and " --ignore" or "",
895 " ".join(names)), 904 " ".join(names),
896 client) 905 ),
906 client,
907 )
897 QApplication.processEvents() 908 QApplication.processEvents()
898 try: 909 try:
899 with EricMutexLocker(self.vcsExecutionMutex): 910 with EricMutexLocker(self.vcsExecutionMutex):
900 client.add(names, recurse=recurse, force=force, ignore=ignore) 911 client.add(names, recurse=recurse, force=force, ignore=ignore)
901 except pysvn.ClientError as e: 912 except pysvn.ClientError as e:
902 dlg.showError(e.args[0]) 913 dlg.showError(e.args[0])
903 dlg.finish() 914 dlg.finish()
904 dlg.exec() 915 dlg.exec()
905 os.chdir(cwd) 916 os.chdir(cwd)
906 917
907 def vcsRemove(self, name, project=False, noDialog=False): 918 def vcsRemove(self, name, project=False, noDialog=False):
908 """ 919 """
909 Public method used to remove a file/directory from the Subversion 920 Public method used to remove a file/directory from the Subversion
910 repository. 921 repository.
911 922
912 The default operation is to remove the local copy as well. 923 The default operation is to remove the local copy as well.
913 924
914 @param name file/directory name to be removed (string or list of 925 @param name file/directory name to be removed (string or list of
915 strings)) 926 strings))
916 @param project flag indicating deletion of a project tree (boolean) 927 @param project flag indicating deletion of a project tree (boolean)
917 (not needed) 928 (not needed)
918 @param noDialog flag indicating quiet operations 929 @param noDialog flag indicating quiet operations
919 @return flag indicating successfull operation (boolean) 930 @return flag indicating successfull operation (boolean)
920 """ 931 """
921 if not isinstance(name, list): 932 if not isinstance(name, list):
922 name = [name] 933 name = [name]
923 opts = self.options['global'] + self.options['remove'] 934 opts = self.options["global"] + self.options["remove"]
924 force = "--force" in opts or noDialog 935 force = "--force" in opts or noDialog
925 client = self.getClient() 936 client = self.getClient()
926 if not noDialog: 937 if not noDialog:
927 dlg = SvnDialog( 938 dlg = SvnDialog(
928 self.tr('Removing files/directories from the Subversion' 939 self.tr("Removing files/directories from the Subversion" " repository"),
929 ' repository'), 940 "remove{0} {1}".format(force and " --force" or "", " ".join(name)),
930 "remove{0} {1}".format( 941 client,
931 force and " --force" or "", 942 )
932 " ".join(name)),
933 client)
934 QApplication.processEvents() 943 QApplication.processEvents()
935 try: 944 try:
936 with EricMutexLocker(self.vcsExecutionMutex): 945 with EricMutexLocker(self.vcsExecutionMutex):
937 client.remove(name, force=force) 946 client.remove(name, force=force)
938 res = True 947 res = True
941 if not noDialog: 950 if not noDialog:
942 dlg.showError(e.args[0]) 951 dlg.showError(e.args[0])
943 if not noDialog: 952 if not noDialog:
944 dlg.finish() 953 dlg.finish()
945 dlg.exec() 954 dlg.exec()
946 955
947 return res 956 return res
948 957
949 def vcsMove(self, name, project, target=None, noDialog=False): 958 def vcsMove(self, name, project, target=None, noDialog=False):
950 """ 959 """
951 Public method used to move a file/directory. 960 Public method used to move a file/directory.
952 961
953 @param name file/directory name to be moved (string) 962 @param name file/directory name to be moved (string)
954 @param project reference to the project object 963 @param project reference to the project object
955 @param target new name of the file/directory (string) 964 @param target new name of the file/directory (string)
956 @param noDialog flag indicating quiet operations 965 @param noDialog flag indicating quiet operations
957 @return flag indicating successfull operation (boolean) 966 @return flag indicating successfull operation (boolean)
958 """ 967 """
959 rx_prot = re.compile('(file:|svn:|svn+ssh:|http:|https:).+') 968 rx_prot = re.compile("(file:|svn:|svn+ssh:|http:|https:).+")
960 opts = self.options['global'] 969 opts = self.options["global"]
961 res = False 970 res = False
962 971
963 if noDialog: 972 if noDialog:
964 if target is None: 973 if target is None:
965 return False 974 return False
966 force = True 975 force = True
967 accepted = True 976 accepted = True
968 else: 977 else:
969 from .SvnCopyDialog import SvnCopyDialog 978 from .SvnCopyDialog import SvnCopyDialog
979
970 dlg = SvnCopyDialog(name, None, True, "--force" in opts) 980 dlg = SvnCopyDialog(name, None, True, "--force" in opts)
971 accepted = (dlg.exec() == QDialog.DialogCode.Accepted) 981 accepted = dlg.exec() == QDialog.DialogCode.Accepted
972 if accepted: 982 if accepted:
973 target, force = dlg.getData() 983 target, force = dlg.getData()
974 if not target: 984 if not target:
975 return False 985 return False
976 986
977 isDir = (os.path.isdir(name) if rx_prot.fullmatch(target) is None 987 isDir = os.path.isdir(name) if rx_prot.fullmatch(target) is None else False
978 else False) 988
979
980 if accepted: 989 if accepted:
981 client = self.getClient() 990 client = self.getClient()
982 if rx_prot.fullmatch(target) is not None: 991 if rx_prot.fullmatch(target) is not None:
983 target = self.__svnURL(target) 992 target = self.__svnURL(target)
984 log = "Moving {0} to {1}".format(name, target) 993 log = "Moving {0} to {1}".format(name, target)
985 else: 994 else:
986 log = "" 995 log = ""
987 target = target 996 target = target
988 if not noDialog: 997 if not noDialog:
989 dlg = SvnDialog( 998 dlg = SvnDialog(
990 self.tr('Moving {0}').format(name), 999 self.tr("Moving {0}").format(name),
991 "move{0}{1} {2} {3}".format( 1000 "move{0}{1} {2} {3}".format(
992 force and " --force" or "", 1001 force and " --force" or "",
993 log and (" --message {0}".format(log)) or "", 1002 log and (" --message {0}".format(log)) or "",
994 name, target), 1003 name,
995 client, log=log) 1004 target,
1005 ),
1006 client,
1007 log=log,
1008 )
996 QApplication.processEvents() 1009 QApplication.processEvents()
997 try: 1010 try:
998 with EricMutexLocker(self.vcsExecutionMutex): 1011 with EricMutexLocker(self.vcsExecutionMutex):
999 client.move(name, target, force=force) 1012 client.move(name, target, force=force)
1000 res = True 1013 res = True
1015 if isDir: 1028 if isDir:
1016 project.removeDirectory(name) 1029 project.removeDirectory(name)
1017 else: 1030 else:
1018 project.removeFile(name) 1031 project.removeFile(name)
1019 return res 1032 return res
1020 1033
1021 def vcsDiff(self, name): 1034 def vcsDiff(self, name):
1022 """ 1035 """
1023 Public method used to view the difference of a file/directory to the 1036 Public method used to view the difference of a file/directory to the
1024 Subversion repository. 1037 Subversion repository.
1025 1038
1026 If name is a directory and is the project directory, all project files 1039 If name is a directory and is the project directory, all project files
1027 are saved first. If name is a file (or list of files), which is/are 1040 are saved first. If name is a file (or list of files), which is/are
1028 being edited and has unsaved modification, they can be saved or the 1041 being edited and has unsaved modification, they can be saved or the
1029 operation may be aborted. 1042 operation may be aborted.
1030 1043
1031 @param name file/directory name to be diffed (string) 1044 @param name file/directory name to be diffed (string)
1032 """ 1045 """
1033 names = name[:] if isinstance(name, list) else [name] 1046 names = name[:] if isinstance(name, list) else [name]
1034 for nam in names: 1047 for nam in names:
1035 if os.path.isfile(nam): 1048 if os.path.isfile(nam):
1040 project = ericApp().getObject("Project") 1053 project = ericApp().getObject("Project")
1041 if nam == project.ppath and not project.saveAllScripts(): 1054 if nam == project.ppath and not project.saveAllScripts():
1042 return 1055 return
1043 if self.diff is None: 1056 if self.diff is None:
1044 from .SvnDiffDialog import SvnDiffDialog 1057 from .SvnDiffDialog import SvnDiffDialog
1058
1045 self.diff = SvnDiffDialog(self) 1059 self.diff = SvnDiffDialog(self)
1046 self.diff.show() 1060 self.diff.show()
1047 self.diff.raise_() 1061 self.diff.raise_()
1048 QApplication.processEvents() 1062 QApplication.processEvents()
1049 self.diff.start(name, refreshable=True) 1063 self.diff.start(name, refreshable=True)
1050 1064
1051 def vcsStatus(self, name): 1065 def vcsStatus(self, name):
1052 """ 1066 """
1053 Public method used to view the status of files/directories in the 1067 Public method used to view the status of files/directories in the
1054 Subversion repository. 1068 Subversion repository.
1055 1069
1056 @param name file/directory name(s) to show the status of 1070 @param name file/directory name(s) to show the status of
1057 (string or list of strings) 1071 (string or list of strings)
1058 """ 1072 """
1059 if self.status is None: 1073 if self.status is None:
1060 from .SvnStatusDialog import SvnStatusDialog 1074 from .SvnStatusDialog import SvnStatusDialog
1075
1061 self.status = SvnStatusDialog(self) 1076 self.status = SvnStatusDialog(self)
1062 self.status.show() 1077 self.status.show()
1063 self.status.raise_() 1078 self.status.raise_()
1064 QApplication.processEvents() 1079 QApplication.processEvents()
1065 self.status.start(name) 1080 self.status.start(name)
1066 1081
1067 def vcsTag(self, name): 1082 def vcsTag(self, name):
1068 """ 1083 """
1069 Public method used to set the tag of a file/directory in the 1084 Public method used to set the tag of a file/directory in the
1070 Subversion repository. 1085 Subversion repository.
1071 1086
1072 @param name file/directory name to be tagged (string) 1087 @param name file/directory name to be tagged (string)
1073 """ 1088 """
1074 dname, fname = self.splitPath(name) 1089 dname, fname = self.splitPath(name)
1075 1090
1076 reposURL = self.svnGetReposName(dname) 1091 reposURL = self.svnGetReposName(dname)
1077 if reposURL is None: 1092 if reposURL is None:
1078 EricMessageBox.critical( 1093 EricMessageBox.critical(
1079 self.__ui, 1094 self.__ui,
1080 self.tr("Subversion Error"), 1095 self.tr("Subversion Error"),
1081 self.tr( 1096 self.tr(
1082 """The URL of the project repository could not be""" 1097 """The URL of the project repository could not be"""
1083 """ retrieved from the working copy. The tag operation""" 1098 """ retrieved from the working copy. The tag operation"""
1084 """ will be aborted""")) 1099 """ will be aborted"""
1100 ),
1101 )
1085 return 1102 return
1086 1103
1087 url = ( 1104 url = (
1088 None 1105 None if self.otherData["standardLayout"] else self.svnNormalizeURL(reposURL)
1089 if self.otherData["standardLayout"] else
1090 self.svnNormalizeURL(reposURL)
1091 ) 1106 )
1092 from .SvnTagDialog import SvnTagDialog 1107 from .SvnTagDialog import SvnTagDialog
1093 dlg = SvnTagDialog(self.allTagsBranchesList, url, 1108
1094 self.otherData["standardLayout"]) 1109 dlg = SvnTagDialog(
1110 self.allTagsBranchesList, url, self.otherData["standardLayout"]
1111 )
1095 if dlg.exec() == QDialog.DialogCode.Accepted: 1112 if dlg.exec() == QDialog.DialogCode.Accepted:
1096 tag, tagOp = dlg.getParameters() 1113 tag, tagOp = dlg.getParameters()
1097 if tag in self.allTagsBranchesList: 1114 if tag in self.allTagsBranchesList:
1098 self.allTagsBranchesList.remove(tag) 1115 self.allTagsBranchesList.remove(tag)
1099 self.allTagsBranchesList.insert(0, tag) 1116 self.allTagsBranchesList.insert(0, tag)
1100 else: 1117 else:
1101 return 1118 return
1102 1119
1103 if self.otherData["standardLayout"]: 1120 if self.otherData["standardLayout"]:
1104 rx_base = re.compile('(.+)/(trunk|tags|branches).*') 1121 rx_base = re.compile("(.+)/(trunk|tags|branches).*")
1105 1122
1106 match = rx_base.fullmatch(reposURL) 1123 match = rx_base.fullmatch(reposURL)
1107 if match is None: 1124 if match is None:
1108 EricMessageBox.critical( 1125 EricMessageBox.critical(
1109 self.__ui, 1126 self.__ui,
1110 self.tr("Subversion Error"), 1127 self.tr("Subversion Error"),
1111 self.tr( 1128 self.tr(
1112 """The URL of the project repository has an""" 1129 """The URL of the project repository has an"""
1113 """ invalid format. The tag operation will""" 1130 """ invalid format. The tag operation will"""
1114 """ be aborted""")) 1131 """ be aborted"""
1132 ),
1133 )
1115 return 1134 return
1116 1135
1117 reposRoot = match.group(1) 1136 reposRoot = match.group(1)
1118 if tagOp in [1, 4]: 1137 if tagOp in [1, 4]:
1119 url = '{0}/tags/{1}'.format(reposRoot, quote(tag)) 1138 url = "{0}/tags/{1}".format(reposRoot, quote(tag))
1120 elif tagOp in [2, 8]: 1139 elif tagOp in [2, 8]:
1121 url = '{0}/branches/{1}'.format(reposRoot, quote(tag)) 1140 url = "{0}/branches/{1}".format(reposRoot, quote(tag))
1122 else: 1141 else:
1123 url = self.__svnURL(tag) 1142 url = self.__svnURL(tag)
1124 1143
1125 self.tagName = tag 1144 self.tagName = tag
1126 client = self.getClient() 1145 client = self.getClient()
1127 rev = None 1146 rev = None
1128 if tagOp in [1, 2]: 1147 if tagOp in [1, 2]:
1129 log = 'Created tag <{0}>'.format(self.tagName) 1148 log = "Created tag <{0}>".format(self.tagName)
1130 dlg = SvnDialog( 1149 dlg = SvnDialog(
1131 self.tr('Tagging {0} in the Subversion repository') 1150 self.tr("Tagging {0} in the Subversion repository").format(name),
1132 .format(name),
1133 "copy --message {0} {1} {2}".format(log, reposURL, url), 1151 "copy --message {0} {1} {2}".format(log, reposURL, url),
1134 client, log=log) 1152 client,
1153 log=log,
1154 )
1135 QApplication.processEvents() 1155 QApplication.processEvents()
1136 try: 1156 try:
1137 with EricMutexLocker(self.vcsExecutionMutex): 1157 with EricMutexLocker(self.vcsExecutionMutex):
1138 rev = client.copy(reposURL, url) 1158 rev = client.copy(reposURL, url)
1139 except pysvn.ClientError as e: 1159 except pysvn.ClientError as e:
1140 dlg.showError(e.args[0]) 1160 dlg.showError(e.args[0])
1141 else: 1161 else:
1142 log = 'Deleted tag <{0}>'.format(self.tagName) 1162 log = "Deleted tag <{0}>".format(self.tagName)
1143 dlg = SvnDialog( 1163 dlg = SvnDialog(
1144 self.tr('Tagging {0} in the Subversion repository') 1164 self.tr("Tagging {0} in the Subversion repository").format(name),
1145 .format(name),
1146 "remove --message {0} {1}".format(log, url), 1165 "remove --message {0} {1}".format(log, url),
1147 client, log=log) 1166 client,
1167 log=log,
1168 )
1148 QApplication.processEvents() 1169 QApplication.processEvents()
1149 try: 1170 try:
1150 with EricMutexLocker(self.vcsExecutionMutex): 1171 with EricMutexLocker(self.vcsExecutionMutex):
1151 rev = client.remove(url) 1172 rev = client.remove(url)
1152 except pysvn.ClientError as e: 1173 except pysvn.ClientError as e:
1153 dlg.showError(e.args[0]) 1174 dlg.showError(e.args[0])
1154 rev and dlg.showMessage( 1175 rev and dlg.showMessage(self.tr("Revision {0}.\n").format(rev.number))
1155 self.tr("Revision {0}.\n").format(rev.number))
1156 dlg.finish() 1176 dlg.finish()
1157 dlg.exec() 1177 dlg.exec()
1158 1178
1159 def vcsRevert(self, name): 1179 def vcsRevert(self, name):
1160 """ 1180 """
1161 Public method used to revert changes made to a file/directory. 1181 Public method used to revert changes made to a file/directory.
1162 1182
1163 @param name file/directory name to be reverted 1183 @param name file/directory name to be reverted
1164 @type str 1184 @type str
1165 @return flag indicating, that the update contained an add 1185 @return flag indicating, that the update contained an add
1166 or delete 1186 or delete
1167 @rtype bool 1187 @rtype bool
1169 recurse = False 1189 recurse = False
1170 if not isinstance(name, list): 1190 if not isinstance(name, list):
1171 name = [name] 1191 name = [name]
1172 if os.path.isdir(name[0]): 1192 if os.path.isdir(name[0]):
1173 recurse = True 1193 recurse = True
1174 1194
1175 project = ericApp().getObject("Project") 1195 project = ericApp().getObject("Project")
1176 names = [project.getRelativePath(nam) for nam in name] 1196 names = [project.getRelativePath(nam) for nam in name]
1177 if names[0]: 1197 if names[0]:
1178 from UI.DeleteFilesConfirmationDialog import ( 1198 from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
1179 DeleteFilesConfirmationDialog 1199
1180 )
1181 dia = DeleteFilesConfirmationDialog( 1200 dia = DeleteFilesConfirmationDialog(
1182 self.parent(), 1201 self.parent(),
1183 self.tr("Revert changes"), 1202 self.tr("Revert changes"),
1184 self.tr( 1203 self.tr(
1185 "Do you really want to revert all changes to these files" 1204 "Do you really want to revert all changes to these files"
1186 " or directories?"), 1205 " or directories?"
1187 name) 1206 ),
1207 name,
1208 )
1188 yes = dia.exec() == QDialog.DialogCode.Accepted 1209 yes = dia.exec() == QDialog.DialogCode.Accepted
1189 else: 1210 else:
1190 yes = EricMessageBox.yesNo( 1211 yes = EricMessageBox.yesNo(
1191 None, 1212 None,
1192 self.tr("Revert changes"), 1213 self.tr("Revert changes"),
1193 self.tr("""Do you really want to revert all changes of""" 1214 self.tr(
1194 """ the project?""")) 1215 """Do you really want to revert all changes of"""
1216 """ the project?"""
1217 ),
1218 )
1195 if yes: 1219 if yes:
1196 client = self.getClient() 1220 client = self.getClient()
1197 dlg = SvnDialog( 1221 dlg = SvnDialog(
1198 self.tr('Reverting changes'), 1222 self.tr("Reverting changes"),
1199 "revert {0} {1}".format( 1223 "revert {0} {1}".format(
1200 (not recurse) and " --non-recursive" or "", 1224 (not recurse) and " --non-recursive" or "", " ".join(name)
1201 " ".join(name)), 1225 ),
1202 client) 1226 client,
1227 )
1203 QApplication.processEvents() 1228 QApplication.processEvents()
1204 try: 1229 try:
1205 with EricMutexLocker(self.vcsExecutionMutex): 1230 with EricMutexLocker(self.vcsExecutionMutex):
1206 client.revert(name, recurse) 1231 client.revert(name, recurse)
1207 except pysvn.ClientError as e: 1232 except pysvn.ClientError as e:
1208 dlg.showError(e.args[0]) 1233 dlg.showError(e.args[0])
1209 dlg.finish() 1234 dlg.finish()
1210 dlg.exec() 1235 dlg.exec()
1211 self.checkVCSStatus() 1236 self.checkVCSStatus()
1212 1237
1213 return False 1238 return False
1214 1239
1215 def vcsForget(self, name): 1240 def vcsForget(self, name):
1216 """ 1241 """
1217 Public method used to remove a file from the repository. 1242 Public method used to remove a file from the repository.
1218 1243
1219 Note: svn does not support this operation. The method is implemented 1244 Note: svn does not support this operation. The method is implemented
1220 as a NoOp. 1245 as a NoOp.
1221 1246
1222 @param name file/directory name to be removed 1247 @param name file/directory name to be removed
1223 @type str or list of str 1248 @type str or list of str
1224 """ 1249 """
1225 pass 1250 pass
1226 1251
1227 def vcsSwitch(self, name): 1252 def vcsSwitch(self, name):
1228 """ 1253 """
1229 Public method used to switch a directory to a different tag/branch. 1254 Public method used to switch a directory to a different tag/branch.
1230 1255
1231 @param name directory name to be switched (string) 1256 @param name directory name to be switched (string)
1232 @return flag indicating, that the switch contained an add 1257 @return flag indicating, that the switch contained an add
1233 or delete (boolean) 1258 or delete (boolean)
1234 """ 1259 """
1235 dname, fname = self.splitPath(name) 1260 dname, fname = self.splitPath(name)
1236 1261
1237 reposURL = self.svnGetReposName(dname) 1262 reposURL = self.svnGetReposName(dname)
1238 if reposURL is None: 1263 if reposURL is None:
1239 EricMessageBox.critical( 1264 EricMessageBox.critical(
1240 self.__ui, 1265 self.__ui,
1241 self.tr("Subversion Error"), 1266 self.tr("Subversion Error"),
1242 self.tr( 1267 self.tr(
1243 """The URL of the project repository could not be""" 1268 """The URL of the project repository could not be"""
1244 """ retrieved from the working copy. The switch""" 1269 """ retrieved from the working copy. The switch"""
1245 """ operation will be aborted""")) 1270 """ operation will be aborted"""
1271 ),
1272 )
1246 return False 1273 return False
1247 1274
1248 url = ( 1275 url = (
1249 None 1276 None if self.otherData["standardLayout"] else self.svnNormalizeURL(reposURL)
1250 if self.otherData["standardLayout"] else
1251 self.svnNormalizeURL(reposURL)
1252 ) 1277 )
1253 from .SvnSwitchDialog import SvnSwitchDialog 1278 from .SvnSwitchDialog import SvnSwitchDialog
1254 dlg = SvnSwitchDialog(self.allTagsBranchesList, url, 1279
1255 self.otherData["standardLayout"]) 1280 dlg = SvnSwitchDialog(
1281 self.allTagsBranchesList, url, self.otherData["standardLayout"]
1282 )
1256 if dlg.exec() == QDialog.DialogCode.Accepted: 1283 if dlg.exec() == QDialog.DialogCode.Accepted:
1257 tag, tagType = dlg.getParameters() 1284 tag, tagType = dlg.getParameters()
1258 if tag in self.allTagsBranchesList: 1285 if tag in self.allTagsBranchesList:
1259 self.allTagsBranchesList.remove(tag) 1286 self.allTagsBranchesList.remove(tag)
1260 self.allTagsBranchesList.insert(0, tag) 1287 self.allTagsBranchesList.insert(0, tag)
1261 else: 1288 else:
1262 return False 1289 return False
1263 1290
1264 if self.otherData["standardLayout"]: 1291 if self.otherData["standardLayout"]:
1265 rx_base = re.compile('(.+)/(trunk|tags|branches).*') 1292 rx_base = re.compile("(.+)/(trunk|tags|branches).*")
1266 match = rx_base.fullmatch(reposURL) 1293 match = rx_base.fullmatch(reposURL)
1267 if match is None: 1294 if match is None:
1268 EricMessageBox.critical( 1295 EricMessageBox.critical(
1269 self.__ui, 1296 self.__ui,
1270 self.tr("Subversion Error"), 1297 self.tr("Subversion Error"),
1271 self.tr( 1298 self.tr(
1272 """The URL of the project repository has an""" 1299 """The URL of the project repository has an"""
1273 """ invalid format. The switch operation will""" 1300 """ invalid format. The switch operation will"""
1274 """ be aborted""")) 1301 """ be aborted"""
1302 ),
1303 )
1275 return False 1304 return False
1276 1305
1277 reposRoot = match.group(1) 1306 reposRoot = match.group(1)
1278 tn = tag 1307 tn = tag
1279 if tagType == 1: 1308 if tagType == 1:
1280 url = '{0}/tags/{1}'.format(reposRoot, quote(tag)) 1309 url = "{0}/tags/{1}".format(reposRoot, quote(tag))
1281 elif tagType == 2: 1310 elif tagType == 2:
1282 url = '{0}/branches/{1}'.format(reposRoot, quote(tag)) 1311 url = "{0}/branches/{1}".format(reposRoot, quote(tag))
1283 elif tagType == 4: 1312 elif tagType == 4:
1284 url = '{0}/trunk'.format(reposRoot) 1313 url = "{0}/trunk".format(reposRoot)
1285 tn = 'HEAD' 1314 tn = "HEAD"
1286 else: 1315 else:
1287 url = self.__svnURL(tag) 1316 url = self.__svnURL(tag)
1288 tn = url 1317 tn = url
1289 1318
1290 client = self.getClient() 1319 client = self.getClient()
1291 dlg = SvnDialog(self.tr('Switching to {0}').format(tn), 1320 dlg = SvnDialog(
1292 "switch {0} {1}".format(url, name), 1321 self.tr("Switching to {0}").format(tn),
1293 client) 1322 "switch {0} {1}".format(url, name),
1323 client,
1324 )
1294 QApplication.processEvents() 1325 QApplication.processEvents()
1295 try: 1326 try:
1296 with EricMutexLocker(self.vcsExecutionMutex): 1327 with EricMutexLocker(self.vcsExecutionMutex):
1297 rev = client.switch(name, url) 1328 rev = client.switch(name, url)
1298 dlg.showMessage(self.tr("Revision {0}.\n").format(rev.number)) 1329 dlg.showMessage(self.tr("Revision {0}.\n").format(rev.number))
1301 dlg.finish() 1332 dlg.finish()
1302 dlg.exec() 1333 dlg.exec()
1303 res = dlg.hasAddOrDelete() 1334 res = dlg.hasAddOrDelete()
1304 self.checkVCSStatus() 1335 self.checkVCSStatus()
1305 return res 1336 return res
1306 1337
1307 def vcsMerge(self, name): 1338 def vcsMerge(self, name):
1308 """ 1339 """
1309 Public method used to merge a URL/revision into the local project. 1340 Public method used to merge a URL/revision into the local project.
1310 1341
1311 @param name file/directory name to be merged (string) 1342 @param name file/directory name to be merged (string)
1312 """ 1343 """
1313 dname, fname = self.splitPath(name) 1344 dname, fname = self.splitPath(name)
1314 1345
1315 opts = self.options['global'] 1346 opts = self.options["global"]
1316 from .SvnMergeDialog import SvnMergeDialog 1347 from .SvnMergeDialog import SvnMergeDialog
1317 dlg = SvnMergeDialog(self.mergeList[0], self.mergeList[1], 1348
1318 self.mergeList[2], "--force" in opts) 1349 dlg = SvnMergeDialog(
1350 self.mergeList[0], self.mergeList[1], self.mergeList[2], "--force" in opts
1351 )
1319 if dlg.exec() == QDialog.DialogCode.Accepted: 1352 if dlg.exec() == QDialog.DialogCode.Accepted:
1320 urlrev1, urlrev2, target, force = dlg.getParameters() 1353 urlrev1, urlrev2, target, force = dlg.getParameters()
1321 else: 1354 else:
1322 return 1355 return
1323 1356
1324 # remember URL or revision 1357 # remember URL or revision
1325 if urlrev1 in self.mergeList[0]: 1358 if urlrev1 in self.mergeList[0]:
1326 self.mergeList[0].remove(urlrev1) 1359 self.mergeList[0].remove(urlrev1)
1327 self.mergeList[0].insert(0, urlrev1) 1360 self.mergeList[0].insert(0, urlrev1)
1328 if urlrev2 in self.mergeList[1]: 1361 if urlrev2 in self.mergeList[1]:
1329 self.mergeList[1].remove(urlrev2) 1362 self.mergeList[1].remove(urlrev2)
1330 self.mergeList[1].insert(0, urlrev2) 1363 self.mergeList[1].insert(0, urlrev2)
1331 1364
1332 rx_rev = re.compile('\\d+|HEAD|head') 1365 rx_rev = re.compile("\\d+|HEAD|head")
1333 1366
1334 cwd = os.getcwd() 1367 cwd = os.getcwd()
1335 os.chdir(dname) 1368 os.chdir(dname)
1336 recurse = "--non-recursive" not in opts 1369 recurse = "--non-recursive" not in opts
1337 if bool(rx_rev.fullmatch(urlrev1)): 1370 if bool(rx_rev.fullmatch(urlrev1)):
1338 if urlrev1 in ["HEAD", "head"]: 1371 if urlrev1 in ["HEAD", "head"]:
1339 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head) 1372 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head)
1340 rev1 = "HEAD" 1373 rev1 = "HEAD"
1341 else: 1374 else:
1342 revision1 = pysvn.Revision( 1375 revision1 = pysvn.Revision(pysvn.opt_revision_kind.number, int(urlrev1))
1343 pysvn.opt_revision_kind.number, int(urlrev1))
1344 rev1 = urlrev1 1376 rev1 = urlrev1
1345 if urlrev2 in ["HEAD", "head"]: 1377 if urlrev2 in ["HEAD", "head"]:
1346 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head) 1378 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head)
1347 rev2 = "HEAD" 1379 rev2 = "HEAD"
1348 else: 1380 else:
1349 revision2 = pysvn.Revision( 1381 revision2 = pysvn.Revision(pysvn.opt_revision_kind.number, int(urlrev2))
1350 pysvn.opt_revision_kind.number, int(urlrev2))
1351 rev2 = urlrev2 1382 rev2 = urlrev2
1352 if not target: 1383 if not target:
1353 url1 = name 1384 url1 = name
1354 url2 = name 1385 url2 = name
1355 else: 1386 else:
1356 url1 = target 1387 url1 = target
1357 url2 = target 1388 url2 = target
1358 1389
1359 # remember target 1390 # remember target
1360 if target in self.mergeList[2]: 1391 if target in self.mergeList[2]:
1361 self.mergeList[2].remove(target) 1392 self.mergeList[2].remove(target)
1362 self.mergeList[2].insert(0, target) 1393 self.mergeList[2].insert(0, target)
1363 else: 1394 else:
1365 url1, rev = urlrev1.split("@") 1396 url1, rev = urlrev1.split("@")
1366 if rev in ["HEAD", "head"]: 1397 if rev in ["HEAD", "head"]:
1367 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head) 1398 revision1 = pysvn.Revision(pysvn.opt_revision_kind.head)
1368 rev1 = "HEAD" 1399 rev1 = "HEAD"
1369 else: 1400 else:
1370 revision1 = pysvn.Revision( 1401 revision1 = pysvn.Revision(pysvn.opt_revision_kind.number, int(rev))
1371 pysvn.opt_revision_kind.number, int(rev))
1372 rev1 = rev 1402 rev1 = rev
1373 else: 1403 else:
1374 url1 = urlrev1 1404 url1 = urlrev1
1375 revision1 = pysvn.Revision(pysvn.opt_revision_kind.unspecified) 1405 revision1 = pysvn.Revision(pysvn.opt_revision_kind.unspecified)
1376 rev1 = "" 1406 rev1 = ""
1378 url2, rev = urlrev2.split("@") 1408 url2, rev = urlrev2.split("@")
1379 if rev in ["HEAD", "head"]: 1409 if rev in ["HEAD", "head"]:
1380 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head) 1410 revision2 = pysvn.Revision(pysvn.opt_revision_kind.head)
1381 rev2 = "HEAD" 1411 rev2 = "HEAD"
1382 else: 1412 else:
1383 revision2 = pysvn.Revision( 1413 revision2 = pysvn.Revision(pysvn.opt_revision_kind.number, int(rev))
1384 pysvn.opt_revision_kind.number, int(rev))
1385 rev2 = rev 1414 rev2 = rev
1386 else: 1415 else:
1387 url2 = urlrev2 1416 url2 = urlrev2
1388 revision2 = pysvn.Revision(pysvn.opt_revision_kind.unspecified) 1417 revision2 = pysvn.Revision(pysvn.opt_revision_kind.unspecified)
1389 rev2 = "" 1418 rev2 = ""
1390 client = self.getClient() 1419 client = self.getClient()
1391 dlg = SvnDialog( 1420 dlg = SvnDialog(
1392 self.tr('Merging {0}').format(name), 1421 self.tr("Merging {0}").format(name),
1393 "merge{0}{1} {2} {3} {4}".format( 1422 "merge{0}{1} {2} {3} {4}".format(
1394 (not recurse) and " --non-recursive" or "", 1423 (not recurse) and " --non-recursive" or "",
1395 force and " --force" or "", 1424 force and " --force" or "",
1396 "{0}{1}".format(url1, rev1 and ("@" + rev1) or ""), 1425 "{0}{1}".format(url1, rev1 and ("@" + rev1) or ""),
1397 "{0}{1}".format(url2, rev2 and ("@" + rev2) or ""), 1426 "{0}{1}".format(url2, rev2 and ("@" + rev2) or ""),
1398 fname), 1427 fname,
1399 client) 1428 ),
1429 client,
1430 )
1400 QApplication.processEvents() 1431 QApplication.processEvents()
1401 try: 1432 try:
1402 with EricMutexLocker(self.vcsExecutionMutex): 1433 with EricMutexLocker(self.vcsExecutionMutex):
1403 client.merge(url1, revision1, url2, revision2, fname, 1434 client.merge(
1404 recurse=recurse, force=force) 1435 url1,
1436 revision1,
1437 url2,
1438 revision2,
1439 fname,
1440 recurse=recurse,
1441 force=force,
1442 )
1405 except pysvn.ClientError as e: 1443 except pysvn.ClientError as e:
1406 dlg.showError(e.args[0]) 1444 dlg.showError(e.args[0])
1407 dlg.finish() 1445 dlg.finish()
1408 dlg.exec() 1446 dlg.exec()
1409 os.chdir(cwd) 1447 os.chdir(cwd)
1410 1448
1411 def vcsRegisteredState(self, name): 1449 def vcsRegisteredState(self, name):
1412 """ 1450 """
1413 Public method used to get the registered state of a file in the vcs. 1451 Public method used to get the registered state of a file in the vcs.
1414 1452
1415 @param name filename to check (string) 1453 @param name filename to check (string)
1416 @return a combination of canBeCommited and canBeAdded 1454 @return a combination of canBeCommited and canBeAdded
1417 """ 1455 """
1418 if self.__wcng: 1456 if self.__wcng:
1419 return self.__vcsRegisteredState_wcng(name) 1457 return self.__vcsRegisteredState_wcng(name)
1420 else: 1458 else:
1421 return self.__vcsRegisteredState_wc(name) 1459 return self.__vcsRegisteredState_wc(name)
1422 1460
1423 def __vcsRegisteredState_wcng(self, name): 1461 def __vcsRegisteredState_wcng(self, name):
1424 """ 1462 """
1425 Private method used to get the registered state of a file in the vcs. 1463 Private method used to get the registered state of a file in the vcs.
1426 1464
1427 This is the variant for subversion installations using the new 1465 This is the variant for subversion installations using the new
1428 working copy meta-data format. 1466 working copy meta-data format.
1429 1467
1430 @param name filename to check (string) 1468 @param name filename to check (string)
1431 @return a combination of canBeCommited and canBeAdded 1469 @return a combination of canBeCommited and canBeAdded
1432 """ 1470 """
1433 if name.endswith(os.sep): 1471 if name.endswith(os.sep):
1434 name = name[:-1] 1472 name = name[:-1]
1435 name = os.path.normcase(name) 1473 name = os.path.normcase(name)
1436 dname, fname = self.splitPath(name) 1474 dname, fname = self.splitPath(name)
1437 1475
1438 if fname == '.' and os.path.isdir(os.path.join(dname, self.adminDir)): 1476 if fname == "." and os.path.isdir(os.path.join(dname, self.adminDir)):
1439 return self.canBeCommitted 1477 return self.canBeCommitted
1440 1478
1441 if name in self.statusCache: 1479 if name in self.statusCache:
1442 return self.statusCache[name] 1480 return self.statusCache[name]
1443 1481
1444 name = os.path.normcase(name) 1482 name = os.path.normcase(name)
1445 states = {name: 0} 1483 states = {name: 0}
1446 states = self.vcsAllRegisteredStates(states, dname, False) 1484 states = self.vcsAllRegisteredStates(states, dname, False)
1447 if states[name] == self.canBeCommitted: 1485 if states[name] == self.canBeCommitted:
1448 return self.canBeCommitted 1486 return self.canBeCommitted
1449 else: 1487 else:
1450 return self.canBeAdded 1488 return self.canBeAdded
1451 1489
1452 def __vcsRegisteredState_wc(self, name): 1490 def __vcsRegisteredState_wc(self, name):
1453 """ 1491 """
1454 Private method used to get the registered state of a file in the vcs. 1492 Private method used to get the registered state of a file in the vcs.
1455 1493
1456 This is the variant for subversion installations using the old working 1494 This is the variant for subversion installations using the old working
1457 copy meta-data format. 1495 copy meta-data format.
1458 1496
1459 @param name filename to check (string) 1497 @param name filename to check (string)
1460 @return a combination of canBeCommited and canBeAdded 1498 @return a combination of canBeCommited and canBeAdded
1461 """ 1499 """
1462 dname, fname = self.splitPath(name) 1500 dname, fname = self.splitPath(name)
1463 1501
1464 if fname == '.': 1502 if fname == ".":
1465 if os.path.isdir(os.path.join(dname, self.adminDir)): 1503 if os.path.isdir(os.path.join(dname, self.adminDir)):
1466 return self.canBeCommitted 1504 return self.canBeCommitted
1467 else: 1505 else:
1468 return self.canBeAdded 1506 return self.canBeAdded
1469 1507
1470 name = os.path.normcase(name) 1508 name = os.path.normcase(name)
1471 states = {name: 0} 1509 states = {name: 0}
1472 states = self.vcsAllRegisteredStates(states, dname, False) 1510 states = self.vcsAllRegisteredStates(states, dname, False)
1473 if states[name] == self.canBeCommitted: 1511 if states[name] == self.canBeCommitted:
1474 return self.canBeCommitted 1512 return self.canBeCommitted
1475 else: 1513 else:
1476 return self.canBeAdded 1514 return self.canBeAdded
1477 1515
1478 def vcsAllRegisteredStates(self, names, dname, shortcut=True): 1516 def vcsAllRegisteredStates(self, names, dname, shortcut=True):
1479 """ 1517 """
1480 Public method used to get the registered states of a number of files 1518 Public method used to get the registered states of a number of files
1481 in the vcs. 1519 in the vcs.
1482 1520
1483 <b>Note:</b> If a shortcut is to be taken, the code will only check, 1521 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1484 if the named directory has been scanned already. If so, it is assumed, 1522 if the named directory has been scanned already. If so, it is assumed,
1485 that the states for all files has been populated by the previous run. 1523 that the states for all files has been populated by the previous run.
1486 1524
1487 @param names dictionary with all filenames to be checked as keys 1525 @param names dictionary with all filenames to be checked as keys
1488 @param dname directory to check in (string) 1526 @param dname directory to check in (string)
1489 @param shortcut flag indicating a shortcut should be taken (boolean) 1527 @param shortcut flag indicating a shortcut should be taken (boolean)
1490 @return the received dictionary completed with a combination of 1528 @return the received dictionary completed with a combination of
1491 canBeCommited and canBeAdded or None in order to signal an error 1529 canBeCommited and canBeAdded or None in order to signal an error
1492 """ 1530 """
1493 if self.__wcng: 1531 if self.__wcng:
1494 return self.__vcsAllRegisteredStates_wcng(names, dname, shortcut) 1532 return self.__vcsAllRegisteredStates_wcng(names, dname, shortcut)
1495 else: 1533 else:
1496 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut) 1534 return self.__vcsAllRegisteredStates_wc(names, dname, shortcut)
1497 1535
1498 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True): 1536 def __vcsAllRegisteredStates_wcng(self, names, dname, shortcut=True):
1499 """ 1537 """
1500 Private method used to get the registered states of a number of files 1538 Private method used to get the registered states of a number of files
1501 in the vcs. 1539 in the vcs.
1502 1540
1503 This is the variant for subversion installations using the new working 1541 This is the variant for subversion installations using the new working
1504 copy meta-data format. 1542 copy meta-data format.
1505 1543
1506 <b>Note:</b> If a shortcut is to be taken, the code will only check, 1544 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1507 if the named directory has been scanned already. If so, it is assumed, 1545 if the named directory has been scanned already. If so, it is assumed,
1508 that the states for all files has been populated by the previous run. 1546 that the states for all files has been populated by the previous run.
1509 1547
1510 @param names dictionary with all filenames to be checked as keys 1548 @param names dictionary with all filenames to be checked as keys
1511 @param dname directory to check in (string) 1549 @param dname directory to check in (string)
1512 @param shortcut flag indicating a shortcut should be taken (boolean) 1550 @param shortcut flag indicating a shortcut should be taken (boolean)
1513 @return the received dictionary completed with a combination of 1551 @return the received dictionary completed with a combination of
1514 canBeCommited and canBeAdded or None in order to signal an error 1552 canBeCommited and canBeAdded or None in order to signal an error
1515 """ 1553 """
1516 if dname.endswith(os.sep): 1554 if dname.endswith(os.sep):
1517 dname = dname[:-1] 1555 dname = dname[:-1]
1518 dname = os.path.normcase(dname) 1556 dname = os.path.normcase(dname)
1519 1557
1520 found = False 1558 found = False
1521 for name in self.statusCache: 1559 for name in self.statusCache:
1522 if name in names: 1560 if name in names:
1523 found = True 1561 found = True
1524 names[name] = self.statusCache[name] 1562 names[name] = self.statusCache[name]
1525 1563
1526 if not found: 1564 if not found:
1527 # find the root of the repo 1565 # find the root of the repo
1528 repodir = dname 1566 repodir = dname
1529 while not os.path.isdir(os.path.join(repodir, self.adminDir)): 1567 while not os.path.isdir(os.path.join(repodir, self.adminDir)):
1530 repodir = os.path.dirname(repodir) 1568 repodir = os.path.dirname(repodir)
1531 if os.path.splitdrive(repodir)[1] == os.sep: 1569 if os.path.splitdrive(repodir)[1] == os.sep:
1532 return names 1570 return names
1533 1571
1534 from .SvnDialogMixin import SvnDialogMixin 1572 from .SvnDialogMixin import SvnDialogMixin
1573
1535 mixin = SvnDialogMixin() 1574 mixin = SvnDialogMixin()
1536 client = self.getClient() 1575 client = self.getClient()
1537 client.callback_get_login = mixin._clientLoginCallback 1576 client.callback_get_login = mixin._clientLoginCallback
1538 client.callback_ssl_server_trust_prompt = ( 1577 client.callback_ssl_server_trust_prompt = (
1539 mixin._clientSslServerTrustPromptCallback 1578 mixin._clientSslServerTrustPromptCallback
1540 ) 1579 )
1541 1580
1542 with contextlib.suppress(pysvn.ClientError): 1581 with contextlib.suppress(pysvn.ClientError):
1543 with EricMutexLocker(self.vcsExecutionMutex): 1582 with EricMutexLocker(self.vcsExecutionMutex):
1544 allFiles = client.status(dname, recurse=True, get_all=True, 1583 allFiles = client.status(
1545 ignore=True, update=False) 1584 dname, recurse=True, get_all=True, ignore=True, update=False
1585 )
1546 dirs = [x for x in names.keys() if os.path.isdir(x)] 1586 dirs = [x for x in names.keys() if os.path.isdir(x)]
1547 for file in allFiles: 1587 for file in allFiles:
1548 name = os.path.normcase(file.path) 1588 name = os.path.normcase(file.path)
1549 if self.__isVersioned(file): 1589 if self.__isVersioned(file):
1550 if name in names: 1590 if name in names:
1551 names[name] = self.canBeCommitted 1591 names[name] = self.canBeCommitted
1552 dn = name 1592 dn = name
1553 while ( 1593 while os.path.splitdrive(dn)[1] != os.sep and dn != repodir:
1554 os.path.splitdrive(dn)[1] != os.sep and
1555 dn != repodir
1556 ):
1557 dn = os.path.dirname(dn) 1594 dn = os.path.dirname(dn)
1558 if ( 1595 if (
1559 dn in self.statusCache and 1596 dn in self.statusCache
1560 self.statusCache[dn] == 1597 and self.statusCache[dn] == self.canBeCommitted
1561 self.canBeCommitted
1562 ): 1598 ):
1563 break 1599 break
1564 self.statusCache[dn] = self.canBeCommitted 1600 self.statusCache[dn] = self.canBeCommitted
1565 self.statusCache[name] = self.canBeCommitted 1601 self.statusCache[name] = self.canBeCommitted
1566 if dirs: 1602 if dirs:
1570 self.statusCache[d] = self.canBeCommitted 1606 self.statusCache[d] = self.canBeCommitted
1571 dirs.remove(d) 1607 dirs.remove(d)
1572 break 1608 break
1573 else: 1609 else:
1574 self.statusCache[name] = self.canBeAdded 1610 self.statusCache[name] = self.canBeAdded
1575 1611
1576 return names 1612 return names
1577 1613
1578 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True): 1614 def __vcsAllRegisteredStates_wc(self, names, dname, shortcut=True):
1579 """ 1615 """
1580 Private method used to get the registered states of a number of files 1616 Private method used to get the registered states of a number of files
1581 in the VCS. 1617 in the VCS.
1582 1618
1583 This is the variant for subversion installations using the old working 1619 This is the variant for subversion installations using the old working
1584 copy meta-data format. 1620 copy meta-data format.
1585 1621
1586 <b>Note:</b> If a shortcut is to be taken, the code will only check, 1622 <b>Note:</b> If a shortcut is to be taken, the code will only check,
1587 if the named directory has been scanned already. If so, it is assumed, 1623 if the named directory has been scanned already. If so, it is assumed,
1588 that the states for all files has been populated by the previous run. 1624 that the states for all files has been populated by the previous run.
1589 1625
1590 @param names dictionary with all filenames to be checked as keys 1626 @param names dictionary with all filenames to be checked as keys
1591 @param dname directory to check in (string) 1627 @param dname directory to check in (string)
1592 @param shortcut flag indicating a shortcut should be taken (boolean) 1628 @param shortcut flag indicating a shortcut should be taken (boolean)
1593 @return the received dictionary completed with a combination of 1629 @return the received dictionary completed with a combination of
1594 canBeCommited and canBeAdded or None in order to signal an error 1630 canBeCommited and canBeAdded or None in order to signal an error
1595 """ 1631 """
1596 if not os.path.isdir(os.path.join(dname, self.adminDir)): 1632 if not os.path.isdir(os.path.join(dname, self.adminDir)):
1597 # not under version control -> do nothing 1633 # not under version control -> do nothing
1598 return names 1634 return names
1599 1635
1600 found = False 1636 found = False
1601 for name in self.statusCache: 1637 for name in self.statusCache:
1602 if os.path.dirname(name) == dname: 1638 if os.path.dirname(name) == dname:
1603 if shortcut: 1639 if shortcut:
1604 found = True 1640 found = True
1605 break 1641 break
1606 if name in names: 1642 if name in names:
1607 found = True 1643 found = True
1608 names[name] = self.statusCache[name] 1644 names[name] = self.statusCache[name]
1609 1645
1610 if not found: 1646 if not found:
1611 from .SvnDialogMixin import SvnDialogMixin 1647 from .SvnDialogMixin import SvnDialogMixin
1648
1612 mixin = SvnDialogMixin() 1649 mixin = SvnDialogMixin()
1613 client = self.getClient() 1650 client = self.getClient()
1614 client.callback_get_login = mixin._clientLoginCallback 1651 client.callback_get_login = mixin._clientLoginCallback
1615 client.callback_ssl_server_trust_prompt = ( 1652 client.callback_ssl_server_trust_prompt = (
1616 mixin._clientSslServerTrustPromptCallback 1653 mixin._clientSslServerTrustPromptCallback
1617 ) 1654 )
1618 1655
1619 with contextlib.suppress(pysvn.ClientError): 1656 with contextlib.suppress(pysvn.ClientError):
1620 with EricMutexLocker(self.vcsExecutionMutex): 1657 with EricMutexLocker(self.vcsExecutionMutex):
1621 allFiles = client.status(dname, recurse=True, get_all=True, 1658 allFiles = client.status(
1622 ignore=True, update=False) 1659 dname, recurse=True, get_all=True, ignore=True, update=False
1660 )
1623 for file in allFiles: 1661 for file in allFiles:
1624 name = os.path.normcase(file.path) 1662 name = os.path.normcase(file.path)
1625 if self.__isVersioned(file): 1663 if self.__isVersioned(file):
1626 if name in names: 1664 if name in names:
1627 names[name] = self.canBeCommitted 1665 names[name] = self.canBeCommitted
1628 self.statusCache[name] = self.canBeCommitted 1666 self.statusCache[name] = self.canBeCommitted
1629 else: 1667 else:
1630 self.statusCache[name] = self.canBeAdded 1668 self.statusCache[name] = self.canBeAdded
1631 1669
1632 return names 1670 return names
1633 1671
1634 def __isVersioned(self, status): 1672 def __isVersioned(self, status):
1635 """ 1673 """
1636 Private method to check, if the given status indicates a 1674 Private method to check, if the given status indicates a
1637 versioned state. 1675 versioned state.
1638 1676
1639 @param status status object to check (pysvn.PysvnStatus) 1677 @param status status object to check (pysvn.PysvnStatus)
1640 @return flag indicating a versioned state (boolean) 1678 @return flag indicating a versioned state (boolean)
1641 """ 1679 """
1642 return status["text_status"] in [ 1680 return status["text_status"] in [
1643 pysvn.wc_status_kind.normal, 1681 pysvn.wc_status_kind.normal,
1647 pysvn.wc_status_kind.replaced, 1685 pysvn.wc_status_kind.replaced,
1648 pysvn.wc_status_kind.modified, 1686 pysvn.wc_status_kind.modified,
1649 pysvn.wc_status_kind.merged, 1687 pysvn.wc_status_kind.merged,
1650 pysvn.wc_status_kind.conflicted, 1688 pysvn.wc_status_kind.conflicted,
1651 ] 1689 ]
1652 1690
1653 def clearStatusCache(self): 1691 def clearStatusCache(self):
1654 """ 1692 """
1655 Public method to clear the status cache. 1693 Public method to clear the status cache.
1656 """ 1694 """
1657 self.statusCache = {} 1695 self.statusCache = {}
1658 1696
1659 def vcsInitConfig(self, project): 1697 def vcsInitConfig(self, project):
1660 """ 1698 """
1661 Public method to initialize the VCS configuration. 1699 Public method to initialize the VCS configuration.
1662 1700
1663 This method ensures, that eric specific files and directories are 1701 This method ensures, that eric specific files and directories are
1664 ignored. 1702 ignored.
1665 1703
1666 @param project reference to the project (Project) 1704 @param project reference to the project (Project)
1667 """ 1705 """
1668 configPath = getConfigPath() 1706 configPath = getConfigPath()
1669 if os.path.exists(configPath): 1707 if os.path.exists(configPath):
1670 amendConfig() 1708 amendConfig()
1671 else: 1709 else:
1672 createDefaultConfig() 1710 createDefaultConfig()
1673 1711
1674 def vcsName(self): 1712 def vcsName(self):
1675 """ 1713 """
1676 Public method returning the name of the vcs. 1714 Public method returning the name of the vcs.
1677 1715
1678 @return always 'Subversion' (string) 1716 @return always 'Subversion' (string)
1679 """ 1717 """
1680 return "Subversion" 1718 return "Subversion"
1681 1719
1682 def vcsCleanup(self, name): 1720 def vcsCleanup(self, name):
1683 """ 1721 """
1684 Public method used to cleanup the working copy. 1722 Public method used to cleanup the working copy.
1685 1723
1686 @param name directory name to be cleaned up (string) 1724 @param name directory name to be cleaned up (string)
1687 """ 1725 """
1688 client = self.getClient() 1726 client = self.getClient()
1689 dlg = SvnDialog(self.tr('Cleaning up {0}').format(name), 1727 dlg = SvnDialog(
1690 "cleanup {0}".format(name), 1728 self.tr("Cleaning up {0}").format(name), "cleanup {0}".format(name), client
1691 client) 1729 )
1692 QApplication.processEvents() 1730 QApplication.processEvents()
1693 try: 1731 try:
1694 with EricMutexLocker(self.vcsExecutionMutex): 1732 with EricMutexLocker(self.vcsExecutionMutex):
1695 client.cleanup(name) 1733 client.cleanup(name)
1696 except pysvn.ClientError as e: 1734 except pysvn.ClientError as e:
1697 dlg.showError(e.args[0]) 1735 dlg.showError(e.args[0])
1698 dlg.finish() 1736 dlg.finish()
1699 dlg.exec() 1737 dlg.exec()
1700 1738
1701 def vcsCommandLine(self, name): 1739 def vcsCommandLine(self, name):
1702 """ 1740 """
1703 Public method used to execute arbitrary subversion commands. 1741 Public method used to execute arbitrary subversion commands.
1704 1742
1705 @param name directory name of the working directory (string) 1743 @param name directory name of the working directory (string)
1706 """ 1744 """
1707 from .SvnCommandDialog import SvnCommandDialog 1745 from .SvnCommandDialog import SvnCommandDialog
1746
1708 dlg = SvnCommandDialog(self.commandHistory, self.wdHistory, name) 1747 dlg = SvnCommandDialog(self.commandHistory, self.wdHistory, name)
1709 if dlg.exec() == QDialog.DialogCode.Accepted: 1748 if dlg.exec() == QDialog.DialogCode.Accepted:
1710 command, wd = dlg.getData() 1749 command, wd = dlg.getData()
1711 commandList = Utilities.parseOptionString(command) 1750 commandList = Utilities.parseOptionString(command)
1712 1751
1713 # This moves any previous occurrence of these arguments to the head 1752 # This moves any previous occurrence of these arguments to the head
1714 # of the list. 1753 # of the list.
1715 if command in self.commandHistory: 1754 if command in self.commandHistory:
1716 self.commandHistory.remove(command) 1755 self.commandHistory.remove(command)
1717 self.commandHistory.insert(0, command) 1756 self.commandHistory.insert(0, command)
1718 if wd in self.wdHistory: 1757 if wd in self.wdHistory:
1719 self.wdHistory.remove(wd) 1758 self.wdHistory.remove(wd)
1720 self.wdHistory.insert(0, wd) 1759 self.wdHistory.insert(0, wd)
1721 1760
1722 args = [] 1761 args = []
1723 self.addArguments(args, commandList) 1762 self.addArguments(args, commandList)
1724 1763
1725 from Plugins.VcsPlugins.vcsSubversion.SvnDialog import ( 1764 from Plugins.VcsPlugins.vcsSubversion.SvnDialog import (
1726 SvnDialog as SvnProcessDialog 1765 SvnDialog as SvnProcessDialog,
1727 ) 1766 )
1728 dia = SvnProcessDialog(self.tr('Subversion command')) 1767
1768 dia = SvnProcessDialog(self.tr("Subversion command"))
1729 res = dia.startProcess(args, wd) 1769 res = dia.startProcess(args, wd)
1730 if res: 1770 if res:
1731 dia.exec() 1771 dia.exec()
1732 1772
1733 def vcsOptionsDialog(self, project, archive, editable=False, parent=None): 1773 def vcsOptionsDialog(self, project, archive, editable=False, parent=None):
1734 """ 1774 """
1735 Public method to get a dialog to enter repository info. 1775 Public method to get a dialog to enter repository info.
1736 1776
1737 @param project reference to the project object 1777 @param project reference to the project object
1738 @param archive name of the project in the repository (string) 1778 @param archive name of the project in the repository (string)
1739 @param editable flag indicating that the project name is editable 1779 @param editable flag indicating that the project name is editable
1740 (boolean) 1780 (boolean)
1741 @param parent parent widget (QWidget) 1781 @param parent parent widget (QWidget)
1742 @return reference to the instantiated options dialog (SvnOptionsDialog) 1782 @return reference to the instantiated options dialog (SvnOptionsDialog)
1743 """ 1783 """
1744 from .SvnOptionsDialog import SvnOptionsDialog 1784 from .SvnOptionsDialog import SvnOptionsDialog
1785
1745 return SvnOptionsDialog(self, project, parent) 1786 return SvnOptionsDialog(self, project, parent)
1746 1787
1747 def vcsNewProjectOptionsDialog(self, parent=None): 1788 def vcsNewProjectOptionsDialog(self, parent=None):
1748 """ 1789 """
1749 Public method to get a dialog to enter repository info for getting a 1790 Public method to get a dialog to enter repository info for getting a
1750 new project. 1791 new project.
1751 1792
1752 @param parent parent widget (QWidget) 1793 @param parent parent widget (QWidget)
1753 @return reference to the instantiated options dialog 1794 @return reference to the instantiated options dialog
1754 (SvnNewProjectOptionsDialog) 1795 (SvnNewProjectOptionsDialog)
1755 """ 1796 """
1756 from .SvnNewProjectOptionsDialog import SvnNewProjectOptionsDialog 1797 from .SvnNewProjectOptionsDialog import SvnNewProjectOptionsDialog
1798
1757 return SvnNewProjectOptionsDialog(self, parent) 1799 return SvnNewProjectOptionsDialog(self, parent)
1758 1800
1759 def vcsRepositoryInfos(self, ppath): 1801 def vcsRepositoryInfos(self, ppath):
1760 """ 1802 """
1761 Public method to retrieve information about the repository. 1803 Public method to retrieve information about the repository.
1762 1804
1763 @param ppath local path to get the repository infos (string) 1805 @param ppath local path to get the repository infos (string)
1764 @return string with ready formated info for display (string) 1806 @return string with ready formated info for display (string)
1765 """ 1807 """
1766 try: 1808 try:
1767 entry = self.getClient().info(ppath) 1809 entry = self.getClient().info(ppath)
1768 except pysvn.ClientError as e: 1810 except pysvn.ClientError as e:
1769 return e.args[0] 1811 return e.args[0]
1770 1812
1771 apiVersion = ( 1813 apiVersion = (
1772 "{0} {1}".format( 1814 "{0} {1}".format(
1773 ".".join([str(v) for v in pysvn.svn_api_version[:3]]), 1815 ".".join([str(v) for v in pysvn.svn_api_version[:3]]),
1774 pysvn.svn_api_version[3]) 1816 pysvn.svn_api_version[3],
1775 if hasattr(pysvn, 'svn_api_version') else 1817 )
1776 QCoreApplication.translate('subversion', "unknown") 1818 if hasattr(pysvn, "svn_api_version")
1819 else QCoreApplication.translate("subversion", "unknown")
1777 ) 1820 )
1778 1821
1779 hmsz = time.strftime("%H:%M:%S %Z", time.localtime(entry.commit_time)) 1822 hmsz = time.strftime("%H:%M:%S %Z", time.localtime(entry.commit_time))
1780 return QCoreApplication.translate( 1823 return QCoreApplication.translate(
1781 'subversion', 1824 "subversion",
1782 """<h3>Repository information</h3>""" 1825 """<h3>Repository information</h3>"""
1783 """<table>""" 1826 """<table>"""
1784 """<tr><td><b>PySvn V.</b></td><td>{0}</td></tr>""" 1827 """<tr><td><b>PySvn V.</b></td><td>{0}</td></tr>"""
1785 """<tr><td><b>Subversion V.</b></td><td>{1}</td></tr>""" 1828 """<tr><td><b>Subversion V.</b></td><td>{1}</td></tr>"""
1786 """<tr><td><b>Subversion API V.</b></td><td>{2}</td></tr>""" 1829 """<tr><td><b>Subversion API V.</b></td><td>{2}</td></tr>"""
1788 """<tr><td><b>Current revision</b></td><td>{4}</td></tr>""" 1831 """<tr><td><b>Current revision</b></td><td>{4}</td></tr>"""
1789 """<tr><td><b>Committed revision</b></td><td>{5}</td></tr>""" 1832 """<tr><td><b>Committed revision</b></td><td>{5}</td></tr>"""
1790 """<tr><td><b>Committed date</b></td><td>{6}</td></tr>""" 1833 """<tr><td><b>Committed date</b></td><td>{6}</td></tr>"""
1791 """<tr><td><b>Comitted time</b></td><td>{7}</td></tr>""" 1834 """<tr><td><b>Comitted time</b></td><td>{7}</td></tr>"""
1792 """<tr><td><b>Last author</b></td><td>{8}</td></tr>""" 1835 """<tr><td><b>Last author</b></td><td>{8}</td></tr>"""
1793 """</table>""" 1836 """</table>""",
1794 ).format( 1837 ).format(
1795 ".".join([str(v) for v in pysvn.version]), 1838 ".".join([str(v) for v in pysvn.version]),
1796 ".".join([str(v) for v in pysvn.svn_version[:3]]), 1839 ".".join([str(v) for v in pysvn.svn_version[:3]]),
1797 apiVersion, 1840 apiVersion,
1798 entry.url, 1841 entry.url,
1799 entry.revision.number, 1842 entry.revision.number,
1800 entry.commit_revision.number, 1843 entry.commit_revision.number,
1801 time.strftime( 1844 time.strftime("%Y-%m-%d", time.localtime(entry.commit_time)),
1802 "%Y-%m-%d", time.localtime(entry.commit_time)),
1803 hmsz, 1845 hmsz,
1804 entry.commit_author 1846 entry.commit_author,
1805 ) 1847 )
1806 1848
1807 ########################################################################### 1849 ###########################################################################
1808 ## Public Subversion specific methods are below. 1850 ## Public Subversion specific methods are below.
1809 ########################################################################### 1851 ###########################################################################
1810 1852
1811 def svnGetReposName(self, path): 1853 def svnGetReposName(self, path):
1812 """ 1854 """
1813 Public method used to retrieve the URL of the subversion repository 1855 Public method used to retrieve the URL of the subversion repository
1814 path. 1856 path.
1815 1857
1816 @param path local path to get the svn repository path for (string) 1858 @param path local path to get the svn repository path for (string)
1817 @return string with the repository path URL 1859 @return string with the repository path URL
1818 """ 1860 """
1819 client = pysvn.Client() 1861 client = pysvn.Client()
1820 try: 1862 try:
1826 return url 1868 return url
1827 1869
1828 def vcsResolved(self, name): 1870 def vcsResolved(self, name):
1829 """ 1871 """
1830 Public method used to resolve conflicts of a file/directory. 1872 Public method used to resolve conflicts of a file/directory.
1831 1873
1832 @param name file/directory name to be resolved (string) 1874 @param name file/directory name to be resolved (string)
1833 """ 1875 """
1834 if isinstance(name, list): 1876 if isinstance(name, list):
1835 dname, fnames = self.splitPathList(name) 1877 dname, fnames = self.splitPathList(name)
1836 else: 1878 else:
1837 dname, fname = self.splitPath(name) 1879 dname, fname = self.splitPath(name)
1838 fnames = [fname] 1880 fnames = [fname]
1839 1881
1840 cwd = os.getcwd() 1882 cwd = os.getcwd()
1841 os.chdir(dname) 1883 os.chdir(dname)
1842 opts = self.options['global'] 1884 opts = self.options["global"]
1843 recurse = "--non-recursive" not in opts 1885 recurse = "--non-recursive" not in opts
1844 client = self.getClient() 1886 client = self.getClient()
1845 dlg = SvnDialog(self.tr('Resolving conficts'), 1887 dlg = SvnDialog(
1846 "resolved{0} {1}".format( 1888 self.tr("Resolving conficts"),
1847 (not recurse) and " --non-recursive" or "", 1889 "resolved{0} {1}".format(
1848 " ".join(fnames)), 1890 (not recurse) and " --non-recursive" or "", " ".join(fnames)
1849 client) 1891 ),
1892 client,
1893 )
1850 QApplication.processEvents() 1894 QApplication.processEvents()
1851 try: 1895 try:
1852 with EricMutexLocker(self.vcsExecutionMutex): 1896 with EricMutexLocker(self.vcsExecutionMutex):
1853 for name in fnames: 1897 for name in fnames:
1854 client.resolved(name, recurse=recurse) 1898 client.resolved(name, recurse=recurse)
1856 dlg.showError(e.args[0]) 1900 dlg.showError(e.args[0])
1857 dlg.finish() 1901 dlg.finish()
1858 dlg.exec() 1902 dlg.exec()
1859 os.chdir(cwd) 1903 os.chdir(cwd)
1860 self.checkVCSStatus() 1904 self.checkVCSStatus()
1861 1905
1862 def svnCopy(self, name, project): 1906 def svnCopy(self, name, project):
1863 """ 1907 """
1864 Public method used to copy a file/directory. 1908 Public method used to copy a file/directory.
1865 1909
1866 @param name file/directory name to be copied (string) 1910 @param name file/directory name to be copied (string)
1867 @param project reference to the project object 1911 @param project reference to the project object
1868 @return flag indicating successfull operation (boolean) 1912 @return flag indicating successfull operation (boolean)
1869 """ 1913 """
1870 from .SvnCopyDialog import SvnCopyDialog 1914 from .SvnCopyDialog import SvnCopyDialog
1871 rx_prot = re.compile('(file:|svn:|svn+ssh:|http:|https:).+') 1915
1916 rx_prot = re.compile("(file:|svn:|svn+ssh:|http:|https:).+")
1872 dlg = SvnCopyDialog(name) 1917 dlg = SvnCopyDialog(name)
1873 res = False 1918 res = False
1874 if dlg.exec() == QDialog.DialogCode.Accepted: 1919 if dlg.exec() == QDialog.DialogCode.Accepted:
1875 target, force = dlg.getData() 1920 target, force = dlg.getData()
1876 1921
1877 client = self.getClient() 1922 client = self.getClient()
1878 if bool(rx_prot.fullmatch(target)): 1923 if bool(rx_prot.fullmatch(target)):
1879 target = self.__svnURL(target) 1924 target = self.__svnURL(target)
1880 log = "Copying {0} to {1}".format(name, target) 1925 log = "Copying {0} to {1}".format(name, target)
1881 else: 1926 else:
1882 log = "" 1927 log = ""
1883 target = target 1928 target = target
1884 dlg = SvnDialog( 1929 dlg = SvnDialog(
1885 self.tr('Copying {0}').format(name), 1930 self.tr("Copying {0}").format(name),
1886 "copy{0} {1} {2}".format( 1931 "copy{0} {1} {2}".format(
1887 log and (" --message {0}".format(log)) or "", 1932 log and (" --message {0}".format(log)) or "", name, target
1888 name, target), 1933 ),
1889 client, log=log) 1934 client,
1935 log=log,
1936 )
1890 QApplication.processEvents() 1937 QApplication.processEvents()
1891 try: 1938 try:
1892 with EricMutexLocker(self.vcsExecutionMutex): 1939 with EricMutexLocker(self.vcsExecutionMutex):
1893 client.copy(name, target) 1940 client.copy(name, target)
1894 res = True 1941 res = True
1896 res = False 1943 res = False
1897 dlg.showError(e.args[0]) 1944 dlg.showError(e.args[0])
1898 dlg.finish() 1945 dlg.finish()
1899 dlg.exec() 1946 dlg.exec()
1900 if ( 1947 if (
1901 res and 1948 res
1902 not bool(rx_prot.fullmatch(target)) and 1949 and not bool(rx_prot.fullmatch(target))
1903 target.startswith(project.getProjectPath()) 1950 and target.startswith(project.getProjectPath())
1904 ): 1951 ):
1905 if os.path.isdir(name): 1952 if os.path.isdir(name):
1906 project.copyDirectory(name, target) 1953 project.copyDirectory(name, target)
1907 else: 1954 else:
1908 project.appendFile(target) 1955 project.appendFile(target)
1909 return res 1956 return res
1910 1957
1911 def svnListProps(self, name, recursive=False): 1958 def svnListProps(self, name, recursive=False):
1912 """ 1959 """
1913 Public method used to list the properties of a file/directory. 1960 Public method used to list the properties of a file/directory.
1914 1961
1915 @param name file/directory name (string or list of strings) 1962 @param name file/directory name (string or list of strings)
1916 @param recursive flag indicating a recursive list is requested 1963 @param recursive flag indicating a recursive list is requested
1917 """ 1964 """
1918 if self.propList is None: 1965 if self.propList is None:
1919 from .SvnPropListDialog import SvnPropListDialog 1966 from .SvnPropListDialog import SvnPropListDialog
1967
1920 self.propList = SvnPropListDialog(self) 1968 self.propList = SvnPropListDialog(self)
1921 self.propList.show() 1969 self.propList.show()
1922 self.propList.raise_() 1970 self.propList.raise_()
1923 QApplication.processEvents() 1971 QApplication.processEvents()
1924 self.propList.start(name, recursive) 1972 self.propList.start(name, recursive)
1925 1973
1926 def svnSetProp(self, name, recursive=False): 1974 def svnSetProp(self, name, recursive=False):
1927 """ 1975 """
1928 Public method used to add a property to a file/directory. 1976 Public method used to add a property to a file/directory.
1929 1977
1930 @param name file/directory name (string or list of strings) 1978 @param name file/directory name (string or list of strings)
1931 @param recursive flag indicating a recursive set is requested 1979 @param recursive flag indicating a recursive set is requested
1932 """ 1980 """
1933 from .SvnPropSetDialog import SvnPropSetDialog 1981 from .SvnPropSetDialog import SvnPropSetDialog
1982
1934 dlg = SvnPropSetDialog(recursive) 1983 dlg = SvnPropSetDialog(recursive)
1935 if dlg.exec() == QDialog.DialogCode.Accepted: 1984 if dlg.exec() == QDialog.DialogCode.Accepted:
1936 propName, propValue, recurse = dlg.getData() 1985 propName, propValue, recurse = dlg.getData()
1937 if not propName: 1986 if not propName:
1938 EricMessageBox.critical( 1987 EricMessageBox.critical(
1939 self.__ui, 1988 self.__ui,
1940 self.tr("Subversion Set Property"), 1989 self.tr("Subversion Set Property"),
1941 self.tr( 1990 self.tr("""You have to supply a property name. Aborting."""),
1942 """You have to supply a property name. Aborting.""")) 1991 )
1943 return 1992 return
1944 1993
1945 if isinstance(name, list): 1994 if isinstance(name, list):
1946 dname, fnames = self.splitPathList(name) 1995 dname, fnames = self.splitPathList(name)
1947 else: 1996 else:
1948 dname, fname = self.splitPath(name) 1997 dname, fname = self.splitPath(name)
1949 fnames = [fname] 1998 fnames = [fname]
1950 1999
1951 cwd = os.getcwd() 2000 cwd = os.getcwd()
1952 os.chdir(dname) 2001 os.chdir(dname)
1953 opts = self.options['global'] 2002 opts = self.options["global"]
1954 skipchecks = "--skip-checks" in opts 2003 skipchecks = "--skip-checks" in opts
1955 client = self.getClient() 2004 client = self.getClient()
1956 dlg = SvnDialog( 2005 dlg = SvnDialog(
1957 self.tr('Subversion Set Property'), 2006 self.tr("Subversion Set Property"),
1958 "propset{0}{1} {2} {3} {4}".format( 2007 "propset{0}{1} {2} {3} {4}".format(
1959 recurse and " --recurse" or "", 2008 recurse and " --recurse" or "",
1960 skipchecks and " --skip-checks" or "", 2009 skipchecks and " --skip-checks" or "",
1961 propName, propValue, 2010 propName,
1962 " ".join(fnames)), 2011 propValue,
1963 client) 2012 " ".join(fnames),
2013 ),
2014 client,
2015 )
1964 QApplication.processEvents() 2016 QApplication.processEvents()
1965 try: 2017 try:
1966 with EricMutexLocker(self.vcsExecutionMutex): 2018 with EricMutexLocker(self.vcsExecutionMutex):
1967 for name in fnames: 2019 for name in fnames:
1968 client.propset(propName, propValue, name, 2020 client.propset(
1969 recurse=recurse, skip_checks=skipchecks) 2021 propName,
2022 propValue,
2023 name,
2024 recurse=recurse,
2025 skip_checks=skipchecks,
2026 )
1970 except pysvn.ClientError as e: 2027 except pysvn.ClientError as e:
1971 dlg.showError(e.args[0]) 2028 dlg.showError(e.args[0])
1972 dlg.showMessage(self.tr("Property set.")) 2029 dlg.showMessage(self.tr("Property set."))
1973 dlg.finish() 2030 dlg.finish()
1974 dlg.exec() 2031 dlg.exec()
1975 os.chdir(cwd) 2032 os.chdir(cwd)
1976 2033
1977 def svnDelProp(self, name, recursive=False): 2034 def svnDelProp(self, name, recursive=False):
1978 """ 2035 """
1979 Public method used to delete a property of a file/directory. 2036 Public method used to delete a property of a file/directory.
1980 2037
1981 @param name file/directory name (string or list of strings) 2038 @param name file/directory name (string or list of strings)
1982 @param recursive flag indicating a recursive list is requested 2039 @param recursive flag indicating a recursive list is requested
1983 """ 2040 """
1984 from .SvnPropDelDialog import SvnPropDelDialog 2041 from .SvnPropDelDialog import SvnPropDelDialog
2042
1985 dlg = SvnPropDelDialog(recursive) 2043 dlg = SvnPropDelDialog(recursive)
1986 if dlg.exec() == QDialog.DialogCode.Accepted: 2044 if dlg.exec() == QDialog.DialogCode.Accepted:
1987 propName, recurse = dlg.getData() 2045 propName, recurse = dlg.getData()
1988 2046
1989 if not propName: 2047 if not propName:
1990 EricMessageBox.critical( 2048 EricMessageBox.critical(
1991 self.__ui, 2049 self.__ui,
1992 self.tr("Subversion Delete Property"), 2050 self.tr("Subversion Delete Property"),
1993 self.tr( 2051 self.tr("""You have to supply a property name. Aborting."""),
1994 """You have to supply a property name. Aborting.""")) 2052 )
1995 return 2053 return
1996 2054
1997 if isinstance(name, list): 2055 if isinstance(name, list):
1998 dname, fnames = self.splitPathList(name) 2056 dname, fnames = self.splitPathList(name)
1999 else: 2057 else:
2000 dname, fname = self.splitPath(name) 2058 dname, fname = self.splitPath(name)
2001 fnames = [fname] 2059 fnames = [fname]
2002 2060
2003 cwd = os.getcwd() 2061 cwd = os.getcwd()
2004 os.chdir(dname) 2062 os.chdir(dname)
2005 opts = self.options['global'] 2063 opts = self.options["global"]
2006 skipchecks = "--skip-checks" in opts 2064 skipchecks = "--skip-checks" in opts
2007 client = self.getClient() 2065 client = self.getClient()
2008 dlg = SvnDialog( 2066 dlg = SvnDialog(
2009 self.tr('Subversion Delete Property'), 2067 self.tr("Subversion Delete Property"),
2010 "propdel{0}{1} {2} {3}".format( 2068 "propdel{0}{1} {2} {3}".format(
2011 recurse and " --recurse" or "", 2069 recurse and " --recurse" or "",
2012 skipchecks and " --skip-checks" or "", 2070 skipchecks and " --skip-checks" or "",
2013 propName, " ".join(fnames)), 2071 propName,
2014 client) 2072 " ".join(fnames),
2073 ),
2074 client,
2075 )
2015 QApplication.processEvents() 2076 QApplication.processEvents()
2016 try: 2077 try:
2017 with EricMutexLocker(self.vcsExecutionMutex): 2078 with EricMutexLocker(self.vcsExecutionMutex):
2018 for name in fnames: 2079 for name in fnames:
2019 client.propdel(propName, name, 2080 client.propdel(
2020 recurse=recurse, skip_checks=skipchecks) 2081 propName, name, recurse=recurse, skip_checks=skipchecks
2082 )
2021 except pysvn.ClientError as e: 2083 except pysvn.ClientError as e:
2022 dlg.showError(e.args[0]) 2084 dlg.showError(e.args[0])
2023 dlg.showMessage(self.tr("Property deleted.")) 2085 dlg.showMessage(self.tr("Property deleted."))
2024 dlg.finish() 2086 dlg.finish()
2025 dlg.exec() 2087 dlg.exec()
2026 os.chdir(cwd) 2088 os.chdir(cwd)
2027 2089
2028 def svnListTagBranch(self, path, tags=True): 2090 def svnListTagBranch(self, path, tags=True):
2029 """ 2091 """
2030 Public method used to list the available tags or branches. 2092 Public method used to list the available tags or branches.
2031 2093
2032 @param path directory name of the project (string) 2094 @param path directory name of the project (string)
2033 @param tags flag indicating listing of branches or tags 2095 @param tags flag indicating listing of branches or tags
2034 (False = branches, True = tags) 2096 (False = branches, True = tags)
2035 """ 2097 """
2036 if self.tagbranchList is None: 2098 if self.tagbranchList is None:
2037 from .SvnTagBranchListDialog import SvnTagBranchListDialog 2099 from .SvnTagBranchListDialog import SvnTagBranchListDialog
2100
2038 self.tagbranchList = SvnTagBranchListDialog(self) 2101 self.tagbranchList = SvnTagBranchListDialog(self)
2039 self.tagbranchList.show() 2102 self.tagbranchList.show()
2040 self.tagbranchList.raise_() 2103 self.tagbranchList.raise_()
2041 QApplication.processEvents() 2104 QApplication.processEvents()
2042 res = self.tagbranchList.start(path, tags) 2105 res = self.tagbranchList.start(path, tags)
2043 if res: 2106 if res:
2044 if tags: 2107 if tags:
2045 self.tagsList = self.tagbranchList.getTagList() 2108 self.tagsList = self.tagbranchList.getTagList()
2046 if not self.showedTags: 2109 if not self.showedTags:
2047 self.allTagsBranchesList = ( 2110 self.allTagsBranchesList = self.allTagsBranchesList + self.tagsList
2048 self.allTagsBranchesList +
2049 self.tagsList
2050 )
2051 self.showedTags = True 2111 self.showedTags = True
2052 elif not tags: 2112 elif not tags:
2053 self.branchesList = self.tagbranchList.getTagList() 2113 self.branchesList = self.tagbranchList.getTagList()
2054 if not self.showedBranches: 2114 if not self.showedBranches:
2055 self.allTagsBranchesList = ( 2115 self.allTagsBranchesList = (
2056 self.allTagsBranchesList + 2116 self.allTagsBranchesList + self.branchesList
2057 self.branchesList
2058 ) 2117 )
2059 self.showedBranches = True 2118 self.showedBranches = True
2060 2119
2061 def svnBlame(self, name): 2120 def svnBlame(self, name):
2062 """ 2121 """
2063 Public method to show the output of the svn blame command. 2122 Public method to show the output of the svn blame command.
2064 2123
2065 @param name file name to show the blame for (string) 2124 @param name file name to show the blame for (string)
2066 """ 2125 """
2067 if self.blame is None: 2126 if self.blame is None:
2068 from .SvnBlameDialog import SvnBlameDialog 2127 from .SvnBlameDialog import SvnBlameDialog
2128
2069 self.blame = SvnBlameDialog(self) 2129 self.blame = SvnBlameDialog(self)
2070 self.blame.show() 2130 self.blame.show()
2071 self.blame.raise_() 2131 self.blame.raise_()
2072 QApplication.processEvents() 2132 QApplication.processEvents()
2073 self.blame.start(name) 2133 self.blame.start(name)
2074 2134
2075 def svnExtendedDiff(self, name): 2135 def svnExtendedDiff(self, name):
2076 """ 2136 """
2077 Public method used to view the difference of a file/directory to the 2137 Public method used to view the difference of a file/directory to the
2078 Subversion repository. 2138 Subversion repository.
2079 2139
2080 If name is a directory and is the project directory, all project files 2140 If name is a directory and is the project directory, all project files
2081 are saved first. If name is a file (or list of files), which is/are 2141 are saved first. If name is a file (or list of files), which is/are
2082 being edited and has unsaved modification, they can be saved or the 2142 being edited and has unsaved modification, they can be saved or the
2083 operation may be aborted. 2143 operation may be aborted.
2084 2144
2085 This method gives the chance to enter the revisions to be compared. 2145 This method gives the chance to enter the revisions to be compared.
2086 2146
2087 @param name file/directory name to be diffed (string) 2147 @param name file/directory name to be diffed (string)
2088 """ 2148 """
2089 names = name[:] if isinstance(name, list) else [name] 2149 names = name[:] if isinstance(name, list) else [name]
2090 for nam in names: 2150 for nam in names:
2091 if os.path.isfile(nam): 2151 if os.path.isfile(nam):
2095 else: 2155 else:
2096 project = ericApp().getObject("Project") 2156 project = ericApp().getObject("Project")
2097 if nam == project.ppath and not project.saveAllScripts(): 2157 if nam == project.ppath and not project.saveAllScripts():
2098 return 2158 return
2099 from .SvnRevisionSelectionDialog import SvnRevisionSelectionDialog 2159 from .SvnRevisionSelectionDialog import SvnRevisionSelectionDialog
2160
2100 dlg = SvnRevisionSelectionDialog() 2161 dlg = SvnRevisionSelectionDialog()
2101 if dlg.exec() == QDialog.DialogCode.Accepted: 2162 if dlg.exec() == QDialog.DialogCode.Accepted:
2102 revisions = dlg.getRevisions() 2163 revisions = dlg.getRevisions()
2103 if self.diff is None: 2164 if self.diff is None:
2104 from .SvnDiffDialog import SvnDiffDialog 2165 from .SvnDiffDialog import SvnDiffDialog
2166
2105 self.diff = SvnDiffDialog(self) 2167 self.diff = SvnDiffDialog(self)
2106 self.diff.show() 2168 self.diff.show()
2107 self.diff.raise_() 2169 self.diff.raise_()
2108 QApplication.processEvents() 2170 QApplication.processEvents()
2109 self.diff.start(name, revisions) 2171 self.diff.start(name, revisions)
2110 2172
2111 def svnUrlDiff(self, name): 2173 def svnUrlDiff(self, name):
2112 """ 2174 """
2113 Public method used to view the difference of a file/directory of two 2175 Public method used to view the difference of a file/directory of two
2114 repository URLs. 2176 repository URLs.
2115 2177
2116 If name is a directory and is the project directory, all project files 2178 If name is a directory and is the project directory, all project files
2117 are saved first. If name is a file (or list of files), which is/are 2179 are saved first. If name is a file (or list of files), which is/are
2118 being edited and has unsaved modification, they can be saved or the 2180 being edited and has unsaved modification, they can be saved or the
2119 operation may be aborted. 2181 operation may be aborted.
2120 2182
2121 This method gives the chance to enter the revisions to be compared. 2183 This method gives the chance to enter the revisions to be compared.
2122 2184
2123 @param name file/directory name to be diffed (string) 2185 @param name file/directory name to be diffed (string)
2124 """ 2186 """
2125 names = name[:] if isinstance(name, list) else [name] 2187 names = name[:] if isinstance(name, list) else [name]
2126 for nam in names: 2188 for nam in names:
2127 if os.path.isfile(nam): 2189 if os.path.isfile(nam):
2130 return 2192 return
2131 else: 2193 else:
2132 project = ericApp().getObject("Project") 2194 project = ericApp().getObject("Project")
2133 if nam == project.ppath and not project.saveAllScripts(): 2195 if nam == project.ppath and not project.saveAllScripts():
2134 return 2196 return
2135 2197
2136 dname = self.splitPath(names[0])[0] 2198 dname = self.splitPath(names[0])[0]
2137 2199
2138 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog 2200 from .SvnUrlSelectionDialog import SvnUrlSelectionDialog
2139 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList, 2201
2140 dname) 2202 dlg = SvnUrlSelectionDialog(self, self.tagsList, self.branchesList, dname)
2141 if dlg.exec() == QDialog.DialogCode.Accepted: 2203 if dlg.exec() == QDialog.DialogCode.Accepted:
2142 urls, summary = dlg.getURLs() 2204 urls, summary = dlg.getURLs()
2143 if self.diff is None: 2205 if self.diff is None:
2144 from .SvnDiffDialog import SvnDiffDialog 2206 from .SvnDiffDialog import SvnDiffDialog
2207
2145 self.diff = SvnDiffDialog(self) 2208 self.diff = SvnDiffDialog(self)
2146 self.diff.show() 2209 self.diff.show()
2147 self.diff.raise_() 2210 self.diff.raise_()
2148 QApplication.processEvents() 2211 QApplication.processEvents()
2149 self.diff.start(name, urls=urls, summary=summary) 2212 self.diff.start(name, urls=urls, summary=summary)
2150 2213
2151 def __svnGetFileForRevision(self, name, rev=""): 2214 def __svnGetFileForRevision(self, name, rev=""):
2152 """ 2215 """
2153 Private method to get a file for a specific revision from the 2216 Private method to get a file for a specific revision from the
2154 repository. 2217 repository.
2155 2218
2156 @param name file name to get from the repository (string) 2219 @param name file name to get from the repository (string)
2157 @param rev revision to retrieve (integer or string) 2220 @param rev revision to retrieve (integer or string)
2158 @return contents of the file (string) and an error message (string) 2221 @return contents of the file (string) and an error message (string)
2159 """ 2222 """
2160 output = "" 2223 output = ""
2161 error = "" 2224 error = ""
2162 2225
2163 client = self.getClient() 2226 client = self.getClient()
2164 try: 2227 try:
2165 if rev: 2228 if rev:
2166 if isinstance(rev, int) or rev.isdecimal(): 2229 if isinstance(rev, int) or rev.isdecimal():
2167 rev = pysvn.Revision( 2230 rev = pysvn.Revision(pysvn.opt_revision_kind.number, int(rev))
2168 pysvn.opt_revision_kind.number, int(rev))
2169 elif rev.startswith("{"): 2231 elif rev.startswith("{"):
2170 dateStr = rev[1:-1] 2232 dateStr = rev[1:-1]
2171 secs = QDateTime.fromString( 2233 secs = QDateTime.fromString(
2172 dateStr, Qt.DateFormat.ISODate).toTime_t() 2234 dateStr, Qt.DateFormat.ISODate
2235 ).toTime_t()
2173 rev = pysvn.Revision(pysvn.opt_revision_kind.date, secs) 2236 rev = pysvn.Revision(pysvn.opt_revision_kind.date, secs)
2174 elif rev == "HEAD": 2237 elif rev == "HEAD":
2175 rev = pysvn.Revision(pysvn.opt_revision_kind.head) 2238 rev = pysvn.Revision(pysvn.opt_revision_kind.head)
2176 elif rev == "COMMITTED": 2239 elif rev == "COMMITTED":
2177 rev = pysvn.Revision(pysvn.opt_revision_kind.committed) 2240 rev = pysvn.Revision(pysvn.opt_revision_kind.committed)
2184 else: 2247 else:
2185 rev = pysvn.Revision(pysvn.opt_revision_kind.unspecified) 2248 rev = pysvn.Revision(pysvn.opt_revision_kind.unspecified)
2186 output = client.cat(name, revision=rev) 2249 output = client.cat(name, revision=rev)
2187 else: 2250 else:
2188 output = client.cat(name) 2251 output = client.cat(name)
2189 output = output.decode('utf-8') 2252 output = output.decode("utf-8")
2190 except pysvn.ClientError as e: 2253 except pysvn.ClientError as e:
2191 error = str(e) 2254 error = str(e)
2192 2255
2193 return output, error 2256 return output, error
2194 2257
2195 def vcsSbsDiff(self, name, extended=False, revisions=None): 2258 def vcsSbsDiff(self, name, extended=False, revisions=None):
2196 """ 2259 """
2197 Public method used to view the difference of a file to the Mercurial 2260 Public method used to view the difference of a file to the Mercurial
2198 repository side-by-side. 2261 repository side-by-side.
2199 2262
2200 @param name file name to be diffed (string) 2263 @param name file name to be diffed (string)
2201 @param extended flag indicating the extended variant (boolean) 2264 @param extended flag indicating the extended variant (boolean)
2202 @param revisions tuple of two revisions (tuple of strings) 2265 @param revisions tuple of two revisions (tuple of strings)
2203 @exception ValueError raised to indicate an invalid name parameter type 2266 @exception ValueError raised to indicate an invalid name parameter type
2204 """ 2267 """
2205 if isinstance(name, list): 2268 if isinstance(name, list):
2206 raise ValueError("Wrong parameter type") 2269 raise ValueError("Wrong parameter type")
2207 2270
2208 if extended: 2271 if extended:
2209 from .SvnRevisionSelectionDialog import SvnRevisionSelectionDialog 2272 from .SvnRevisionSelectionDialog import SvnRevisionSelectionDialog
2273
2210 dlg = SvnRevisionSelectionDialog() 2274 dlg = SvnRevisionSelectionDialog()
2211 if dlg.exec() == QDialog.DialogCode.Accepted: 2275 if dlg.exec() == QDialog.DialogCode.Accepted:
2212 rev1, rev2 = dlg.getRevisions() 2276 rev1, rev2 = dlg.getRevisions()
2213 if rev1 == "WORKING": 2277 if rev1 == "WORKING":
2214 rev1 = "" 2278 rev1 = ""
2218 return 2282 return
2219 elif revisions: 2283 elif revisions:
2220 rev1, rev2 = revisions[0], revisions[1] 2284 rev1, rev2 = revisions[0], revisions[1]
2221 else: 2285 else:
2222 rev1, rev2 = "", "" 2286 rev1, rev2 = "", ""
2223 2287
2224 output1, error = self.__svnGetFileForRevision(name, rev=rev1) 2288 output1, error = self.__svnGetFileForRevision(name, rev=rev1)
2225 if error: 2289 if error:
2226 EricMessageBox.critical( 2290 EricMessageBox.critical(
2227 self.__ui, 2291 self.__ui, self.tr("Subversion Side-by-Side Difference"), error
2228 self.tr("Subversion Side-by-Side Difference"), 2292 )
2229 error)
2230 return 2293 return
2231 name1 = "{0} (rev. {1})".format(name, rev1 and rev1 or ".") 2294 name1 = "{0} (rev. {1})".format(name, rev1 and rev1 or ".")
2232 2295
2233 if rev2: 2296 if rev2:
2234 output2, error = self.__svnGetFileForRevision(name, rev=rev2) 2297 output2, error = self.__svnGetFileForRevision(name, rev=rev2)
2235 if error: 2298 if error:
2236 EricMessageBox.critical( 2299 EricMessageBox.critical(
2237 self.__ui, 2300 self.__ui, self.tr("Subversion Side-by-Side Difference"), error
2238 self.tr("Subversion Side-by-Side Difference"), 2301 )
2239 error)
2240 return 2302 return
2241 name2 = "{0} (rev. {1})".format(name, rev2) 2303 name2 = "{0} (rev. {1})".format(name, rev2)
2242 else: 2304 else:
2243 try: 2305 try:
2244 with open(name, "r", encoding="utf-8") as f1: 2306 with open(name, "r", encoding="utf-8") as f1:
2246 name2 = name 2308 name2 = name
2247 except OSError: 2309 except OSError:
2248 EricMessageBox.critical( 2310 EricMessageBox.critical(
2249 self.__ui, 2311 self.__ui,
2250 self.tr("Subversion Side-by-Side Difference"), 2312 self.tr("Subversion Side-by-Side Difference"),
2251 self.tr( 2313 self.tr("""<p>The file <b>{0}</b> could not be read.</p>""").format(
2252 """<p>The file <b>{0}</b> could not be read.</p>""") 2314 name
2253 .format(name)) 2315 ),
2316 )
2254 return 2317 return
2255 2318
2256 if self.sbsDiff is None: 2319 if self.sbsDiff is None:
2257 from UI.CompareDialog import CompareDialog 2320 from UI.CompareDialog import CompareDialog
2321
2258 self.sbsDiff = CompareDialog() 2322 self.sbsDiff = CompareDialog()
2259 self.sbsDiff.show() 2323 self.sbsDiff.show()
2260 self.sbsDiff.raise_() 2324 self.sbsDiff.raise_()
2261 self.sbsDiff.compare(output1, output2, name1, name2) 2325 self.sbsDiff.compare(output1, output2, name1, name2)
2262 2326
2263 def vcsLogBrowser(self, name, isFile=False): 2327 def vcsLogBrowser(self, name, isFile=False):
2264 """ 2328 """
2265 Public method used to browse the log of a file/directory from the 2329 Public method used to browse the log of a file/directory from the
2266 Subversion repository. 2330 Subversion repository.
2267 2331
2268 @param name file/directory name to show the log of (string) 2332 @param name file/directory name to show the log of (string)
2269 @param isFile flag indicating log for a file is to be shown (boolean) 2333 @param isFile flag indicating log for a file is to be shown (boolean)
2270 """ 2334 """
2271 if self.logBrowser is None: 2335 if self.logBrowser is None:
2272 from .SvnLogBrowserDialog import SvnLogBrowserDialog 2336 from .SvnLogBrowserDialog import SvnLogBrowserDialog
2337
2273 self.logBrowser = SvnLogBrowserDialog(self) 2338 self.logBrowser = SvnLogBrowserDialog(self)
2274 self.logBrowser.show() 2339 self.logBrowser.show()
2275 self.logBrowser.raise_() 2340 self.logBrowser.raise_()
2276 QApplication.processEvents() 2341 QApplication.processEvents()
2277 self.logBrowser.start(name, isFile=isFile) 2342 self.logBrowser.start(name, isFile=isFile)
2278 2343
2279 def svnLock(self, name, stealIt=False, parent=None): 2344 def svnLock(self, name, stealIt=False, parent=None):
2280 """ 2345 """
2281 Public method used to lock a file in the Subversion repository. 2346 Public method used to lock a file in the Subversion repository.
2282 2347
2283 @param name file/directory name to be locked (string or list of 2348 @param name file/directory name to be locked (string or list of
2284 strings) 2349 strings)
2285 @param stealIt flag indicating a forced operation (boolean) 2350 @param stealIt flag indicating a forced operation (boolean)
2286 @param parent reference to the parent object of the subversion dialog 2351 @param parent reference to the parent object of the subversion dialog
2287 (QWidget) 2352 (QWidget)
2288 """ 2353 """
2289 comment, ok = QInputDialog.getText( 2354 comment, ok = QInputDialog.getText(
2290 None, 2355 None,
2291 self.tr("Subversion Lock"), 2356 self.tr("Subversion Lock"),
2292 self.tr("Enter lock comment"), 2357 self.tr("Enter lock comment"),
2293 QLineEdit.EchoMode.Normal) 2358 QLineEdit.EchoMode.Normal,
2294 2359 )
2360
2295 if not ok: 2361 if not ok:
2296 return 2362 return
2297 2363
2298 if isinstance(name, list): 2364 if isinstance(name, list):
2299 dname, fnames = self.splitPathList(name) 2365 dname, fnames = self.splitPathList(name)
2300 else: 2366 else:
2301 dname, fname = self.splitPath(name) 2367 dname, fname = self.splitPath(name)
2302 fnames = [fname] 2368 fnames = [fname]
2303 2369
2304 cwd = os.getcwd() 2370 cwd = os.getcwd()
2305 os.chdir(dname) 2371 os.chdir(dname)
2306 client = self.getClient() 2372 client = self.getClient()
2307 dlg = SvnDialog( 2373 dlg = SvnDialog(
2308 self.tr('Locking in the Subversion repository'), 2374 self.tr("Locking in the Subversion repository"),
2309 "lock{0}{1} {2}".format( 2375 "lock{0}{1} {2}".format(
2310 stealIt and " --force" or "", 2376 stealIt and " --force" or "",
2311 comment and (" --message {0}".format(comment)) or "", 2377 comment and (" --message {0}".format(comment)) or "",
2312 " ".join(fnames)), 2378 " ".join(fnames),
2313 client, parent=parent) 2379 ),
2380 client,
2381 parent=parent,
2382 )
2314 QApplication.processEvents() 2383 QApplication.processEvents()
2315 try: 2384 try:
2316 with EricMutexLocker(self.vcsExecutionMutex): 2385 with EricMutexLocker(self.vcsExecutionMutex):
2317 client.lock(fnames, comment, force=stealIt) 2386 client.lock(fnames, comment, force=stealIt)
2318 except pysvn.ClientError as e: 2387 except pysvn.ClientError as e:
2320 except AttributeError as e: 2389 except AttributeError as e:
2321 dlg.showError(str(e)) 2390 dlg.showError(str(e))
2322 dlg.finish() 2391 dlg.finish()
2323 dlg.exec() 2392 dlg.exec()
2324 os.chdir(cwd) 2393 os.chdir(cwd)
2325 2394
2326 def svnUnlock(self, name, breakIt=False, parent=None): 2395 def svnUnlock(self, name, breakIt=False, parent=None):
2327 """ 2396 """
2328 Public method used to unlock a file in the Subversion repository. 2397 Public method used to unlock a file in the Subversion repository.
2329 2398
2330 @param name file/directory name to be unlocked (string or list of 2399 @param name file/directory name to be unlocked (string or list of
2331 strings) 2400 strings)
2332 @param breakIt flag indicating a forced operation (boolean) 2401 @param breakIt flag indicating a forced operation (boolean)
2333 @param parent reference to the parent object of the subversion dialog 2402 @param parent reference to the parent object of the subversion dialog
2334 (QWidget) 2403 (QWidget)
2336 if isinstance(name, list): 2405 if isinstance(name, list):
2337 dname, fnames = self.splitPathList(name) 2406 dname, fnames = self.splitPathList(name)
2338 else: 2407 else:
2339 dname, fname = self.splitPath(name) 2408 dname, fname = self.splitPath(name)
2340 fnames = [fname] 2409 fnames = [fname]
2341 2410
2342 cwd = os.getcwd() 2411 cwd = os.getcwd()
2343 os.chdir(dname) 2412 os.chdir(dname)
2344 client = self.getClient() 2413 client = self.getClient()
2345 dlg = SvnDialog( 2414 dlg = SvnDialog(
2346 self.tr('Unlocking in the Subversion repository'), 2415 self.tr("Unlocking in the Subversion repository"),
2347 "unlock{0} {1}".format(breakIt and " --force" or "", 2416 "unlock{0} {1}".format(breakIt and " --force" or "", " ".join(fnames)),
2348 " ".join(fnames)), 2417 client,
2349 client, parent=parent) 2418 parent=parent,
2419 )
2350 QApplication.processEvents() 2420 QApplication.processEvents()
2351 try: 2421 try:
2352 with EricMutexLocker(self.vcsExecutionMutex): 2422 with EricMutexLocker(self.vcsExecutionMutex):
2353 client.unlock(fnames, force=breakIt) 2423 client.unlock(fnames, force=breakIt)
2354 except pysvn.ClientError as e: 2424 except pysvn.ClientError as e:
2356 except AttributeError as e: 2426 except AttributeError as e:
2357 dlg.showError(str(e)) 2427 dlg.showError(str(e))
2358 dlg.finish() 2428 dlg.finish()
2359 dlg.exec() 2429 dlg.exec()
2360 os.chdir(cwd) 2430 os.chdir(cwd)
2361 2431
2362 def svnInfo(self, projectPath, name): 2432 def svnInfo(self, projectPath, name):
2363 """ 2433 """
2364 Public method to show repository information about a file or directory. 2434 Public method to show repository information about a file or directory.
2365 2435
2366 @param projectPath path name of the project (string) 2436 @param projectPath path name of the project (string)
2367 @param name file/directory name relative to the project (string) 2437 @param name file/directory name relative to the project (string)
2368 """ 2438 """
2369 from .SvnInfoDialog import SvnInfoDialog 2439 from .SvnInfoDialog import SvnInfoDialog
2440
2370 dlg = SvnInfoDialog(self) 2441 dlg = SvnInfoDialog(self)
2371 dlg.start(projectPath, name) 2442 dlg.start(projectPath, name)
2372 dlg.exec() 2443 dlg.exec()
2373 2444
2374 def svnRelocate(self, projectPath): 2445 def svnRelocate(self, projectPath):
2375 """ 2446 """
2376 Public method to relocate the working copy to a new repository URL. 2447 Public method to relocate the working copy to a new repository URL.
2377 2448
2378 @param projectPath path name of the project (string) 2449 @param projectPath path name of the project (string)
2379 """ 2450 """
2380 from .SvnRelocateDialog import SvnRelocateDialog 2451 from .SvnRelocateDialog import SvnRelocateDialog
2452
2381 currUrl = self.svnGetReposName(projectPath) 2453 currUrl = self.svnGetReposName(projectPath)
2382 dlg = SvnRelocateDialog(currUrl) 2454 dlg = SvnRelocateDialog(currUrl)
2383 if dlg.exec() == QDialog.DialogCode.Accepted: 2455 if dlg.exec() == QDialog.DialogCode.Accepted:
2384 newUrl, inside = dlg.getData() 2456 newUrl, inside = dlg.getData()
2385 if inside: 2457 if inside:
2386 msg = "switch {0} {1}".format(newUrl, projectPath) 2458 msg = "switch {0} {1}".format(newUrl, projectPath)
2387 else: 2459 else:
2388 msg = "relocate {0} {1} {2}".format(currUrl, newUrl, 2460 msg = "relocate {0} {1} {2}".format(currUrl, newUrl, projectPath)
2389 projectPath)
2390 client = self.getClient() 2461 client = self.getClient()
2391 dlg = SvnDialog(self.tr('Relocating'), msg, client) 2462 dlg = SvnDialog(self.tr("Relocating"), msg, client)
2392 QApplication.processEvents() 2463 QApplication.processEvents()
2393 try: 2464 try:
2394 with EricMutexLocker(self.vcsExecutionMutex): 2465 with EricMutexLocker(self.vcsExecutionMutex):
2395 if inside: 2466 if inside:
2396 client.switch(projectPath, newUrl) 2467 client.switch(projectPath, newUrl)
2397 else: 2468 else:
2398 client.relocate(currUrl, newUrl, projectPath, 2469 client.relocate(currUrl, newUrl, projectPath, recurse=True)
2399 recurse=True)
2400 except pysvn.ClientError as e: 2470 except pysvn.ClientError as e:
2401 dlg.showError(e.args[0]) 2471 dlg.showError(e.args[0])
2402 dlg.finish() 2472 dlg.finish()
2403 dlg.exec() 2473 dlg.exec()
2404 2474
2405 def svnRepoBrowser(self, projectPath=None): 2475 def svnRepoBrowser(self, projectPath=None):
2406 """ 2476 """
2407 Public method to open the repository browser. 2477 Public method to open the repository browser.
2408 2478
2409 @param projectPath path name of the project (string) 2479 @param projectPath path name of the project (string)
2410 """ 2480 """
2411 url = self.svnGetReposName(projectPath) if projectPath else None 2481 url = self.svnGetReposName(projectPath) if projectPath else None
2412 if url is None: 2482 if url is None:
2413 url, ok = QInputDialog.getText( 2483 url, ok = QInputDialog.getText(
2414 None, 2484 None,
2415 self.tr("Repository Browser"), 2485 self.tr("Repository Browser"),
2416 self.tr("Enter the repository URL."), 2486 self.tr("Enter the repository URL."),
2417 QLineEdit.EchoMode.Normal) 2487 QLineEdit.EchoMode.Normal,
2488 )
2418 if not ok or not url: 2489 if not ok or not url:
2419 return 2490 return
2420 2491
2421 if self.repoBrowser is None: 2492 if self.repoBrowser is None:
2422 from .SvnRepoBrowserDialog import SvnRepoBrowserDialog 2493 from .SvnRepoBrowserDialog import SvnRepoBrowserDialog
2494
2423 self.repoBrowser = SvnRepoBrowserDialog(self) 2495 self.repoBrowser = SvnRepoBrowserDialog(self)
2424 self.repoBrowser.start(url) 2496 self.repoBrowser.start(url)
2425 self.repoBrowser.show() 2497 self.repoBrowser.show()
2426 self.repoBrowser.raise_() 2498 self.repoBrowser.raise_()
2427 2499
2428 def svnRemoveFromChangelist(self, names): 2500 def svnRemoveFromChangelist(self, names):
2429 """ 2501 """
2430 Public method to remove a file or directory from its changelist. 2502 Public method to remove a file or directory from its changelist.
2431 2503
2432 Note: Directories will be removed recursively. 2504 Note: Directories will be removed recursively.
2433 2505
2434 @param names name or list of names of file or directory to remove 2506 @param names name or list of names of file or directory to remove
2435 (string) 2507 (string)
2436 """ 2508 """
2437 if not isinstance(names, list): 2509 if not isinstance(names, list):
2438 names = [names] 2510 names = [names]
2439 client = self.getClient() 2511 client = self.getClient()
2440 dlg = SvnDialog( 2512 dlg = SvnDialog(
2441 self.tr('Remove from changelist'), 2513 self.tr("Remove from changelist"),
2442 "changelist --remove {0}".format(" ".join(names)), 2514 "changelist --remove {0}".format(" ".join(names)),
2443 client) 2515 client,
2516 )
2444 QApplication.processEvents() 2517 QApplication.processEvents()
2445 try: 2518 try:
2446 with EricMutexLocker(self.vcsExecutionMutex): 2519 with EricMutexLocker(self.vcsExecutionMutex):
2447 for name in names: 2520 for name in names:
2448 client.remove_from_changelists(name) 2521 client.remove_from_changelists(name)
2449 except pysvn.ClientError as e: 2522 except pysvn.ClientError as e:
2450 dlg.showError(e.args[0]) 2523 dlg.showError(e.args[0])
2451 dlg.finish() 2524 dlg.finish()
2452 dlg.exec() 2525 dlg.exec()
2453 2526
2454 def svnAddToChangelist(self, names): 2527 def svnAddToChangelist(self, names):
2455 """ 2528 """
2456 Public method to add a file or directory to a changelist. 2529 Public method to add a file or directory to a changelist.
2457 2530
2458 Note: Directories will be added recursively. 2531 Note: Directories will be added recursively.
2459 2532
2460 @param names name or list of names of file or directory to add 2533 @param names name or list of names of file or directory to add
2461 (string) 2534 (string)
2462 """ 2535 """
2463 if not isinstance(names, list): 2536 if not isinstance(names, list):
2464 names = [names] 2537 names = [names]
2465 2538
2466 clname, ok = QInputDialog.getItem( 2539 clname, ok = QInputDialog.getItem(
2467 None, 2540 None,
2468 self.tr("Add to changelist"), 2541 self.tr("Add to changelist"),
2469 self.tr("Enter name of the changelist:"), 2542 self.tr("Enter name of the changelist:"),
2470 sorted(self.svnGetChangelists()), 2543 sorted(self.svnGetChangelists()),
2471 0, True) 2544 0,
2545 True,
2546 )
2472 if not ok or not clname: 2547 if not ok or not clname:
2473 return 2548 return
2474 2549
2475 client = self.getClient() 2550 client = self.getClient()
2476 dlg = SvnDialog( 2551 dlg = SvnDialog(
2477 self.tr('Add to changelist'), 2552 self.tr("Add to changelist"),
2478 "changelist {0}".format(" ".join(names)), 2553 "changelist {0}".format(" ".join(names)),
2479 client) 2554 client,
2555 )
2480 QApplication.processEvents() 2556 QApplication.processEvents()
2481 try: 2557 try:
2482 with EricMutexLocker(self.vcsExecutionMutex): 2558 with EricMutexLocker(self.vcsExecutionMutex):
2483 for name in names: 2559 for name in names:
2484 client.add_to_changelist( 2560 client.add_to_changelist(name, clname, depth=pysvn.depth.infinity)
2485 name, clname, depth=pysvn.depth.infinity)
2486 except pysvn.ClientError as e: 2561 except pysvn.ClientError as e:
2487 dlg.showError(e.args[0]) 2562 dlg.showError(e.args[0])
2488 dlg.finish() 2563 dlg.finish()
2489 dlg.exec() 2564 dlg.exec()
2490 2565
2491 def svnShowChangelists(self, path): 2566 def svnShowChangelists(self, path):
2492 """ 2567 """
2493 Public method used to inspect the change lists defined for the project. 2568 Public method used to inspect the change lists defined for the project.
2494 2569
2495 @param path directory name to show change lists for (string) 2570 @param path directory name to show change lists for (string)
2496 """ 2571 """
2497 from .SvnChangeListsDialog import SvnChangeListsDialog 2572 from .SvnChangeListsDialog import SvnChangeListsDialog
2573
2498 self.changeLists = SvnChangeListsDialog(self) 2574 self.changeLists = SvnChangeListsDialog(self)
2499 self.changeLists.show() 2575 self.changeLists.show()
2500 QApplication.processEvents() 2576 QApplication.processEvents()
2501 self.changeLists.start(path) 2577 self.changeLists.start(path)
2502 2578
2503 def svnGetChangelists(self): 2579 def svnGetChangelists(self):
2504 """ 2580 """
2505 Public method to get a list of all defined change lists. 2581 Public method to get a list of all defined change lists.
2506 2582
2507 @return list of defined change list names (list of strings) 2583 @return list of defined change list names (list of strings)
2508 """ 2584 """
2509 changelists = [] 2585 changelists = []
2510 client = self.getClient() 2586 client = self.getClient()
2511 if hasattr(client, 'get_changelist'): 2587 if hasattr(client, "get_changelist"):
2512 ppath = ericApp().getObject("Project").getProjectPath() 2588 ppath = ericApp().getObject("Project").getProjectPath()
2513 with contextlib.suppress(pysvn.ClientError): 2589 with contextlib.suppress(pysvn.ClientError):
2514 with EricMutexLocker(self.vcsExecutionMutex): 2590 with EricMutexLocker(self.vcsExecutionMutex):
2515 entries = client.get_changelist( 2591 entries = client.get_changelist(ppath, depth=pysvn.depth.infinity)
2516 ppath, depth=pysvn.depth.infinity)
2517 for entry in entries: 2592 for entry in entries:
2518 changelist = entry[1] 2593 changelist = entry[1]
2519 if changelist not in changelists: 2594 if changelist not in changelists:
2520 changelists.append(changelist) 2595 changelists.append(changelist)
2521 2596
2522 return changelists 2597 return changelists
2523 2598
2524 def svnUpgrade(self, path): 2599 def svnUpgrade(self, path):
2525 """ 2600 """
2526 Public method to upgrade the working copy format. 2601 Public method to upgrade the working copy format.
2527 2602
2528 @param path directory name to show change lists for (string) 2603 @param path directory name to show change lists for (string)
2529 """ 2604 """
2530 client = self.getClient() 2605 client = self.getClient()
2531 dlg = SvnDialog( 2606 dlg = SvnDialog(self.tr("Upgrade"), "upgrade {0}".format(path), client)
2532 self.tr('Upgrade'),
2533 "upgrade {0}".format(path),
2534 client)
2535 QApplication.processEvents() 2607 QApplication.processEvents()
2536 try: 2608 try:
2537 with EricMutexLocker(self.vcsExecutionMutex): 2609 with EricMutexLocker(self.vcsExecutionMutex):
2538 client.upgrade(path) 2610 client.upgrade(path)
2539 except pysvn.ClientError as e: 2611 except pysvn.ClientError as e:
2542 dlg.exec() 2614 dlg.exec()
2543 2615
2544 ########################################################################### 2616 ###########################################################################
2545 ## Private Subversion specific methods are below. 2617 ## Private Subversion specific methods are below.
2546 ########################################################################### 2618 ###########################################################################
2547 2619
2548 def __svnURL(self, url): 2620 def __svnURL(self, url):
2549 """ 2621 """
2550 Private method to format a url for subversion. 2622 Private method to format a url for subversion.
2551 2623
2552 @param url unformatted url string (string) 2624 @param url unformatted url string (string)
2553 @return properly formated url for subversion (string) 2625 @return properly formated url for subversion (string)
2554 """ 2626 """
2555 url = self.svnNormalizeURL(url) 2627 url = self.svnNormalizeURL(url)
2556 url = url.split(':', 2) 2628 url = url.split(":", 2)
2557 if len(url) == 3: 2629 if len(url) == 3:
2558 scheme = url[0] 2630 scheme = url[0]
2559 host = url[1] 2631 host = url[1]
2560 port, path = url[2].split("/", 1) 2632 port, path = url[2].split("/", 1)
2561 return "{0}:{1}:{2}/{3}".format(scheme, host, port, quote(path)) 2633 return "{0}:{1}:{2}/{3}".format(scheme, host, port, quote(path))
2572 return "{0}://{1}/{2}".format(scheme, host, quote(path)) 2644 return "{0}://{1}/{2}".format(scheme, host, quote(path))
2573 2645
2574 def svnNormalizeURL(self, url): 2646 def svnNormalizeURL(self, url):
2575 """ 2647 """
2576 Public method to normalize a url for subversion. 2648 Public method to normalize a url for subversion.
2577 2649
2578 @param url url string (string) 2650 @param url url string (string)
2579 @return properly normalized url for subversion (string) 2651 @return properly normalized url for subversion (string)
2580 """ 2652 """
2581 protocol, url = url.split("://", 1) 2653 protocol, url = url.split("://", 1)
2582 if url.startswith("\\\\"): 2654 if url.startswith("\\\\"):
2583 url = url[2:] 2655 url = url[2:]
2584 if protocol == "file": 2656 if protocol == "file":
2585 url = os.path.normcase(url) 2657 url = os.path.normcase(url)
2586 if url[1] == ":": 2658 if url[1] == ":":
2587 url = url.replace(":", "|", 1) 2659 url = url.replace(":", "|", 1)
2588 url = url.replace('\\', '/') 2660 url = url.replace("\\", "/")
2589 if url.endswith('/'): 2661 if url.endswith("/"):
2590 url = url[:-1] 2662 url = url[:-1]
2591 if not url.startswith("/") and url[1] in [":", "|"]: 2663 if not url.startswith("/") and url[1] in [":", "|"]:
2592 url = "/{0}".format(url) 2664 url = "/{0}".format(url)
2593 return "{0}://{1}".format(protocol, url) 2665 return "{0}://{1}".format(protocol, url)
2594 2666
2595 ########################################################################### 2667 ###########################################################################
2596 ## Methods to get the helper objects are below. 2668 ## Methods to get the helper objects are below.
2597 ########################################################################### 2669 ###########################################################################
2598 2670
2599 def vcsGetProjectBrowserHelper(self, browser, project, 2671 def vcsGetProjectBrowserHelper(self, browser, project, isTranslationsBrowser=False):
2600 isTranslationsBrowser=False):
2601 """ 2672 """
2602 Public method to instanciate a helper object for the different 2673 Public method to instanciate a helper object for the different
2603 project browsers. 2674 project browsers.
2604 2675
2605 @param browser reference to the project browser object 2676 @param browser reference to the project browser object
2606 @param project reference to the project object 2677 @param project reference to the project object
2607 @param isTranslationsBrowser flag indicating, the helper is requested 2678 @param isTranslationsBrowser flag indicating, the helper is requested
2608 for the translations browser (this needs some special treatment) 2679 for the translations browser (this needs some special treatment)
2609 @return the project browser helper object 2680 @return the project browser helper object
2610 """ 2681 """
2611 from .ProjectBrowserHelper import SvnProjectBrowserHelper 2682 from .ProjectBrowserHelper import SvnProjectBrowserHelper
2612 return SvnProjectBrowserHelper(self, browser, project, 2683
2613 isTranslationsBrowser) 2684 return SvnProjectBrowserHelper(self, browser, project, isTranslationsBrowser)
2614 2685
2615 def vcsGetProjectHelper(self, project): 2686 def vcsGetProjectHelper(self, project):
2616 """ 2687 """
2617 Public method to instanciate a helper object for the project. 2688 Public method to instanciate a helper object for the project.
2618 2689
2619 @param project reference to the project object 2690 @param project reference to the project object
2620 @return the project helper object 2691 @return the project helper object
2621 """ 2692 """
2622 helper = self.__plugin.getProjectHelper() 2693 helper = self.__plugin.getProjectHelper()
2623 helper.setObjects(self, project) 2694 helper.setObjects(self, project)
2624 self.__wcng = ( 2695 self.__wcng = (
2625 os.path.exists( 2696 os.path.exists(os.path.join(project.getProjectPath(), ".svn", "format"))
2626 os.path.join(project.getProjectPath(), ".svn", "format")) or 2697 or os.path.exists(os.path.join(project.getProjectPath(), "_svn", "format"))
2627 os.path.exists( 2698 or os.path.exists(os.path.join(project.getProjectPath(), ".svn", "wc.db"))
2628 os.path.join(project.getProjectPath(), "_svn", "format")) or 2699 or os.path.exists(os.path.join(project.getProjectPath(), "_svn", "wc.db"))
2629 os.path.exists(
2630 os.path.join(project.getProjectPath(), ".svn", "wc.db")) or
2631 os.path.exists(
2632 os.path.join(project.getProjectPath(), "_svn", "wc.db"))
2633 ) 2700 )
2634 return helper 2701 return helper
2635 2702
2636 ########################################################################### 2703 ###########################################################################
2637 ## Status Monitor Thread methods 2704 ## Status Monitor Thread methods
2639 2706
2640 def _createStatusMonitorThread(self, interval, project): 2707 def _createStatusMonitorThread(self, interval, project):
2641 """ 2708 """
2642 Protected method to create an instance of the VCS status monitor 2709 Protected method to create an instance of the VCS status monitor
2643 thread. 2710 thread.
2644 2711
2645 @param interval check interval for the monitor thread in seconds 2712 @param interval check interval for the monitor thread in seconds
2646 (integer) 2713 (integer)
2647 @param project reference to the project object 2714 @param project reference to the project object
2648 @return reference to the monitor thread (QThread) 2715 @return reference to the monitor thread (QThread)
2649 """ 2716 """
2650 from .SvnStatusMonitorThread import SvnStatusMonitorThread 2717 from .SvnStatusMonitorThread import SvnStatusMonitorThread
2718
2651 return SvnStatusMonitorThread(interval, project, self) 2719 return SvnStatusMonitorThread(interval, project, self)

eric ide

mercurial