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