[PATCH] Added ability to clone from a local repository to a (new) remote one

Sean Meiners sean.meiners at linspire.com
Mon Jun 19 19:08:19 CDT 2006


# HG changeset patch
# User smeiners at slick.sd.linspire.com
# Node ID a6cd9514f2bc94508ec0f13336ef5977de4cc013
# Parent  35fb62a3a673d5322f6274a44ba6456e5e4b3b37
Added ability to clone from a local repository to a (new) remote one.

Updating the <repo>/.hg/hgrc file is now optional and will automatically set the default pull location when cloning to a remote repository. This was done with the intention of making it easier for those of us who like to work in a more centralized model (even if only for backup purposes).

I had to rearrange the clone command a good bit to make sure it validates that the source does exist and that the destination doesn't before doing anything. Before I moved the source repo check it would create the destination repository before it verified the source existed. I also changed the names of the 'repo' and 'other' variables to 'destRepo' and 'srcRepo' to maintain my own sanity.

diff -r 35fb62a3a673 -r a6cd9514f2bc mercurial/commands.py
--- a/mercurial/commands.py	Wed May 10 13:39:12 2006 -0700
+++ b/mercurial/commands.py	Mon Jun 19 16:50:52 2006 -0700
@@ -865,8 +865,6 @@ def clone(ui, source, dest=None, **opts)
     if os.path.exists(dest):
         raise util.Abort(_("destination '%s' already exists"), dest)
 
-    dest = os.path.realpath(dest)
-
     class Dircleanup(object):
         def __init__(self, dir_):
             self.rmtree = shutil.rmtree
@@ -884,13 +882,31 @@ def clone(ui, source, dest=None, **opts)
         ui.setconfig("ui", "remotecmd", opts['remotecmd'])
 
     source = ui.expandpath(source)
-
-    d = Dircleanup(dest)
+    srcRepo = hg.repository(ui, source)
+
+    destRepo = None
+    try:
+        destRepo = hg.repository(ui, dest)
+    except hg.RepoError:
+        pass
+
+    if destRepo:
+        error = _("destination '%s' already exists." % dest)
+        raise util.Abort(error)
+        
+    destRepo = hg.repository(ui, dest, create=1)
+
+    destPath = None
+    d = None
+    if destRepo.dev() != -1
+        destPath = os.path.realpath(dest)
+        d = Dircleanup(destPath)
+        
     abspath = source
-    other = hg.repository(ui, source)
+    srcRepo = hg.repository(ui, source)
 
     copy = False
-    if other.dev() != -1:
+    if srcRepo.dev() != -1 and destRepo.dev() != -1:
         abspath = os.path.abspath(source)
         if not opts['pull'] and not opts['rev']:
             copy = True
@@ -901,47 +917,80 @@ def clone(ui, source, dest=None, **opts)
             # can end up with extra data in the cloned revlogs that's
             # not pointed to by changesets, thus causing verify to
             # fail
-            l1 = other.lock()
+            l1 = srcRepo.lock()
         except lock.LockException:
             copy = False
 
     if copy:
         # we lock here to avoid premature writing to the target
-        os.mkdir(os.path.join(dest, ".hg"))
-        l2 = lock.lock(os.path.join(dest, ".hg", "lock"))
+        os.mkdir(os.path.join(destPath, ".hg"))
+        l2 = lock.lock(os.path.join(destPath, ".hg", "lock"))
 
         files = "data 00manifest.d 00manifest.i 00changelog.d 00changelog.i"
         for f in files.split():
             src = os.path.join(source, ".hg", f)
-            dst = os.path.join(dest, ".hg", f)
+            dst = os.path.join(destPath, ".hg", f)
             try:
                 util.copyfiles(src, dst)
             except OSError, inst:
                 if inst.errno != errno.ENOENT:
                     raise
 
-        repo = hg.repository(ui, dest)
-
     else:
         revs = None
         if opts['rev']:
-            if not other.local():
+            if not srcRepo.local():
                 error = _("clone -r not supported yet for remote repositories.")
                 raise util.Abort(error)
             else:
