Merge branch 'svn-externals' of https://github.com/pnd10/Toolchain

Robert Sesek [2012-10-13 18:16]
Merge branch 'svn-externals' of https://github.com/pnd10/Toolchain

Conflicts:
	git-svn-sync.py
Filename
git-svn-sync.py
diff --git a/git-svn-sync.py b/git-svn-sync.py
index f10f4bd..bfa4e43 100755
--- a/git-svn-sync.py
+++ b/git-svn-sync.py
@@ -26,7 +26,7 @@ with that is cloned from SVN. Running this will perform a git-svn-rebase and
 will then update exteranls.

 The external checkouts can be either svn working copies, full git repositories,
-or shallow (no history) git repositories. The default is an SVN working copy.
+or shallow (no history) git repositories. The default is a full git repository.

 Usage:

@@ -98,10 +98,27 @@ def AddExclude(path, exclude):
   fp.write(exclude + "\n")
   fp.close()

+def FixupExternals(svn_root, url, path):
+    """ Externals from version 1.5 onwards are mis-parsed by git svn show-externals
+    Fix them up by spliting around the relative character, and putting the prefix
+    onto the start of path.
+    e.g. An external in app/app1 of ^/trunk/lib/lib1 at rev 1234 would appear in
+    the output as
+         /app/app1/^/trunk/lib/lib1@1234 lib1
+    this needs to be fixed up as
+         <svn_root>/trunk/lib/lib1@1234 app/app1/lib1
+    """
+    if '^/' in url:
+        prefix, url = url.split('^/')
+        path = os.path.join(prefix, path)
+        path = path.lstrip('/')
+        url = svn_root + '/' + url
+    return (url, path)
+
 def Main():
-  """Main function."""
+  """Main function."""
   parser = optparse.OptionParser()
-  parser.add_option("-t", "--type", choices=["svn", "git", "shallow"], default="git", help="Type of checkout to perform for new externals. Choices are svn,git,shallow. git is default.")
+  parser.add_option("-t", "--type", choices=["svn", "git", "shallow"], default="git", help="Type of checkout to perform for new externals. Choices are svn,git,shallow. git is default.")
   (options, args) = parser.parse_args()

   git_path = GitRepoPath()
@@ -109,50 +126,54 @@ def Main():
     print "Please run this script from within a git repository."
     sys.exit(1)
   os.chdir(git_path)
-
+
   if not IsGitSVN(git_path):
     print "This git repository was not cloned via git-svn."
     sys.exit(2)
-
-  # Important info for cloneing.
+
+  # Important info for cloning.
   svn_root = GetSVNRoot()
   externals = GetExternals()
-
+
   if len(externals) > 0:
     if not os.path.exists(".git_sync"):
       os.mkdir(".git_sync")
-
+
   AddExclude(git_path, ".git_sync")
-
+
   for ext in externals:
     # Fix up URLs that are relative to SVN repository root.
     url = ext[0]
     path = ext[1]
-    if url[0:3] == "/^/":
-      url = url[1:]
-    if url[0:2] == "^/":
-      url = svn_root + "/" + url[2:]
-
+    url, path = FixupExternals(svn_root, url, path)
+
     # Split out revision information.
     url_parts = url.split('@')
     url = url_parts[0]
-    rev = url_parts[1]
+    if len(url_parts) > 1:
+      rev = url_parts[1]
+      external_pinned = True
+    else:
+      rev = 'HEAD'
+      external_pinned = False
     sync_path = os.path.join(".git_sync", path)
-
-    curpath = os.getcwd()
-
+
     # Perform the actual checkout.
     if os.path.exists(sync_path):
-      os.chdir(sync_path)
+      print "Updating external at", path
       # Perform an update on a git repository.
-      if os.path.exists(".git"):
+      if os.path.exists(os.path.join(sync_path, ".git")):
+        curpath = os.getcwd()
+        os.chdir(sync_path)
         subprocess.Popen(["git", "svn", "rebase"]).wait()
+        os.chdir(curpath)
       # Perform an update on a SVN WC.
       elif os.path.exists(".svn"):
         subprocess.Popen(["svn", "update", "-r", rev, sync_path]).wait()
       else:
-        print "Unkown repository type at %s" % sync_path
+        print "Unknown repository type at %s" % sync_path
     else:
+      print "Initial checkout of external at", path
       # Perform a git checkout.
       if options.type == "git":
         subprocess.Popen(["git", "svn", "clone", url, sync_path]).wait()
@@ -161,13 +182,20 @@ def Main():
         subprocess.Popen(["svn", "checkout", "-r", rev, url, sync_path]).wait()
       else:
         print "Cannot clone %s as %s" % (sync_path, options.type)
-      os.symlink(sync_path, os.path.join(git_path, path))
-      os.chdir(sync_path)
+      # To deal with externals deep in the tree, symlinks need to count the
+      # number of path elements they have to go up to get to the head of the tree
+      os.symlink(os.path.join('../' * path.count('/'), sync_path),
+                 os.path.join(git_path, path))
     AddExclude(git_path, path)
-
+
     # If the checkout is a git one, then we need to find the proper SVN revision.
     if os.path.exists(os.path.join(sync_path, ".git")):
-      get_rev = subprocess.Popen(["git", "svn", "log", "--show-commit", "-r", rev], stdout=subprocess.PIPE)
+      curpath = os.getcwd()
+      os.chdir(sync_path)
+      if external_pinned:
+        get_rev = subprocess.Popen(["git", "svn", "log", "--show-commit", "-r", rev], stdout=subprocess.PIPE)
+      else:
+        get_rev = subprocess.Popen(["git", "svn", "log", "--show-commit"], stdout=subprocess.PIPE)
       get_rev.wait()
       oneline = get_rev.stdout.readlines()
       print oneline
@@ -177,6 +205,5 @@ def Main():
     os.chdir(curpath)
   # end for

-
 if __name__ == '__main__':
   Main()