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