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