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