##// END OF EJS Templates
convert: use '.' as destination name if renaming subdir into root
Bryan O'Sullivan -
r5133:745cffe5 default
parent child Browse files
Show More
@@ -1,456 +1,459 b''
1 # convert.py Foreign SCM converter
1 # convert.py Foreign SCM converter
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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from common import NoRepo, converter_source, converter_sink, decodeargs
8 from common import NoRepo, converter_source, converter_sink, decodeargs
9 from cvs import convert_cvs
9 from cvs import convert_cvs
10 from git import convert_git
10 from git import convert_git
11 from hg import mercurial_source, mercurial_sink
11 from hg import mercurial_source, mercurial_sink
12 from subversion import convert_svn
12 from subversion import convert_svn
13
13
14 import os, shlex, shutil, sys
14 import os, shlex, shutil, sys
15 from mercurial import hg, ui, util, commands
15 from mercurial import hg, ui, util, commands
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17
17
18 commands.norepo += " convert debug-svn-log"
18 commands.norepo += " convert debug-svn-log"
19
19
20 converters = [convert_cvs, convert_git, convert_svn, mercurial_source,
20 converters = [convert_cvs, convert_git, convert_svn, mercurial_source,
21 mercurial_sink]
21 mercurial_sink]
22
22
23 def convertsource(ui, path, **opts):
23 def convertsource(ui, path, **opts):
24 for c in converters:
24 for c in converters:
25 try:
25 try:
26 return c.getcommit and c(ui, path, **opts)
26 return c.getcommit and c(ui, path, **opts)
27 except (AttributeError, NoRepo):
27 except (AttributeError, NoRepo):
28 pass
28 pass
29 raise util.Abort('%s: unknown repository type' % path)
29 raise util.Abort('%s: unknown repository type' % path)
30
30
31 def convertsink(ui, path):
31 def convertsink(ui, path):
32 if not os.path.isdir(path):
32 if not os.path.isdir(path):
33 raise util.Abort("%s: not a directory" % path)
33 raise util.Abort("%s: not a directory" % path)
34 for c in converters:
34 for c in converters:
35 try:
35 try:
36 return c.putcommit and c(ui, path)
36 return c.putcommit and c(ui, path)
37 except (AttributeError, NoRepo):
37 except (AttributeError, NoRepo):
38 pass
38 pass
39 raise util.Abort('%s: unknown repository type' % path)
39 raise util.Abort('%s: unknown repository type' % path)
40
40
41 class convert(object):
41 class convert(object):
42 def __init__(self, ui, source, dest, revmapfile, filemapper, opts):
42 def __init__(self, ui, source, dest, revmapfile, filemapper, opts):
43
43
44 self.source = source
44 self.source = source
45 self.dest = dest
45 self.dest = dest
46 self.ui = ui
46 self.ui = ui
47 self.opts = opts
47 self.opts = opts
48 self.commitcache = {}
48 self.commitcache = {}
49 self.revmapfile = revmapfile
49 self.revmapfile = revmapfile
50 self.revmapfilefd = None
50 self.revmapfilefd = None
51 self.authors = {}
51 self.authors = {}
52 self.authorfile = None
52 self.authorfile = None
53 self.mapfile = filemapper
53 self.mapfile = filemapper
54
54
55 self.map = {}
55 self.map = {}
56 try:
56 try:
57 origrevmapfile = open(self.revmapfile, 'r')
57 origrevmapfile = open(self.revmapfile, 'r')
58 for l in origrevmapfile:
58 for l in origrevmapfile:
59 sv, dv = l[:-1].split()
59 sv, dv = l[:-1].split()
60 self.map[sv] = dv
60 self.map[sv] = dv
61 origrevmapfile.close()
61 origrevmapfile.close()
62 except IOError:
62 except IOError:
63 pass
63 pass
64
64
65 # Read first the dst author map if any
65 # Read first the dst author map if any
66 authorfile = self.dest.authorfile()
66 authorfile = self.dest.authorfile()
67 if authorfile and os.path.exists(authorfile):
67 if authorfile and os.path.exists(authorfile):
68 self.readauthormap(authorfile)
68 self.readauthormap(authorfile)
69 # Extend/Override with new author map if necessary
69 # Extend/Override with new author map if necessary
70 if opts.get('authors'):
70 if opts.get('authors'):
71 self.readauthormap(opts.get('authors'))
71 self.readauthormap(opts.get('authors'))
72 self.authorfile = self.dest.authorfile()
72 self.authorfile = self.dest.authorfile()
73
73
74 def walktree(self, heads):
74 def walktree(self, heads):
75 '''Return a mapping that identifies the uncommitted parents of every
75 '''Return a mapping that identifies the uncommitted parents of every
76 uncommitted changeset.'''
76 uncommitted changeset.'''
77 visit = heads
77 visit = heads
78 known = {}
78 known = {}
79 parents = {}
79 parents = {}
80 while visit:
80 while visit:
81 n = visit.pop(0)
81 n = visit.pop(0)
82 if n in known or n in self.map: continue
82 if n in known or n in self.map: continue
83 known[n] = 1
83 known[n] = 1
84 self.commitcache[n] = self.source.getcommit(n)
84 self.commitcache[n] = self.source.getcommit(n)
85 cp = self.commitcache[n].parents
85 cp = self.commitcache[n].parents
86 parents[n] = []
86 parents[n] = []
87 for p in cp:
87 for p in cp:
88 parents[n].append(p)
88 parents[n].append(p)
89 visit.append(p)
89 visit.append(p)
90
90
91 return parents
91 return parents
92
92
93 def toposort(self, parents):
93 def toposort(self, parents):
94 '''Return an ordering such that every uncommitted changeset is
94 '''Return an ordering such that every uncommitted changeset is
95 preceeded by all its uncommitted ancestors.'''
95 preceeded by all its uncommitted ancestors.'''
96 visit = parents.keys()
96 visit = parents.keys()
97 seen = {}
97 seen = {}
98 children = {}
98 children = {}
99
99
100 while visit:
100 while visit:
101 n = visit.pop(0)
101 n = visit.pop(0)
102 if n in seen: continue
102 if n in seen: continue
103 seen[n] = 1
103 seen[n] = 1
104 # Ensure that nodes without parents are present in the 'children'
104 # Ensure that nodes without parents are present in the 'children'
105 # mapping.
105 # mapping.
106 children.setdefault(n, [])
106 children.setdefault(n, [])
107 for p in parents[n]:
107 for p in parents[n]:
108 if not p in self.map:
108 if not p in self.map:
109 visit.append(p)
109 visit.append(p)
110 children.setdefault(p, []).append(n)
110 children.setdefault(p, []).append(n)
111
111
112 s = []
112 s = []
113 removed = {}
113 removed = {}
114 visit = children.keys()
114 visit = children.keys()
115 while visit:
115 while visit:
116 n = visit.pop(0)
116 n = visit.pop(0)
117 if n in removed: continue
117 if n in removed: continue
118 dep = 0
118 dep = 0
119 if n in parents:
119 if n in parents:
120 for p in parents[n]:
120 for p in parents[n]:
121 if p in self.map: continue
121 if p in self.map: continue
122 if p not in removed:
122 if p not in removed:
123 # we're still dependent
123 # we're still dependent
124 visit.append(n)
124 visit.append(n)
125 dep = 1
125 dep = 1
126 break
126 break
127
127
128 if not dep:
128 if not dep:
129 # all n's parents are in the list
129 # all n's parents are in the list
130 removed[n] = 1
130 removed[n] = 1
131 if n not in self.map:
131 if n not in self.map:
132 s.append(n)
132 s.append(n)
133 if n in children:
133 if n in children:
134 for c in children[n]:
134 for c in children[n]:
135 visit.insert(0, c)
135 visit.insert(0, c)
136
136
137 if self.opts.get('datesort'):
137 if self.opts.get('datesort'):
138 depth = {}
138 depth = {}
139 for n in s:
139 for n in s:
140 depth[n] = 0
140 depth[n] = 0
141 pl = [p for p in self.commitcache[n].parents
141 pl = [p for p in self.commitcache[n].parents
142 if p not in self.map]
142 if p not in self.map]
143 if pl:
143 if pl:
144 depth[n] = max([depth[p] for p in pl]) + 1
144 depth[n] = max([depth[p] for p in pl]) + 1
145
145
146 s = [(depth[n], self.commitcache[n].date, n) for n in s]
146 s = [(depth[n], self.commitcache[n].date, n) for n in s]
147 s.sort()
147 s.sort()
148 s = [e[2] for e in s]
148 s = [e[2] for e in s]
149
149
150 return s
150 return s
151
151
152 def mapentry(self, src, dst):
152 def mapentry(self, src, dst):
153 if self.revmapfilefd is None:
153 if self.revmapfilefd is None:
154 try:
154 try:
155 self.revmapfilefd = open(self.revmapfile, "a")
155 self.revmapfilefd = open(self.revmapfile, "a")
156 except IOError, (errno, strerror):
156 except IOError, (errno, strerror):
157 raise util.Abort("Could not open map file %s: %s, %s\n" % (self.revmapfile, errno, strerror))
157 raise util.Abort("Could not open map file %s: %s, %s\n" % (self.revmapfile, errno, strerror))
158 self.map[src] = dst
158 self.map[src] = dst
159 self.revmapfilefd.write("%s %s\n" % (src, dst))
159 self.revmapfilefd.write("%s %s\n" % (src, dst))
160 self.revmapfilefd.flush()
160 self.revmapfilefd.flush()
161
161
162 def writeauthormap(self):
162 def writeauthormap(self):
163 authorfile = self.authorfile
163 authorfile = self.authorfile
164 if authorfile:
164 if authorfile:
165 self.ui.status('Writing author map file %s\n' % authorfile)
165 self.ui.status('Writing author map file %s\n' % authorfile)
166 ofile = open(authorfile, 'w+')
166 ofile = open(authorfile, 'w+')
167 for author in self.authors:
167 for author in self.authors:
168 ofile.write("%s=%s\n" % (author, self.authors[author]))
168 ofile.write("%s=%s\n" % (author, self.authors[author]))
169 ofile.close()
169 ofile.close()
170
170
171 def readauthormap(self, authorfile):
171 def readauthormap(self, authorfile):
172 afile = open(authorfile, 'r')
172 afile = open(authorfile, 'r')
173 for line in afile:
173 for line in afile:
174 try:
174 try:
175 srcauthor = line.split('=')[0].strip()
175 srcauthor = line.split('=')[0].strip()
176 dstauthor = line.split('=')[1].strip()
176 dstauthor = line.split('=')[1].strip()
177 if srcauthor in self.authors and dstauthor != self.authors[srcauthor]:
177 if srcauthor in self.authors and dstauthor != self.authors[srcauthor]:
178 self.ui.status(
178 self.ui.status(
179 'Overriding mapping for author %s, was %s, will be %s\n'
179 'Overriding mapping for author %s, was %s, will be %s\n'
180 % (srcauthor, self.authors[srcauthor], dstauthor))
180 % (srcauthor, self.authors[srcauthor], dstauthor))
181 else:
181 else:
182 self.ui.debug('Mapping author %s to %s\n'
182 self.ui.debug('Mapping author %s to %s\n'
183 % (srcauthor, dstauthor))
183 % (srcauthor, dstauthor))
184 self.authors[srcauthor] = dstauthor
184 self.authors[srcauthor] = dstauthor
185 except IndexError:
185 except IndexError:
186 self.ui.warn(
186 self.ui.warn(
187 'Ignoring bad line in author file map %s: %s\n'
187 'Ignoring bad line in author file map %s: %s\n'
188 % (authorfile, line))
188 % (authorfile, line))
189 afile.close()
189 afile.close()
190
190
191 def copy(self, rev):
191 def copy(self, rev):
192 commit = self.commitcache[rev]
192 commit = self.commitcache[rev]
193 do_copies = hasattr(self.dest, 'copyfile')
193 do_copies = hasattr(self.dest, 'copyfile')
194 filenames = []
194 filenames = []
195
195
196 files, copies = self.source.getchanges(rev)
196 files, copies = self.source.getchanges(rev)
197 for f, v in files:
197 for f, v in files:
198 newf = self.mapfile(f)
198 newf = self.mapfile(f)
199 if not newf:
199 if not newf:
200 continue
200 continue
201 filenames.append(newf)
201 filenames.append(newf)
202 try:
202 try:
203 data = self.source.getfile(f, v)
203 data = self.source.getfile(f, v)
204 except IOError, inst:
204 except IOError, inst:
205 self.dest.delfile(newf)
205 self.dest.delfile(newf)
206 else:
206 else:
207 e = self.source.getmode(f, v)
207 e = self.source.getmode(f, v)
208 self.dest.putfile(newf, e, data)
208 self.dest.putfile(newf, e, data)
209 if do_copies:
209 if do_copies:
210 if f in copies:
210 if f in copies:
211 copyf = self.mapfile(copies[f])
211 copyf = self.mapfile(copies[f])
212 if copyf:
212 if copyf:
213 # Merely marks that a copy happened.
213 # Merely marks that a copy happened.
214 self.dest.copyfile(copyf, newf)
214 self.dest.copyfile(copyf, newf)
215
215
216 parents = [self.map[r] for r in commit.parents]
216 parents = [self.map[r] for r in commit.parents]
217 newnode = self.dest.putcommit(filenames, parents, commit)
217 newnode = self.dest.putcommit(filenames, parents, commit)
218 self.mapentry(rev, newnode)
218 self.mapentry(rev, newnode)
219
219
220 def convert(self):
220 def convert(self):
221 try:
221 try:
222 self.dest.before()
222 self.dest.before()
223 self.source.setrevmap(self.map)
223 self.source.setrevmap(self.map)
224 self.ui.status("scanning source...\n")
224 self.ui.status("scanning source...\n")
225 heads = self.source.getheads()
225 heads = self.source.getheads()
226 parents = self.walktree(heads)
226 parents = self.walktree(heads)
227 self.ui.status("sorting...\n")
227 self.ui.status("sorting...\n")
228 t = self.toposort(parents)
228 t = self.toposort(parents)
229 num = len(t)
229 num = len(t)
230 c = None
230 c = None
231
231
232 self.ui.status("converting...\n")
232 self.ui.status("converting...\n")
233 for c in t:
233 for c in t:
234 num -= 1
234 num -= 1
235 desc = self.commitcache[c].desc
235 desc = self.commitcache[c].desc
236 if "\n" in desc:
236 if "\n" in desc:
237 desc = desc.splitlines()[0]
237 desc = desc.splitlines()[0]
238 author = self.commitcache[c].author
238 author = self.commitcache[c].author
239 author = self.authors.get(author, author)
239 author = self.authors.get(author, author)
240 self.commitcache[c].author = author
240 self.commitcache[c].author = author
241 self.ui.status("%d %s\n" % (num, desc))
241 self.ui.status("%d %s\n" % (num, desc))
242 self.copy(c)
242 self.copy(c)
243
243
244 tags = self.source.gettags()
244 tags = self.source.gettags()
245 ctags = {}
245 ctags = {}
246 for k in tags:
246 for k in tags:
247 v = tags[k]
247 v = tags[k]
248 if v in self.map:
248 if v in self.map:
249 ctags[k] = self.map[v]
249 ctags[k] = self.map[v]
250
250
251 if c and ctags:
251 if c and ctags:
252 nrev = self.dest.puttags(ctags)
252 nrev = self.dest.puttags(ctags)
253 # write another hash correspondence to override the previous
253 # write another hash correspondence to override the previous
254 # one so we don't end up with extra tag heads
254 # one so we don't end up with extra tag heads
255 if nrev:
255 if nrev:
256 self.mapentry(c, nrev)
256 self.mapentry(c, nrev)
257
257
258 self.writeauthormap()
258 self.writeauthormap()
259 finally:
259 finally:
260 self.cleanup()
260 self.cleanup()
261
261
262 def cleanup(self):
262 def cleanup(self):
263 self.dest.after()
263 self.dest.after()
264 if self.revmapfilefd:
264 if self.revmapfilefd:
265 self.revmapfilefd.close()
265 self.revmapfilefd.close()
266
266
267 def rpairs(name):
267 def rpairs(name):
268 e = len(name)
268 e = len(name)
269 while e != -1:
269 while e != -1:
270 yield name[:e], name[e+1:]
270 yield name[:e], name[e+1:]
271 e = name.rfind('/', 0, e)
271 e = name.rfind('/', 0, e)
272
272
273 class filemapper(object):
273 class filemapper(object):
274 '''Map and filter filenames when importing.
274 '''Map and filter filenames when importing.
275 A name can be mapped to itself, a new name, or None (omit from new
275 A name can be mapped to itself, a new name, or None (omit from new
276 repository).'''
276 repository).'''
277
277
278 def __init__(self, ui, path=None):
278 def __init__(self, ui, path=None):
279 self.ui = ui
279 self.ui = ui
280 self.include = {}
280 self.include = {}
281 self.exclude = {}
281 self.exclude = {}
282 self.rename = {}
282 self.rename = {}
283 if path:
283 if path:
284 if self.parse(path):
284 if self.parse(path):
285 raise util.Abort(_('errors in filemap'))
285 raise util.Abort(_('errors in filemap'))
286
286
287 def parse(self, path):
287 def parse(self, path):
288 errs = 0
288 errs = 0
289 def check(name, mapping, listname):
289 def check(name, mapping, listname):
290 if name in mapping:
290 if name in mapping:
291 self.ui.warn(_('%s:%d: %r already in %s list\n') %
291 self.ui.warn(_('%s:%d: %r already in %s list\n') %
292 (lex.infile, lex.lineno, name, listname))
292 (lex.infile, lex.lineno, name, listname))
293 return 1
293 return 1
294 return 0
294 return 0
295 lex = shlex.shlex(open(path), path, True)
295 lex = shlex.shlex(open(path), path, True)
296 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
296 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
297 cmd = lex.get_token()
297 cmd = lex.get_token()
298 while cmd:
298 while cmd:
299 if cmd == 'include':
299 if cmd == 'include':
300 name = lex.get_token()
300 name = lex.get_token()
301 errs += check(name, self.exclude, 'exclude')
301 errs += check(name, self.exclude, 'exclude')
302 self.include[name] = name
302 self.include[name] = name
303 elif cmd == 'exclude':
303 elif cmd == 'exclude':
304 name = lex.get_token()
304 name = lex.get_token()
305 errs += check(name, self.include, 'include')
305 errs += check(name, self.include, 'include')
306 errs += check(name, self.rename, 'rename')
306 errs += check(name, self.rename, 'rename')
307 self.exclude[name] = name
307 self.exclude[name] = name
308 elif cmd == 'rename':
308 elif cmd == 'rename':
309 src = lex.get_token()
309 src = lex.get_token()
310 dest = lex.get_token()
310 dest = lex.get_token()
311 errs += check(src, self.exclude, 'exclude')
311 errs += check(src, self.exclude, 'exclude')
312 self.rename[src] = dest
312 self.rename[src] = dest
313 elif cmd == 'source':
313 elif cmd == 'source':
314 errs += self.parse(lex.get_token())
314 errs += self.parse(lex.get_token())
315 else:
315 else:
316 self.ui.warn(_('%s:%d: unknown directive %r\n') %
316 self.ui.warn(_('%s:%d: unknown directive %r\n') %
317 (lex.infile, lex.lineno, cmd))
317 (lex.infile, lex.lineno, cmd))
318 errs += 1
318 errs += 1
319 cmd = lex.get_token()
319 cmd = lex.get_token()
320 return errs
320 return errs
321
321
322 def lookup(self, name, mapping):
322 def lookup(self, name, mapping):
323 for pre, suf in rpairs(name):
323 for pre, suf in rpairs(name):
324 try:
324 try:
325 return mapping[pre], pre, suf
325 return mapping[pre], pre, suf
326 except KeyError, err:
326 except KeyError, err:
327 pass
327 pass
328 return '', name, ''
328 return '', name, ''
329
329
330 def __call__(self, name):
330 def __call__(self, name):
331 if self.include:
331 if self.include:
332 inc = self.lookup(name, self.include)[0]
332 inc = self.lookup(name, self.include)[0]
333 else:
333 else:
334 inc = name
334 inc = name
335 if self.exclude:
335 if self.exclude:
336 exc = self.lookup(name, self.exclude)[0]
336 exc = self.lookup(name, self.exclude)[0]
337 else:
337 else:
338 exc = ''
338 exc = ''
339 if not inc or exc:
339 if not inc or exc:
340 return None
340 return None
341 newpre, pre, suf = self.lookup(name, self.rename)
341 newpre, pre, suf = self.lookup(name, self.rename)
342 print 'XXX', (newpre, pre, suf)
342 if newpre:
343 if newpre:
344 if newpre == '.':
345 return suf
343 if suf:
346 if suf:
344 return newpre + '/' + suf
347 return newpre + '/' + suf
345 return newpre
348 return newpre
346 return name
349 return name
347
350
348 def _convert(ui, src, dest=None, revmapfile=None, **opts):
351 def _convert(ui, src, dest=None, revmapfile=None, **opts):
349 """Convert a foreign SCM repository to a Mercurial one.
352 """Convert a foreign SCM repository to a Mercurial one.
350
353
351 Accepted source formats:
354 Accepted source formats:
352 - GIT
355 - GIT
353 - CVS
356 - CVS
354 - SVN
357 - SVN
355
358
356 Accepted destination formats:
359 Accepted destination formats:
357 - Mercurial
360 - Mercurial
358
361
359 If no revision is given, all revisions will be converted. Otherwise,
362 If no revision is given, all revisions will be converted. Otherwise,
360 convert will only import up to the named revision (given in a format
363 convert will only import up to the named revision (given in a format
361 understood by the source).
364 understood by the source).
362
365
363 If no destination directory name is specified, it defaults to the
366 If no destination directory name is specified, it defaults to the
364 basename of the source with '-hg' appended. If the destination
367 basename of the source with '-hg' appended. If the destination
365 repository doesn't exist, it will be created.
368 repository doesn't exist, it will be created.
366
369
367 If <revmapfile> isn't given, it will be put in a default location
370 If <revmapfile> isn't given, it will be put in a default location
368 (<dest>/.hg/shamap by default). The <revmapfile> is a simple text
371 (<dest>/.hg/shamap by default). The <revmapfile> is a simple text
369 file that maps each source commit ID to the destination ID for
372 file that maps each source commit ID to the destination ID for
370 that revision, like so:
373 that revision, like so:
371 <source ID> <destination ID>
374 <source ID> <destination ID>
372
375
373 If the file doesn't exist, it's automatically created. It's updated
376 If the file doesn't exist, it's automatically created. It's updated
374 on each commit copied, so convert-repo can be interrupted and can
377 on each commit copied, so convert-repo can be interrupted and can
375 be run repeatedly to copy new commits.
378 be run repeatedly to copy new commits.
376
379
377 The [username mapping] file is a simple text file that maps each source
380 The [username mapping] file is a simple text file that maps each source
378 commit author to a destination commit author. It is handy for source SCMs
381 commit author to a destination commit author. It is handy for source SCMs
379 that use unix logins to identify authors (eg: CVS). One line per author
382 that use unix logins to identify authors (eg: CVS). One line per author
380 mapping and the line format is:
383 mapping and the line format is:
381 srcauthor=whatever string you want
384 srcauthor=whatever string you want
382 """
385 """
383
386
384 util._encoding = 'UTF-8'
387 util._encoding = 'UTF-8'
385
388
386 if not dest:
389 if not dest:
387 dest = hg.defaultdest(src) + "-hg"
390 dest = hg.defaultdest(src) + "-hg"
388 ui.status("assuming destination %s\n" % dest)
391 ui.status("assuming destination %s\n" % dest)
389
392
390 # Try to be smart and initalize things when required
393 # Try to be smart and initalize things when required
391 created = False
394 created = False
392 if os.path.isdir(dest):
395 if os.path.isdir(dest):
393 if len(os.listdir(dest)) > 0:
396 if len(os.listdir(dest)) > 0:
394 try:
397 try:
395 hg.repository(ui, dest)
398 hg.repository(ui, dest)
396 ui.status("destination %s is a Mercurial repository\n" % dest)
399 ui.status("destination %s is a Mercurial repository\n" % dest)
397 except hg.RepoError:
400 except hg.RepoError:
398 raise util.Abort(
401 raise util.Abort(
399 "destination directory %s is not empty.\n"
402 "destination directory %s is not empty.\n"
400 "Please specify an empty directory to be initialized\n"
403 "Please specify an empty directory to be initialized\n"
401 "or an already initialized mercurial repository"
404 "or an already initialized mercurial repository"
402 % dest)
405 % dest)
403 else:
406 else:
404 ui.status("initializing destination %s repository\n" % dest)
407 ui.status("initializing destination %s repository\n" % dest)
405 hg.repository(ui, dest, create=True)
408 hg.repository(ui, dest, create=True)
406 created = True
409 created = True
407 elif os.path.exists(dest):
410 elif os.path.exists(dest):
408 raise util.Abort("destination %s exists and is not a directory" % dest)
411 raise util.Abort("destination %s exists and is not a directory" % dest)
409 else:
412 else:
410 ui.status("initializing destination %s repository\n" % dest)
413 ui.status("initializing destination %s repository\n" % dest)
411 hg.repository(ui, dest, create=True)
414 hg.repository(ui, dest, create=True)
412 created = True
415 created = True
413
416
414 destc = convertsink(ui, dest)
417 destc = convertsink(ui, dest)
415
418
416 try:
419 try:
417 srcc = convertsource(ui, src, rev=opts.get('rev'))
420 srcc = convertsource(ui, src, rev=opts.get('rev'))
418 except Exception:
421 except Exception:
419 if created:
422 if created:
420 shutil.rmtree(dest, True)
423 shutil.rmtree(dest, True)
421 raise
424 raise
422
425
423 if not revmapfile:
426 if not revmapfile:
424 try:
427 try:
425 revmapfile = destc.revmapfile()
428 revmapfile = destc.revmapfile()
426 except:
429 except:
427 revmapfile = os.path.join(destc, "map")
430 revmapfile = os.path.join(destc, "map")
428
431
429
432
430 c = convert(ui, srcc, destc, revmapfile, filemapper(ui, opts['filemap']),
433 c = convert(ui, srcc, destc, revmapfile, filemapper(ui, opts['filemap']),
431 opts)
434 opts)
432 c.convert()
435 c.convert()
433
436
434 def debugsvnlog(ui, **opts):
437 def debugsvnlog(ui, **opts):
435 """Fetch SVN log in a subprocess and channel them back to parent to
438 """Fetch SVN log in a subprocess and channel them back to parent to
436 avoid memory collection issues.
439 avoid memory collection issues.
437 """
440 """
438 util.set_binary(sys.stdin)
441 util.set_binary(sys.stdin)
439 util.set_binary(sys.stdout)
442 util.set_binary(sys.stdout)
440 args = decodeargs(sys.stdin.read())
443 args = decodeargs(sys.stdin.read())
441 subversion.get_log_child(sys.stdout, *args)
444 subversion.get_log_child(sys.stdout, *args)
442
445
443 cmdtable = {
446 cmdtable = {
444 "convert":
447 "convert":
445 (_convert,
448 (_convert,
446 [('A', 'authors', '', 'username mapping filename'),
449 [('A', 'authors', '', 'username mapping filename'),
447 ('', 'filemap', '', 'remap file names using contents of file'),
450 ('', 'filemap', '', 'remap file names using contents of file'),
448 ('r', 'rev', '', 'import up to target revision REV'),
451 ('r', 'rev', '', 'import up to target revision REV'),
449 ('', 'datesort', None, 'try to sort changesets by date')],
452 ('', 'datesort', None, 'try to sort changesets by date')],
450 'hg convert [OPTION]... SOURCE [DEST [MAPFILE]]'),
453 'hg convert [OPTION]... SOURCE [DEST [MAPFILE]]'),
451 "debug-svn-log":
454 "debug-svn-log":
452 (debugsvnlog,
455 (debugsvnlog,
453 [],
456 [],
454 'hg debug-svn-log'),
457 'hg debug-svn-log'),
455 }
458 }
456
459
General Comments 0
You need to be logged in to leave comments. Login now