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