comparison hgext/convert/subversion.py @ 13690:af331f557942

convert/svn: extract revsplit() in a function
author Patrick Mezard <pmezard@gmail.com>
date Thu, 17 Mar 2011 22:17:27 +0100
parents 30a0e3519f69
children d13913355390
comparison
equal deleted inserted replaced
13689:65399579da68 13690:af331f557942
38 except ImportError: 38 except ImportError:
39 svn = None 39 svn = None
40 40
41 class SvnPathNotFound(Exception): 41 class SvnPathNotFound(Exception):
42 pass 42 pass
43
44 def revsplit(rev):
45 """Parse a revision string and return (uuid, path, revnum)."""
46 url, revnum = rev.rsplit('@', 1)
47 parts = url.split('/', 1)
48 mod = ''
49 if len(parts) > 1:
50 mod = '/' + parts[1]
51 return parts[0][4:], mod, int(revnum)
43 52
44 def geturl(path): 53 def geturl(path):
45 try: 54 try:
46 return svn.client.url_from_path(svn.core.svn_path_canonicalize(path)) 55 return svn.client.url_from_path(svn.core.svn_path_canonicalize(path))
47 except SubversionException: 56 except SubversionException:
284 self.convertfp = None 293 self.convertfp = None
285 294
286 def setrevmap(self, revmap): 295 def setrevmap(self, revmap):
287 lastrevs = {} 296 lastrevs = {}
288 for revid in revmap.iterkeys(): 297 for revid in revmap.iterkeys():
289 uuid, module, revnum = self.revsplit(revid) 298 uuid, module, revnum = revsplit(revid)
290 lastrevnum = lastrevs.setdefault(module, revnum) 299 lastrevnum = lastrevs.setdefault(module, revnum)
291 if revnum > lastrevnum: 300 if revnum > lastrevnum:
292 lastrevs[module] = revnum 301 lastrevs[module] = revnum
293 self.lastrevs = lastrevs 302 self.lastrevs = lastrevs
294 303
379 (paths, parents) = self.paths[rev] 388 (paths, parents) = self.paths[rev]
380 if parents: 389 if parents:
381 files, self.removed, copies = self.expandpaths(rev, paths, parents) 390 files, self.removed, copies = self.expandpaths(rev, paths, parents)
382 else: 391 else:
383 # Perform a full checkout on roots 392 # Perform a full checkout on roots
384 uuid, module, revnum = self.revsplit(rev) 393 uuid, module, revnum = revsplit(rev)
385 entries = svn.client.ls(self.baseurl + urllib.quote(module), 394 entries = svn.client.ls(self.baseurl + urllib.quote(module),
386 optrev(revnum), True, self.ctx) 395 optrev(revnum), True, self.ctx)
387 files = [n for n, e in entries.iteritems() 396 files = [n for n, e in entries.iteritems()
388 if e.kind == svn.core.svn_node_file] 397 if e.kind == svn.core.svn_node_file]
389 copies = {} 398 copies = {}
401 self._changescache = (rev, changes) 410 self._changescache = (rev, changes)
402 return [f[0] for f in changes[0]] 411 return [f[0] for f in changes[0]]
403 412
404 def getcommit(self, rev): 413 def getcommit(self, rev):
405 if rev not in self.commits: 414 if rev not in self.commits:
406 uuid, module, revnum = self.revsplit(rev) 415 uuid, module, revnum = revsplit(rev)
407 self.module = module 416 self.module = module
408 self.reparent(module) 417 self.reparent(module)
409 # We assume that: 418 # We assume that:
410 # - requests for revisions after "stop" come from the 419 # - requests for revisions after "stop" come from the
411 # revision graph backward traversal. Cache all of them 420 # revision graph backward traversal. Cache all of them
528 return 'svn:%s%s@%s' % (self.uuid, module or self.module, revnum) 537 return 'svn:%s%s@%s' % (self.uuid, module or self.module, revnum)
529 538
530 def revnum(self, rev): 539 def revnum(self, rev):
531 return int(rev.split('@')[-1]) 540 return int(rev.split('@')[-1])
532 541
533 def revsplit(self, rev):
534 url, revnum = rev.rsplit('@', 1)
535 revnum = int(revnum)
536 parts = url.split('/', 1)
537 uuid = parts.pop(0)[4:]
538 mod = ''
539 if parts:
540 mod = '/' + parts[0]
541 return uuid, mod, revnum
542
543 def latest(self, path, stop=0): 542 def latest(self, path, stop=0):
544 """Find the latest revid affecting path, up to stop. It may return 543 """Find the latest revid affecting path, up to stop. It may return
545 a revision in a different module, since a branch may be moved without 544 a revision in a different module, since a branch may be moved without
546 a change being reported. Return None if computed module does not 545 a change being reported. Return None if computed module does not
547 belong to rootmodule subtree. 546 belong to rootmodule subtree.
604 603
605 def expandpaths(self, rev, paths, parents): 604 def expandpaths(self, rev, paths, parents):
606 changed, removed = set(), set() 605 changed, removed = set(), set()
607 copies = {} 606 copies = {}
608 607
609 new_module, revnum = self.revsplit(rev)[1:] 608 new_module, revnum = revsplit(rev)[1:]
610 if new_module != self.module: 609 if new_module != self.module:
611 self.module = new_module 610 self.module = new_module
612 self.reparent(self.module) 611 self.reparent(self.module)
613 612
614 for i, (path, ent) in enumerate(paths): 613 for i, (path, ent) in enumerate(paths):
621 changed.add(self.recode(entrypath)) 620 changed.add(self.recode(entrypath))
622 if not ent.copyfrom_path or not parents: 621 if not ent.copyfrom_path or not parents:
623 continue 622 continue
624 # Copy sources not in parent revisions cannot be 623 # Copy sources not in parent revisions cannot be
625 # represented, ignore their origin for now 624 # represented, ignore their origin for now
626 pmodule, prevnum = self.revsplit(parents[0])[1:] 625 pmodule, prevnum = revsplit(parents[0])[1:]
627 if ent.copyfrom_rev < prevnum: 626 if ent.copyfrom_rev < prevnum:
628 continue 627 continue
629 copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule) 628 copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule)
630 if not copyfrom_path: 629 if not copyfrom_path:
631 continue 630 continue
632 self.ui.debug("copied to %s from %s@%s\n" % 631 self.ui.debug("copied to %s from %s@%s\n" %
633 (entrypath, copyfrom_path, ent.copyfrom_rev)) 632 (entrypath, copyfrom_path, ent.copyfrom_rev))
634 copies[self.recode(entrypath)] = self.recode(copyfrom_path) 633 copies[self.recode(entrypath)] = self.recode(copyfrom_path)
635 elif kind == 0: # gone, but had better be a deleted *file* 634 elif kind == 0: # gone, but had better be a deleted *file*
636 self.ui.debug("gone from %s\n" % ent.copyfrom_rev) 635 self.ui.debug("gone from %s\n" % ent.copyfrom_rev)
637 pmodule, prevnum = self.revsplit(parents[0])[1:] 636 pmodule, prevnum = revsplit(parents[0])[1:]
638 parentpath = pmodule + "/" + entrypath 637 parentpath = pmodule + "/" + entrypath
639 fromkind = self._checkpath(entrypath, prevnum, pmodule) 638 fromkind = self._checkpath(entrypath, prevnum, pmodule)
640 639
641 if fromkind == svn.core.svn_node_file: 640 if fromkind == svn.core.svn_node_file:
642 removed.add(self.recode(entrypath)) 641 removed.add(self.recode(entrypath))
658 # then we shouldn't need to look for its children. 657 # then we shouldn't need to look for its children.
659 continue 658 continue
660 if ent.action == 'R' and parents: 659 if ent.action == 'R' and parents:
661 # If a directory is replacing a file, mark the previous 660 # If a directory is replacing a file, mark the previous
662 # file as deleted 661 # file as deleted
663 pmodule, prevnum = self.revsplit(parents[0])[1:] 662 pmodule, prevnum = revsplit(parents[0])[1:]
664 pkind = self._checkpath(entrypath, prevnum, pmodule) 663 pkind = self._checkpath(entrypath, prevnum, pmodule)
665 if pkind == svn.core.svn_node_file: 664 if pkind == svn.core.svn_node_file:
666 removed.add(self.recode(entrypath)) 665 removed.add(self.recode(entrypath))
667 elif pkind == svn.core.svn_node_dir: 666 elif pkind == svn.core.svn_node_dir:
668 # We do not know what files were kept or removed, 667 # We do not know what files were kept or removed,
680 # Handle directory copies 679 # Handle directory copies
681 if not ent.copyfrom_path or not parents: 680 if not ent.copyfrom_path or not parents:
682 continue 681 continue
683 # Copy sources not in parent revisions cannot be 682 # Copy sources not in parent revisions cannot be
684 # represented, ignore their origin for now 683 # represented, ignore their origin for now
685 pmodule, prevnum = self.revsplit(parents[0])[1:] 684 pmodule, prevnum = revsplit(parents[0])[1:]
686 if ent.copyfrom_rev < prevnum: 685 if ent.copyfrom_rev < prevnum:
687 continue 686 continue
688 copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule) 687 copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule)
689 if not copyfrompath: 688 if not copyfrompath:
690 continue 689 continue
735 branched = True 734 branched = True
736 newpath = ent.copyfrom_path + self.module[len(path):] 735 newpath = ent.copyfrom_path + self.module[len(path):]
737 # ent.copyfrom_rev may not be the actual last revision 736 # ent.copyfrom_rev may not be the actual last revision
738 previd = self.latest(newpath, ent.copyfrom_rev) 737 previd = self.latest(newpath, ent.copyfrom_rev)
739 if previd is not None: 738 if previd is not None:
740 prevmodule, prevnum = self.revsplit(previd)[1:] 739 prevmodule, prevnum = revsplit(previd)[1:]
741 if prevnum >= self.startrev: 740 if prevnum >= self.startrev:
742 parents = [previd] 741 parents = [previd]
743 self.ui.note( 742 self.ui.note(
744 _('found parent of branch %s at %d: %s\n') % 743 _('found parent of branch %s at %d: %s\n') %
745 (self.module, prevnum, prevmodule)) 744 (self.module, prevnum, prevmodule))
832 # TODO: ra.get_file transmits the whole file instead of diffs. 831 # TODO: ra.get_file transmits the whole file instead of diffs.
833 if file in self.removed: 832 if file in self.removed:
834 raise IOError() 833 raise IOError()
835 mode = '' 834 mode = ''
836 try: 835 try:
837 new_module, revnum = self.revsplit(rev)[1:] 836 new_module, revnum = revsplit(rev)[1:]
838 if self.module != new_module: 837 if self.module != new_module:
839 self.module = new_module 838 self.module = new_module
840 self.reparent(self.module) 839 self.reparent(self.module)
841 io = StringIO() 840 io = StringIO()
842 info = svn.ra.get_file(self.ra, file, revnum, io) 841 info = svn.ra.get_file(self.ra, file, revnum, io)