convert_svn ("release early" edition)

Brendan Cully brendan at kublai.com
Fri Jun 29 17:39:38 CDT 2007


On Sunday, 11 February 2007 at 23:47, Daniel Holth wrote:
> convert-repo patched to convert from Subversion.
> 
> http://dingoskidneys.com/cgi-bin/hgwebdir.cgi/outgoing (patches applied)
> http://dingoskidneys.com/cgi-bin/hgwebdir.cgi/queue-convert-svn (just
> the patches)

Here's an update to 0.9.4. I can't really test it yet since my svn
1.4.3 bindings don't seem to return the right information from
get_dir2. But this patch does allow convert to churn for a while
before bailing out :)
-------------- next part --------------
# HG changeset patch
# User Brendan Cully <brendan at kublai.com>
# Date 1183156645 25200
# Node ID 0b6906b6035b2a5ff07fc9f18184bb58710bd34f
# Parent  1bcae4ff7dfacee7e4ae32290526dd00512dbdc4
Update convertsvn for 0.9.4

diff --git a/convert_svn b/convert_svn
--- a/convert_svn
+++ b/convert_svn
@@ -1,13 +1,78 @@ add convert_svn class
 add convert_svn class
 Patch to work with subversion binding 1.4 and python 2.3.
 
-diff -r e061269bc66b hgext/convert/__init__.py
---- a/hgext/convert/__init__.py	Sun Jun 10 10:16:59 2007 -0400
-+++ b/hgext/convert/__init__.py	Sun Jun 10 10:21:06 2007 -0400
-@@ -7,6 +7,18 @@
- 
- import sys, os, zlib, sha, time, re, locale, socket
+diff --git a/hgext/convert/__init__.py b/hgext/convert/__init__.py
+--- a/hgext/convert/__init__.py
++++ b/hgext/convert/__init__.py
+@@ -9,17 +9,19 @@ from cvs import convert_cvs
+ from cvs import convert_cvs
+ from git import convert_git
+ from hg import convert_mercurial
++from convertsvn import convert_svn
+ 
+ import os
  from mercurial import hg, ui, util, commands
+ 
+ commands.norepo += " convert"
+ 
+-converters = [convert_cvs, convert_git, convert_mercurial]
++converters = [convert_svn, convert_cvs, convert_git, convert_mercurial]
+ 
+ def converter(ui, path):
+-    if not os.path.isdir(path):
+-        raise util.Abort("%s: not a directory" % path)
++    # Subversion URLs are not directories
++    # if not os.path.isdir(path):
++    #     raise util.Abort("%s: not a directory" % path)
+     for c in converters:
+         try:
+             return c(ui, path)
+@@ -179,6 +181,8 @@ class convert(object):
+     def copy(self, rev):
+         c = self.commitcache[rev]
+         files = self.source.getchanges(rev)
++        
++        do_copies = (hasattr(c, 'copies') and hasattr(self.dest, 'copyfile'))
+ 
+         for f, v in files:
+             try:
+@@ -188,6 +192,11 @@ class convert(object):
+             else:
+                 e = self.source.getmode(f, v)
+                 self.dest.putfile(f, e, data)
++                if do_copies:
++                    if f in c.copies:
++                        # Merely marks that a copy happened.
++                        self.dest.copyfile(c.copies[f], f)
++
+ 
+         r = [self.map[v] for v in c.parents]
+         f = [f for f, v in files]
+diff --git a/hgext/convert/common.py b/hgext/convert/common.py
+--- a/hgext/convert/common.py
++++ b/hgext/convert/common.py
+@@ -94,3 +94,12 @@ class converter_sink(object):
+         """Put tags into sink.
+         tags: {tagname: sink_rev_id, ...}"""
+         raise NotImplementedError()
++
++def recode(s):
++    try:
++        return s.decode("utf-8").encode("utf-8")
++    except:
++        try:
++            return s.decode("latin-1").encode("utf-8")
++        except:
++            return s.decode("utf-8", "replace").encode("utf-8")
+diff --git a/hgext/convert/convertsvn.py b/hgext/convert/convertsvn.py
+new file mode 100644
+--- /dev/null
++++ b/hgext/convert/convertsvn.py
+@@ -0,0 +1,401 @@
++# svn backend for convert extension
++
++from common import NoRepo, converter_source, commit, recode
++from mercurial import util
 +
 +import pprint
 +# Subversion stuff. Works best with very recent Python SVN bindings
