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