4 |
4 |
5 import os, re, sys, tempfile, urllib, urllib2 |
5 import os, re, sys, tempfile, urllib, urllib2 |
6 import xml.dom.minidom |
6 import xml.dom.minidom |
7 import cPickle as pickle |
7 import cPickle as pickle |
8 |
8 |
9 from mercurial import strutil, scmutil, util, encoding |
9 from mercurial import strutil, scmutil, util, encoding, error |
10 from mercurial.i18n import _ |
10 from mercurial.i18n import _ |
11 |
11 |
12 propertycache = util.propertycache |
12 propertycache = util.propertycache |
13 |
13 |
14 # Subversion stuff. Works best with very recent Python SVN bindings |
14 # Subversion stuff. Works best with very recent Python SVN bindings |
139 def debugsvnlog(ui, **opts): |
139 def debugsvnlog(ui, **opts): |
140 """Fetch SVN log in a subprocess and channel them back to parent to |
140 """Fetch SVN log in a subprocess and channel them back to parent to |
141 avoid memory collection issues. |
141 avoid memory collection issues. |
142 """ |
142 """ |
143 if svn is None: |
143 if svn is None: |
144 raise util.Abort(_('debugsvnlog could not load Subversion python ' |
144 raise error.Abort(_('debugsvnlog could not load Subversion python ' |
145 'bindings')) |
145 'bindings')) |
146 |
146 |
147 util.setbinary(sys.stdin) |
147 util.setbinary(sys.stdin) |
148 util.setbinary(sys.stdout) |
148 util.setbinary(sys.stdout) |
149 args = decodeargs(sys.stdin.read()) |
149 args = decodeargs(sys.stdin.read()) |
157 def __iter__(self): |
157 def __iter__(self): |
158 while True: |
158 while True: |
159 try: |
159 try: |
160 entry = pickle.load(self._stdout) |
160 entry = pickle.load(self._stdout) |
161 except EOFError: |
161 except EOFError: |
162 raise util.Abort(_('Mercurial failed to run itself, check' |
162 raise error.Abort(_('Mercurial failed to run itself, check' |
163 ' hg executable is in PATH')) |
163 ' hg executable is in PATH')) |
164 try: |
164 try: |
165 orig_paths, revnum, author, date, message = entry |
165 orig_paths, revnum, author, date, message = entry |
166 except (TypeError, ValueError): |
166 except (TypeError, ValueError): |
167 if entry is None: |
167 if entry is None: |
168 break |
168 break |
169 raise util.Abort(_("log stream exception '%s'") % entry) |
169 raise error.Abort(_("log stream exception '%s'") % entry) |
170 yield entry |
170 yield entry |
171 |
171 |
172 def close(self): |
172 def close(self): |
173 if self._stdout: |
173 if self._stdout: |
174 self._stdout.close() |
174 self._stdout.close() |
325 "to libsvn version %s") |
325 "to libsvn version %s") |
326 % (self.url, svnversion)) |
326 % (self.url, svnversion)) |
327 |
327 |
328 if revs: |
328 if revs: |
329 if len(revs) > 1: |
329 if len(revs) > 1: |
330 raise util.Abort(_('subversion source does not support ' |
330 raise error.Abort(_('subversion source does not support ' |
331 'specifying multiple revisions')) |
331 'specifying multiple revisions')) |
332 try: |
332 try: |
333 latest = int(revs[0]) |
333 latest = int(revs[0]) |
334 except ValueError: |
334 except ValueError: |
335 raise util.Abort(_('svn: revision %s is not an integer') % |
335 raise error.Abort(_('svn: revision %s is not an integer') % |
336 revs[0]) |
336 revs[0]) |
337 |
337 |
338 self.trunkname = self.ui.config('convert', 'svn.trunk', |
338 self.trunkname = self.ui.config('convert', 'svn.trunk', |
339 'trunk').strip('/') |
339 'trunk').strip('/') |
340 self.startrev = self.ui.config('convert', 'svn.startrev', default=0) |
340 self.startrev = self.ui.config('convert', 'svn.startrev', default=0) |
341 try: |
341 try: |
342 self.startrev = int(self.startrev) |
342 self.startrev = int(self.startrev) |
343 if self.startrev < 0: |
343 if self.startrev < 0: |
344 self.startrev = 0 |
344 self.startrev = 0 |
345 except ValueError: |
345 except ValueError: |
346 raise util.Abort(_('svn: start revision %s is not an integer') |
346 raise error.Abort(_('svn: start revision %s is not an integer') |
347 % self.startrev) |
347 % self.startrev) |
348 |
348 |
349 try: |
349 try: |
350 self.head = self.latest(self.module, latest) |
350 self.head = self.latest(self.module, latest) |
351 except SvnPathNotFound: |
351 except SvnPathNotFound: |
352 self.head = None |
352 self.head = None |
353 if not self.head: |
353 if not self.head: |
354 raise util.Abort(_('no revision found in module %s') |
354 raise error.Abort(_('no revision found in module %s') |
355 % self.module) |
355 % self.module) |
356 self.last_changed = self.revnum(self.head) |
356 self.last_changed = self.revnum(self.head) |
357 |
357 |
358 self._changescache = (None, None) |
358 self._changescache = (None, None) |
359 |
359 |
394 if not self.exists(path, rev): |
394 if not self.exists(path, rev): |
395 if self.module.endswith(path) and name == 'trunk': |
395 if self.module.endswith(path) and name == 'trunk': |
396 # we are converting from inside this directory |
396 # we are converting from inside this directory |
397 return None |
397 return None |
398 if cfgpath: |
398 if cfgpath: |
399 raise util.Abort(_('expected %s to be at %r, but not found') |
399 raise error.Abort(_('expected %s to be at %r, but not found' |
400 % (name, path)) |
400 ) % (name, path)) |
401 return None |
401 return None |
402 self.ui.note(_('found %s at %r\n') % (name, path)) |
402 self.ui.note(_('found %s at %r\n') % (name, path)) |
403 return path |
403 return path |
404 |
404 |
405 rev = optrev(self.last_changed) |
405 rev = optrev(self.last_changed) |
413 if trunk: |
413 if trunk: |
414 oldmodule = self.module or '' |
414 oldmodule = self.module or '' |
415 self.module += '/' + trunk |
415 self.module += '/' + trunk |
416 self.head = self.latest(self.module, self.last_changed) |
416 self.head = self.latest(self.module, self.last_changed) |
417 if not self.head: |
417 if not self.head: |
418 raise util.Abort(_('no revision found in module %s') |
418 raise error.Abort(_('no revision found in module %s') |
419 % self.module) |
419 % self.module) |
420 |
420 |
421 # First head in the list is the module's head |
421 # First head in the list is the module's head |
422 self.heads = [self.head] |
422 self.heads = [self.head] |
423 if self.tags is not None: |
423 if self.tags is not None: |
440 (branch, self.revnum(brevid))) |
440 (branch, self.revnum(brevid))) |
441 self.heads.append(brevid) |
441 self.heads.append(brevid) |
442 |
442 |
443 if self.startrev and self.heads: |
443 if self.startrev and self.heads: |
444 if len(self.heads) > 1: |
444 if len(self.heads) > 1: |
445 raise util.Abort(_('svn: start revision is not supported ' |
445 raise error.Abort(_('svn: start revision is not supported ' |
446 'with more than one branch')) |
446 'with more than one branch')) |
447 revnum = self.revnum(self.heads[0]) |
447 revnum = self.revnum(self.heads[0]) |
448 if revnum < self.startrev: |
448 if revnum < self.startrev: |
449 raise util.Abort( |
449 raise error.Abort( |
450 _('svn: no revision found after start revision %d') |
450 _('svn: no revision found after start revision %d') |
451 % self.startrev) |
451 % self.startrev) |
452 |
452 |
453 return self.heads |
453 return self.heads |
454 |
454 |
500 stop = self.lastrevs.get(module, 0) |
500 stop = self.lastrevs.get(module, 0) |
501 if revnum < stop: |
501 if revnum < stop: |
502 stop = revnum + 1 |
502 stop = revnum + 1 |
503 self._fetch_revisions(revnum, stop) |
503 self._fetch_revisions(revnum, stop) |
504 if rev not in self.commits: |
504 if rev not in self.commits: |
505 raise util.Abort(_('svn: revision %s not found') % revnum) |
505 raise error.Abort(_('svn: revision %s not found') % revnum) |
506 revcommit = self.commits[rev] |
506 revcommit = self.commits[rev] |
507 # caller caches the result, so free it here to release memory |
507 # caller caches the result, so free it here to release memory |
508 del self.commits[rev] |
508 del self.commits[rev] |
509 return revcommit |
509 return revcommit |
510 |
510 |
511 def checkrevformat(self, revstr, mapname='splicemap'): |
511 def checkrevformat(self, revstr, mapname='splicemap'): |
512 """ fails if revision format does not match the correct format""" |
512 """ fails if revision format does not match the correct format""" |
513 if not re.match(r'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-' |
513 if not re.match(r'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-' |
514 '[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]' |
514 '[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]' |
515 '{12,12}(.*)\@[0-9]+$',revstr): |
515 '{12,12}(.*)\@[0-9]+$',revstr): |
516 raise util.Abort(_('%s entry %s is not a valid revision' |
516 raise error.Abort(_('%s entry %s is not a valid revision' |
517 ' identifier') % (mapname, revstr)) |
517 ' identifier') % (mapname, revstr)) |
518 |
518 |
519 def numcommits(self): |
519 def numcommits(self): |
520 return int(self.head.rsplit('@', 1)[1]) - self.startrev |
520 return int(self.head.rsplit('@', 1)[1]) - self.startrev |
521 |
521 |
949 except SvnPathNotFound: |
949 except SvnPathNotFound: |
950 pass |
950 pass |
951 except SubversionException as xxx_todo_changeme: |
951 except SubversionException as xxx_todo_changeme: |
952 (inst, num) = xxx_todo_changeme.args |
952 (inst, num) = xxx_todo_changeme.args |
953 if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: |
953 if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: |
954 raise util.Abort(_('svn: branch has no revision %s') |
954 raise error.Abort(_('svn: branch has no revision %s') |
955 % to_revnum) |
955 % to_revnum) |
956 raise |
956 raise |
957 |
957 |
958 def getfile(self, file, rev): |
958 def getfile(self, file, rev): |
959 # TODO: ra.get_file transmits the whole file instead of diffs. |
959 # TODO: ra.get_file transmits the whole file instead of diffs. |
1050 stdin, stdout = util.popen2(util.quotecommand(cmd)) |
1050 stdin, stdout = util.popen2(util.quotecommand(cmd)) |
1051 stdin.write(arg) |
1051 stdin.write(arg) |
1052 try: |
1052 try: |
1053 stdin.close() |
1053 stdin.close() |
1054 except IOError: |
1054 except IOError: |
1055 raise util.Abort(_('Mercurial failed to run itself, check' |
1055 raise error.Abort(_('Mercurial failed to run itself, check' |
1056 ' hg executable is in PATH')) |
1056 ' hg executable is in PATH')) |
1057 return logstream(stdout) |
1057 return logstream(stdout) |
1058 |
1058 |
1059 pre_revprop_change = '''#!/bin/sh |
1059 pre_revprop_change = '''#!/bin/sh |
1060 |
1060 |
1300 except AttributeError: |
1300 except AttributeError: |
1301 if parents and not files: |
1301 if parents and not files: |
1302 return parents[0] |
1302 return parents[0] |
1303 self.ui.warn(_('unexpected svn output:\n')) |
1303 self.ui.warn(_('unexpected svn output:\n')) |
1304 self.ui.warn(output) |
1304 self.ui.warn(output) |
1305 raise util.Abort(_('unable to cope with svn output')) |
1305 raise error.Abort(_('unable to cope with svn output')) |
1306 if commit.rev: |
1306 if commit.rev: |
1307 self.run('propset', 'hg:convert-rev', commit.rev, |
1307 self.run('propset', 'hg:convert-rev', commit.rev, |
1308 revprop=True, revision=rev) |
1308 revprop=True, revision=rev) |
1309 if commit.branch and commit.branch != 'default': |
1309 if commit.branch and commit.branch != 'default': |
1310 self.run('propset', 'hg:convert-branch', commit.branch, |
1310 self.run('propset', 'hg:convert-branch', commit.branch, |
1327 def hascommitforsplicemap(self, rev): |
1327 def hascommitforsplicemap(self, rev): |
1328 # This is not correct as one can convert to an existing subversion |
1328 # This is not correct as one can convert to an existing subversion |
1329 # repository and childmap would not list all revisions. Too bad. |
1329 # repository and childmap would not list all revisions. Too bad. |
1330 if rev in self.childmap: |
1330 if rev in self.childmap: |
1331 return True |
1331 return True |
1332 raise util.Abort(_('splice map revision %s not found in subversion ' |
1332 raise error.Abort(_('splice map revision %s not found in subversion ' |
1333 'child map (revision lookups are not implemented)') |
1333 'child map (revision lookups are not implemented)') |
1334 % rev) |
1334 % rev) |