##// END OF EJS Templates
convert: Avoid redundant newline on authormap errors....
Marti Raudsepp -
r6185:c48d778d default
parent child Browse files
Show More
@@ -1,351 +1,351 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
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, SKIPREV, converter_source, converter_sink, mapfile
8 from common import NoRepo, SKIPREV, converter_source, converter_sink, mapfile
9 from cvs import convert_cvs
9 from cvs import convert_cvs
10 from darcs import darcs_source
10 from darcs import darcs_source
11 from git import convert_git
11 from git import convert_git
12 from hg import mercurial_source, mercurial_sink
12 from hg import mercurial_source, mercurial_sink
13 from subversion import debugsvnlog, svn_source, svn_sink
13 from subversion import debugsvnlog, svn_source, svn_sink
14 from gnuarch import gnuarch_source
14 from gnuarch import gnuarch_source
15 import filemap
15 import filemap
16
16
17 import os, shutil
17 import os, shutil
18 from mercurial import hg, util
18 from mercurial import hg, util
19 from mercurial.i18n import _
19 from mercurial.i18n import _
20
20
21 orig_encoding = 'ascii'
21 orig_encoding = 'ascii'
22
22
23 def recode(s):
23 def recode(s):
24 if isinstance(s, unicode):
24 if isinstance(s, unicode):
25 return s.encode(orig_encoding, 'replace')
25 return s.encode(orig_encoding, 'replace')
26 else:
26 else:
27 return s.decode('utf-8').encode(orig_encoding, 'replace')
27 return s.decode('utf-8').encode(orig_encoding, 'replace')
28
28
29 source_converters = [
29 source_converters = [
30 ('cvs', convert_cvs),
30 ('cvs', convert_cvs),
31 ('git', convert_git),
31 ('git', convert_git),
32 ('svn', svn_source),
32 ('svn', svn_source),
33 ('hg', mercurial_source),
33 ('hg', mercurial_source),
34 ('darcs', darcs_source),
34 ('darcs', darcs_source),
35 ('gnuarch', gnuarch_source),
35 ('gnuarch', gnuarch_source),
36 ]
36 ]
37
37
38 sink_converters = [
38 sink_converters = [
39 ('hg', mercurial_sink),
39 ('hg', mercurial_sink),
40 ('svn', svn_sink),
40 ('svn', svn_sink),
41 ]
41 ]
42
42
43 def convertsource(ui, path, type, rev):
43 def convertsource(ui, path, type, rev):
44 exceptions = []
44 exceptions = []
45 for name, source in source_converters:
45 for name, source in source_converters:
46 try:
46 try:
47 if not type or name == type:
47 if not type or name == type:
48 return source(ui, path, rev)
48 return source(ui, path, rev)
49 except NoRepo, inst:
49 except NoRepo, inst:
50 exceptions.append(inst)
50 exceptions.append(inst)
51 if not ui.quiet:
51 if not ui.quiet:
52 for inst in exceptions:
52 for inst in exceptions:
53 ui.write(_("%s\n") % inst)
53 ui.write(_("%s\n") % inst)
54 raise util.Abort('%s: unknown repository type' % path)
54 raise util.Abort('%s: unknown repository type' % path)
55
55
56 def convertsink(ui, path, type):
56 def convertsink(ui, path, type):
57 for name, sink in sink_converters:
57 for name, sink in sink_converters:
58 try:
58 try:
59 if not type or name == type:
59 if not type or name == type:
60 return sink(ui, path)
60 return sink(ui, path)
61 except NoRepo, inst:
61 except NoRepo, inst:
62 ui.note(_("convert: %s\n") % inst)
62 ui.note(_("convert: %s\n") % inst)
63 raise util.Abort('%s: unknown repository type' % path)
63 raise util.Abort('%s: unknown repository type' % path)
64
64
65 class converter(object):
65 class converter(object):
66 def __init__(self, ui, source, dest, revmapfile, opts):
66 def __init__(self, ui, source, dest, revmapfile, opts):
67
67
68 self.source = source
68 self.source = source
69 self.dest = dest
69 self.dest = dest
70 self.ui = ui
70 self.ui = ui
71 self.opts = opts
71 self.opts = opts
72 self.commitcache = {}
72 self.commitcache = {}
73 self.authors = {}
73 self.authors = {}
74 self.authorfile = None
74 self.authorfile = None
75
75
76 self.map = mapfile(ui, revmapfile)
76 self.map = mapfile(ui, revmapfile)
77
77
78 # Read first the dst author map if any
78 # Read first the dst author map if any
79 authorfile = self.dest.authorfile()
79 authorfile = self.dest.authorfile()
80 if authorfile and os.path.exists(authorfile):
80 if authorfile and os.path.exists(authorfile):
81 self.readauthormap(authorfile)
81 self.readauthormap(authorfile)
82 # Extend/Override with new author map if necessary
82 # Extend/Override with new author map if necessary
83 if opts.get('authors'):
83 if opts.get('authors'):
84 self.readauthormap(opts.get('authors'))
84 self.readauthormap(opts.get('authors'))
85 self.authorfile = self.dest.authorfile()
85 self.authorfile = self.dest.authorfile()
86
86
87 self.splicemap = mapfile(ui, opts.get('splicemap'))
87 self.splicemap = mapfile(ui, opts.get('splicemap'))
88
88
89 def walktree(self, heads):
89 def walktree(self, heads):
90 '''Return a mapping that identifies the uncommitted parents of every
90 '''Return a mapping that identifies the uncommitted parents of every
91 uncommitted changeset.'''
91 uncommitted changeset.'''
92 visit = heads
92 visit = heads
93 known = {}
93 known = {}
94 parents = {}
94 parents = {}
95 while visit:
95 while visit:
96 n = visit.pop(0)
96 n = visit.pop(0)
97 if n in known or n in self.map: continue
97 if n in known or n in self.map: continue
98 known[n] = 1
98 known[n] = 1
99 commit = self.cachecommit(n)
99 commit = self.cachecommit(n)
100 parents[n] = []
100 parents[n] = []
101 for p in commit.parents:
101 for p in commit.parents:
102 parents[n].append(p)
102 parents[n].append(p)
103 visit.append(p)
103 visit.append(p)
104
104
105 return parents
105 return parents
106
106
107 def toposort(self, parents):
107 def toposort(self, parents):
108 '''Return an ordering such that every uncommitted changeset is
108 '''Return an ordering such that every uncommitted changeset is
109 preceeded by all its uncommitted ancestors.'''
109 preceeded by all its uncommitted ancestors.'''
110 visit = parents.keys()
110 visit = parents.keys()
111 seen = {}
111 seen = {}
112 children = {}
112 children = {}
113 actives = []
113 actives = []
114
114
115 while visit:
115 while visit:
116 n = visit.pop(0)
116 n = visit.pop(0)
117 if n in seen: continue
117 if n in seen: continue
118 seen[n] = 1
118 seen[n] = 1
119 # Ensure that nodes without parents are present in the 'children'
119 # Ensure that nodes without parents are present in the 'children'
120 # mapping.
120 # mapping.
121 children.setdefault(n, [])
121 children.setdefault(n, [])
122 hasparent = False
122 hasparent = False
123 for p in parents[n]:
123 for p in parents[n]:
124 if not p in self.map:
124 if not p in self.map:
125 visit.append(p)
125 visit.append(p)
126 hasparent = True
126 hasparent = True
127 children.setdefault(p, []).append(n)
127 children.setdefault(p, []).append(n)
128 if not hasparent:
128 if not hasparent:
129 actives.append(n)
129 actives.append(n)
130
130
131 del seen
131 del seen
132 del visit
132 del visit
133
133
134 if self.opts.get('datesort'):
134 if self.opts.get('datesort'):
135 dates = {}
135 dates = {}
136 def getdate(n):
136 def getdate(n):
137 if n not in dates:
137 if n not in dates:
138 dates[n] = util.parsedate(self.commitcache[n].date)
138 dates[n] = util.parsedate(self.commitcache[n].date)
139 return dates[n]
139 return dates[n]
140
140
141 def picknext(nodes):
141 def picknext(nodes):
142 return min([(getdate(n), n) for n in nodes])[1]
142 return min([(getdate(n), n) for n in nodes])[1]
143 else:
143 else:
144 prev = [None]
144 prev = [None]
145 def picknext(nodes):
145 def picknext(nodes):
146 # Return the first eligible child of the previously converted
146 # Return the first eligible child of the previously converted
147 # revision, or any of them.
147 # revision, or any of them.
148 next = nodes[0]
148 next = nodes[0]
149 for n in nodes:
149 for n in nodes:
150 if prev[0] in parents[n]:
150 if prev[0] in parents[n]:
151 next = n
151 next = n
152 break
152 break
153 prev[0] = next
153 prev[0] = next
154 return next
154 return next
155
155
156 s = []
156 s = []
157 pendings = {}
157 pendings = {}
158 while actives:
158 while actives:
159 n = picknext(actives)
159 n = picknext(actives)
160 actives.remove(n)
160 actives.remove(n)
161 s.append(n)
161 s.append(n)
162
162
163 # Update dependents list
163 # Update dependents list
164 for c in children.get(n, []):
164 for c in children.get(n, []):
165 if c not in pendings:
165 if c not in pendings:
166 pendings[c] = [p for p in parents[c] if p not in self.map]
166 pendings[c] = [p for p in parents[c] if p not in self.map]
167 try:
167 try:
168 pendings[c].remove(n)
168 pendings[c].remove(n)
169 except ValueError:
169 except ValueError:
170 raise util.Abort(_('cycle detected between %s and %s')
170 raise util.Abort(_('cycle detected between %s and %s')
171 % (recode(c), recode(n)))
171 % (recode(c), recode(n)))
172 if not pendings[c]:
172 if not pendings[c]:
173 # Parents are converted, node is eligible
173 # Parents are converted, node is eligible
174 actives.insert(0, c)
174 actives.insert(0, c)
175 pendings[c] = None
175 pendings[c] = None
176
176
177 if len(s) != len(parents):
177 if len(s) != len(parents):
178 raise util.Abort(_("not all revisions were sorted"))
178 raise util.Abort(_("not all revisions were sorted"))
179
179
180 return s
180 return s
181
181
182 def writeauthormap(self):
182 def writeauthormap(self):
183 authorfile = self.authorfile
183 authorfile = self.authorfile
184 if authorfile:
184 if authorfile:
185 self.ui.status('Writing author map file %s\n' % authorfile)
185 self.ui.status('Writing author map file %s\n' % authorfile)
186 ofile = open(authorfile, 'w+')
186 ofile = open(authorfile, 'w+')
187 for author in self.authors:
187 for author in self.authors:
188 ofile.write("%s=%s\n" % (author, self.authors[author]))
188 ofile.write("%s=%s\n" % (author, self.authors[author]))
189 ofile.close()
189 ofile.close()
190
190
191 def readauthormap(self, authorfile):
191 def readauthormap(self, authorfile):
192 afile = open(authorfile, 'r')
192 afile = open(authorfile, 'r')
193 for line in afile:
193 for line in afile:
194 if line.strip() == '':
194 if line.strip() == '':
195 continue
195 continue
196 try:
196 try:
197 srcauthor = line.split('=')[0].strip()
197 srcauthor = line.split('=')[0].strip()
198 dstauthor = line.split('=')[1].strip()
198 dstauthor = line.split('=')[1].strip()
199 if srcauthor in self.authors and dstauthor != self.authors[srcauthor]:
199 if srcauthor in self.authors and dstauthor != self.authors[srcauthor]:
200 self.ui.status(
200 self.ui.status(
201 'Overriding mapping for author %s, was %s, will be %s\n'
201 'Overriding mapping for author %s, was %s, will be %s\n'
202 % (srcauthor, self.authors[srcauthor], dstauthor))
202 % (srcauthor, self.authors[srcauthor], dstauthor))
203 else:
203 else:
204 self.ui.debug('Mapping author %s to %s\n'
204 self.ui.debug('Mapping author %s to %s\n'
205 % (srcauthor, dstauthor))
205 % (srcauthor, dstauthor))
206 self.authors[srcauthor] = dstauthor
206 self.authors[srcauthor] = dstauthor
207 except IndexError:
207 except IndexError:
208 self.ui.warn(
208 self.ui.warn(
209 'Ignoring bad line in author file map %s: %s\n'
209 'Ignoring bad line in author map file %s: %s\n'
210 % (authorfile, line))
210 % (authorfile, line.rstrip()))
211 afile.close()
211 afile.close()
212
212
213 def cachecommit(self, rev):
213 def cachecommit(self, rev):
214 commit = self.source.getcommit(rev)
214 commit = self.source.getcommit(rev)
215 commit.author = self.authors.get(commit.author, commit.author)
215 commit.author = self.authors.get(commit.author, commit.author)
216 self.commitcache[rev] = commit
216 self.commitcache[rev] = commit
217 return commit
217 return commit
218
218
219 def copy(self, rev):
219 def copy(self, rev):
220 commit = self.commitcache[rev]
220 commit = self.commitcache[rev]
221 do_copies = hasattr(self.dest, 'copyfile')
221 do_copies = hasattr(self.dest, 'copyfile')
222 filenames = []
222 filenames = []
223
223
224 changes = self.source.getchanges(rev)
224 changes = self.source.getchanges(rev)
225 if isinstance(changes, basestring):
225 if isinstance(changes, basestring):
226 if changes == SKIPREV:
226 if changes == SKIPREV:
227 dest = SKIPREV
227 dest = SKIPREV
228 else:
228 else:
229 dest = self.map[changes]
229 dest = self.map[changes]
230 self.map[rev] = dest
230 self.map[rev] = dest
231 return
231 return
232 files, copies = changes
232 files, copies = changes
233 pbranches = []
233 pbranches = []
234 if commit.parents:
234 if commit.parents:
235 for prev in commit.parents:
235 for prev in commit.parents:
236 if prev not in self.commitcache:
236 if prev not in self.commitcache:
237 self.cachecommit(prev)
237 self.cachecommit(prev)
238 pbranches.append((self.map[prev],
238 pbranches.append((self.map[prev],
239 self.commitcache[prev].branch))
239 self.commitcache[prev].branch))
240 self.dest.setbranch(commit.branch, pbranches)
240 self.dest.setbranch(commit.branch, pbranches)
241 for f, v in files:
241 for f, v in files:
242 filenames.append(f)
242 filenames.append(f)
243 try:
243 try:
244 data = self.source.getfile(f, v)
244 data = self.source.getfile(f, v)
245 except IOError, inst:
245 except IOError, inst:
246 self.dest.delfile(f)
246 self.dest.delfile(f)
247 else:
247 else:
248 e = self.source.getmode(f, v)
248 e = self.source.getmode(f, v)
249 self.dest.putfile(f, e, data)
249 self.dest.putfile(f, e, data)
250 if do_copies:
250 if do_copies:
251 if f in copies:
251 if f in copies:
252 copyf = copies[f]
252 copyf = copies[f]
253 # Merely marks that a copy happened.
253 # Merely marks that a copy happened.
254 self.dest.copyfile(copyf, f)
254 self.dest.copyfile(copyf, f)
255
255
256 try:
256 try:
257 parents = self.splicemap[rev].replace(',', ' ').split()
257 parents = self.splicemap[rev].replace(',', ' ').split()
258 self.ui.status('spliced in %s as parents of %s\n' %
258 self.ui.status('spliced in %s as parents of %s\n' %
259 (parents, rev))
259 (parents, rev))
260 parents = [self.map.get(p, p) for p in parents]
260 parents = [self.map.get(p, p) for p in parents]
261 except KeyError:
261 except KeyError:
262 parents = [b[0] for b in pbranches]
262 parents = [b[0] for b in pbranches]
263 newnode = self.dest.putcommit(filenames, parents, commit)
263 newnode = self.dest.putcommit(filenames, parents, commit)
264 self.source.converted(rev, newnode)
264 self.source.converted(rev, newnode)
265 self.map[rev] = newnode
265 self.map[rev] = newnode
266
266
267 def convert(self):
267 def convert(self):
268
268
269 try:
269 try:
270 self.source.before()
270 self.source.before()
271 self.dest.before()
271 self.dest.before()
272 self.source.setrevmap(self.map)
272 self.source.setrevmap(self.map)
273 self.ui.status("scanning source...\n")
273 self.ui.status("scanning source...\n")
274 heads = self.source.getheads()
274 heads = self.source.getheads()
275 parents = self.walktree(heads)
275 parents = self.walktree(heads)
276 self.ui.status("sorting...\n")
276 self.ui.status("sorting...\n")
277 t = self.toposort(parents)
277 t = self.toposort(parents)
278 num = len(t)
278 num = len(t)
279 c = None
279 c = None
280
280
281 self.ui.status("converting...\n")
281 self.ui.status("converting...\n")
282 for c in t:
282 for c in t:
283 num -= 1
283 num -= 1
284 desc = self.commitcache[c].desc
284 desc = self.commitcache[c].desc
285 if "\n" in desc:
285 if "\n" in desc:
286 desc = desc.splitlines()[0]
286 desc = desc.splitlines()[0]
287 # convert log message to local encoding without using
287 # convert log message to local encoding without using
288 # tolocal() because util._encoding conver() use it as
288 # tolocal() because util._encoding conver() use it as
289 # 'utf-8'
289 # 'utf-8'
290 self.ui.status("%d %s\n" % (num, recode(desc)))
290 self.ui.status("%d %s\n" % (num, recode(desc)))
291 self.ui.note(_("source: %s\n" % recode(c)))
291 self.ui.note(_("source: %s\n" % recode(c)))
292 self.copy(c)
292 self.copy(c)
293
293
294 tags = self.source.gettags()
294 tags = self.source.gettags()
295 ctags = {}
295 ctags = {}
296 for k in tags:
296 for k in tags:
297 v = tags[k]
297 v = tags[k]
298 if self.map.get(v, SKIPREV) != SKIPREV:
298 if self.map.get(v, SKIPREV) != SKIPREV:
299 ctags[k] = self.map[v]
299 ctags[k] = self.map[v]
300
300
301 if c and ctags:
301 if c and ctags:
302 nrev = self.dest.puttags(ctags)
302 nrev = self.dest.puttags(ctags)
303 # write another hash correspondence to override the previous
303 # write another hash correspondence to override the previous
304 # one so we don't end up with extra tag heads
304 # one so we don't end up with extra tag heads
305 if nrev:
305 if nrev:
306 self.map[c] = nrev
306 self.map[c] = nrev
307
307
308 self.writeauthormap()
308 self.writeauthormap()
309 finally:
309 finally:
310 self.cleanup()
310 self.cleanup()
311
311
312 def cleanup(self):
312 def cleanup(self):
313 try:
313 try:
314 self.dest.after()
314 self.dest.after()
315 finally:
315 finally:
316 self.source.after()
316 self.source.after()
317 self.map.close()
317 self.map.close()
318
318
319 def convert(ui, src, dest=None, revmapfile=None, **opts):
319 def convert(ui, src, dest=None, revmapfile=None, **opts):
320 global orig_encoding
320 global orig_encoding
321 orig_encoding = util._encoding
321 orig_encoding = util._encoding
322 util._encoding = 'UTF-8'
322 util._encoding = 'UTF-8'
323
323
324 if not dest:
324 if not dest:
325 dest = hg.defaultdest(src) + "-hg"
325 dest = hg.defaultdest(src) + "-hg"
326 ui.status("assuming destination %s\n" % dest)
326 ui.status("assuming destination %s\n" % dest)
327
327
328 destc = convertsink(ui, dest, opts.get('dest_type'))
328 destc = convertsink(ui, dest, opts.get('dest_type'))
329
329
330 try:
330 try:
331 srcc = convertsource(ui, src, opts.get('source_type'),
331 srcc = convertsource(ui, src, opts.get('source_type'),
332 opts.get('rev'))
332 opts.get('rev'))
333 except Exception:
333 except Exception:
334 for path in destc.created:
334 for path in destc.created:
335 shutil.rmtree(path, True)
335 shutil.rmtree(path, True)
336 raise
336 raise
337
337
338 fmap = opts.get('filemap')
338 fmap = opts.get('filemap')
339 if fmap:
339 if fmap:
340 srcc = filemap.filemap_source(ui, srcc, fmap)
340 srcc = filemap.filemap_source(ui, srcc, fmap)
341 destc.setfilemapmode(True)
341 destc.setfilemapmode(True)
342
342
343 if not revmapfile:
343 if not revmapfile:
344 try:
344 try:
345 revmapfile = destc.revmapfile()
345 revmapfile = destc.revmapfile()
346 except:
346 except:
347 revmapfile = os.path.join(destc, "map")
347 revmapfile = os.path.join(destc, "map")
348
348
349 c = converter(ui, srcc, destc, revmapfile, opts)
349 c = converter(ui, srcc, destc, revmapfile, opts)
350 c.convert()
350 c.convert()
351
351
General Comments 0
You need to be logged in to leave comments. Login now