Mercurial > hg
changeset 5361:adce4d30a6ea
Merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Tue, 02 Oct 2007 18:04:18 -0500 |
parents | d0c48891dd4a (current diff) b98c377b3c16 (diff) |
children | ff32b2725651 |
files | |
diffstat | 10 files changed, 287 insertions(+), 22 deletions(-) [+] |
line wrap: on
line diff
--- a/contrib/darcs2hg.py Thu Sep 27 23:59:18 2007 -0500 +++ b/contrib/darcs2hg.py Tue Oct 02 18:04:18 2007 -0500 @@ -3,18 +3,22 @@ # vim: tw=80 ts=4 sw=4 noet # ----------------------------------------------------------------------------- # Project : Basic Darcs to Mercurial conversion script +# +# *** DEPRECATED. Use the convert extension instead. This script will +# *** be removed soon. +# # ----------------------------------------------------------------------------- # Authors : Sebastien Pierre <sebastien@xprima.com> # TK Soh <teekaysoh@gmail.com> # ----------------------------------------------------------------------------- # Creation : 24-May-2006 -# Last mod : 05-Jun-2006 # ----------------------------------------------------------------------------- import os, sys import tempfile import xml.dom.minidom as xml_dom from time import strptime, mktime +import re DARCS_REPO = None HG_REPO = None @@ -93,11 +97,50 @@ 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) + if re.search('^We have conflicts in the following files:$', res, re.MULTILINE): + print "Trying to revert files to work around conflict..." + rev_res = cmd ("darcs revert --all", hg_repo) + print rev_res print res new_tip = darcs_tip(darcs_repo) if not new_tip != old_tip + 1: error("Darcs pull did not work as expected: " + res) +def darcs_changes_summary(darcs_repo, chash): + """Gets the changes from the darcs summary. This returns the chronological + list of changes as (change_type, args). Eg. ('add_file', 'foo.txt') or + ('move', ['foo.txt','bar.txt']).""" + change = cmd("darcs changes --summary --xml-output --match=\"hash %s\"" % (chash), darcs_repo) + doc = xml_dom.parseString(change) + for patch_node in doc.childNodes[0].childNodes: + summary_nodes = filter(lambda n: n.nodeName == "summary" and n.nodeType == n.ELEMENT_NODE, patch_node.childNodes) + for summary_node in summary_nodes: + change_nodes = filter(lambda n: n.nodeType == n.ELEMENT_NODE, summary_node.childNodes) + if len(change_nodes) == 0: + name = filter(lambda n: n.nodeName == "name", patch_node.childNodes) + if not name: + error("Darcs patch has an empty summary node and no name: " + patch_node.toxml()) + name = name[0].childNodes[0].data.strip() + (tag, sub_count) = re.subn('^TAG ', '', name, 1) + if sub_count != 1: + error("Darcs patch has an empty summary node but doesn't look like a tag: " + patch_node.toxml()); + for change_node in change_nodes: + change = change_node.nodeName + if change == 'modify_file': + yield change, change_node.childNodes[0].data.strip() + elif change == 'add_file': + yield change, change_node.childNodes[0].data.strip() + elif change == 'remove_file': + yield change, change_node.childNodes[0].data.strip() + elif change == 'add_directory': + yield change, change_node.childNodes[0].data.strip() + elif change == 'remove_directory': + yield change, change_node.childNodes[0].data.strip() + elif change == 'move': + yield change, (change_node.getAttribute('from'), change_node.getAttribute('to')) + else: + error('Problem parsing summary xml: Unexpected element: ' + change_node.toxml()) + # ------------------------------------------------------------------------------ # # Mercurial interface @@ -127,6 +170,36 @@ tip = tip.split("\n")[0].split(":")[1].strip() return int(tip) +def hg_rename( hg_repo, from_file, to_file ): + cmd("hg rename --after \"%s\" \"%s\"" % (from_file, to_file), hg_repo); + +def hg_tag ( hg_repo, text, author, date ): + old_tip = hg_tip(hg_repo) + res = cmd("hg tag -u \"%s\" -d \"%s 0\" \"%s\"" % (author, date, text), hg_repo) + new_tip = hg_tip(hg_repo) + if not new_tip == old_tip + 1: + error("Mercurial tag did not work as expected: " + res) + +def hg_handle_change( hg_repo, author, date, change, arg ): + """Processes a change event as output by darcs_changes_summary. These + consist of file move/rename/add/delete commands.""" + if change == 'modify_file': + pass + elif change == 'add_file': + pass + elif change =='remove_file': + pass + elif change == 'add_directory': + pass + elif change == 'remove_directory': + pass + elif change == 'move': + hg_rename(hg_repo, arg[0], arg[1]) + elif change == 'tag': + hg_tag(hg_repo, arg, author, date) + else: + error('Unknown change type ' + change + ': ' + arg) + # ------------------------------------------------------------------------------ # # Main @@ -147,6 +220,7 @@ else: print USAGE sys.exit(-1) + print 'This command is deprecated. Use the convert extension instead.' # Initializes the target repo if not os.path.isdir(darcs_repo + "/_darcs"): print "No darcs directory found at: " + darcs_repo @@ -167,11 +241,13 @@ 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'))) + darcs_pull(hg_repo, darcs_repo, chash) + for change, arg in darcs_changes_summary(darcs_repo, chash): + hg_handle_change(hg_repo, author, epoch, change, arg) hg_commit(hg_repo, text, author, epoch) change_number += 1 print "Darcs repository (_darcs) was not deleted. You can keep or remove it."
--- a/hgext/convert/__init__.py Thu Sep 27 23:59:18 2007 -0500 +++ b/hgext/convert/__init__.py Tue Oct 02 18:04:18 2007 -0500 @@ -7,6 +7,7 @@ from common import NoRepo, converter_source, converter_sink from cvs import convert_cvs +from darcs import darcs_source from git import convert_git from hg import mercurial_source, mercurial_sink from subversion import convert_svn, debugsvnlog @@ -18,7 +19,7 @@ commands.norepo += " convert debugsvnlog" converters = [convert_cvs, convert_git, convert_svn, mercurial_source, - mercurial_sink] + mercurial_sink, darcs_source] def convertsource(ui, path, **opts): for c in converters: @@ -235,6 +236,7 @@ def convert(self): try: + self.source.before() self.dest.before() self.source.setrevmap(self.map) self.ui.status("scanning source...\n") @@ -273,7 +275,10 @@ self.cleanup() def cleanup(self): - self.dest.after() + try: + self.dest.after() + finally: + self.source.after() if self.revmapfilefd: self.revmapfilefd.close() @@ -367,9 +372,10 @@ """Convert a foreign SCM repository to a Mercurial one. Accepted source formats: - - GIT - CVS - - SVN + - Darcs + - git + - Subversion Accepted destination formats: - Mercurial
--- a/hgext/convert/common.py Thu Sep 27 23:59:18 2007 -0500 +++ b/hgext/convert/common.py Tue Oct 02 18:04:18 2007 -0500 @@ -38,6 +38,12 @@ self.encoding = 'utf-8' + def before(self): + pass + + def after(self): + pass + def setrevmap(self, revmap): """set the map of already-converted revisions""" pass
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/convert/darcs.py Tue Oct 02 18:04:18 2007 -0500 @@ -0,0 +1,137 @@ +# darcs support for the convert extension + +from common import NoRepo, commit, converter_source +from mercurial.i18n import _ +from mercurial import util +import os, shutil, tempfile + +# The naming drift of ElementTree is fun! + +try: from xml.etree.cElementTree import ElementTree +except ImportError: + try: from xml.etree.ElementTree import ElementTree + except ImportError: + try: from elementtree.cElementTree import ElementTree + except ImportError: + try: from elementtree.ElementTree import ElementTree + except ImportError: ElementTree = None + + +class darcs_source(converter_source): + def __init__(self, ui, path, rev=None): + super(darcs_source, self).__init__(ui, path, rev=rev) + + if not os.path.exists(os.path.join(path, '_darcs', 'inventory')): + raise NoRepo("couldn't open darcs repo %s" % path) + + if ElementTree is None: + raise util.Abort(_("Python ElementTree module is not available")) + + self.path = os.path.realpath(path) + + self.lastrev = None + self.changes = {} + self.parents = {} + self.tags = {} + + def before(self): + self.tmppath = tempfile.mkdtemp( + prefix='convert-' + os.path.basename(self.path) + '-') + output, status = self.run('init', repodir=self.tmppath) + self.checkexit(status) + + tree = self.xml('changes', '--xml-output', '--summary') + tagname = None + child = None + for elt in tree.findall('patch'): + node = elt.get('hash') + name = elt.findtext('name', '') + if name.startswith('TAG '): + tagname = name[4:].strip() + elif tagname is not None: + self.tags[tagname] = node + tagname = None + self.changes[node] = elt + self.parents[child] = [node] + child = node + self.parents[child] = [] + + def after(self): + self.ui.debug('cleaning up %s\n' % self.tmppath) + #shutil.rmtree(self.tmppath, ignore_errors=True) + + def _run(self, cmd, *args, **kwargs): + cmdline = 'darcs %s --repodir=%r %s </dev/null' % ( + cmd, kwargs.get('repodir', self.path), ' '.join(args)) + self.ui.debug(cmdline, '\n') + return os.popen(cmdline, 'r') + + def run(self, cmd, *args, **kwargs): + fp = self._run(cmd, *args, **kwargs) + output = fp.read() + return output, fp.close() + + def checkexit(self, status, output=''): + if status: + if output: + ui.warn(_('darcs error:\n')) + ui.warn(output) + msg = util.explain_exit(status)[0] + raise util.Abort(_('darcs %s') % msg) + + def xml(self, cmd, *opts): + etree = ElementTree() + fp = self._run(cmd, *opts) + etree.parse(fp) + self.checkexit(fp.close()) + return etree.getroot() + + def getheads(self): + return self.parents[None] + + def getcommit(self, rev): + elt = self.changes[rev] + date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y') + desc = elt.findtext('name') + '\n' + elt.findtext('comment', '') + return commit(author=elt.get('author'), date=util.datestr(date), + desc=desc.strip(), parents=self.parents[rev]) + + def pull(self, rev): + output, status = self.run('pull %r --all --match="hash %s"' % + (self.path, rev), + '--no-test', '--no-posthook', + '--external-merge=/bin/false', + repodir=self.tmppath) + if status: + if output.find('We have conflicts in') == -1: + self.checkexit(status, output) + output, status = self.run('revert --all', repodir=self.tmppath) + self.checkexit(status, output) + + def getchanges(self, rev): + self.pull(rev) + copies = {} + changes = [] + for elt in self.changes[rev].find('summary').getchildren(): + if elt.tag in ('add_directory', 'remove_directory'): + continue + if elt.tag == 'move': + changes.append((elt.get('from'), rev)) + copies[elt.get('from')] = elt.get('to') + else: + changes.append((elt.text.strip(), rev)) + changes.sort() + self.lastrev = rev + return changes, copies + + def getfile(self, name, rev): + if rev != self.lastrev: + raise util.Abort(_('internal calling inconsistency')) + return open(os.path.join(self.tmppath, name), 'rb').read() + + def getmode(self, name, rev): + mode = os.lstat(os.path.join(self.tmppath, name)).st_mode + return (mode & 0111) and 'x' or '' + + def gettags(self): + return self.tags
--- a/hgext/convert/hg.py Thu Sep 27 23:59:18 2007 -0500 +++ b/hgext/convert/hg.py Tue Oct 02 18:04:18 2007 -0500 @@ -59,9 +59,9 @@ def delfile(self, f): try: - os.unlink(self.repo.wjoin(f)) + util.unlink(self.repo.wjoin(f)) #self.repo.remove([f]) - except: + except OSError: pass def setbranch(self, branch, pbranch, parents): @@ -156,7 +156,10 @@ class mercurial_source(converter_source): def __init__(self, ui, path, rev=None): converter_source.__init__(self, ui, path, rev) - self.repo = hg.repository(self.ui, path) + try: + self.repo = hg.repository(self.ui, path) + except: + raise NoRepo("could not open hg repo %s as source" % path) self.lastrev = None self.lastctx = None
--- a/mercurial/util.py Thu Sep 27 23:59:18 2007 -0500 +++ b/mercurial/util.py Tue Oct 02 18:04:18 2007 -0500 @@ -1095,7 +1095,7 @@ def set_exec(f, mode): s = os.lstat(f).st_mode - if (s & 0100 != 0) == mode: + if stat.S_ISLNK(s) or (s & 0100 != 0) == mode: return if mode: # Turn on +x for every +r bit when making a file executable @@ -1468,7 +1468,7 @@ s += timezone_format % (-tz / 3600, ((-tz % 3600) / 60)) return s -def strdate(string, format, defaults): +def strdate(string, format, defaults=[]): """parse a localized time string and return a (unixtime, offset) tuple. if the string cannot be parsed, ValueError is raised.""" def timezone(string):
--- a/tests/test-convert-git Thu Sep 27 23:59:18 2007 -0500 +++ b/tests/test-convert-git Tue Oct 02 18:04:18 2007 -0500 @@ -25,16 +25,26 @@ cd git-repo git init-db >/dev/null 2>/dev/null echo a > a -git add a -commit -m t1 +mkdir d +echo b > d/b +git add a d +commit -a -m t1 + +# Remove the directory, then try to replace it with a file +# (issue 754) +git rm -r d +commit -m t2 +echo d > d +git add d +commit -m t3 echo b >> a -commit -a -m t2.1 +commit -a -m t4.1 git checkout -b other HEAD^ >/dev/null 2>/dev/null echo c > a echo a >> a -commit -a -m t2.2 +commit -a -m t4.2 git checkout master >/dev/null 2>/dev/null git pull --no-commit . other > /dev/null 2>/dev/null
--- a/tests/test-convert-git.out Thu Sep 27 23:59:18 2007 -0500 +++ b/tests/test-convert-git.out Tue Oct 02 18:04:18 2007 -0500 @@ -1,18 +1,21 @@ +rm 'd/b' assuming destination git-repo-hg initializing destination git-repo-hg repository scanning source... sorting... converting... -3 t1 -2 t2.1 -1 t2.2 +5 t1 +4 t2 +3 t3 +2 t4.1 +1 t4.2 0 Merge branch other -changeset: 3:69b3a302b4a1 +changeset: 5:c6d72c98aa00 tag: tip -parent: 1:0de2a40e261b -parent: 2:8815d3b33506 +parent: 3:a18bdfccf429 +parent: 4:48cb5b72ce56 user: test <test@example.org> -date: Mon Jan 01 00:00:13 2007 +0000 +date: Mon Jan 01 00:00:15 2007 +0000 files: a description: Merge branch other
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-debugindexdot Tue Oct 02 18:04:18 2007 -0500 @@ -0,0 +1,17 @@ +#!/bin/sh + +# Just exercize debugindexdot +# Create a short file history including a merge. +hg init t +cd t +echo a > a +hg ci -qAm t1 -d '0 0' +echo a >> a +hg ci -m t2 -d '1 0' +hg up -qC 0 +echo b >> a +hg ci -m t3 -d '2 0' +HGMERGE=true hg merge -q +hg ci -m merge -d '3 0' + +hg debugindexdot .hg/store/data/a.i