[Pkg-ocaml-maint-commits] r5603 - /trunk/tools/svn2git/glondu_svn2git.py

glondu-guest at users.alioth.debian.org glondu-guest at users.alioth.debian.org
Fri May 9 20:06:30 UTC 2008


Author: glondu-guest
Date: Fri May  9 20:06:30 2008
New Revision: 5603

URL: http://svn.debian.org/wsvn/?sc=1&rev=5603
Log:
svn2git script customized for alioth which handles upstream sources

I ended up rewriting everything from scratch. This script is still a
draft. It succeeded in converting ocsigen packaging (the result shoud
be available soon on git.debian.org among my own repos). I put it here
so that I don't loose it and everyone can have a look, but it is not
directly reusable as it is.

Added:
    trunk/tools/svn2git/glondu_svn2git.py

Added: trunk/tools/svn2git/glondu_svn2git.py
URL: http://svn.debian.org/wsvn/trunk/tools/svn2git/glondu_svn2git.py?rev=5603&op=file
==============================================================================
--- trunk/tools/svn2git/glondu_svn2git.py (added)
+++ trunk/tools/svn2git/glondu_svn2git.py Fri May  9 20:06:30 2008
@@ -1,0 +1,211 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright © 2008 Stéphane Glondu <steph at glondu.net>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+import sys, os, re
+from datetime import datetime, tzinfo, timedelta
+from debian_bundle.debian_support import version_compare
+from tempfile import NamedTemporaryFile
+from commands import getoutput, getstatusoutput
+from xml.dom.minidom import parseString
+
+
+svntag_re = re.compile(r"^\[svn-buildpackage\][^(]+\(([^)]+)\)$")
+
+
+# Mapping from alioth login to name and email
+users_dict = {
+    "glondu-guest": ("Stephane Glondu", "steph at glondu.net"),
+    "smimram": ("Samuel Mimram", "smimram at debian.org"),
+    "zack": ("Stefano Zacchiroli", "zack at debian.org"),
+}
+
+
+def run_command(name, cmd):
+    s, o = getstatusoutput(cmd)
+    if s:
+        raise IOError("'%s' returned with code %d" % (cmd, s))
+    return o
+
+
+ZERO = timedelta(0)
+class UTC(tzinfo):
+    """UTC"""
+    def utcoffset(self, dt):
+        return ZERO
+    def tzname(self, dt):
+        return "UTC"
+    def dst(self, dt):
+        return ZERO
+utc = UTC()
+
+
+def parse_datetime(str):
+    if len(str) >= 21 and str[4] == '-' and str[7] == '-' \
+            and str[10] == 'T' and str[13] == ':' and str[16] == ':' \
+            and str[19] == '.' and str[-1] == 'Z':
+        year, month, day = int(str[0:4]), int(str[5:7]), int(str[8:10])
+        hour, minute, second = int(str[11:13]), int(str[14:16]), int(str[17:19])
+        microsecond = int(float(str[19:-1]) * 1000000.)
+        return datetime(year, month, day, hour, minute, second, microsecond, utc)
+    else:
+        raise ValueError("Unable to parse date '%s'" % str)
+
+
+def git_init():
+    os.mkdir("git")
+    run_command("git", "cd git && git init")
+
+
+class GitCommit:
+
+    def __init__(self, logentry, svn2git):
+        self.svn2git = svn2git
+        self.rev = int(logentry.getAttribute("revision"))
+        self.msg = logentry.getElementsByTagName("msg")[0].firstChild.nodeValue
+        user_elt = logentry.getElementsByTagName("author")[0]
+        self.name, self.email = users_dict[user_elt.firstChild.nodeValue]
+        date_elt = logentry.getElementsByTagName("date")[0]
+        date = parse_datetime(date_elt.firstChild.nodeValue)
+        self.date = date.strftime("%Y-%m-%d %H:%M:%S %z")
+
+    def setup_env(self):
+        os.putenv("GIT_AUTHOR_NAME", self.name)
+        os.putenv("GIT_AUTHOR_EMAIL", self.email)
+        os.putenv("GIT_AUTHOR_DATE", self.date)
+        os.putenv("GIT_COMMITTER_NAME", self.name)
+        os.putenv("GIT_COMMITTER_EMAIL", self.email)
+        os.putenv("GIT_COMMITTER_DATE", self.date)
+
+    def checkout(self):
+        if os.path.exists("svn"):
+            os.chdir("svn")
+            # Actually an update
+            print "Retreiving revision %d from svn..." % self.rev,
+            run_command("svn", "svn update -r%d" % self.rev)
+            print "OK!"
+            os.chdir("..")
+        else:
+            # Really a checkout
+            print "Checking out revision %d from svn..." % self.rev,
+            run_command("svn", "svn checkout %s@%d svn" % (self.svn2git.repos, self.rev))
+            print "OK!"
+
+    def commit(self):
+        tarball_path = "../svn/" + self.svn2git.tarball_path
+        os.chdir("git")
+
+        # Call git-import-orig if needed
+        if os.path.exists(tarball_path):
+            n = []
+            for x in os.listdir(tarball_path):
+                if not self.svn2git.seen.has_key(x):
+                    n.append(x)
+            if len(n) == 1:
+                tgz = n[0]
+                print "New upstream tarball:", tgz
+                run_command("git-import-orig", "git-import-orig --pristine-tar --no-dch %s/%s" % (tarball_path, tgz))
+                self.svn2git.seen[n[0]] = True
+            elif len(n) > 1:
+                print "Too many new tarballs:", ", ".join(n)
+                sys.exit(1)
+        else:
+            print "No upstream directory!"
+
+        print "Committing revision %d to git..." % self.rev,
+        self.setup_env()
+
+        s, o = getstatusoutput("rsync -rt --exclude=.svn ../svn/trunk/debian/ debian")
+        if s:
+            print "nothing to sync! (rsync returned with code %d)" % s
+            os.chdir("..")
+            return None
+        s, o = getstatusoutput("git add .")
+        if s:
+            print "nothing to add! (git returned with code %d)" % s
+            os.chdir("..")
+            return None
+        f = NamedTemporaryFile()
+        f.file.write(self.msg.encode("UTF-8"))
+        f.file.close()
+        s, o = getstatusoutput("git commit -F%s" % f.name)
+        f.close()
+        if s:
+            print "nothing to commit! (git returned with code %d)" % s
+            os.chdir("..")
+            return None
+        print "OK!"
+        os.chdir("..")
+
+    def check_clean(self):
+        s, o = getstatusoutput("find svn|grep -vE '^svn($|/(.svn|upstream)($|/)|/trunk($|/(debian|\.svn)))'")
+        if not s:
+            print "Unexpected content in svn repos:"
+            print o
+
+
+class GitTag(GitCommit):
+
+    def commit(self):
+        m = svntag_re.match(self.msg)
+        if m:
+            tagname = "debian/" + m.group(1)
+        else:
+            print "Ignoring tag from revision %d:" % self.rev, self.msg
+            return None
+        # '~' is not valid in tag names
+        tagname = tagname.replace('~', '.')
+        os.chdir("git")
+        print "Tagging revision %d as %s..." % (self.rev, tagname),
+        self.setup_env()
+        f = NamedTemporaryFile()
+        f.file.write(self.msg.encode("UTF-8"))
+        f.file.close()
+        run_command("git", "git tag -a -F%s %s" % (f.name, tagname))
+        f.close()
+        print "OK!"
+        os.chdir("..")
+
+
+class Svn2Git:
+
+    def __init__(self, package, tarball_path):
+        self.tarball_path = tarball_path
+        self.repos = "svn://svn.debian.org/svn/pkg-ocaml-maint/trunk/packages/%s" % package
+        self.tagrepos = "svn://svn.debian.org/svn/pkg-ocaml-maint/tags/packages/%s" % package
+        # Retrieve history
+        r = run_command("svn", "svn log --xml %s" % self.repos)
+        r = parseString(r).getElementsByTagName("logentry")
+        revs = [GitCommit(x, self) for x in r]
+        r = run_command("svn", "svn log --xml %s" % self.tagrepos)
+        r = parseString(r).getElementsByTagName("logentry")
+        tags = [GitTag(x, self) for x in r]
+        self.logentries = revs+tags
+        self.logentries.sort(key=lambda x: x.rev)
+        # Initialize the list of already-seen tarballs
+        self.seen = {".svn": True}
+        s, o = getstatusoutput("cd git && git log -b pristine-tar 2>/dev/null|sed -nr 's/^    pristine-tar data for //p'")
+        for x in o.split("\n"):
+            if x:
+                print "Seen:", x
+                self.seen[x] = True
+
+    def do(self, from_revision):
+        for x in self.logentries:
+            if x.rev >= from_revision:
+                x.checkout()
+                x.check_clean()
+                x.commit()
+
+
+if __name__ == "__main__":
+    #run_command("clean", "rm -Rf git svn")
+    #git_init()
+    a = Svn2Git("ocsigen", "upstream")
+    a.do(0)




More information about the Pkg-ocaml-maint-commits mailing list