# HG changeset patch # User Sébastien Pierre # Date 1152548377 14400 # Node ID fe3e87358b4755a92730c458b9e4221e8bf01b6f # Parent 5ec2dded1bdab0ab2751b9aadc99f2a5bfef2ad1 darcs2hg: pause and resume support, date extraction from commit hash, does not break on empty commits diff --git a/contrib/darcs2hg.py b/contrib/darcs2hg.py --- a/contrib/darcs2hg.py +++ b/contrib/darcs2hg.py @@ -4,12 +4,11 @@ # ----------------------------------------------------------------------------- # Project : Basic Darcs to Mercurial conversion script # ----------------------------------------------------------------------------- -# Author : Sebastien Pierre +# Authors : Sebastien Pierre +# TK Soh +# ----------------------------------------------------------------------------- # Creation : 24-May-2006 -# Last mod : 26-May-2006 -# History : -# 26-May-2006 - Updated -# 24-May-2006 - First implementation +# Last mod : 05-Jun-2006 # ----------------------------------------------------------------------------- import os, sys @@ -21,12 +20,14 @@ DARCS_REPO = None HG_REPO = None USAGE = """\ -%s DARCSREPO HGREPO +%s DARCSREPO HGREPO [SKIP] Converts the given Darcs repository to a new Mercurial repository. The given HGREPO must not exist, as it will be created and filled up (this will avoid overwriting valuable data. + In case an error occurs within the process, you can resume the process by + giving the last successfuly applied change number. """ % (os.path.basename(sys.argv[0])) # ------------------------------------------------------------------------------ @@ -35,7 +36,7 @@ USAGE = """\ # # ------------------------------------------------------------------------------ -def cmd(text, path=None): +def cmd(text, path=None, silent=False): """Executes a command, in the given directory (if any), and returns the command result as a string.""" cwd = None @@ -43,7 +44,7 @@ def cmd(text, path=None): path = os.path.abspath(path) cwd = os.getcwd() os.chdir(path) - print text + if not silent: print "> ", text res = os.popen(text).read() if path: os.chdir(cwd) @@ -53,6 +54,14 @@ def writefile(path, data): """Writes the given data into the given file.""" f = file(path, "w") ; f.write(data) ; f.close() +def error( *args ): + sys.stderr.write("ERROR: ") + for a in args: sys.stderr.write(str(a)) + sys.stderr.write("\n") + sys.stderr.write("You can make manual fixes if necessary and then resume by" + " giving the last changeset number") + sys.exit(-1) + # ------------------------------------------------------------------------------ # # Darcs interface @@ -64,7 +73,6 @@ def darcs_changes(darcsRepo): chronological list of changes as (change name, change summary).""" changes = cmd("darcs changes --reverse --xml-output", darcsRepo) doc = xml_dom.parseString(changes) - res = [] for patch_node in doc.childNodes[0].childNodes: name = filter(lambda n:n.nodeName == "name", patch_node.childNodes) comm = filter(lambda n:n.nodeName == "comment", patch_node.childNodes) @@ -73,12 +81,22 @@ def darcs_changes(darcsRepo): if not comm: comm = "" else: comm = comm[0].childNodes[0].data author = patch_node.getAttribute("author") - date = patch_node.getAttribute("date") - hash = patch_node.getAttribute("hash") - yield hash, author, date, name, comm + date = patch_node.getAttribute("date") + chash = os.path.splitext(patch_node.getAttribute("hash"))[0] + yield author, date, name, chash, comm -def darcs_pull(hg_repo, darcs_repo, change): - cmd("darcs pull '%s' --all --patches='%s'" % (darcs_repo, change), hg_repo) +def darcs_tip(darcs_repo): + changes = cmd("darcs changes",darcs_repo,silent=True) + changes = filter(lambda l:l.strip().startswith("* "), changes.split("\n")) + return len(changes) + +def darcs_pull(hg_repo, darcs_repo, chash): + old_tip = darcs_tip(darcs_repo) + res = cmd("darcs pull '%s' --all --match='hash %s'" % (darcs_repo, chash), hg_repo) + print res + new_tip = darcs_tip(darcs_repo) + if not new_tip != old_tip + 1: + error("Darcs pull did not work as expected: " + res) # ------------------------------------------------------------------------------ # @@ -89,10 +107,24 @@ def darcs_pull(hg_repo, darcs_repo, chan def hg_commit( hg_repo, text, author, date ): fd, tmpfile = tempfile.mkstemp(prefix="darcs2hg_") writefile(tmpfile, text) + old_tip = hg_tip(hg_repo) cmd("hg add -X _darcs", hg_repo) cmd("hg remove -X _darcs --after", hg_repo) - cmd("hg commit -l %s -u '%s' -d '%s 0'" % (tmpfile, author, date), hg_repo) + res = cmd("hg commit -l %s -u '%s' -d '%s 0'" % (tmpfile, author, date), hg_repo) os.unlink(tmpfile) + new_tip = hg_tip(hg_repo) + if not new_tip == old_tip + 1: + # Sometimes we may have empty commits, we simply skip them + if res.strip().lower().find("nothing changed") != -1: + pass + else: + error("Mercurial commit did not work as expected: " + res) + +def hg_tip( hg_repo ): + """Returns the latest local revision number in the given repository.""" + tip = cmd("hg tip", hg_repo, silent=True) + tip = tip.split("\n")[0].split(":")[1].strip() + return int(tip) # ------------------------------------------------------------------------------ # @@ -106,26 +138,41 @@ if __name__ == "__main__": if len(args) == 2: darcs_repo = os.path.abspath(args[0]) hg_repo = os.path.abspath(args[1]) + skip = None + elif len(args) == 3: + darcs_repo = os.path.abspath(args[0]) + hg_repo = os.path.abspath(args[1]) + skip = int(args[2]) else: print USAGE sys.exit(-1) # Initializes the target repo if not os.path.isdir(darcs_repo + "/_darcs"): - print "No darcs directory found at: " + darc_repo + print "No darcs directory found at: " + darcs_repo sys.exit(-1) if not os.path.isdir(hg_repo): os.mkdir(hg_repo) - else: - print "Given HG repository must not exist. It will be created" + elif skip == None: + print "Given HG repository must not exist when no SKIP is specified." sys.exit(-1) - cmd("hg init '%s'" % (hg_repo)) - cmd("darcs initialize", hg_repo) + if skip == None: + cmd("hg init '%s'" % (hg_repo)) + cmd("darcs initialize", hg_repo) # Get the changes from the Darcs repository - for hash, author, date, summary, description in darcs_changes(darcs_repo): - text = summary + "\n" + description - darcs_pull(hg_repo, darcs_repo, hash) - epoch = int(mktime(strptime(date, '%Y%m%d%H%M%S'))) - hg_commit(hg_repo, text, author, epoch) + change_number = 0 + for author, date, summary, chash, description in darcs_changes(darcs_repo): + print "== changeset", change_number, + if skip != None and change_number <= skip: + print "(skipping)" + else: + text = summary + "\n" + description + darcs_pull(hg_repo, darcs_repo, chash) + # The commit hash has a date like 20021020201112 + # --------------------------------YYYYMMDDHHMMSS + date = chash.split("-")[0] + epoch = int(mktime(strptime(date, '%Y%m%d%H%M%S'))) + hg_commit(hg_repo, text, author, epoch) + change_number += 1 + print "Darcs repository (_darcs) was not deleted. You can keep or remove it." # EOF -