##// END OF EJS Templates
convert: specify unit for ui.progress when operating on files
av6 -
r28470:80bd110d default
parent child Browse files
Show More
@@ -1,608 +1,608 b''
1 # convcmd - convert extension commands definition
1 # convcmd - convert extension commands definition
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 from __future__ import absolute_import
7 from __future__ import absolute_import
8
8
9 import os
9 import os
10 import shlex
10 import shlex
11 import shutil
11 import shutil
12
12
13 from mercurial import (
13 from mercurial import (
14 encoding,
14 encoding,
15 error,
15 error,
16 hg,
16 hg,
17 util,
17 util,
18 )
18 )
19 from mercurial.i18n import _
19 from mercurial.i18n import _
20
20
21 from . import (
21 from . import (
22 bzr,
22 bzr,
23 common,
23 common,
24 cvs,
24 cvs,
25 darcs,
25 darcs,
26 filemap,
26 filemap,
27 git,
27 git,
28 gnuarch,
28 gnuarch,
29 hg as hgconvert,
29 hg as hgconvert,
30 monotone,
30 monotone,
31 p4,
31 p4,
32 subversion,
32 subversion,
33 )
33 )
34
34
35 mapfile = common.mapfile
35 mapfile = common.mapfile
36 MissingTool = common.MissingTool
36 MissingTool = common.MissingTool
37 NoRepo = common.NoRepo
37 NoRepo = common.NoRepo
38 SKIPREV = common.SKIPREV
38 SKIPREV = common.SKIPREV
39
39
40 bzr_source = bzr.bzr_source
40 bzr_source = bzr.bzr_source
41 convert_cvs = cvs.convert_cvs
41 convert_cvs = cvs.convert_cvs
42 convert_git = git.convert_git
42 convert_git = git.convert_git
43 darcs_source = darcs.darcs_source
43 darcs_source = darcs.darcs_source
44 gnuarch_source = gnuarch.gnuarch_source
44 gnuarch_source = gnuarch.gnuarch_source
45 mercurial_sink = hgconvert.mercurial_sink
45 mercurial_sink = hgconvert.mercurial_sink
46 mercurial_source = hgconvert.mercurial_source
46 mercurial_source = hgconvert.mercurial_source
47 monotone_source = monotone.monotone_source
47 monotone_source = monotone.monotone_source
48 p4_source = p4.p4_source
48 p4_source = p4.p4_source
49 svn_sink = subversion.svn_sink
49 svn_sink = subversion.svn_sink
50 svn_source = subversion.svn_source
50 svn_source = subversion.svn_source
51
51
52 orig_encoding = 'ascii'
52 orig_encoding = 'ascii'
53
53
54 def recode(s):
54 def recode(s):
55 if isinstance(s, unicode):
55 if isinstance(s, unicode):
56 return s.encode(orig_encoding, 'replace')
56 return s.encode(orig_encoding, 'replace')
57 else:
57 else:
58 return s.decode('utf-8').encode(orig_encoding, 'replace')
58 return s.decode('utf-8').encode(orig_encoding, 'replace')
59
59
60 def mapbranch(branch, branchmap):
60 def mapbranch(branch, branchmap):
61 '''
61 '''
62 >>> bmap = {'default': 'branch1'}
62 >>> bmap = {'default': 'branch1'}
63 >>> for i in ['', None]:
63 >>> for i in ['', None]:
64 ... mapbranch(i, bmap)
64 ... mapbranch(i, bmap)
65 'branch1'
65 'branch1'
66 'branch1'
66 'branch1'
67 >>> bmap = {'None': 'branch2'}
67 >>> bmap = {'None': 'branch2'}
68 >>> for i in ['', None]:
68 >>> for i in ['', None]:
69 ... mapbranch(i, bmap)
69 ... mapbranch(i, bmap)
70 'branch2'
70 'branch2'
71 'branch2'
71 'branch2'
72 >>> bmap = {'None': 'branch3', 'default': 'branch4'}
72 >>> bmap = {'None': 'branch3', 'default': 'branch4'}
73 >>> for i in ['None', '', None, 'default', 'branch5']:
73 >>> for i in ['None', '', None, 'default', 'branch5']:
74 ... mapbranch(i, bmap)
74 ... mapbranch(i, bmap)
75 'branch3'
75 'branch3'
76 'branch4'
76 'branch4'
77 'branch4'
77 'branch4'
78 'branch4'
78 'branch4'
79 'branch5'
79 'branch5'
80 '''
80 '''
81 # If branch is None or empty, this commit is coming from the source
81 # If branch is None or empty, this commit is coming from the source
82 # repository's default branch and destined for the default branch in the
82 # repository's default branch and destined for the default branch in the
83 # destination repository. For such commits, using a literal "default"
83 # destination repository. For such commits, using a literal "default"
84 # in branchmap below allows the user to map "default" to an alternate
84 # in branchmap below allows the user to map "default" to an alternate
85 # default branch in the destination repository.
85 # default branch in the destination repository.
86 branch = branchmap.get(branch or 'default', branch)
86 branch = branchmap.get(branch or 'default', branch)
87 # At some point we used "None" literal to denote the default branch,
87 # At some point we used "None" literal to denote the default branch,
88 # attempt to use that for backward compatibility.
88 # attempt to use that for backward compatibility.
89 if (not branch):
89 if (not branch):
90 branch = branchmap.get(str(None), branch)
90 branch = branchmap.get(str(None), branch)
91 return branch
91 return branch
92
92
93 source_converters = [
93 source_converters = [
94 ('cvs', convert_cvs, 'branchsort'),
94 ('cvs', convert_cvs, 'branchsort'),
95 ('git', convert_git, 'branchsort'),
95 ('git', convert_git, 'branchsort'),
96 ('svn', svn_source, 'branchsort'),
96 ('svn', svn_source, 'branchsort'),
97 ('hg', mercurial_source, 'sourcesort'),
97 ('hg', mercurial_source, 'sourcesort'),
98 ('darcs', darcs_source, 'branchsort'),
98 ('darcs', darcs_source, 'branchsort'),
99 ('mtn', monotone_source, 'branchsort'),
99 ('mtn', monotone_source, 'branchsort'),
100 ('gnuarch', gnuarch_source, 'branchsort'),
100 ('gnuarch', gnuarch_source, 'branchsort'),
101 ('bzr', bzr_source, 'branchsort'),
101 ('bzr', bzr_source, 'branchsort'),
102 ('p4', p4_source, 'branchsort'),
102 ('p4', p4_source, 'branchsort'),
103 ]
103 ]
104
104
105 sink_converters = [
105 sink_converters = [
106 ('hg', mercurial_sink),
106 ('hg', mercurial_sink),
107 ('svn', svn_sink),
107 ('svn', svn_sink),
108 ]
108 ]
109
109
110 def convertsource(ui, path, type, revs):
110 def convertsource(ui, path, type, revs):
111 exceptions = []
111 exceptions = []
112 if type and type not in [s[0] for s in source_converters]:
112 if type and type not in [s[0] for s in source_converters]:
113 raise error.Abort(_('%s: invalid source repository type') % type)
113 raise error.Abort(_('%s: invalid source repository type') % type)
114 for name, source, sortmode in source_converters:
114 for name, source, sortmode in source_converters:
115 try:
115 try:
116 if not type or name == type:
116 if not type or name == type:
117 return source(ui, path, revs), sortmode
117 return source(ui, path, revs), sortmode
118 except (NoRepo, MissingTool) as inst:
118 except (NoRepo, MissingTool) as inst:
119 exceptions.append(inst)
119 exceptions.append(inst)
120 if not ui.quiet:
120 if not ui.quiet:
121 for inst in exceptions:
121 for inst in exceptions:
122 ui.write("%s\n" % inst)
122 ui.write("%s\n" % inst)
123 raise error.Abort(_('%s: missing or unsupported repository') % path)
123 raise error.Abort(_('%s: missing or unsupported repository') % path)
124
124
125 def convertsink(ui, path, type):
125 def convertsink(ui, path, type):
126 if type and type not in [s[0] for s in sink_converters]:
126 if type and type not in [s[0] for s in sink_converters]:
127 raise error.Abort(_('%s: invalid destination repository type') % type)
127 raise error.Abort(_('%s: invalid destination repository type') % type)
128 for name, sink in sink_converters:
128 for name, sink in sink_converters:
129 try:
129 try:
130 if not type or name == type:
130 if not type or name == type:
131 return sink(ui, path)
131 return sink(ui, path)
132 except NoRepo as inst:
132 except NoRepo as inst:
133 ui.note(_("convert: %s\n") % inst)
133 ui.note(_("convert: %s\n") % inst)
134 except MissingTool as inst:
134 except MissingTool as inst:
135 raise error.Abort('%s\n' % inst)
135 raise error.Abort('%s\n' % inst)
136 raise error.Abort(_('%s: unknown repository type') % path)
136 raise error.Abort(_('%s: unknown repository type') % path)
137
137
138 class progresssource(object):
138 class progresssource(object):
139 def __init__(self, ui, source, filecount):
139 def __init__(self, ui, source, filecount):
140 self.ui = ui
140 self.ui = ui
141 self.source = source
141 self.source = source
142 self.filecount = filecount
142 self.filecount = filecount
143 self.retrieved = 0
143 self.retrieved = 0
144
144
145 def getfile(self, file, rev):
145 def getfile(self, file, rev):
146 self.retrieved += 1
146 self.retrieved += 1
147 self.ui.progress(_('getting files'), self.retrieved,
147 self.ui.progress(_('getting files'), self.retrieved,
148 item=file, total=self.filecount)
148 item=file, total=self.filecount, unit=_('files'))
149 return self.source.getfile(file, rev)
149 return self.source.getfile(file, rev)
150
150
151 def targetfilebelongstosource(self, targetfilename):
151 def targetfilebelongstosource(self, targetfilename):
152 return self.source.targetfilebelongstosource(targetfilename)
152 return self.source.targetfilebelongstosource(targetfilename)
153
153
154 def lookuprev(self, rev):
154 def lookuprev(self, rev):
155 return self.source.lookuprev(rev)
155 return self.source.lookuprev(rev)
156
156
157 def close(self):
157 def close(self):
158 self.ui.progress(_('getting files'), None)
158 self.ui.progress(_('getting files'), None)
159
159
160 class converter(object):
160 class converter(object):
161 def __init__(self, ui, source, dest, revmapfile, opts):
161 def __init__(self, ui, source, dest, revmapfile, opts):
162
162
163 self.source = source
163 self.source = source
164 self.dest = dest
164 self.dest = dest
165 self.ui = ui
165 self.ui = ui
166 self.opts = opts
166 self.opts = opts
167 self.commitcache = {}
167 self.commitcache = {}
168 self.authors = {}
168 self.authors = {}
169 self.authorfile = None
169 self.authorfile = None
170
170
171 # Record converted revisions persistently: maps source revision
171 # Record converted revisions persistently: maps source revision
172 # ID to target revision ID (both strings). (This is how
172 # ID to target revision ID (both strings). (This is how
173 # incremental conversions work.)
173 # incremental conversions work.)
174 self.map = mapfile(ui, revmapfile)
174 self.map = mapfile(ui, revmapfile)
175
175
176 # Read first the dst author map if any
176 # Read first the dst author map if any
177 authorfile = self.dest.authorfile()
177 authorfile = self.dest.authorfile()
178 if authorfile and os.path.exists(authorfile):
178 if authorfile and os.path.exists(authorfile):
179 self.readauthormap(authorfile)
179 self.readauthormap(authorfile)
180 # Extend/Override with new author map if necessary
180 # Extend/Override with new author map if necessary
181 if opts.get('authormap'):
181 if opts.get('authormap'):
182 self.readauthormap(opts.get('authormap'))
182 self.readauthormap(opts.get('authormap'))
183 self.authorfile = self.dest.authorfile()
183 self.authorfile = self.dest.authorfile()
184
184
185 self.splicemap = self.parsesplicemap(opts.get('splicemap'))
185 self.splicemap = self.parsesplicemap(opts.get('splicemap'))
186 self.branchmap = mapfile(ui, opts.get('branchmap'))
186 self.branchmap = mapfile(ui, opts.get('branchmap'))
187
187
188 def parsesplicemap(self, path):
188 def parsesplicemap(self, path):
189 """ check and validate the splicemap format and
189 """ check and validate the splicemap format and
190 return a child/parents dictionary.
190 return a child/parents dictionary.
191 Format checking has two parts.
191 Format checking has two parts.
192 1. generic format which is same across all source types
192 1. generic format which is same across all source types
193 2. specific format checking which may be different for
193 2. specific format checking which may be different for
194 different source type. This logic is implemented in
194 different source type. This logic is implemented in
195 checkrevformat function in source files like
195 checkrevformat function in source files like
196 hg.py, subversion.py etc.
196 hg.py, subversion.py etc.
197 """
197 """
198
198
199 if not path:
199 if not path:
200 return {}
200 return {}
201 m = {}
201 m = {}
202 try:
202 try:
203 fp = open(path, 'r')
203 fp = open(path, 'r')
204 for i, line in enumerate(fp):
204 for i, line in enumerate(fp):
205 line = line.splitlines()[0].rstrip()
205 line = line.splitlines()[0].rstrip()
206 if not line:
206 if not line:
207 # Ignore blank lines
207 # Ignore blank lines
208 continue
208 continue
209 # split line
209 # split line
210 lex = shlex.shlex(line, posix=True)
210 lex = shlex.shlex(line, posix=True)
211 lex.whitespace_split = True
211 lex.whitespace_split = True
212 lex.whitespace += ','
212 lex.whitespace += ','
213 line = list(lex)
213 line = list(lex)
214 # check number of parents
214 # check number of parents
215 if not (2 <= len(line) <= 3):
215 if not (2 <= len(line) <= 3):
216 raise error.Abort(_('syntax error in %s(%d): child parent1'
216 raise error.Abort(_('syntax error in %s(%d): child parent1'
217 '[,parent2] expected') % (path, i + 1))
217 '[,parent2] expected') % (path, i + 1))
218 for part in line:
218 for part in line:
219 self.source.checkrevformat(part)
219 self.source.checkrevformat(part)
220 child, p1, p2 = line[0], line[1:2], line[2:]
220 child, p1, p2 = line[0], line[1:2], line[2:]
221 if p1 == p2:
221 if p1 == p2:
222 m[child] = p1
222 m[child] = p1
223 else:
223 else:
224 m[child] = p1 + p2
224 m[child] = p1 + p2
225 # if file does not exist or error reading, exit
225 # if file does not exist or error reading, exit
226 except IOError:
226 except IOError:
227 raise error.Abort(_('splicemap file not found or error reading %s:')
227 raise error.Abort(_('splicemap file not found or error reading %s:')
228 % path)
228 % path)
229 return m
229 return m
230
230
231
231
232 def walktree(self, heads):
232 def walktree(self, heads):
233 '''Return a mapping that identifies the uncommitted parents of every
233 '''Return a mapping that identifies the uncommitted parents of every
234 uncommitted changeset.'''
234 uncommitted changeset.'''
235 visit = heads
235 visit = heads
236 known = set()
236 known = set()
237 parents = {}
237 parents = {}
238 numcommits = self.source.numcommits()
238 numcommits = self.source.numcommits()
239 while visit:
239 while visit:
240 n = visit.pop(0)
240 n = visit.pop(0)
241 if n in known:
241 if n in known:
242 continue
242 continue
243 if n in self.map:
243 if n in self.map:
244 m = self.map[n]
244 m = self.map[n]
245 if m == SKIPREV or self.dest.hascommitfrommap(m):
245 if m == SKIPREV or self.dest.hascommitfrommap(m):
246 continue
246 continue
247 known.add(n)
247 known.add(n)
248 self.ui.progress(_('scanning'), len(known), unit=_('revisions'),
248 self.ui.progress(_('scanning'), len(known), unit=_('revisions'),
249 total=numcommits)
249 total=numcommits)
250 commit = self.cachecommit(n)
250 commit = self.cachecommit(n)
251 parents[n] = []
251 parents[n] = []
252 for p in commit.parents:
252 for p in commit.parents:
253 parents[n].append(p)
253 parents[n].append(p)
254 visit.append(p)
254 visit.append(p)
255 self.ui.progress(_('scanning'), None)
255 self.ui.progress(_('scanning'), None)
256
256
257 return parents
257 return parents
258
258
259 def mergesplicemap(self, parents, splicemap):
259 def mergesplicemap(self, parents, splicemap):
260 """A splicemap redefines child/parent relationships. Check the
260 """A splicemap redefines child/parent relationships. Check the
261 map contains valid revision identifiers and merge the new
261 map contains valid revision identifiers and merge the new
262 links in the source graph.
262 links in the source graph.
263 """
263 """
264 for c in sorted(splicemap):
264 for c in sorted(splicemap):
265 if c not in parents:
265 if c not in parents:
266 if not self.dest.hascommitforsplicemap(self.map.get(c, c)):
266 if not self.dest.hascommitforsplicemap(self.map.get(c, c)):
267 # Could be in source but not converted during this run
267 # Could be in source but not converted during this run
268 self.ui.warn(_('splice map revision %s is not being '
268 self.ui.warn(_('splice map revision %s is not being '
269 'converted, ignoring\n') % c)
269 'converted, ignoring\n') % c)
270 continue
270 continue
271 pc = []
271 pc = []
272 for p in splicemap[c]:
272 for p in splicemap[c]:
273 # We do not have to wait for nodes already in dest.
273 # We do not have to wait for nodes already in dest.
274 if self.dest.hascommitforsplicemap(self.map.get(p, p)):
274 if self.dest.hascommitforsplicemap(self.map.get(p, p)):
275 continue
275 continue
276 # Parent is not in dest and not being converted, not good
276 # Parent is not in dest and not being converted, not good
277 if p not in parents:
277 if p not in parents:
278 raise error.Abort(_('unknown splice map parent: %s') % p)
278 raise error.Abort(_('unknown splice map parent: %s') % p)
279 pc.append(p)
279 pc.append(p)
280 parents[c] = pc
280 parents[c] = pc
281
281
282 def toposort(self, parents, sortmode):
282 def toposort(self, parents, sortmode):
283 '''Return an ordering such that every uncommitted changeset is
283 '''Return an ordering such that every uncommitted changeset is
284 preceded by all its uncommitted ancestors.'''
284 preceded by all its uncommitted ancestors.'''
285
285
286 def mapchildren(parents):
286 def mapchildren(parents):
287 """Return a (children, roots) tuple where 'children' maps parent
287 """Return a (children, roots) tuple where 'children' maps parent
288 revision identifiers to children ones, and 'roots' is the list of
288 revision identifiers to children ones, and 'roots' is the list of
289 revisions without parents. 'parents' must be a mapping of revision
289 revisions without parents. 'parents' must be a mapping of revision
290 identifier to its parents ones.
290 identifier to its parents ones.
291 """
291 """
292 visit = sorted(parents)
292 visit = sorted(parents)
293 seen = set()
293 seen = set()
294 children = {}
294 children = {}
295 roots = []
295 roots = []
296
296
297 while visit:
297 while visit:
298 n = visit.pop(0)
298 n = visit.pop(0)
299 if n in seen:
299 if n in seen:
300 continue
300 continue
301 seen.add(n)
301 seen.add(n)
302 # Ensure that nodes without parents are present in the
302 # Ensure that nodes without parents are present in the
303 # 'children' mapping.
303 # 'children' mapping.
304 children.setdefault(n, [])
304 children.setdefault(n, [])
305 hasparent = False
305 hasparent = False
306 for p in parents[n]:
306 for p in parents[n]:
307 if p not in self.map:
307 if p not in self.map:
308 visit.append(p)
308 visit.append(p)
309 hasparent = True
309 hasparent = True
310 children.setdefault(p, []).append(n)
310 children.setdefault(p, []).append(n)
311 if not hasparent:
311 if not hasparent:
312 roots.append(n)
312 roots.append(n)
313
313
314 return children, roots
314 return children, roots
315
315
316 # Sort functions are supposed to take a list of revisions which
316 # Sort functions are supposed to take a list of revisions which
317 # can be converted immediately and pick one
317 # can be converted immediately and pick one
318
318
319 def makebranchsorter():
319 def makebranchsorter():
320 """If the previously converted revision has a child in the
320 """If the previously converted revision has a child in the
321 eligible revisions list, pick it. Return the list head
321 eligible revisions list, pick it. Return the list head
322 otherwise. Branch sort attempts to minimize branch
322 otherwise. Branch sort attempts to minimize branch
323 switching, which is harmful for Mercurial backend
323 switching, which is harmful for Mercurial backend
324 compression.
324 compression.
325 """
325 """
326 prev = [None]
326 prev = [None]
327 def picknext(nodes):
327 def picknext(nodes):
328 next = nodes[0]
328 next = nodes[0]
329 for n in nodes:
329 for n in nodes:
330 if prev[0] in parents[n]:
330 if prev[0] in parents[n]:
331 next = n
331 next = n
332 break
332 break
333 prev[0] = next
333 prev[0] = next
334 return next
334 return next
335 return picknext
335 return picknext
336
336
337 def makesourcesorter():
337 def makesourcesorter():
338 """Source specific sort."""
338 """Source specific sort."""
339 keyfn = lambda n: self.commitcache[n].sortkey
339 keyfn = lambda n: self.commitcache[n].sortkey
340 def picknext(nodes):
340 def picknext(nodes):
341 return sorted(nodes, key=keyfn)[0]
341 return sorted(nodes, key=keyfn)[0]
342 return picknext
342 return picknext
343
343
344 def makeclosesorter():
344 def makeclosesorter():
345 """Close order sort."""
345 """Close order sort."""
346 keyfn = lambda n: ('close' not in self.commitcache[n].extra,
346 keyfn = lambda n: ('close' not in self.commitcache[n].extra,
347 self.commitcache[n].sortkey)
347 self.commitcache[n].sortkey)
348 def picknext(nodes):
348 def picknext(nodes):
349 return sorted(nodes, key=keyfn)[0]
349 return sorted(nodes, key=keyfn)[0]
350 return picknext
350 return picknext
351
351
352 def makedatesorter():
352 def makedatesorter():
353 """Sort revisions by date."""
353 """Sort revisions by date."""
354 dates = {}
354 dates = {}
355 def getdate(n):
355 def getdate(n):
356 if n not in dates:
356 if n not in dates:
357 dates[n] = util.parsedate(self.commitcache[n].date)
357 dates[n] = util.parsedate(self.commitcache[n].date)
358 return dates[n]
358 return dates[n]
359
359
360 def picknext(nodes):
360 def picknext(nodes):
361 return min([(getdate(n), n) for n in nodes])[1]
361 return min([(getdate(n), n) for n in nodes])[1]
362
362
363 return picknext
363 return picknext
364
364
365 if sortmode == 'branchsort':
365 if sortmode == 'branchsort':
366 picknext = makebranchsorter()
366 picknext = makebranchsorter()
367 elif sortmode == 'datesort':
367 elif sortmode == 'datesort':
368 picknext = makedatesorter()
368 picknext = makedatesorter()
369 elif sortmode == 'sourcesort':
369 elif sortmode == 'sourcesort':
370 picknext = makesourcesorter()
370 picknext = makesourcesorter()
371 elif sortmode == 'closesort':
371 elif sortmode == 'closesort':
372 picknext = makeclosesorter()
372 picknext = makeclosesorter()
373 else:
373 else:
374 raise error.Abort(_('unknown sort mode: %s') % sortmode)
374 raise error.Abort(_('unknown sort mode: %s') % sortmode)
375
375
376 children, actives = mapchildren(parents)
376 children, actives = mapchildren(parents)
377
377
378 s = []
378 s = []
379 pendings = {}
379 pendings = {}
380 while actives:
380 while actives:
381 n = picknext(actives)
381 n = picknext(actives)
382 actives.remove(n)
382 actives.remove(n)
383 s.append(n)
383 s.append(n)
384
384
385 # Update dependents list
385 # Update dependents list
386 for c in children.get(n, []):
386 for c in children.get(n, []):
387 if c not in pendings:
387 if c not in pendings:
388 pendings[c] = [p for p in parents[c] if p not in self.map]
388 pendings[c] = [p for p in parents[c] if p not in self.map]
389 try:
389 try:
390 pendings[c].remove(n)
390 pendings[c].remove(n)
391 except ValueError:
391 except ValueError:
392 raise error.Abort(_('cycle detected between %s and %s')
392 raise error.Abort(_('cycle detected between %s and %s')
393 % (recode(c), recode(n)))
393 % (recode(c), recode(n)))
394 if not pendings[c]:
394 if not pendings[c]:
395 # Parents are converted, node is eligible
395 # Parents are converted, node is eligible
396 actives.insert(0, c)
396 actives.insert(0, c)
397 pendings[c] = None
397 pendings[c] = None
398
398
399 if len(s) != len(parents):
399 if len(s) != len(parents):
400 raise error.Abort(_("not all revisions were sorted"))
400 raise error.Abort(_("not all revisions were sorted"))
401
401
402 return s
402 return s
403
403
404 def writeauthormap(self):
404 def writeauthormap(self):
405 authorfile = self.authorfile
405 authorfile = self.authorfile
406 if authorfile:
406 if authorfile:
407 self.ui.status(_('writing author map file %s\n') % authorfile)
407 self.ui.status(_('writing author map file %s\n') % authorfile)
408 ofile = open(authorfile, 'w+')
408 ofile = open(authorfile, 'w+')
409 for author in self.authors:
409 for author in self.authors:
410 ofile.write("%s=%s\n" % (author, self.authors[author]))
410 ofile.write("%s=%s\n" % (author, self.authors[author]))
411 ofile.close()
411 ofile.close()
412
412
413 def readauthormap(self, authorfile):
413 def readauthormap(self, authorfile):
414 afile = open(authorfile, 'r')
414 afile = open(authorfile, 'r')
415 for line in afile:
415 for line in afile:
416
416
417 line = line.strip()
417 line = line.strip()
418 if not line or line.startswith('#'):
418 if not line or line.startswith('#'):
419 continue
419 continue
420
420
421 try:
421 try:
422 srcauthor, dstauthor = line.split('=', 1)
422 srcauthor, dstauthor = line.split('=', 1)
423 except ValueError:
423 except ValueError:
424 msg = _('ignoring bad line in author map file %s: %s\n')
424 msg = _('ignoring bad line in author map file %s: %s\n')
425 self.ui.warn(msg % (authorfile, line.rstrip()))
425 self.ui.warn(msg % (authorfile, line.rstrip()))
426 continue
426 continue
427
427
428 srcauthor = srcauthor.strip()
428 srcauthor = srcauthor.strip()
429 dstauthor = dstauthor.strip()
429 dstauthor = dstauthor.strip()
430 if self.authors.get(srcauthor) in (None, dstauthor):
430 if self.authors.get(srcauthor) in (None, dstauthor):
431 msg = _('mapping author %s to %s\n')
431 msg = _('mapping author %s to %s\n')
432 self.ui.debug(msg % (srcauthor, dstauthor))
432 self.ui.debug(msg % (srcauthor, dstauthor))
433 self.authors[srcauthor] = dstauthor
433 self.authors[srcauthor] = dstauthor
434 continue
434 continue
435
435
436 m = _('overriding mapping for author %s, was %s, will be %s\n')
436 m = _('overriding mapping for author %s, was %s, will be %s\n')
437 self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor))
437 self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor))
438
438
439 afile.close()
439 afile.close()
440
440
441 def cachecommit(self, rev):
441 def cachecommit(self, rev):
442 commit = self.source.getcommit(rev)
442 commit = self.source.getcommit(rev)
443 commit.author = self.authors.get(commit.author, commit.author)
443 commit.author = self.authors.get(commit.author, commit.author)
444 commit.branch = mapbranch(commit.branch, self.branchmap)
444 commit.branch = mapbranch(commit.branch, self.branchmap)
445 self.commitcache[rev] = commit
445 self.commitcache[rev] = commit
446 return commit
446 return commit
447
447
448 def copy(self, rev):
448 def copy(self, rev):
449 commit = self.commitcache[rev]
449 commit = self.commitcache[rev]
450 full = self.opts.get('full')
450 full = self.opts.get('full')
451 changes = self.source.getchanges(rev, full)
451 changes = self.source.getchanges(rev, full)
452 if isinstance(changes, basestring):
452 if isinstance(changes, basestring):
453 if changes == SKIPREV:
453 if changes == SKIPREV:
454 dest = SKIPREV
454 dest = SKIPREV
455 else:
455 else:
456 dest = self.map[changes]
456 dest = self.map[changes]
457 self.map[rev] = dest
457 self.map[rev] = dest
458 return
458 return
459 files, copies, cleanp2 = changes
459 files, copies, cleanp2 = changes
460 pbranches = []
460 pbranches = []
461 if commit.parents:
461 if commit.parents:
462 for prev in commit.parents:
462 for prev in commit.parents:
463 if prev not in self.commitcache:
463 if prev not in self.commitcache:
464 self.cachecommit(prev)
464 self.cachecommit(prev)
465 pbranches.append((self.map[prev],
465 pbranches.append((self.map[prev],
466 self.commitcache[prev].branch))
466 self.commitcache[prev].branch))
467 self.dest.setbranch(commit.branch, pbranches)
467 self.dest.setbranch(commit.branch, pbranches)
468 try:
468 try:
469 parents = self.splicemap[rev]
469 parents = self.splicemap[rev]
470 self.ui.status(_('spliced in %s as parents of %s\n') %
470 self.ui.status(_('spliced in %s as parents of %s\n') %
471 (_(' and ').join(parents), rev))
471 (_(' and ').join(parents), rev))
472 parents = [self.map.get(p, p) for p in parents]
472 parents = [self.map.get(p, p) for p in parents]
473 except KeyError:
473 except KeyError:
474 parents = [b[0] for b in pbranches]
474 parents = [b[0] for b in pbranches]
475 if len(pbranches) != 2:
475 if len(pbranches) != 2:
476 cleanp2 = set()
476 cleanp2 = set()
477 if len(parents) < 3:
477 if len(parents) < 3:
478 source = progresssource(self.ui, self.source, len(files))
478 source = progresssource(self.ui, self.source, len(files))
479 else:
479 else:
480 # For an octopus merge, we end up traversing the list of
480 # For an octopus merge, we end up traversing the list of
481 # changed files N-1 times. This tweak to the number of
481 # changed files N-1 times. This tweak to the number of
482 # files makes it so the progress bar doesn't overflow
482 # files makes it so the progress bar doesn't overflow
483 # itself.
483 # itself.
484 source = progresssource(self.ui, self.source,
484 source = progresssource(self.ui, self.source,
485 len(files) * (len(parents) - 1))
485 len(files) * (len(parents) - 1))
486 newnode = self.dest.putcommit(files, copies, parents, commit,
486 newnode = self.dest.putcommit(files, copies, parents, commit,
487 source, self.map, full, cleanp2)
487 source, self.map, full, cleanp2)
488 source.close()
488 source.close()
489 self.source.converted(rev, newnode)
489 self.source.converted(rev, newnode)
490 self.map[rev] = newnode
490 self.map[rev] = newnode
491
491
492 def convert(self, sortmode):
492 def convert(self, sortmode):
493 try:
493 try:
494 self.source.before()
494 self.source.before()
495 self.dest.before()
495 self.dest.before()
496 self.source.setrevmap(self.map)
496 self.source.setrevmap(self.map)
497 self.ui.status(_("scanning source...\n"))
497 self.ui.status(_("scanning source...\n"))
498 heads = self.source.getheads()
498 heads = self.source.getheads()
499 parents = self.walktree(heads)
499 parents = self.walktree(heads)
500 self.mergesplicemap(parents, self.splicemap)
500 self.mergesplicemap(parents, self.splicemap)
501 self.ui.status(_("sorting...\n"))
501 self.ui.status(_("sorting...\n"))
502 t = self.toposort(parents, sortmode)
502 t = self.toposort(parents, sortmode)
503 num = len(t)
503 num = len(t)
504 c = None
504 c = None
505
505
506 self.ui.status(_("converting...\n"))
506 self.ui.status(_("converting...\n"))
507 for i, c in enumerate(t):
507 for i, c in enumerate(t):
508 num -= 1
508 num -= 1
509 desc = self.commitcache[c].desc
509 desc = self.commitcache[c].desc
510 if "\n" in desc:
510 if "\n" in desc:
511 desc = desc.splitlines()[0]
511 desc = desc.splitlines()[0]
512 # convert log message to local encoding without using
512 # convert log message to local encoding without using
513 # tolocal() because the encoding.encoding convert()
513 # tolocal() because the encoding.encoding convert()
514 # uses is 'utf-8'
514 # uses is 'utf-8'
515 self.ui.status("%d %s\n" % (num, recode(desc)))
515 self.ui.status("%d %s\n" % (num, recode(desc)))
516 self.ui.note(_("source: %s\n") % recode(c))
516 self.ui.note(_("source: %s\n") % recode(c))
517 self.ui.progress(_('converting'), i, unit=_('revisions'),
517 self.ui.progress(_('converting'), i, unit=_('revisions'),
518 total=len(t))
518 total=len(t))
519 self.copy(c)
519 self.copy(c)
520 self.ui.progress(_('converting'), None)
520 self.ui.progress(_('converting'), None)
521
521
522 if not self.ui.configbool('convert', 'skiptags'):
522 if not self.ui.configbool('convert', 'skiptags'):
523 tags = self.source.gettags()
523 tags = self.source.gettags()
524 ctags = {}
524 ctags = {}
525 for k in tags:
525 for k in tags:
526 v = tags[k]
526 v = tags[k]
527 if self.map.get(v, SKIPREV) != SKIPREV:
527 if self.map.get(v, SKIPREV) != SKIPREV:
528 ctags[k] = self.map[v]
528 ctags[k] = self.map[v]
529
529
530 if c and ctags:
530 if c and ctags:
531 nrev, tagsparent = self.dest.puttags(ctags)
531 nrev, tagsparent = self.dest.puttags(ctags)
532 if nrev and tagsparent:
532 if nrev and tagsparent:
533 # write another hash correspondence to override the
533 # write another hash correspondence to override the
534 # previous one so we don't end up with extra tag heads
534 # previous one so we don't end up with extra tag heads
535 tagsparents = [e for e in self.map.iteritems()
535 tagsparents = [e for e in self.map.iteritems()
536 if e[1] == tagsparent]
536 if e[1] == tagsparent]
537 if tagsparents:
537 if tagsparents:
538 self.map[tagsparents[0][0]] = nrev
538 self.map[tagsparents[0][0]] = nrev
539
539
540 bookmarks = self.source.getbookmarks()
540 bookmarks = self.source.getbookmarks()
541 cbookmarks = {}
541 cbookmarks = {}
542 for k in bookmarks:
542 for k in bookmarks:
543 v = bookmarks[k]
543 v = bookmarks[k]
544 if self.map.get(v, SKIPREV) != SKIPREV:
544 if self.map.get(v, SKIPREV) != SKIPREV:
545 cbookmarks[k] = self.map[v]
545 cbookmarks[k] = self.map[v]
546
546
547 if c and cbookmarks:
547 if c and cbookmarks:
548 self.dest.putbookmarks(cbookmarks)
548 self.dest.putbookmarks(cbookmarks)
549
549
550 self.writeauthormap()
550 self.writeauthormap()
551 finally:
551 finally:
552 self.cleanup()
552 self.cleanup()
553
553
554 def cleanup(self):
554 def cleanup(self):
555 try:
555 try:
556 self.dest.after()
556 self.dest.after()
557 finally:
557 finally:
558 self.source.after()
558 self.source.after()
559 self.map.close()
559 self.map.close()
560
560
561 def convert(ui, src, dest=None, revmapfile=None, **opts):
561 def convert(ui, src, dest=None, revmapfile=None, **opts):
562 global orig_encoding
562 global orig_encoding
563 orig_encoding = encoding.encoding
563 orig_encoding = encoding.encoding
564 encoding.encoding = 'UTF-8'
564 encoding.encoding = 'UTF-8'
565
565
566 # support --authors as an alias for --authormap
566 # support --authors as an alias for --authormap
567 if not opts.get('authormap'):
567 if not opts.get('authormap'):
568 opts['authormap'] = opts.get('authors')
568 opts['authormap'] = opts.get('authors')
569
569
570 if not dest:
570 if not dest:
571 dest = hg.defaultdest(src) + "-hg"
571 dest = hg.defaultdest(src) + "-hg"
572 ui.status(_("assuming destination %s\n") % dest)
572 ui.status(_("assuming destination %s\n") % dest)
573
573
574 destc = convertsink(ui, dest, opts.get('dest_type'))
574 destc = convertsink(ui, dest, opts.get('dest_type'))
575
575
576 try:
576 try:
577 srcc, defaultsort = convertsource(ui, src, opts.get('source_type'),
577 srcc, defaultsort = convertsource(ui, src, opts.get('source_type'),
578 opts.get('rev'))
578 opts.get('rev'))
579 except Exception:
579 except Exception:
580 for path in destc.created:
580 for path in destc.created:
581 shutil.rmtree(path, True)
581 shutil.rmtree(path, True)
582 raise
582 raise
583
583
584 sortmodes = ('branchsort', 'datesort', 'sourcesort', 'closesort')
584 sortmodes = ('branchsort', 'datesort', 'sourcesort', 'closesort')
585 sortmode = [m for m in sortmodes if opts.get(m)]
585 sortmode = [m for m in sortmodes if opts.get(m)]
586 if len(sortmode) > 1:
586 if len(sortmode) > 1:
587 raise error.Abort(_('more than one sort mode specified'))
587 raise error.Abort(_('more than one sort mode specified'))
588 if sortmode:
588 if sortmode:
589 sortmode = sortmode[0]
589 sortmode = sortmode[0]
590 else:
590 else:
591 sortmode = defaultsort
591 sortmode = defaultsort
592
592
593 if sortmode == 'sourcesort' and not srcc.hasnativeorder():
593 if sortmode == 'sourcesort' and not srcc.hasnativeorder():
594 raise error.Abort(_('--sourcesort is not supported by this data source')
594 raise error.Abort(_('--sourcesort is not supported by this data source')
595 )
595 )
596 if sortmode == 'closesort' and not srcc.hasnativeclose():
596 if sortmode == 'closesort' and not srcc.hasnativeclose():
597 raise error.Abort(_('--closesort is not supported by this data source'))
597 raise error.Abort(_('--closesort is not supported by this data source'))
598
598
599 fmap = opts.get('filemap')
599 fmap = opts.get('filemap')
600 if fmap:
600 if fmap:
601 srcc = filemap.filemap_source(ui, srcc, fmap)
601 srcc = filemap.filemap_source(ui, srcc, fmap)
602 destc.setfilemapmode(True)
602 destc.setfilemapmode(True)
603
603
604 if not revmapfile:
604 if not revmapfile:
605 revmapfile = destc.revmapfile()
605 revmapfile = destc.revmapfile()
606
606
607 c = converter(ui, srcc, destc, revmapfile, opts)
607 c = converter(ui, srcc, destc, revmapfile, opts)
608 c.convert(sortmode)
608 c.convert(sortmode)
@@ -1,144 +1,144 b''
1 #require svn svn-bindings
1 #require svn svn-bindings
2
2
3 $ cat >> $HGRCPATH <<EOF
3 $ cat >> $HGRCPATH <<EOF
4 > [extensions]
4 > [extensions]
5 > convert =
5 > convert =
6 > EOF
6 > EOF
7
7
8 $ svnadmin create svn-repo
8 $ svnadmin create svn-repo
9 $ svnadmin load -q svn-repo < "$TESTDIR/svn/encoding.svndump"
9 $ svnadmin load -q svn-repo < "$TESTDIR/svn/encoding.svndump"
10
10
11 Convert while testing all possible outputs
11 Convert while testing all possible outputs
12
12
13 $ hg --debug convert svn-repo A-hg --config progress.debug=1
13 $ hg --debug convert svn-repo A-hg --config progress.debug=1
14 initializing destination A-hg repository
14 initializing destination A-hg repository
15 reparent to file://*/svn-repo (glob)
15 reparent to file://*/svn-repo (glob)
16 run hg sink pre-conversion action
16 run hg sink pre-conversion action
17 scanning source...
17 scanning source...
18 found trunk at 'trunk'
18 found trunk at 'trunk'
19 found tags at 'tags'
19 found tags at 'tags'
20 found branches at 'branches'
20 found branches at 'branches'
21 found branch branch\xc3\xa9 at 5 (esc)
21 found branch branch\xc3\xa9 at 5 (esc)
22 found branch branch\xc3\xa9e at 6 (esc)
22 found branch branch\xc3\xa9e at 6 (esc)
23 scanning: 1/4 revisions (25.00%)
23 scanning: 1/4 revisions (25.00%)
24 reparent to file://*/svn-repo/trunk (glob)
24 reparent to file://*/svn-repo/trunk (glob)
25 fetching revision log for "/trunk" from 4 to 0
25 fetching revision log for "/trunk" from 4 to 0
26 parsing revision 4 (2 changes)
26 parsing revision 4 (2 changes)
27 parsing revision 3 (4 changes)
27 parsing revision 3 (4 changes)
28 parsing revision 2 (3 changes)
28 parsing revision 2 (3 changes)
29 parsing revision 1 (3 changes)
29 parsing revision 1 (3 changes)
30 no copyfrom path, don't know what to do.
30 no copyfrom path, don't know what to do.
31 '/branches' is not under '/trunk', ignoring
31 '/branches' is not under '/trunk', ignoring
32 '/tags' is not under '/trunk', ignoring
32 '/tags' is not under '/trunk', ignoring
33 scanning: 2/4 revisions (50.00%)
33 scanning: 2/4 revisions (50.00%)
34 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
34 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
35 fetching revision log for "/branches/branch\xc3\xa9" from 5 to 0 (esc)
35 fetching revision log for "/branches/branch\xc3\xa9" from 5 to 0 (esc)
36 parsing revision 5 (1 changes)
36 parsing revision 5 (1 changes)
37 reparent to file://*/svn-repo (glob)
37 reparent to file://*/svn-repo (glob)
38 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
38 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
39 found parent of branch /branches/branch\xc3\xa9 at 4: /trunk (esc)
39 found parent of branch /branches/branch\xc3\xa9 at 4: /trunk (esc)
40 scanning: 3/4 revisions (75.00%)
40 scanning: 3/4 revisions (75.00%)
41 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
41 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
42 fetching revision log for "/branches/branch\xc3\xa9e" from 6 to 0 (esc)
42 fetching revision log for "/branches/branch\xc3\xa9e" from 6 to 0 (esc)
43 parsing revision 6 (1 changes)
43 parsing revision 6 (1 changes)
44 reparent to file://*/svn-repo (glob)
44 reparent to file://*/svn-repo (glob)
45 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
45 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
46 found parent of branch /branches/branch\xc3\xa9e at 5: /branches/branch\xc3\xa9 (esc)
46 found parent of branch /branches/branch\xc3\xa9e at 5: /branches/branch\xc3\xa9 (esc)
47 scanning: 4/4 revisions (100.00%)
47 scanning: 4/4 revisions (100.00%)
48 scanning: 5/4 revisions (125.00%)
48 scanning: 5/4 revisions (125.00%)
49 scanning: 6/4 revisions (150.00%)
49 scanning: 6/4 revisions (150.00%)
50 sorting...
50 sorting...
51 converting...
51 converting...
52 5 init projA
52 5 init projA
53 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@1
53 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@1
54 converting: 0/6 revisions (0.00%)
54 converting: 0/6 revisions (0.00%)
55 committing changelog
55 committing changelog
56 4 hello
56 4 hello
57 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@2
57 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@2
58 converting: 1/6 revisions (16.67%)
58 converting: 1/6 revisions (16.67%)
59 reparent to file://*/svn-repo/trunk (glob)
59 reparent to file://*/svn-repo/trunk (glob)
60 scanning paths: /trunk/\xc3\xa0 0/3 (0.00%) (esc)
60 scanning paths: /trunk/\xc3\xa0 0/3 (0.00%) (esc)
61 scanning paths: /trunk/\xc3\xa0/e\xcc\x81 1/3 (33.33%) (esc)
61 scanning paths: /trunk/\xc3\xa0/e\xcc\x81 1/3 (33.33%) (esc)
62 scanning paths: /trunk/\xc3\xa9 2/3 (66.67%) (esc)
62 scanning paths: /trunk/\xc3\xa9 2/3 (66.67%) (esc)
63 committing files:
63 committing files:
64 \xc3\xa0/e\xcc\x81 (esc)
64 \xc3\xa0/e\xcc\x81 (esc)
65 getting files: \xc3\xa0/e\xcc\x81 1/2 (50.00%) (esc)
65 getting files: \xc3\xa0/e\xcc\x81 1/2 files (50.00%) (esc)
66 \xc3\xa9 (esc)
66 \xc3\xa9 (esc)
67 getting files: \xc3\xa9 2/2 (100.00%) (esc)
67 getting files: \xc3\xa9 2/2 files (100.00%) (esc)
68 committing manifest
68 committing manifest
69 committing changelog
69 committing changelog
70 3 copy files
70 3 copy files
71 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@3
71 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@3
72 converting: 2/6 revisions (33.33%)
72 converting: 2/6 revisions (33.33%)
73 scanning paths: /trunk/\xc3\xa0 0/4 (0.00%) (esc)
73 scanning paths: /trunk/\xc3\xa0 0/4 (0.00%) (esc)
74 gone from -1
74 gone from -1
75 reparent to file://*/svn-repo (glob)
75 reparent to file://*/svn-repo (glob)
76 reparent to file://*/svn-repo/trunk (glob)
76 reparent to file://*/svn-repo/trunk (glob)
77 scanning paths: /trunk/\xc3\xa8 1/4 (25.00%) (esc)
77 scanning paths: /trunk/\xc3\xa8 1/4 (25.00%) (esc)
78 copied to \xc3\xa8 from \xc3\xa9@2 (esc)
78 copied to \xc3\xa8 from \xc3\xa9@2 (esc)
79 scanning paths: /trunk/\xc3\xa9 2/4 (50.00%) (esc)
79 scanning paths: /trunk/\xc3\xa9 2/4 (50.00%) (esc)
80 gone from -1
80 gone from -1
81 reparent to file://*/svn-repo (glob)
81 reparent to file://*/svn-repo (glob)
82 reparent to file://*/svn-repo/trunk (glob)
82 reparent to file://*/svn-repo/trunk (glob)
83 scanning paths: /trunk/\xc3\xb9 3/4 (75.00%) (esc)
83 scanning paths: /trunk/\xc3\xb9 3/4 (75.00%) (esc)
84 mark /trunk/\xc3\xb9 came from \xc3\xa0:2 (esc)
84 mark /trunk/\xc3\xb9 came from \xc3\xa0:2 (esc)
85 getting files: \xc3\xa0/e\xcc\x81 1/4 (25.00%) (esc)
85 getting files: \xc3\xa0/e\xcc\x81 1/4 files (25.00%) (esc)
86 getting files: \xc3\xa9 2/4 (50.00%) (esc)
86 getting files: \xc3\xa9 2/4 files (50.00%) (esc)
87 committing files:
87 committing files:
88 \xc3\xa8 (esc)
88 \xc3\xa8 (esc)
89 getting files: \xc3\xa8 3/4 (75.00%) (esc)
89 getting files: \xc3\xa8 3/4 files (75.00%) (esc)
90 \xc3\xa8: copy \xc3\xa9:6b67ccefd5ce6de77e7ead4f5292843a0255329f (esc)
90 \xc3\xa8: copy \xc3\xa9:6b67ccefd5ce6de77e7ead4f5292843a0255329f (esc)
91 \xc3\xb9/e\xcc\x81 (esc)
91 \xc3\xb9/e\xcc\x81 (esc)
92 getting files: \xc3\xb9/e\xcc\x81 4/4 (100.00%) (esc)
92 getting files: \xc3\xb9/e\xcc\x81 4/4 files (100.00%) (esc)
93 \xc3\xb9/e\xcc\x81: copy \xc3\xa0/e\xcc\x81:a9092a3d84a37b9993b5c73576f6de29b7ea50f6 (esc)
93 \xc3\xb9/e\xcc\x81: copy \xc3\xa0/e\xcc\x81:a9092a3d84a37b9993b5c73576f6de29b7ea50f6 (esc)
94 committing manifest
94 committing manifest
95 committing changelog
95 committing changelog
96 2 remove files
96 2 remove files
97 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@4
97 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/trunk@4
98 converting: 3/6 revisions (50.00%)
98 converting: 3/6 revisions (50.00%)
99 scanning paths: /trunk/\xc3\xa8 0/2 (0.00%) (esc)
99 scanning paths: /trunk/\xc3\xa8 0/2 (0.00%) (esc)
100 gone from -1
100 gone from -1
101 reparent to file://*/svn-repo (glob)
101 reparent to file://*/svn-repo (glob)
102 reparent to file://*/svn-repo/trunk (glob)
102 reparent to file://*/svn-repo/trunk (glob)
103 scanning paths: /trunk/\xc3\xb9 1/2 (50.00%) (esc)
103 scanning paths: /trunk/\xc3\xb9 1/2 (50.00%) (esc)
104 gone from -1
104 gone from -1
105 reparent to file://*/svn-repo (glob)
105 reparent to file://*/svn-repo (glob)
106 reparent to file://*/svn-repo/trunk (glob)
106 reparent to file://*/svn-repo/trunk (glob)
107 getting files: \xc3\xa8 1/2 (50.00%) (esc)
107 getting files: \xc3\xa8 1/2 files (50.00%) (esc)
108 getting files: \xc3\xb9/e\xcc\x81 2/2 (100.00%) (esc)
108 getting files: \xc3\xb9/e\xcc\x81 2/2 files (100.00%) (esc)
109 committing files:
109 committing files:
110 committing manifest
110 committing manifest
111 committing changelog
111 committing changelog
112 1 branch to branch?
112 1 branch to branch?
113 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?@5
113 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?@5
114 converting: 4/6 revisions (66.67%)
114 converting: 4/6 revisions (66.67%)
115 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
115 reparent to file://*/svn-repo/branches/branch%C3%A9 (glob)
116 scanning paths: /branches/branch\xc3\xa9 0/1 (0.00%) (esc)
116 scanning paths: /branches/branch\xc3\xa9 0/1 (0.00%) (esc)
117 committing changelog
117 committing changelog
118 0 branch to branch?e
118 0 branch to branch?e
119 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?e@6
119 source: svn:afeb9c47-92ff-4c0c-9f72-e1f6eb8ac9af/branches/branch?e@6
120 converting: 5/6 revisions (83.33%)
120 converting: 5/6 revisions (83.33%)
121 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
121 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
122 scanning paths: /branches/branch\xc3\xa9e 0/1 (0.00%) (esc)
122 scanning paths: /branches/branch\xc3\xa9e 0/1 (0.00%) (esc)
123 committing changelog
123 committing changelog
124 reparent to file://*/svn-repo (glob)
124 reparent to file://*/svn-repo (glob)
125 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
125 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
126 reparent to file://*/svn-repo (glob)
126 reparent to file://*/svn-repo (glob)
127 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
127 reparent to file://*/svn-repo/branches/branch%C3%A9e (glob)
128 updating tags
128 updating tags
129 committing files:
129 committing files:
130 .hgtags
130 .hgtags
131 committing manifest
131 committing manifest
132 committing changelog
132 committing changelog
133 run hg sink post-conversion action
133 run hg sink post-conversion action
134 $ cd A-hg
134 $ cd A-hg
135 $ hg up
135 $ hg up
136 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
136 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
137
137
138 Check tags are in UTF-8
138 Check tags are in UTF-8
139
139
140 $ cat .hgtags
140 $ cat .hgtags
141 e94e4422020e715add80525e8f0f46c9968689f1 branch\xc3\xa9e (esc)
141 e94e4422020e715add80525e8f0f46c9968689f1 branch\xc3\xa9e (esc)
142 f7e66f98380ed1e53a797c5c7a7a2616a7ab377d branch\xc3\xa9 (esc)
142 f7e66f98380ed1e53a797c5c7a7a2616a7ab377d branch\xc3\xa9 (esc)
143
143
144 $ cd ..
144 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now