##// END OF EJS Templates
convert/darcs: handle directory renaming
Patrick Mezard -
r9527:b3c13e72 default
parent child Browse files
Show More
@@ -1,136 +1,163 b''
1 1 # darcs.py - darcs support for the convert extension
2 2 #
3 3 # Copyright 2007-2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2, incorporated herein by reference.
7 7
8 8 from common import NoRepo, checktool, commandline, commit, converter_source
9 9 from mercurial.i18n import _
10 10 from mercurial import util
11 11 import os, shutil, tempfile
12 12
13 13 # The naming drift of ElementTree is fun!
14 14
15 15 try: from xml.etree.cElementTree import ElementTree
16 16 except ImportError:
17 17 try: from xml.etree.ElementTree import ElementTree
18 18 except ImportError:
19 19 try: from elementtree.cElementTree import ElementTree
20 20 except ImportError:
21 21 try: from elementtree.ElementTree import ElementTree
22 22 except ImportError: ElementTree = None
23 23
24 24
25 25 class darcs_source(converter_source, commandline):
26 26 def __init__(self, ui, path, rev=None):
27 27 converter_source.__init__(self, ui, path, rev=rev)
28 28 commandline.__init__(self, ui, 'darcs')
29 29
30 30 # check for _darcs, ElementTree, _darcs/inventory so that we can
31 31 # easily skip test-convert-darcs if ElementTree is not around
32 32 if not os.path.exists(os.path.join(path, '_darcs', 'inventories')):
33 33 raise NoRepo("%s does not look like a darcs repo" % path)
34 34
35 35 if not os.path.exists(os.path.join(path, '_darcs')):
36 36 raise NoRepo("%s does not look like a darcs repo" % path)
37 37
38 38 checktool('darcs')
39 39 version = self.run0('--version').splitlines()[0].strip()
40 40 if version < '2.1':
41 41 raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') %
42 42 version)
43 43
44 44 if ElementTree is None:
45 45 raise util.Abort(_("Python ElementTree module is not available"))
46 46
47 47 self.path = os.path.realpath(path)
48 48
49 49 self.lastrev = None
50 50 self.changes = {}
51 51 self.parents = {}
52 52 self.tags = {}
53 53
54 54 def before(self):
55 55 self.tmppath = tempfile.mkdtemp(
56 56 prefix='convert-' + os.path.basename(self.path) + '-')
57 57 output, status = self.run('init', repodir=self.tmppath)
58 58 self.checkexit(status)
59 59
60 60 tree = self.xml('changes', xml_output=True, summary=True,
61 61 repodir=self.path)
62 62 tagname = None
63 63 child = None
64 64 for elt in tree.findall('patch'):
65 65 node = elt.get('hash')
66 66 name = elt.findtext('name', '')
67 67 if name.startswith('TAG '):
68 68 tagname = name[4:].strip()
69 69 elif tagname is not None:
70 70 self.tags[tagname] = node
71 71 tagname = None
72 72 self.changes[node] = elt
73 73 self.parents[child] = [node]
74 74 child = node
75 75 self.parents[child] = []
76 76
77 77 def after(self):
78 78 self.ui.debug(_('cleaning up %s\n') % self.tmppath)
79 79 shutil.rmtree(self.tmppath, ignore_errors=True)
80 80
81 81 def xml(self, cmd, **kwargs):
82 82 etree = ElementTree()
83 83 fp = self._run(cmd, **kwargs)
84 84 etree.parse(fp)
85 85 self.checkexit(fp.close())
86 86 return etree.getroot()
87 87
88 def manifest(self):
89 man = []
90 output, status = self.run('show', 'files', no_directories=True,
91 repodir=self.tmppath)
92 self.checkexit(status)
93 for line in output.split('\n'):
94 path = line[2:]
95 if path:
96 man.append(path)
97 return man
98
88 99 def getheads(self):
89 100 return self.parents[None]
90 101
91 102 def getcommit(self, rev):
92 103 elt = self.changes[rev]
93 104 date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y')
94 105 desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
95 106 return commit(author=elt.get('author'), date=util.datestr(date),
96 107 desc=desc.strip(), parents=self.parents[rev])
97 108
98 109 def pull(self, rev):
99 110 output, status = self.run('pull', self.path, all=True,
100 111 match='hash %s' % rev,
101 112 no_test=True, no_posthook=True,
102 113 external_merge='/bin/false',
103 114 repodir=self.tmppath)
104 115 if status:
105 116 if output.find('We have conflicts in') == -1:
106 117 self.checkexit(status, output)
107 118 output, status = self.run('revert', all=True, repodir=self.tmppath)
108 119 self.checkexit(status, output)
109 120
110 def getchanges(self, rev):
111 self.pull(rev)
121 def getchanges(self, rev):
112 122 copies = {}
113 123 changes = []
124 man = None
114 125 for elt in self.changes[rev].find('summary').getchildren():
115 126 if elt.tag in ('add_directory', 'remove_directory'):
116 127 continue
117 128 if elt.tag == 'move':
118 changes.append((elt.get('from'), rev))
119 changes.append((elt.get('to'), rev))
120 copies[elt.get('to')] = elt.get('from')
129 if man is None:
130 man = self.manifest()
131 source, dest = elt.get('from'), elt.get('to')
132 if source in man:
133 # File move
134 changes.append((source, rev))
135 changes.append((dest, rev))
136 copies[dest] = source
137 else:
138 # Directory move, deduce file moves from manifest
139 source = source + '/'
140 for f in man:
141 if not f.startswith(source):
142 continue
143 fdest = dest + '/' + f[len(source):]
144 changes.append((f, rev))
145 changes.append((fdest, rev))
146 copies[fdest] = f
121 147 else:
122 148 changes.append((elt.text.strip(), rev))
149 self.pull(rev)
123 150 self.lastrev = rev
124 151 return sorted(changes), copies
125 152
126 153 def getfile(self, name, rev):
127 154 if rev != self.lastrev:
128 155 raise util.Abort(_('internal calling inconsistency'))
129 156 return open(os.path.join(self.tmppath, name), 'rb').read()
130 157
131 158 def getmode(self, name, rev):
132 159 mode = os.lstat(os.path.join(self.tmppath, name)).st_mode
133 160 return (mode & 0111) and 'x' or ''
134 161
135 162 def gettags(self):
136 163 return self.tags
@@ -1,68 +1,75 b''
1 1 #!/bin/sh
2 2
3 3 "$TESTDIR/hghave" darcs || exit 80
4 4
5 5 echo "[extensions]" >> $HGRCPATH
6 6 echo "convert=" >> $HGRCPATH
7 7 echo 'hgext.graphlog =' >> $HGRCPATH
8 8
9 9 DARCS_EMAIL='test@example.org'; export DARCS_EMAIL
10 10 HOME=`pwd`/do_not_use_HOME_darcs; export HOME
11 11
12 12 # skip if we can't import elementtree
13 13 mkdir dummy
14 14 mkdir dummy/_darcs
15 15 if hg convert dummy 2>&1 | grep ElementTree > /dev/null; then
16 16 echo 'skipped: missing feature: elementtree module'
17 17 exit 80
18 18 fi
19 19
20 20 echo % initialize darcs repo
21 21 mkdir darcs-repo
22 22 cd darcs-repo
23 23 darcs init
24 24 echo a > a
25 25 darcs record -a -l -m p0
26 26 cd ..
27 27
28 28 echo % branch and update
29 29 darcs get darcs-repo darcs-clone >/dev/null
30 30 cd darcs-clone
31 31 echo c >> a
32 32 echo c > c
33 33 darcs record -a -l -m p1.1
34 34 cd ..
35 35
36 36 echo % update source
37 37 cd darcs-repo
38 38 echo b >> a
39 39 echo b > b
40 40 darcs record -a -l -m p1.2
41 41
42 42 echo % merge branch
43 43 darcs pull -a ../darcs-clone
44 44 sleep 1
45 45 echo e > a
46 46 echo f > f
47 mkdir dir
48 echo d > dir/d
49 echo d > dir/d2
47 50 darcs record -a -l -m p2
48 51
49 52 echo % test file and directory move
50 53 darcs mv f ff
54 # Test remove + move
55 darcs remove dir/d2
56 rm dir/d2
57 darcs mv dir dir2
51 58 darcs record -a -l -m p3
52 59 cd ..
53 60
54 61 glog()
55 62 {
56 63 hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
57 64 }
58 65
59 66 hg convert darcs-repo darcs-repo-hg
60 67 # The converter does not currently handle patch conflicts very well.
61 68 # When they occur, it reverts *all* changes and moves forward,
62 69 # letting the conflict resolving patch fix collisions.
63 70 # Unfortunately, non-conflicting changes, like the addition of the
64 71 # "c" file in p1.1 patch are reverted too.
65 72 # Just to say that manifest not listing "c" here is a bug.
66 73 glog -R darcs-repo-hg
67 74 hg up -q -R darcs-repo-hg
68 75 hg -R darcs-repo-hg manifest --debug
@@ -1,36 +1,37 b''
1 1 % initialize darcs repo
2 2 Finished recording patch 'p0'
3 3 % branch and update
4 4 Finished recording patch 'p1.1'
5 5 % update source
6 6 Finished recording patch 'p1.2'
7 7 % merge branch
8 8 Backing up ./a(-darcs-backup0)
9 9 We have conflicts in the following files:
10 10 ./a
11 11 Finished pulling and applying.
12 12 Finished recording patch 'p2'
13 13 % test file and directory move
14 14 Finished recording patch 'p3'
15 15 initializing destination darcs-repo-hg repository
16 16 scanning source...
17 17 sorting...
18 18 converting...
19 19 4 p0
20 20 3 p1.2
21 21 2 p1.1
22 22 1 p2
23 23 0 p3
24 o 4 "p3" files: f ff
24 o 4 "p3" files: dir/d dir/d2 dir2/d f ff
25 25 |
26 o 3 "p2" files: a f
26 o 3 "p2" files: a dir/d dir/d2 f
27 27 |
28 28 o 2 "p1.1" files:
29 29 |
30 30 o 1 "p1.2" files: a b
31 31 |
32 32 o 0 "p0" files: a
33 33
34 34 7225b30cdf38257d5cc7780772c051b6f33e6d6b 644 a
35 35 1e88685f5ddec574a34c70af492f95b6debc8741 644 b
36 d278f41640da5fc303a4cf9894af31c2983fc11d 644 dir2/d
36 37 ef5c76581d78340f568d5f48d679bf307452cbc9 644 ff
General Comments 0
You need to be logged in to leave comments. Login now