##// END OF EJS Templates
convert: ignore blank lines in mapfiles (issue3286)
Patrick Mezard -
r16190:9479c28a stable
parent child Browse files
Show More
@@ -1,435 +1,443
1 1 # common.py - common code for the convert extension
2 2 #
3 3 # Copyright 2005-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 import base64, errno
9 9 import os
10 10 import cPickle as pickle
11 11 from mercurial import util
12 12 from mercurial.i18n import _
13 13
14 14 propertycache = util.propertycache
15 15
16 16 def encodeargs(args):
17 17 def encodearg(s):
18 18 lines = base64.encodestring(s)
19 19 lines = [l.splitlines()[0] for l in lines]
20 20 return ''.join(lines)
21 21
22 22 s = pickle.dumps(args)
23 23 return encodearg(s)
24 24
25 25 def decodeargs(s):
26 26 s = base64.decodestring(s)
27 27 return pickle.loads(s)
28 28
29 29 class MissingTool(Exception):
30 30 pass
31 31
32 32 def checktool(exe, name=None, abort=True):
33 33 name = name or exe
34 34 if not util.findexe(exe):
35 35 exc = abort and util.Abort or MissingTool
36 36 raise exc(_('cannot find required "%s" tool') % name)
37 37
38 38 class NoRepo(Exception):
39 39 pass
40 40
41 41 SKIPREV = 'SKIP'
42 42
43 43 class commit(object):
44 44 def __init__(self, author, date, desc, parents, branch=None, rev=None,
45 45 extra={}, sortkey=None):
46 46 self.author = author or 'unknown'
47 47 self.date = date or '0 0'
48 48 self.desc = desc
49 49 self.parents = parents
50 50 self.branch = branch
51 51 self.rev = rev
52 52 self.extra = extra
53 53 self.sortkey = sortkey
54 54
55 55 class converter_source(object):
56 56 """Conversion source interface"""
57 57
58 58 def __init__(self, ui, path=None, rev=None):
59 59 """Initialize conversion source (or raise NoRepo("message")
60 60 exception if path is not a valid repository)"""
61 61 self.ui = ui
62 62 self.path = path
63 63 self.rev = rev
64 64
65 65 self.encoding = 'utf-8'
66 66
67 67 def before(self):
68 68 pass
69 69
70 70 def after(self):
71 71 pass
72 72
73 73 def setrevmap(self, revmap):
74 74 """set the map of already-converted revisions"""
75 75 pass
76 76
77 77 def getheads(self):
78 78 """Return a list of this repository's heads"""
79 79 raise NotImplementedError()
80 80
81 81 def getfile(self, name, rev):
82 82 """Return a pair (data, mode) where data is the file content
83 83 as a string and mode one of '', 'x' or 'l'. rev is the
84 84 identifier returned by a previous call to getchanges(). Raise
85 85 IOError to indicate that name was deleted in rev.
86 86 """
87 87 raise NotImplementedError()
88 88
89 89 def getchanges(self, version):
90 90 """Returns a tuple of (files, copies).
91 91
92 92 files is a sorted list of (filename, id) tuples for all files
93 93 changed between version and its first parent returned by
94 94 getcommit(). id is the source revision id of the file.
95 95
96 96 copies is a dictionary of dest: source
97 97 """
98 98 raise NotImplementedError()
99 99
100 100 def getcommit(self, version):
101 101 """Return the commit object for version"""
102 102 raise NotImplementedError()
103 103
104 104 def gettags(self):
105 105 """Return the tags as a dictionary of name: revision
106 106
107 107 Tag names must be UTF-8 strings.
108 108 """
109 109 raise NotImplementedError()
110 110
111 111 def recode(self, s, encoding=None):
112 112 if not encoding:
113 113 encoding = self.encoding or 'utf-8'
114 114
115 115 if isinstance(s, unicode):
116 116 return s.encode("utf-8")
117 117 try:
118 118 return s.decode(encoding).encode("utf-8")
119 119 except:
120 120 try:
121 121 return s.decode("latin-1").encode("utf-8")
122 122 except:
123 123 return s.decode(encoding, "replace").encode("utf-8")
124 124
125 125 def getchangedfiles(self, rev, i):
126 126 """Return the files changed by rev compared to parent[i].
127 127
128 128 i is an index selecting one of the parents of rev. The return
129 129 value should be the list of files that are different in rev and
130 130 this parent.
131 131
132 132 If rev has no parents, i is None.
133 133
134 134 This function is only needed to support --filemap
135 135 """
136 136 raise NotImplementedError()
137 137
138 138 def converted(self, rev, sinkrev):
139 139 '''Notify the source that a revision has been converted.'''
140 140 pass
141 141
142 142 def hasnativeorder(self):
143 143 """Return true if this source has a meaningful, native revision
144 144 order. For instance, Mercurial revisions are store sequentially
145 145 while there is no such global ordering with Darcs.
146 146 """
147 147 return False
148 148
149 149 def lookuprev(self, rev):
150 150 """If rev is a meaningful revision reference in source, return
151 151 the referenced identifier in the same format used by getcommit().
152 152 return None otherwise.
153 153 """
154 154 return None
155 155
156 156 def getbookmarks(self):
157 157 """Return the bookmarks as a dictionary of name: revision
158 158
159 159 Bookmark names are to be UTF-8 strings.
160 160 """
161 161 return {}
162 162
163 163 class converter_sink(object):
164 164 """Conversion sink (target) interface"""
165 165
166 166 def __init__(self, ui, path):
167 167 """Initialize conversion sink (or raise NoRepo("message")
168 168 exception if path is not a valid repository)
169 169
170 170 created is a list of paths to remove if a fatal error occurs
171 171 later"""
172 172 self.ui = ui
173 173 self.path = path
174 174 self.created = []
175 175
176 176 def getheads(self):
177 177 """Return a list of this repository's heads"""
178 178 raise NotImplementedError()
179 179
180 180 def revmapfile(self):
181 181 """Path to a file that will contain lines
182 182 source_rev_id sink_rev_id
183 183 mapping equivalent revision identifiers for each system."""
184 184 raise NotImplementedError()
185 185
186 186 def authorfile(self):
187 187 """Path to a file that will contain lines
188 188 srcauthor=dstauthor
189 189 mapping equivalent authors identifiers for each system."""
190 190 return None
191 191
192 192 def putcommit(self, files, copies, parents, commit, source, revmap):
193 193 """Create a revision with all changed files listed in 'files'
194 194 and having listed parents. 'commit' is a commit object
195 195 containing at a minimum the author, date, and message for this
196 196 changeset. 'files' is a list of (path, version) tuples,
197 197 'copies' is a dictionary mapping destinations to sources,
198 198 'source' is the source repository, and 'revmap' is a mapfile
199 199 of source revisions to converted revisions. Only getfile() and
200 200 lookuprev() should be called on 'source'.
201 201
202 202 Note that the sink repository is not told to update itself to
203 203 a particular revision (or even what that revision would be)
204 204 before it receives the file data.
205 205 """
206 206 raise NotImplementedError()
207 207
208 208 def puttags(self, tags):
209 209 """Put tags into sink.
210 210
211 211 tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
212 212 Return a pair (tag_revision, tag_parent_revision), or (None, None)
213 213 if nothing was changed.
214 214 """
215 215 raise NotImplementedError()
216 216
217 217 def setbranch(self, branch, pbranches):
218 218 """Set the current branch name. Called before the first putcommit
219 219 on the branch.
220 220 branch: branch name for subsequent commits
221 221 pbranches: (converted parent revision, parent branch) tuples"""
222 222 pass
223 223
224 224 def setfilemapmode(self, active):
225 225 """Tell the destination that we're using a filemap
226 226
227 227 Some converter_sources (svn in particular) can claim that a file
228 228 was changed in a revision, even if there was no change. This method
229 229 tells the destination that we're using a filemap and that it should
230 230 filter empty revisions.
231 231 """
232 232 pass
233 233
234 234 def before(self):
235 235 pass
236 236
237 237 def after(self):
238 238 pass
239 239
240 240 def putbookmarks(self, bookmarks):
241 241 """Put bookmarks into sink.
242 242
243 243 bookmarks: {bookmarkname: sink_rev_id, ...}
244 244 where bookmarkname is an UTF-8 string.
245 245 """
246 246 pass
247 247
248 248 def hascommit(self, rev):
249 249 """Return True if the sink contains rev"""
250 250 raise NotImplementedError()
251 251
252 252 class commandline(object):
253 253 def __init__(self, ui, command):
254 254 self.ui = ui
255 255 self.command = command
256 256
257 257 def prerun(self):
258 258 pass
259 259
260 260 def postrun(self):
261 261 pass
262 262
263 263 def _cmdline(self, cmd, closestdin, *args, **kwargs):
264 264 cmdline = [self.command, cmd] + list(args)
265 265 for k, v in kwargs.iteritems():
266 266 if len(k) == 1:
267 267 cmdline.append('-' + k)
268 268 else:
269 269 cmdline.append('--' + k.replace('_', '-'))
270 270 try:
271 271 if len(k) == 1:
272 272 cmdline.append('' + v)
273 273 else:
274 274 cmdline[-1] += '=' + v
275 275 except TypeError:
276 276 pass
277 277 cmdline = [util.shellquote(arg) for arg in cmdline]
278 278 if not self.ui.debugflag:
279 279 cmdline += ['2>', util.nulldev]
280 280 if closestdin:
281 281 cmdline += ['<', util.nulldev]
282 282 cmdline = ' '.join(cmdline)
283 283 return cmdline
284 284
285 285 def _run(self, cmd, *args, **kwargs):
286 286 return self._dorun(util.popen, cmd, True, *args, **kwargs)
287 287
288 288 def _run2(self, cmd, *args, **kwargs):
289 289 return self._dorun(util.popen2, cmd, False, *args, **kwargs)
290 290
291 291 def _dorun(self, openfunc, cmd, closestdin, *args, **kwargs):
292 292 cmdline = self._cmdline(cmd, closestdin, *args, **kwargs)
293 293 self.ui.debug('running: %s\n' % (cmdline,))
294 294 self.prerun()
295 295 try:
296 296 return openfunc(cmdline)
297 297 finally:
298 298 self.postrun()
299 299
300 300 def run(self, cmd, *args, **kwargs):
301 301 fp = self._run(cmd, *args, **kwargs)
302 302 output = fp.read()
303 303 self.ui.debug(output)
304 304 return output, fp.close()
305 305
306 306 def runlines(self, cmd, *args, **kwargs):
307 307 fp = self._run(cmd, *args, **kwargs)
308 308 output = fp.readlines()
309 309 self.ui.debug(''.join(output))
310 310 return output, fp.close()
311 311
312 312 def checkexit(self, status, output=''):
313 313 if status:
314 314 if output:
315 315 self.ui.warn(_('%s error:\n') % self.command)
316 316 self.ui.warn(output)
317 317 msg = util.explainexit(status)[0]
318 318 raise util.Abort('%s %s' % (self.command, msg))
319 319
320 320 def run0(self, cmd, *args, **kwargs):
321 321 output, status = self.run(cmd, *args, **kwargs)
322 322 self.checkexit(status, output)
323 323 return output
324 324
325 325 def runlines0(self, cmd, *args, **kwargs):
326 326 output, status = self.runlines(cmd, *args, **kwargs)
327 327 self.checkexit(status, ''.join(output))
328 328 return output
329 329
330 330 @propertycache
331 331 def argmax(self):
332 332 # POSIX requires at least 4096 bytes for ARG_MAX
333 333 argmax = 4096
334 334 try:
335 335 argmax = os.sysconf("SC_ARG_MAX")
336 336 except:
337 337 pass
338 338
339 339 # Windows shells impose their own limits on command line length,
340 340 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
341 341 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
342 342 # details about cmd.exe limitations.
343 343
344 344 # Since ARG_MAX is for command line _and_ environment, lower our limit
345 345 # (and make happy Windows shells while doing this).
346 346 return argmax // 2 - 1
347 347
348 348 def limit_arglist(self, arglist, cmd, closestdin, *args, **kwargs):
349 349 cmdlen = len(self._cmdline(cmd, closestdin, *args, **kwargs))
350 350 limit = self.argmax - cmdlen
351 351 bytes = 0
352 352 fl = []
353 353 for fn in arglist:
354 354 b = len(fn) + 3
355 355 if bytes + b < limit or len(fl) == 0:
356 356 fl.append(fn)
357 357 bytes += b
358 358 else:
359 359 yield fl
360 360 fl = [fn]
361 361 bytes = b
362 362 if fl:
363 363 yield fl
364 364
365 365 def xargs(self, arglist, cmd, *args, **kwargs):
366 366 for l in self.limit_arglist(arglist, cmd, True, *args, **kwargs):
367 367 self.run0(cmd, *(list(args) + l), **kwargs)
368 368
369 369 class mapfile(dict):
370 370 def __init__(self, ui, path):
371 371 super(mapfile, self).__init__()
372 372 self.ui = ui
373 373 self.path = path
374 374 self.fp = None
375 375 self.order = []
376 376 self._read()
377 377
378 378 def _read(self):
379 379 if not self.path:
380 380 return
381 381 try:
382 382 fp = open(self.path, 'r')
383 383 except IOError, err:
384 384 if err.errno != errno.ENOENT:
385 385 raise
386 386 return
387 387 for i, line in enumerate(fp):
388 line = line.splitlines()[0].rstrip()
389 if not line:
390 # Ignore blank lines
391 continue
388 392 try:
389 key, value = line.splitlines()[0].rstrip().rsplit(' ', 1)
393 key, value = line.rsplit(' ', 1)
390 394 except ValueError:
391 395 raise util.Abort(
392 396 _('syntax error in %s(%d): key/value pair expected')
393 397 % (self.path, i + 1))
394 398 if key not in self:
395 399 self.order.append(key)
396 400 super(mapfile, self).__setitem__(key, value)
397 401 fp.close()
398 402
399 403 def __setitem__(self, key, value):
400 404 if self.fp is None:
401 405 try:
402 406 self.fp = open(self.path, 'a')
403 407 except IOError, err:
404 408 raise util.Abort(_('could not open map file %r: %s') %
405 409 (self.path, err.strerror))
406 410 self.fp.write('%s %s\n' % (key, value))
407 411 self.fp.flush()
408 412 super(mapfile, self).__setitem__(key, value)
409 413
410 414 def close(self):
411 415 if self.fp:
412 416 self.fp.close()
413 417 self.fp = None
414 418
415 419 def parsesplicemap(path):
416 420 """Parse a splicemap, return a child/parents dictionary."""
417 421 m = {}
418 422 try:
419 423 fp = open(path, 'r')
420 424 for i, line in enumerate(fp):
425 line = line.splitlines()[0].rstrip()
426 if not line:
427 # Ignore blank lines
428 continue
421 429 try:
422 child, parents = line.splitlines()[0].rstrip().split(' ', 1)
430 child, parents = line.split(' ', 1)
423 431 parents = parents.replace(',', ' ').split()
424 432 except ValueError:
425 433 raise util.Abort(_('syntax error in %s(%d): child parent1'
426 434 '[,parent2] expected') % (path, i + 1))
427 435 pp = []
428 436 for p in parents:
429 437 if p not in pp:
430 438 pp.append(p)
431 439 m[child] = pp
432 440 except IOError, e:
433 441 if e.errno != errno.ENOENT:
434 442 raise
435 443 return m
@@ -1,220 +1,222
1 1
2 2 $ echo "[extensions]" >> $HGRCPATH
3 3 $ echo "convert=" >> $HGRCPATH
4 4 $ echo 'graphlog =' >> $HGRCPATH
5 5 $ glog()
6 6 > {
7 7 > hg glog --template '{rev}:{node|short} "{desc|firstline}"\
8 8 > files: {files}\n' "$@"
9 9 > }
10 10 $ hg init repo1
11 11 $ cd repo1
12 12 $ echo a > a
13 13 $ hg ci -Am adda
14 14 adding a
15 15 $ echo b > b
16 16 $ echo a >> a
17 17 $ hg ci -Am addb
18 18 adding b
19 19 $ PARENTID1=`hg id --debug -i`
20 20 $ echo c > c
21 21 $ hg ci -Am addc
22 22 adding c
23 23 $ PARENTID2=`hg id --debug -i`
24 24 $ cd ..
25 25 $ glog -R repo1
26 26 @ 2:e55c719b85b6 "addc" files: c
27 27 |
28 28 o 1:6d4c2037ddc2 "addb" files: a b
29 29 |
30 30 o 0:07f494440405 "adda" files: a
31 31
32 32
33 33 $ hg init repo2
34 34 $ cd repo2
35 35 $ echo b > a
36 36 $ echo d > d
37 37 $ hg ci -Am addaandd
38 38 adding a
39 39 adding d
40 40 $ CHILDID1=`hg id --debug -i`
41 41 $ echo d >> d
42 42 $ hg ci -Am changed
43 43 $ CHILDID2=`hg id --debug -i`
44 44 $ echo e > e
45 45 $ hg ci -Am adde
46 46 adding e
47 47 $ cd ..
48 48 $ glog -R repo2
49 49 @ 2:a39b65753b0a "adde" files: e
50 50 |
51 51 o 1:e4ea00df9189 "changed" files: d
52 52 |
53 53 o 0:527cdedf31fb "addaandd" files: a d
54 54
55 55
56 56 test invalid splicemap
57 57
58 58 $ cat > splicemap <<EOF
59 59 > $CHILDID2
60 60 > EOF
61 61 $ hg convert --splicemap splicemap repo2 repo1
62 62 abort: syntax error in splicemap(1): child parent1[,parent2] expected
63 63 [255]
64 64
65 65 splice repo2 on repo1
66 66
67 67 $ cat > splicemap <<EOF
68 68 > $CHILDID1 $PARENTID1
69 69 > $CHILDID2 $PARENTID2,$CHILDID1
70 >
70 71 > EOF
71 72 $ cat splicemap
72 73 527cdedf31fbd5ea708aa14eeecf53d4676f38db 6d4c2037ddc2cb2627ac3a244ecce35283268f8e
73 74 e4ea00df91897da3079a10fab658c1eddba6617b e55c719b85b60e5102fac26110ba626e7cb6b7dc,527cdedf31fbd5ea708aa14eeecf53d4676f38db
75
74 76 $ hg clone repo1 target1
75 77 updating to branch default
76 78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 79 $ hg convert --splicemap splicemap repo2 target1
78 80 scanning source...
79 81 sorting...
80 82 converting...
81 83 2 addaandd
82 84 spliced in ['6d4c2037ddc2cb2627ac3a244ecce35283268f8e'] as parents of 527cdedf31fbd5ea708aa14eeecf53d4676f38db
83 85 1 changed
84 86 spliced in ['e55c719b85b60e5102fac26110ba626e7cb6b7dc', '527cdedf31fbd5ea708aa14eeecf53d4676f38db'] as parents of e4ea00df91897da3079a10fab658c1eddba6617b
85 87 0 adde
86 88 $ glog -R target1
87 89 o 5:16bc847b02aa "adde" files: e
88 90 |
89 91 o 4:e30e4fee3418 "changed" files: d
90 92 |\
91 93 | o 3:e673348c3a3c "addaandd" files: a d
92 94 | |
93 95 @ | 2:e55c719b85b6 "addc" files: c
94 96 |/
95 97 o 1:6d4c2037ddc2 "addb" files: a b
96 98 |
97 99 o 0:07f494440405 "adda" files: a
98 100
99 101
100 102
101 103
102 104 Test splicemap and conversion order
103 105
104 106 $ hg init ordered
105 107 $ cd ordered
106 108 $ echo a > a
107 109 $ hg ci -Am adda
108 110 adding a
109 111 $ hg branch branch
110 112 marked working directory as branch branch
111 113 (branches are permanent and global, did you want a bookmark?)
112 114 $ echo a >> a
113 115 $ hg ci -Am changea
114 116 $ echo a >> a
115 117 $ hg ci -Am changeaagain
116 118 $ hg up 0
117 119 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 120 $ echo b > b
119 121 $ hg ci -Am addb
120 122 adding b
121 123
122 124 We want 2 to depend on 1 and 3. Since 3 is always converted after 2,
123 125 the bug should be exhibited with all conversion orders.
124 126
125 127 $ cat > ../splicemap <<EOF
126 128 > $(hg id -r 2 -i --debug) $(hg id -r 1 -i --debug), $(hg id -r 3 -i --debug)
127 129 > EOF
128 130 $ cd ..
129 131 $ cat splicemap
130 132 7c364e7fa7d70ae525610c016317ed717b519d97 717d54d67e6c31fd75ffef2ff3042bdd98418437, 102a90ea7b4a3361e4082ed620918c261189a36a
131 133
132 134 Test regular conversion
133 135
134 136 $ hg convert --splicemap splicemap ordered ordered-hg1
135 137 initializing destination ordered-hg1 repository
136 138 scanning source...
137 139 sorting...
138 140 converting...
139 141 3 adda
140 142 2 changea
141 143 1 addb
142 144 0 changeaagain
143 145 spliced in ['717d54d67e6c31fd75ffef2ff3042bdd98418437', '102a90ea7b4a3361e4082ed620918c261189a36a'] as parents of 7c364e7fa7d70ae525610c016317ed717b519d97
144 146 $ glog -R ordered-hg1
145 147 o 3:4cb04b9afbf2 "changeaagain" files: a
146 148 |\
147 149 | o 2:102a90ea7b4a "addb" files: b
148 150 | |
149 151 o | 1:717d54d67e6c "changea" files: a
150 152 |/
151 153 o 0:07f494440405 "adda" files: a
152 154
153 155
154 156 Test conversion with parent revisions already in dest, using source
155 157 and destination identifiers. Test unknown splicemap target.
156 158
157 159 $ hg convert -r1 ordered ordered-hg2
158 160 initializing destination ordered-hg2 repository
159 161 scanning source...
160 162 sorting...
161 163 converting...
162 164 1 adda
163 165 0 changea
164 166 $ hg convert -r3 ordered ordered-hg2
165 167 scanning source...
166 168 sorting...
167 169 converting...
168 170 0 addb
169 171 $ cat > splicemap <<EOF
170 172 > $(hg -R ordered id -r 2 -i --debug) \
171 173 > $(hg -R ordered-hg2 id -r 1 -i --debug),\
172 174 > $(hg -R ordered-hg2 id -r 2 -i --debug)
173 175 > deadbeef102a90ea7b4a3361e4082ed620918c26 deadbeef102a90ea7b4a3361e4082ed620918c27
174 176 > EOF
175 177 $ hg convert --splicemap splicemap ordered ordered-hg2
176 178 scanning source...
177 179 splice map revision deadbeef102a90ea7b4a3361e4082ed620918c26 is not being converted, ignoring
178 180 sorting...
179 181 converting...
180 182 0 changeaagain
181 183 spliced in ['717d54d67e6c31fd75ffef2ff3042bdd98418437', '102a90ea7b4a3361e4082ed620918c261189a36a'] as parents of 7c364e7fa7d70ae525610c016317ed717b519d97
182 184 $ glog -R ordered-hg2
183 185 o 3:4cb04b9afbf2 "changeaagain" files: a
184 186 |\
185 187 | o 2:102a90ea7b4a "addb" files: b
186 188 | |
187 189 o | 1:717d54d67e6c "changea" files: a
188 190 |/
189 191 o 0:07f494440405 "adda" files: a
190 192
191 193
192 194 Test empty conversion
193 195
194 196 $ hg convert --splicemap splicemap ordered ordered-hg2
195 197 scanning source...
196 198 splice map revision deadbeef102a90ea7b4a3361e4082ed620918c26 is not being converted, ignoring
197 199 sorting...
198 200 converting...
199 201
200 202 Test clonebranches
201 203
202 204 $ hg --config convert.hg.clonebranches=true convert \
203 205 > --splicemap splicemap ordered ordered-hg3
204 206 initializing destination ordered-hg3 repository
205 207 scanning source...
206 208 abort: revision 717d54d67e6c31fd75ffef2ff3042bdd98418437 not found in destination repository (lookups with clonebranches=true are not implemented)
207 209 [255]
208 210
209 211 Test invalid dependency
210 212
211 213 $ cat > splicemap <<EOF
212 214 > $(hg -R ordered id -r 2 -i --debug) \
213 215 > deadbeef102a90ea7b4a3361e4082ed620918c26,\
214 216 > $(hg -R ordered-hg2 id -r 2 -i --debug)
215 217 > EOF
216 218 $ hg convert --splicemap splicemap ordered ordered-hg4
217 219 initializing destination ordered-hg4 repository
218 220 scanning source...
219 221 abort: unknown splice map parent: deadbeef102a90ea7b4a3361e4082ed620918c26
220 222 [255]
@@ -1,101 +1,103
1 1
2 2 $ "$TESTDIR/hghave" svn svn-bindings || exit 80
3 3
4 4 $ cat >> $HGRCPATH <<EOF
5 5 > [extensions]
6 6 > convert =
7 7 > graphlog =
8 8 > EOF
9 9
10 10 $ svnadmin create svn-repo
11 11 $ svnadmin load -q svn-repo < "$TESTDIR/svn/branches.svndump"
12 12
13 13 Convert trunk and branches
14 14
15 15 $ cat > branchmap <<EOF
16 16 > old3 newbranch
17 >
18 >
17 19 > EOF
18 20 $ hg convert --branchmap=branchmap --datesort -r 10 svn-repo A-hg
19 21 initializing destination A-hg repository
20 22 scanning source...
21 23 sorting...
22 24 converting...
23 25 10 init projA
24 26 9 hello
25 27 8 branch trunk, remove c and dir
26 28 7 change a
27 29 6 change b
28 30 5 move and update c
29 31 4 move and update c
30 32 3 change b again
31 33 2 move to old2
32 34 1 move back to old
33 35 0 last change to a
34 36
35 37 Test template keywords
36 38
37 39 $ hg -R A-hg log --template '{rev} {svnuuid}{svnpath}@{svnrev}\n'
38 40 10 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@10
39 41 9 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@9
40 42 8 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old2@8
41 43 7 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@7
42 44 6 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@6
43 45 5 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@6
44 46 4 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@5
45 47 3 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@4
46 48 2 644ede6c-2b81-4367-9dc8-d786514f2cde/branches/old@3
47 49 1 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@2
48 50 0 644ede6c-2b81-4367-9dc8-d786514f2cde/trunk@1
49 51
50 52 Convert again
51 53
52 54 $ hg convert --branchmap=branchmap --datesort svn-repo A-hg
53 55 scanning source...
54 56 sorting...
55 57 converting...
56 58 0 branch trunk@1 into old3
57 59
58 60 $ cd A-hg
59 61 $ hg glog --template 'branch={branches} {rev} {desc|firstline} files: {files}\n'
60 62 o branch=newbranch 11 branch trunk@1 into old3 files:
61 63 |
62 64 | o branch= 10 last change to a files: a
63 65 | |
64 66 | | o branch=old 9 move back to old files:
65 67 | | |
66 68 | | o branch=old2 8 move to old2 files:
67 69 | | |
68 70 | | o branch=old 7 change b again files: b
69 71 | | |
70 72 | o | branch= 6 move and update c files: b
71 73 | | |
72 74 | | o branch=old 5 move and update c files: c
73 75 | | |
74 76 | | o branch=old 4 change b files: b
75 77 | | |
76 78 | o | branch= 3 change a files: a
77 79 | | |
78 80 | | o branch=old 2 branch trunk, remove c and dir files: c
79 81 | |/
80 82 | o branch= 1 hello files: a b c dir/e
81 83 |/
82 84 o branch= 0 init projA files:
83 85
84 86
85 87 $ hg branches
86 88 newbranch 11:a6d7cc050ad1
87 89 default 10:6e2b33404495
88 90 old 9:93c4b0f99529
89 91 old2 8:b52884d7bead (inactive)
90 92 $ hg tags -q
91 93 tip
92 94 $ cd ..
93 95
94 96 Test hg failing to call itself
95 97
96 98 $ HG=foobar hg convert svn-repo B-hg
97 99 * (glob)
98 100 initializing destination B-hg repository
99 101 abort: Mercurial failed to run itself, check hg executable is in PATH
100 102 [255]
101 103
General Comments 0
You need to be logged in to leave comments. Login now