@@ -20,16 +85,54 @@ diff -r e061269bc66b hgext/convert/__ini
 +import svn
 +import transport
 +from cStringIO import StringIO
- 
- commands.norepo += " convert"
- 
-@@ -108,6 +120,391 @@ class converter_sink(object):
-         tags: {tagname: sink_rev_id, ...}"""
-         raise NotImplementedError()
- 
 +
 +# SVN conversion code stolen from bzr-svn and tailor
 +class convert_svn(converter_source):
++    def __init__(self, ui, url):
++        try:
++            # Support file://path@rev syntax. Useful e.g. to convert
++            # deleted branches.
++            url, latest = url.rsplit("@", 1)
++            latest = int(latest)
++        except ValueError, e:
++            latest = None
++        self.url = url
++        self.encoding = 'UTF-8'
++        try:
++            self.transport = transport.SvnRaTransport(url = url)
++            self.ra = self.transport.ra
++            self.base = svn.ra.get_repos_root(self.ra)
++            self.module = self.url[len(self.base):]
++            self.modulemap = {} # revision, module
++            self.commits = {}
++            self.files = {}
++            self.uuid = svn.ra.get_uuid(self.ra).decode(self.encoding)
++        except SubversionException, e:
++            raise NoRepo("couldn't open SVN repo %s" % url)
++
++        try:
++            self.get_blacklist()
++        except IOError, e:
++            pass
++
++        try:
++            self.get_authors()
++        except IOError, e:
++            self.authors = None
++        
++        if not latest:
++            latest = svn.ra.get_latest_revnum(self.ra)
++        dirent = svn.ra.stat(self.ra, self.module, latest)
++        self.last_changed = dirent.created_rev
++
++        self.head = (u"svn:%s%s@%s" % (self.uuid, self.module, self.last_changed)).decode(self.encoding)
++        # print "head is" + self.head
++
++        # Should lazily fetch revisions in batches of, say, 1,000...:
++        self._fetch_revisions(from_revnum=self.last_changed, to_revnum=0)
++        # self._parse()
++        # self._connect()
++            
 +    def get_blacklist(self):
 +        """Avoid certain revision numbers.
 +        It is not uncommon for two nearby revisions to cancel each other
@@ -65,51 +168,6 @@ diff -r e061269bc66b hgext/convert/__ini
 +            authors[author] = email
 +        self.authors = authors
 +
-+    def __init__(self, url):
-+        try:
-+            # Support file://path@rev syntax. Useful e.g. to convert
-+            # deleted branches.
-+            url, latest = url.rsplit("@", 1)
-+            latest = int(latest)
-+        except ValueError, e:
-+            latest = None
-+        self.url = url
-+        self.encoding = 'UTF-8'
-+        try:
-+            self.transport = transport.SvnRaTransport(url = url)
-+            self.ra = self.transport.ra
-+            self.base = svn.ra.get_repos_root(self.ra)
-+            self.module = self.url[len(self.base):]
-+            self.modulemap = {} # revision, module
-+            self.commits = {}
-+            self.files = {}
-+            self.uuid = svn.ra.get_uuid(self.ra).decode(self.encoding)
-+        except SubversionException, e:
-+            raise NoRepo("couldn't open SVN repo %s" % url)
-+
-+        try:
-+            self.get_blacklist()
-+        except IOError, e:
-+            pass
-+
-+        try:
-+            self.get_authors()
-+        except IOError, e:
-+            self.authors = None
-+        
-+        if not latest:
-+            latest = svn.ra.get_latest_revnum(self.ra)
-+        dirent = svn.ra.stat(self.ra, self.module, latest)
-+        self.last_changed = dirent.created_rev
-+
-+        self.head = (u"svn:%s%s@%s" % (self.uuid, self.module, self.last_changed)).decode(self.encoding)
-+        # print "head is" + self.head
-+
-+        # Should lazily fetch revisions in batches of, say, 1,000...:
-+        self._fetch_revisions(from_revnum=self.last_changed, to_revnum=0)
-+        # self._parse()
-+        # self._connect()
-+            
 +    def reparent(self, module):
 +        svn_url = self.base + module
 +        # print "reparent to %s" % svn_url.encode(self.encoding)
