##// END OF EJS Templates
merge with stable
Matt Mackall -
r12718:372abc79 merge default
parent child Browse files
Show More
@@ -1,188 +1,200
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 or any later version.
7 7
8 8 from common import NoRepo, checktool, commandline, commit, converter_source
9 9 from mercurial.i18n import _
10 from mercurial import util
10 from mercurial import encoding, util
11 11 import os, shutil, tempfile, re
12 12
13 13 # The naming drift of ElementTree is fun!
14 14
15 15 try:
16 from xml.etree.cElementTree import ElementTree
16 from xml.etree.cElementTree import ElementTree, XMLParser
17 17 except ImportError:
18 18 try:
19 from xml.etree.ElementTree import ElementTree
19 from xml.etree.ElementTree import ElementTree, XMLParser
20 20 except ImportError:
21 21 try:
22 from elementtree.cElementTree import ElementTree
22 from elementtree.cElementTree import ElementTree, XMLParser
23 23 except ImportError:
24 24 try:
25 from elementtree.ElementTree import ElementTree
25 from elementtree.ElementTree import ElementTree, XMLParser
26 26 except ImportError:
27 27 ElementTree = None
28 28
29 29 class darcs_source(converter_source, commandline):
30 30 def __init__(self, ui, path, rev=None):
31 31 converter_source.__init__(self, ui, path, rev=rev)
32 32 commandline.__init__(self, ui, 'darcs')
33 33
34 34 # check for _darcs, ElementTree so that we can easily skip
35 35 # test-convert-darcs if ElementTree is not around
36 36 if not os.path.exists(os.path.join(path, '_darcs')):
37 37 raise NoRepo(_("%s does not look like a darcs repository") % path)
38 38
39 39 checktool('darcs')
40 40 version = self.run0('--version').splitlines()[0].strip()
41 41 if version < '2.1':
42 42 raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') %
43 43 version)
44 44
45 45 if ElementTree is None:
46 46 raise util.Abort(_("Python ElementTree module is not available"))
47 47
48 48 self.path = os.path.realpath(path)
49 49
50 50 self.lastrev = None
51 51 self.changes = {}
52 52 self.parents = {}
53 53 self.tags = {}
54 54
55 55 # Check darcs repository format
56 56 format = self.format()
57 57 if format:
58 58 if format in ('darcs-1.0', 'hashed'):
59 59 raise NoRepo(_("%s repository format is unsupported, "
60 60 "please upgrade") % format)
61 61 else:
62 62 self.ui.warn(_('failed to detect repository format!'))
63 63
64 64 def before(self):
65 65 self.tmppath = tempfile.mkdtemp(
66 66 prefix='convert-' + os.path.basename(self.path) + '-')
67 67 output, status = self.run('init', repodir=self.tmppath)
68 68 self.checkexit(status)
69 69
70 70 tree = self.xml('changes', xml_output=True, summary=True,
71 71 repodir=self.path)
72 72 tagname = None
73 73 child = None
74 74 for elt in tree.findall('patch'):
75 75 node = elt.get('hash')
76 76 name = elt.findtext('name', '')
77 77 if name.startswith('TAG '):
78 78 tagname = name[4:].strip()
79 79 elif tagname is not None:
80 80 self.tags[tagname] = node
81 81 tagname = None
82 82 self.changes[node] = elt
83 83 self.parents[child] = [node]
84 84 child = node
85 85 self.parents[child] = []
86 86
87 87 def after(self):
88 88 self.ui.debug('cleaning up %s\n' % self.tmppath)
89 89 shutil.rmtree(self.tmppath, ignore_errors=True)
90 90
91 def recode(self, s, encoding=None):
92 if isinstance(s, unicode):
93 # XMLParser returns unicode objects for anything it can't
94 # encode into ASCII. We convert them back to str to get
95 # recode's normal conversion behavior.
96 s = s.encode('latin-1')
97 return super(darcs_source, self).recode(s, encoding)
98
91 99 def xml(self, cmd, **kwargs):
92 100 # NOTE: darcs is currently encoding agnostic and will print
93 101 # patch metadata byte-for-byte, even in the XML changelog.
94 102 etree = ElementTree()
103 # While we are decoding the XML as latin-1 to be as liberal as
104 # possible, etree will still raise an exception if any
105 # non-printable characters are in the XML changelog.
106 parser = XMLParser(encoding='latin-1')
95 107 fp = self._run(cmd, **kwargs)
96 etree.parse(fp)
108 etree.parse(fp, parser=parser)
97 109 self.checkexit(fp.close())
98 110 return etree.getroot()
99 111
100 112 def format(self):
101 113 output, status = self.run('show', 'repo', no_files=True,
102 114 repodir=self.path)
103 115 self.checkexit(status)
104 116 m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE)
105 117 if not m:
106 118 return None
107 119 return ','.join(sorted(f.strip() for f in m.group(1).split(',')))
108 120
109 121 def manifest(self):
110 122 man = []
111 123 output, status = self.run('show', 'files', no_directories=True,
112 124 repodir=self.tmppath)
113 125 self.checkexit(status)
114 126 for line in output.split('\n'):
115 127 path = line[2:]
116 128 if path:
117 129 man.append(path)
118 130 return man
119 131
120 132 def getheads(self):
121 133 return self.parents[None]
122 134
123 135 def getcommit(self, rev):
124 136 elt = self.changes[rev]
125 137 date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y')
126 138 desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
127 139 # etree can return unicode objects for name, comment, and author,
128 140 # so recode() is used to ensure str objects are emitted.
129 141 return commit(author=self.recode(elt.get('author')),
130 142 date=util.datestr(date),
131 143 desc=self.recode(desc).strip(),
132 144 parents=self.parents[rev])
133 145
134 146 def pull(self, rev):
135 147 output, status = self.run('pull', self.path, all=True,
136 148 match='hash %s' % rev,
137 149 no_test=True, no_posthook=True,
138 150 external_merge='/bin/false',
139 151 repodir=self.tmppath)
140 152 if status:
141 153 if output.find('We have conflicts in') == -1:
142 154 self.checkexit(status, output)
143 155 output, status = self.run('revert', all=True, repodir=self.tmppath)
144 156 self.checkexit(status, output)
145 157
146 158 def getchanges(self, rev):
147 159 copies = {}
148 160 changes = []
149 161 man = None
150 162 for elt in self.changes[rev].find('summary').getchildren():
151 163 if elt.tag in ('add_directory', 'remove_directory'):
152 164 continue
153 165 if elt.tag == 'move':
154 166 if man is None:
155 167 man = self.manifest()
156 168 source, dest = elt.get('from'), elt.get('to')
157 169 if source in man:
158 170 # File move
159 171 changes.append((source, rev))
160 172 changes.append((dest, rev))
161 173 copies[dest] = source
162 174 else:
163 175 # Directory move, deduce file moves from manifest
164 176 source = source + '/'
165 177 for f in man:
166 178 if not f.startswith(source):
167 179 continue
168 180 fdest = dest + '/' + f[len(source):]
169 181 changes.append((f, rev))
170 182 changes.append((fdest, rev))
171 183 copies[fdest] = f
172 184 else:
173 185 changes.append((elt.text.strip(), rev))
174 186 self.pull(rev)
175 187 self.lastrev = rev
176 188 return sorted(changes), copies
177 189
178 190 def getfile(self, name, rev):
179 191 if rev != self.lastrev:
180 192 raise util.Abort(_('internal calling inconsistency'))
181 193 path = os.path.join(self.tmppath, name)
182 194 data = open(path, 'rb').read()
183 195 mode = os.lstat(path).st_mode
184 196 mode = (mode & 0111) and 'x' or ''
185 197 return data, mode
186 198
187 199 def gettags(self):
188 200 return self.tags
@@ -1,131 +1,144
1 1
2 2 $ "$TESTDIR/hghave" darcs || exit 80
3 3 $ echo "[extensions]" >> $HGRCPATH
4 4 $ echo "convert=" >> $HGRCPATH
5 5 $ echo 'graphlog =' >> $HGRCPATH
6 6 $ DARCS_EMAIL='test@example.org'; export DARCS_EMAIL
7 7 $ HOME=`pwd`/do_not_use_HOME_darcs; export HOME
8 8
9 9 skip if we can't import elementtree
10 10
11 11 $ mkdir dummy
12 12 $ mkdir dummy/_darcs
13 13 $ if hg convert dummy 2>&1 | grep ElementTree > /dev/null; then
14 14 > echo 'skipped: missing feature: elementtree module'
15 15 > exit 80
16 16 > fi
17 17
18 18 try converting darcs1 repository
19 19
20 20 $ hg clone -q "$TESTDIR/darcs1.hg" darcs
21 21 $ hg convert -s darcs darcs/darcs1 2>&1 | grep darcs-1.0
22 22 darcs-1.0 repository format is unsupported, please upgrade
23 23
24 24 initialize darcs repo
25 25
26 26 $ mkdir darcs-repo
27 27 $ cd darcs-repo
28 28 $ darcs init
29 29 $ echo a > a
30 30 $ darcs record -a -l -m p0
31 31 Finished recording patch 'p0'
32 32 $ cd ..
33 33
34 34 branch and update
35 35
36 36 $ darcs get darcs-repo darcs-clone >/dev/null
37 37 $ cd darcs-clone
38 38 $ echo c >> a
39 39 $ echo c > c
40 40 $ darcs record -a -l -m p1.1
41 41 Finished recording patch 'p1.1'
42 42 $ cd ..
43 43
44 44 update source
45 45
46 46 $ cd darcs-repo
47 47 $ echo b >> a
48 48 $ echo b > b
49 49 $ darcs record -a -l -m p1.2
50 50 Finished recording patch 'p1.2'
51 51
52 merge branch
53
54 52 $ darcs pull -a ../darcs-clone
55 53 Backing up ./a(-darcs-backup0)
56 54 We have conflicts in the following files:
57 55 ./a
58 56 Finished pulling and applying.
59 57 $ sleep 1
60 58 $ echo e > a
61 59 $ echo f > f
62 60 $ mkdir dir
63 61 $ echo d > dir/d
64 62 $ echo d > dir/d2
65 63 $ darcs record -a -l -m p2
66 64 Finished recording patch 'p2'
67 65
68 66 test file and directory move
69 67
70 68 $ darcs mv f ff
71 69
72 70 Test remove + move
73 71
74 72 $ darcs remove dir/d2
75 73 $ rm dir/d2
76 74 $ darcs mv dir dir2
77 75 $ darcs record -a -l -m p3
78 76 Finished recording patch 'p3'
79 77
80 78 test utf-8 commit message and author
81 79
82 80 $ echo g > g
83 81
84 82 darcs is encoding agnostic, so it takes whatever bytes it's given
85 83
86 84 $ darcs record -a -l -m 'p4: desc ñ' -A 'author ñ'
87 85 Finished recording patch 'p4: desc ñ'
86
87 Test latin-1 commit message
88
89 $ echo h > h
90 $ printf "p5: desc " > ../p5
91 $ python -c 'print "".join([chr(i) for i in range(128, 256)])' >> ../p5
92 $ darcs record -a -l --logfile ../p5
93 Finished recording patch 'p5: desc ��������������������������������������������������������������������������������������������������������������������������������'
94
88 95 $ glog()
89 96 > {
90 97 > HGENCODING=utf-8 hg glog --template '{rev} "{desc|firstline}" ({author}) files: {files}\n' "$@"
91 98 > }
92 99 $ cd ..
93 100 $ hg convert darcs-repo darcs-repo-hg
94 101 initializing destination darcs-repo-hg repository
95 102 scanning source...
96 103 sorting...
97 104 converting...
98 5 p0
99 4 p1.2
100 3 p1.1
101 2 p2
102 1 p3
103 0 p4: desc ?
105 6 p0
106 5 p1.2
107 4 p1.1
108 3 p2
109 2 p3
110 1 p4: desc ?
111 0 p5: desc ????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
104 112
105 113 The converter does not currently handle patch conflicts very well.
106 114 When they occur, it reverts *all* changes and moves forward,
107 115 letting the conflict resolving patch fix collisions.
108 116 Unfortunately, non-conflicting changes, like the addition of the
109 117 "c" file in p1.1 patch are reverted too.
110 118 Just to say that manifest not listing "c" here is a bug.
111 119
112 $ glog -R darcs-repo-hg
113 o 5 "p4: desc ñ" (author ñ) files: g
120 $ HGENCODING=latin-1 glog -R darcs-repo-hg -r 6 | "$TESTDIR"/printrepr.py
121 o 6 "p5: desc \xc2\x80\xc2\x81\xc2\x82\xc2\x83\xc2\x84\xc2\x85\xc2\x86\xc2\x87\xc2\x88\xc2\x89\xc2\x8a\xc2\x8b\xc2\x8c\xc2\x8d\xc2\x8e\xc2\x8f\xc2\x90\xc2\x91\xc2\x92\xc2\x93\xc2\x94\xc2\x95\xc2\x96\xc2\x97\xc2\x98\xc2\x99\xc2\x9a\xc2\x9b\xc2\x9c\xc2\x9d\xc2\x9e\xc2\x9f\xc2\xa0\xc2\xa1\xc2\xa2\xc2\xa3\xc2\xa4\xc2\xa5\xc2\xa6\xc2\xa7\xc2\xa8\xc2\xa9\xc2\xaa\xc2\xab\xc2\xac\xc2\xad\xc2\xae\xc2\xaf\xc2\xb0\xc2\xb1\xc2\xb2\xc2\xb3\xc2\xb4\xc2\xb5\xc2\xb6\xc2\xb7\xc2\xb8\xc2\xb9\xc2\xba\xc2\xbb\xc2\xbc\xc2\xbd\xc2\xbe\xc2\xbf\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x97\xc3\x98\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\x9e\xc3\x9f\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb7\xc3\xb8\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbe\xc3\xbf" (test@example.org) files: h
122 |
123 $ HGENCODING=utf-8 glog -R darcs-repo-hg -r 0:5 | "$TESTDIR"/printrepr.py
124 o 5 "p4: desc \xc3\xb1" (author \xc3\xb1) files: g
114 125 |
115 126 o 4 "p3" (test@example.org) files: dir/d dir/d2 dir2/d f ff
116 127 |
117 128 o 3 "p2" (test@example.org) files: a dir/d dir/d2 f
118 129 |
119 130 o 2 "p1.1" (test@example.org) files:
120 131 |
121 132 o 1 "p1.2" (test@example.org) files: a b
122 133 |
123 134 o 0 "p0" (test@example.org) files: a
124 135
136
125 137 $ hg up -q -R darcs-repo-hg
126 138 $ hg -R darcs-repo-hg manifest --debug
127 139 7225b30cdf38257d5cc7780772c051b6f33e6d6b 644 a
128 140 1e88685f5ddec574a34c70af492f95b6debc8741 644 b
129 141 37406831adc447ec2385014019599dfec953c806 644 dir2/d
130 142 b783a337463792a5c7d548ad85a7d3253c16ba8c 644 ff
131 143 0973eb1b2ecc4de7fafe7447ce1b7462108b4848 644 g
144 fe6f8b4f507fe3eb524c527192a84920a4288dac 644 h
General Comments 0
You need to be logged in to leave comments. Login now