-                revs = [other.lookup(rev) for rev in opts['rev']]
-        repo = hg.repository(ui, dest, create=1)
-        repo.pull(other, heads = revs)
-
-    f = repo.opener("hgrc", "w", text=True)
-    f.write("[paths]\n")
-    f.write("default = %s\n" % abspath)
-    f.close()
-
-    if not opts['noupdate']:
-        update(repo.ui, repo)
-
-    d.close()
+                revs = [srcRepo.lookup(rev) for rev in opts['rev']]
+
+        if destRepo.dev() != -1:
+            destRepo.pull(srcRepo, heads = revs)
+        elif srcRepo.dev() != -1:
+            srcRepo.push(destRepo, revs = revs)
+        else:
+            error = _("clone from remote to remote not supported.")
+            raise util.Abort(error)
+
+    if destRepo.dev() != -1:
+        if not opts['nohgrc']:
+            f = destRepo.opener("hgrc", "w", text=True)
+            f.write("[paths]\n")
+            f.write("default = %s\n" % abspath)
+            f.close()
+
+        if not opts['noupdate']:
+            update(destRepo.ui, destRepo)
+            
+    elif srcRepo.dev() != -1:
+        if not opts['nohgrc']:
+            inPaths = False
+            groupRE = re.compile(r'^\s*\[([^\]]+)\].*')
+            defaultRE = re.compile(r'^\s*default\s*=.*')
+            lines = []
+            f = srcRepo.opener("hgrc", "r", text=True)
+            for line in f:
+                match = groupRE.match(line)
+                if match:
+                    if match.group(1) == 'paths':
+                        inPaths = True
+                    else:
+                        inPaths = False
+                elif inPaths:
+                    if defaultRE.match(line):
+                        lines.append( 'default = %s\n' % dest )
+                        continue
+                lines.append(line)
+            f.close()
+                
+            f = srcRepo.opener("hgrc", "w", text=True)
+            for line in lines:
+                f.write(line)
+            f.close()
+
+    if d:
+        d.close()
 
 def commit(ui, repo, *pats, **opts):
     """commit the specified files or all outstanding changes
@@ -2830,6 +2879,7 @@ table = {
            _('a changeset you would like to have after cloning')),
           ('', 'pull', None, _('use pull protocol to copy metadata')),
           ('e', 'ssh', '', _('specify ssh command to use')),
+          ('n', 'nohgrc', None, _('do not update local hgrc file')),
           ('', 'remotecmd', '',
            _('specify hg command to run on the remote side'))],
          _('hg clone [OPTION]... SOURCE [DEST]')),
diff -r 35fb62a3a673 -r a6cd9514f2bc mercurial/hg.py
--- a/mercurial/hg.py	Wed May 10 13:39:12 2006 -0700
+++ b/mercurial/hg.py	Mon Jun 19 16:50:52 2006 -0700
@@ -23,7 +23,7 @@ def repository(ui, path=None, create=0):
             return statichttprepo.statichttprepository(
                 ui, path.replace("old-http://", "http://"))
         if path.startswith("ssh://"):
-            return sshrepo.sshrepository(ui, path)
+            return sshrepo.sshrepository(ui, path, create)
         if path.startswith("bundle://"):
             path = path[9:]
             s = path.split("+", 1)
diff -r 35fb62a3a673 -r a6cd9514f2bc mercurial/sshrepo.py
--- a/mercurial/sshrepo.py	Wed May 10 13:39:12 2006 -0700
+++ b/mercurial/sshrepo.py	Mon Jun 19 16:50:52 2006 -0700
@@ -12,7 +12,7 @@ demandload(globals(), "hg os re stat uti
 demandload(globals(), "hg os re stat util")
 
 class sshrepository(remoterepository):
-    def __init__(self, ui, path):
+    def __init__(self, ui, path, create=0):
         self.url = path
         self.ui = ui
 
@@ -30,6 +30,25 @@ class sshrepository(remoterepository):
 
         sshcmd = self.ui.config("ui", "ssh", "ssh")
         remotecmd = self.ui.config("ui", "remotecmd", "hg")
+
+        if create:
+            try:
+                self.validate_repo(ui, sshcmd, args, remotecmd)
+                return # the repo is good, nothing more to do
+            except hg.RepoError:
+                pass
+
+            cmd = '%s %s "%s init %s"'
+            cmd = cmd % (sshcmd, args, remotecmd, self.path)
+
+            ui.note('running %s\n' % cmd)
+            res = os.system(cmd)
+            if res != 0:
+                raise hg.RepoError(_("Could not create remote repo"))
+
+        self.validate_repo(ui, sshcmd, args, remotecmd)
+        
+    def validate_repo(self, ui, sshcmd, args, remotecmd):
         cmd = '%s %s "%s -R %s serve --stdio"'
         cmd = cmd % (sshcmd, args, remotecmd, self.path)
 


More information about the Mercurial mailing list