@@ -412,57 +470,41 @@ diff -r e061269bc66b hgext/convert/__ini
 +
 +        self.reparent(self.module)
 +        return [path + "/" + c for c in children]
- 
- # CVS conversion code inspired by hg-cvs-import and git-cvsimport
- class convert_cvs(converter_source):
-@@ -458,6 +855,13 @@ class convert_mercurial(converter_sink):
+diff --git a/hgext/convert/git.py b/hgext/convert/git.py
+--- a/hgext/convert/git.py
++++ b/hgext/convert/git.py
+@@ -2,16 +2,7 @@
+ 
+ import os
+ 
+-from common import NoRepo, commit, converter_source
+-
+-def recode(s):
+-    try:
+-        return s.decode("utf-8").encode("utf-8")
+-    except:
+-        try:
+-            return s.decode("latin-1").encode("utf-8")
+-        except:
+-            return s.decode("utf-8", "replace").encode("utf-8")
++from common import NoRepo, commit, converter_source, recode
+ 
+ class convert_git(converter_source):
+     def __init__(self, ui, path):
+diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py
+--- a/hgext/convert/hg.py
++++ b/hgext/convert/hg.py
+@@ -28,6 +28,13 @@ class convert_mercurial(converter_sink):
+         self.repo.wwrite(f, data, e)
          if self.repo.dirstate.state(f) == '?':
              self.repo.dirstate.update([f], "a")
- 
++
 +    def copyfile(self, source, dest):
 +        # Hold a copymap map[dest] = source, like Mercurial does?
 +        # Might need to say self.repo.dirstate.copies()[dest] = source
 +        # Just mark it, don't let it actually do anything:
 +        assert hasattr(self.repo.dirstate, 'copymap')
 +        self.repo.dirstate.copymap[dest] = source
-+
+ 
      def delfile(self, f):
          try:
-             os.unlink(self.repo.wjoin(f))
-@@ -522,11 +926,12 @@ class convert_mercurial(converter_sink):
-                                 date, self.repo.changelog.tip(), hg.nullid)
-             return hg.hex(self.repo.changelog.tip())
- 
--converters = [convert_cvs, convert_git, convert_mercurial]
-+converters = [convert_svn, convert_cvs, convert_git, convert_mercurial]
- 
- def converter(ui, path):
--    if not os.path.isdir(path):
--        raise util.Abort("%s: not a directory" % path)
-+    # Subversion URLs are not directories
-+    # if not os.path.isdir(path):
-+    #     raise util.Abort("%s: not a directory" % path)
-     for c in converters:
-         try:
-             return c(ui, path)
-@@ -628,6 +1033,8 @@ class convert(object):
-     def copy(self, rev):
-         c = self.commitcache[rev]
-         files = self.source.getchanges(rev)
-+        
-+        do_copies = (hasattr(c, 'copies') and hasattr(self.dest, 'copyfile'))
- 
-         for f, v in files:
-             try:
-@@ -637,6 +1044,11 @@ class convert(object):
-             else:
-                 e = self.source.getmode(f, v)
-                 self.dest.putfile(f, e, data)
-+                if do_copies:
-+                    if f in c.copies:
-+                        # Merely marks that a copy happened.
-+                        self.dest.copyfile(c.copies[f], f)
-+
- 
-         r = [self.map[v] for v in c.parents]
-         f = [f for f, v in files]
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 186 bytes
Desc: not available
Url : http://selenic.com/pipermail/mercurial-devel/attachments/20070629/d607823e/attachment.pgp 


More information about the Mercurial-devel mailing list