##// END OF EJS Templates
convert-hg: use localrepo.pull...
Pierre-Yves David -
r22698:32a8ad78 default
parent child Browse files
Show More
@@ -1,477 +1,478
1 # hg.py - hg backend for convert extension
1 # hg.py - hg backend for convert extension
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 # Notes for hg->hg conversion:
8 # Notes for hg->hg conversion:
9 #
9 #
10 # * Old versions of Mercurial didn't trim the whitespace from the ends
10 # * Old versions of Mercurial didn't trim the whitespace from the ends
11 # of commit messages, but new versions do. Changesets created by
11 # of commit messages, but new versions do. Changesets created by
12 # those older versions, then converted, may thus have different
12 # those older versions, then converted, may thus have different
13 # hashes for changesets that are otherwise identical.
13 # hashes for changesets that are otherwise identical.
14 #
14 #
15 # * Using "--config convert.hg.saverev=true" will make the source
15 # * Using "--config convert.hg.saverev=true" will make the source
16 # identifier to be stored in the converted revision. This will cause
16 # identifier to be stored in the converted revision. This will cause
17 # the converted revision to have a different identity than the
17 # the converted revision to have a different identity than the
18 # source.
18 # source.
19
19
20
20
21 import os, time, cStringIO
21 import os, time, cStringIO
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23 from mercurial.node import bin, hex, nullid
23 from mercurial.node import bin, hex, nullid
24 from mercurial import hg, util, context, bookmarks, error, scmutil
24 from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
25
25
26 from common import NoRepo, commit, converter_source, converter_sink
26 from common import NoRepo, commit, converter_source, converter_sink
27
27
28 import re
28 import re
29 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
29 sha1re = re.compile(r'\b[0-9a-f]{6,40}\b')
30
30
31 class mercurial_sink(converter_sink):
31 class mercurial_sink(converter_sink):
32 def __init__(self, ui, path):
32 def __init__(self, ui, path):
33 converter_sink.__init__(self, ui, path)
33 converter_sink.__init__(self, ui, path)
34 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
34 self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True)
35 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
35 self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False)
36 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
36 self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default')
37 self.lastbranch = None
37 self.lastbranch = None
38 if os.path.isdir(path) and len(os.listdir(path)) > 0:
38 if os.path.isdir(path) and len(os.listdir(path)) > 0:
39 try:
39 try:
40 self.repo = hg.repository(self.ui, path)
40 self.repo = hg.repository(self.ui, path)
41 if not self.repo.local():
41 if not self.repo.local():
42 raise NoRepo(_('%s is not a local Mercurial repository')
42 raise NoRepo(_('%s is not a local Mercurial repository')
43 % path)
43 % path)
44 except error.RepoError, err:
44 except error.RepoError, err:
45 ui.traceback()
45 ui.traceback()
46 raise NoRepo(err.args[0])
46 raise NoRepo(err.args[0])
47 else:
47 else:
48 try:
48 try:
49 ui.status(_('initializing destination %s repository\n') % path)
49 ui.status(_('initializing destination %s repository\n') % path)
50 self.repo = hg.repository(self.ui, path, create=True)
50 self.repo = hg.repository(self.ui, path, create=True)
51 if not self.repo.local():
51 if not self.repo.local():
52 raise NoRepo(_('%s is not a local Mercurial repository')
52 raise NoRepo(_('%s is not a local Mercurial repository')
53 % path)
53 % path)
54 self.created.append(path)
54 self.created.append(path)
55 except error.RepoError:
55 except error.RepoError:
56 ui.traceback()
56 ui.traceback()
57 raise NoRepo(_("could not create hg repository %s as sink")
57 raise NoRepo(_("could not create hg repository %s as sink")
58 % path)
58 % path)
59 self.lock = None
59 self.lock = None
60 self.wlock = None
60 self.wlock = None
61 self.filemapmode = False
61 self.filemapmode = False
62
62
63 def before(self):
63 def before(self):
64 self.ui.debug('run hg sink pre-conversion action\n')
64 self.ui.debug('run hg sink pre-conversion action\n')
65 self.wlock = self.repo.wlock()
65 self.wlock = self.repo.wlock()
66 self.lock = self.repo.lock()
66 self.lock = self.repo.lock()
67
67
68 def after(self):
68 def after(self):
69 self.ui.debug('run hg sink post-conversion action\n')
69 self.ui.debug('run hg sink post-conversion action\n')
70 if self.lock:
70 if self.lock:
71 self.lock.release()
71 self.lock.release()
72 if self.wlock:
72 if self.wlock:
73 self.wlock.release()
73 self.wlock.release()
74
74
75 def revmapfile(self):
75 def revmapfile(self):
76 return self.repo.join("shamap")
76 return self.repo.join("shamap")
77
77
78 def authorfile(self):
78 def authorfile(self):
79 return self.repo.join("authormap")
79 return self.repo.join("authormap")
80
80
81 def setbranch(self, branch, pbranches):
81 def setbranch(self, branch, pbranches):
82 if not self.clonebranches:
82 if not self.clonebranches:
83 return
83 return
84
84
85 setbranch = (branch != self.lastbranch)
85 setbranch = (branch != self.lastbranch)
86 self.lastbranch = branch
86 self.lastbranch = branch
87 if not branch:
87 if not branch:
88 branch = 'default'
88 branch = 'default'
89 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
89 pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches]
90 pbranch = pbranches and pbranches[0][1] or 'default'
90 pbranch = pbranches and pbranches[0][1] or 'default'
91
91
92 branchpath = os.path.join(self.path, branch)
92 branchpath = os.path.join(self.path, branch)
93 if setbranch:
93 if setbranch:
94 self.after()
94 self.after()
95 try:
95 try:
96 self.repo = hg.repository(self.ui, branchpath)
96 self.repo = hg.repository(self.ui, branchpath)
97 except Exception:
97 except Exception:
98 self.repo = hg.repository(self.ui, branchpath, create=True)
98 self.repo = hg.repository(self.ui, branchpath, create=True)
99 self.before()
99 self.before()
100
100
101 # pbranches may bring revisions from other branches (merge parents)
101 # pbranches may bring revisions from other branches (merge parents)
102 # Make sure we have them, or pull them.
102 # Make sure we have them, or pull them.
103 missings = {}
103 missings = {}
104 for b in pbranches:
104 for b in pbranches:
105 try:
105 try:
106 self.repo.lookup(b[0])
106 self.repo.lookup(b[0])
107 except Exception:
107 except Exception:
108 missings.setdefault(b[1], []).append(b[0])
108 missings.setdefault(b[1], []).append(b[0])
109
109
110 if missings:
110 if missings:
111 self.after()
111 self.after()
112 for pbranch, heads in sorted(missings.iteritems()):
112 for pbranch, heads in sorted(missings.iteritems()):
113 pbranchpath = os.path.join(self.path, pbranch)
113 pbranchpath = os.path.join(self.path, pbranch)
114 prepo = hg.peer(self.ui, {}, pbranchpath)
114 prepo = hg.peer(self.ui, {}, pbranchpath)
115 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
115 self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch))
116 self.repo.pull(prepo, [prepo.lookup(h) for h in heads])
116 exchange.pull(self.repo, prepo,
117 [prepo.lookup(h) for h in heads])
117 self.before()
118 self.before()
118
119
119 def _rewritetags(self, source, revmap, data):
120 def _rewritetags(self, source, revmap, data):
120 fp = cStringIO.StringIO()
121 fp = cStringIO.StringIO()
121 for line in data.splitlines():
122 for line in data.splitlines():
122 s = line.split(' ', 1)
123 s = line.split(' ', 1)
123 if len(s) != 2:
124 if len(s) != 2:
124 continue
125 continue
125 revid = revmap.get(source.lookuprev(s[0]))
126 revid = revmap.get(source.lookuprev(s[0]))
126 if not revid:
127 if not revid:
127 continue
128 continue
128 fp.write('%s %s\n' % (revid, s[1]))
129 fp.write('%s %s\n' % (revid, s[1]))
129 return fp.getvalue()
130 return fp.getvalue()
130
131
131 def putcommit(self, files, copies, parents, commit, source, revmap, full):
132 def putcommit(self, files, copies, parents, commit, source, revmap, full):
132 files = dict(files)
133 files = dict(files)
133 def getfilectx(repo, memctx, f):
134 def getfilectx(repo, memctx, f):
134 try:
135 try:
135 v = files[f]
136 v = files[f]
136 except KeyError:
137 except KeyError:
137 return None
138 return None
138 data, mode = source.getfile(f, v)
139 data, mode = source.getfile(f, v)
139 if data is None:
140 if data is None:
140 return None
141 return None
141 if f == '.hgtags':
142 if f == '.hgtags':
142 data = self._rewritetags(source, revmap, data)
143 data = self._rewritetags(source, revmap, data)
143 return context.memfilectx(self.repo, f, data, 'l' in mode,
144 return context.memfilectx(self.repo, f, data, 'l' in mode,
144 'x' in mode, copies.get(f))
145 'x' in mode, copies.get(f))
145
146
146 pl = []
147 pl = []
147 for p in parents:
148 for p in parents:
148 if p not in pl:
149 if p not in pl:
149 pl.append(p)
150 pl.append(p)
150 parents = pl
151 parents = pl
151 nparents = len(parents)
152 nparents = len(parents)
152 if self.filemapmode and nparents == 1:
153 if self.filemapmode and nparents == 1:
153 m1node = self.repo.changelog.read(bin(parents[0]))[0]
154 m1node = self.repo.changelog.read(bin(parents[0]))[0]
154 parent = parents[0]
155 parent = parents[0]
155
156
156 if len(parents) < 2:
157 if len(parents) < 2:
157 parents.append(nullid)
158 parents.append(nullid)
158 if len(parents) < 2:
159 if len(parents) < 2:
159 parents.append(nullid)
160 parents.append(nullid)
160 p2 = parents.pop(0)
161 p2 = parents.pop(0)
161
162
162 text = commit.desc
163 text = commit.desc
163
164
164 sha1s = re.findall(sha1re, text)
165 sha1s = re.findall(sha1re, text)
165 for sha1 in sha1s:
166 for sha1 in sha1s:
166 oldrev = source.lookuprev(sha1)
167 oldrev = source.lookuprev(sha1)
167 newrev = revmap.get(oldrev)
168 newrev = revmap.get(oldrev)
168 if newrev is not None:
169 if newrev is not None:
169 text = text.replace(sha1, newrev[:len(sha1)])
170 text = text.replace(sha1, newrev[:len(sha1)])
170
171
171 extra = commit.extra.copy()
172 extra = commit.extra.copy()
172
173
173 for label in ('source', 'transplant_source', 'rebase_source'):
174 for label in ('source', 'transplant_source', 'rebase_source'):
174 node = extra.get(label)
175 node = extra.get(label)
175
176
176 if node is None:
177 if node is None:
177 continue
178 continue
178
179
179 # Only transplant stores its reference in binary
180 # Only transplant stores its reference in binary
180 if label == 'transplant_source':
181 if label == 'transplant_source':
181 node = hex(node)
182 node = hex(node)
182
183
183 newrev = revmap.get(node)
184 newrev = revmap.get(node)
184 if newrev is not None:
185 if newrev is not None:
185 if label == 'transplant_source':
186 if label == 'transplant_source':
186 newrev = bin(newrev)
187 newrev = bin(newrev)
187
188
188 extra[label] = newrev
189 extra[label] = newrev
189
190
190 if self.branchnames and commit.branch:
191 if self.branchnames and commit.branch:
191 extra['branch'] = commit.branch
192 extra['branch'] = commit.branch
192 if commit.rev:
193 if commit.rev:
193 extra['convert_revision'] = commit.rev
194 extra['convert_revision'] = commit.rev
194
195
195 while parents:
196 while parents:
196 p1 = p2
197 p1 = p2
197 p2 = parents.pop(0)
198 p2 = parents.pop(0)
198 fileset = set(files)
199 fileset = set(files)
199 if full:
200 if full:
200 fileset.update(self.repo[p1])
201 fileset.update(self.repo[p1])
201 fileset.update(self.repo[p2])
202 fileset.update(self.repo[p2])
202 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
203 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
203 getfilectx, commit.author, commit.date, extra)
204 getfilectx, commit.author, commit.date, extra)
204 self.repo.commitctx(ctx)
205 self.repo.commitctx(ctx)
205 text = "(octopus merge fixup)\n"
206 text = "(octopus merge fixup)\n"
206 p2 = hex(self.repo.changelog.tip())
207 p2 = hex(self.repo.changelog.tip())
207
208
208 if self.filemapmode and nparents == 1:
209 if self.filemapmode and nparents == 1:
209 man = self.repo.manifest
210 man = self.repo.manifest
210 mnode = self.repo.changelog.read(bin(p2))[0]
211 mnode = self.repo.changelog.read(bin(p2))[0]
211 closed = 'close' in commit.extra
212 closed = 'close' in commit.extra
212 if not closed and not man.cmp(m1node, man.revision(mnode)):
213 if not closed and not man.cmp(m1node, man.revision(mnode)):
213 self.ui.status(_("filtering out empty revision\n"))
214 self.ui.status(_("filtering out empty revision\n"))
214 self.repo.rollback(force=True)
215 self.repo.rollback(force=True)
215 return parent
216 return parent
216 return p2
217 return p2
217
218
218 def puttags(self, tags):
219 def puttags(self, tags):
219 try:
220 try:
220 parentctx = self.repo[self.tagsbranch]
221 parentctx = self.repo[self.tagsbranch]
221 tagparent = parentctx.node()
222 tagparent = parentctx.node()
222 except error.RepoError:
223 except error.RepoError:
223 parentctx = None
224 parentctx = None
224 tagparent = nullid
225 tagparent = nullid
225
226
226 oldlines = set()
227 oldlines = set()
227 for branch, heads in self.repo.branchmap().iteritems():
228 for branch, heads in self.repo.branchmap().iteritems():
228 for h in heads:
229 for h in heads:
229 if '.hgtags' in self.repo[h]:
230 if '.hgtags' in self.repo[h]:
230 oldlines.update(
231 oldlines.update(
231 set(self.repo[h]['.hgtags'].data().splitlines(True)))
232 set(self.repo[h]['.hgtags'].data().splitlines(True)))
232 oldlines = sorted(list(oldlines))
233 oldlines = sorted(list(oldlines))
233
234
234 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
235 newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags])
235 if newlines == oldlines:
236 if newlines == oldlines:
236 return None, None
237 return None, None
237
238
238 # if the old and new tags match, then there is nothing to update
239 # if the old and new tags match, then there is nothing to update
239 oldtags = set()
240 oldtags = set()
240 newtags = set()
241 newtags = set()
241 for line in oldlines:
242 for line in oldlines:
242 s = line.strip().split(' ', 1)
243 s = line.strip().split(' ', 1)
243 if len(s) != 2:
244 if len(s) != 2:
244 continue
245 continue
245 oldtags.add(s[1])
246 oldtags.add(s[1])
246 for line in newlines:
247 for line in newlines:
247 s = line.strip().split(' ', 1)
248 s = line.strip().split(' ', 1)
248 if len(s) != 2:
249 if len(s) != 2:
249 continue
250 continue
250 if s[1] not in oldtags:
251 if s[1] not in oldtags:
251 newtags.add(s[1].strip())
252 newtags.add(s[1].strip())
252
253
253 if not newtags:
254 if not newtags:
254 return None, None
255 return None, None
255
256
256 data = "".join(newlines)
257 data = "".join(newlines)
257 def getfilectx(repo, memctx, f):
258 def getfilectx(repo, memctx, f):
258 return context.memfilectx(repo, f, data, False, False, None)
259 return context.memfilectx(repo, f, data, False, False, None)
259
260
260 self.ui.status(_("updating tags\n"))
261 self.ui.status(_("updating tags\n"))
261 date = "%s 0" % int(time.mktime(time.gmtime()))
262 date = "%s 0" % int(time.mktime(time.gmtime()))
262 extra = {'branch': self.tagsbranch}
263 extra = {'branch': self.tagsbranch}
263 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
264 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
264 [".hgtags"], getfilectx, "convert-repo", date,
265 [".hgtags"], getfilectx, "convert-repo", date,
265 extra)
266 extra)
266 self.repo.commitctx(ctx)
267 self.repo.commitctx(ctx)
267 return hex(self.repo.changelog.tip()), hex(tagparent)
268 return hex(self.repo.changelog.tip()), hex(tagparent)
268
269
269 def setfilemapmode(self, active):
270 def setfilemapmode(self, active):
270 self.filemapmode = active
271 self.filemapmode = active
271
272
272 def putbookmarks(self, updatedbookmark):
273 def putbookmarks(self, updatedbookmark):
273 if not len(updatedbookmark):
274 if not len(updatedbookmark):
274 return
275 return
275
276
276 self.ui.status(_("updating bookmarks\n"))
277 self.ui.status(_("updating bookmarks\n"))
277 destmarks = self.repo._bookmarks
278 destmarks = self.repo._bookmarks
278 for bookmark in updatedbookmark:
279 for bookmark in updatedbookmark:
279 destmarks[bookmark] = bin(updatedbookmark[bookmark])
280 destmarks[bookmark] = bin(updatedbookmark[bookmark])
280 destmarks.write()
281 destmarks.write()
281
282
282 def hascommitfrommap(self, rev):
283 def hascommitfrommap(self, rev):
283 # the exact semantics of clonebranches is unclear so we can't say no
284 # the exact semantics of clonebranches is unclear so we can't say no
284 return rev in self.repo or self.clonebranches
285 return rev in self.repo or self.clonebranches
285
286
286 def hascommitforsplicemap(self, rev):
287 def hascommitforsplicemap(self, rev):
287 if rev not in self.repo and self.clonebranches:
288 if rev not in self.repo and self.clonebranches:
288 raise util.Abort(_('revision %s not found in destination '
289 raise util.Abort(_('revision %s not found in destination '
289 'repository (lookups with clonebranches=true '
290 'repository (lookups with clonebranches=true '
290 'are not implemented)') % rev)
291 'are not implemented)') % rev)
291 return rev in self.repo
292 return rev in self.repo
292
293
293 class mercurial_source(converter_source):
294 class mercurial_source(converter_source):
294 def __init__(self, ui, path, rev=None):
295 def __init__(self, ui, path, rev=None):
295 converter_source.__init__(self, ui, path, rev)
296 converter_source.__init__(self, ui, path, rev)
296 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
297 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
297 self.ignored = set()
298 self.ignored = set()
298 self.saverev = ui.configbool('convert', 'hg.saverev', False)
299 self.saverev = ui.configbool('convert', 'hg.saverev', False)
299 try:
300 try:
300 self.repo = hg.repository(self.ui, path)
301 self.repo = hg.repository(self.ui, path)
301 # try to provoke an exception if this isn't really a hg
302 # try to provoke an exception if this isn't really a hg
302 # repo, but some other bogus compatible-looking url
303 # repo, but some other bogus compatible-looking url
303 if not self.repo.local():
304 if not self.repo.local():
304 raise error.RepoError
305 raise error.RepoError
305 except error.RepoError:
306 except error.RepoError:
306 ui.traceback()
307 ui.traceback()
307 raise NoRepo(_("%s is not a local Mercurial repository") % path)
308 raise NoRepo(_("%s is not a local Mercurial repository") % path)
308 self.lastrev = None
309 self.lastrev = None
309 self.lastctx = None
310 self.lastctx = None
310 self._changescache = None, None
311 self._changescache = None, None
311 self.convertfp = None
312 self.convertfp = None
312 # Restrict converted revisions to startrev descendants
313 # Restrict converted revisions to startrev descendants
313 startnode = ui.config('convert', 'hg.startrev')
314 startnode = ui.config('convert', 'hg.startrev')
314 hgrevs = ui.config('convert', 'hg.revs')
315 hgrevs = ui.config('convert', 'hg.revs')
315 if hgrevs is None:
316 if hgrevs is None:
316 if startnode is not None:
317 if startnode is not None:
317 try:
318 try:
318 startnode = self.repo.lookup(startnode)
319 startnode = self.repo.lookup(startnode)
319 except error.RepoError:
320 except error.RepoError:
320 raise util.Abort(_('%s is not a valid start revision')
321 raise util.Abort(_('%s is not a valid start revision')
321 % startnode)
322 % startnode)
322 startrev = self.repo.changelog.rev(startnode)
323 startrev = self.repo.changelog.rev(startnode)
323 children = {startnode: 1}
324 children = {startnode: 1}
324 for r in self.repo.changelog.descendants([startrev]):
325 for r in self.repo.changelog.descendants([startrev]):
325 children[self.repo.changelog.node(r)] = 1
326 children[self.repo.changelog.node(r)] = 1
326 self.keep = children.__contains__
327 self.keep = children.__contains__
327 else:
328 else:
328 self.keep = util.always
329 self.keep = util.always
329 if rev:
330 if rev:
330 self._heads = [self.repo[rev].node()]
331 self._heads = [self.repo[rev].node()]
331 else:
332 else:
332 self._heads = self.repo.heads()
333 self._heads = self.repo.heads()
333 else:
334 else:
334 if rev or startnode is not None:
335 if rev or startnode is not None:
335 raise util.Abort(_('hg.revs cannot be combined with '
336 raise util.Abort(_('hg.revs cannot be combined with '
336 'hg.startrev or --rev'))
337 'hg.startrev or --rev'))
337 nodes = set()
338 nodes = set()
338 parents = set()
339 parents = set()
339 for r in scmutil.revrange(self.repo, [hgrevs]):
340 for r in scmutil.revrange(self.repo, [hgrevs]):
340 ctx = self.repo[r]
341 ctx = self.repo[r]
341 nodes.add(ctx.node())
342 nodes.add(ctx.node())
342 parents.update(p.node() for p in ctx.parents())
343 parents.update(p.node() for p in ctx.parents())
343 self.keep = nodes.__contains__
344 self.keep = nodes.__contains__
344 self._heads = nodes - parents
345 self._heads = nodes - parents
345
346
346 def changectx(self, rev):
347 def changectx(self, rev):
347 if self.lastrev != rev:
348 if self.lastrev != rev:
348 self.lastctx = self.repo[rev]
349 self.lastctx = self.repo[rev]
349 self.lastrev = rev
350 self.lastrev = rev
350 return self.lastctx
351 return self.lastctx
351
352
352 def parents(self, ctx):
353 def parents(self, ctx):
353 return [p for p in ctx.parents() if p and self.keep(p.node())]
354 return [p for p in ctx.parents() if p and self.keep(p.node())]
354
355
355 def getheads(self):
356 def getheads(self):
356 return [hex(h) for h in self._heads if self.keep(h)]
357 return [hex(h) for h in self._heads if self.keep(h)]
357
358
358 def getfile(self, name, rev):
359 def getfile(self, name, rev):
359 try:
360 try:
360 fctx = self.changectx(rev)[name]
361 fctx = self.changectx(rev)[name]
361 return fctx.data(), fctx.flags()
362 return fctx.data(), fctx.flags()
362 except error.LookupError:
363 except error.LookupError:
363 return None, None
364 return None, None
364
365
365 def getchanges(self, rev, full):
366 def getchanges(self, rev, full):
366 ctx = self.changectx(rev)
367 ctx = self.changectx(rev)
367 parents = self.parents(ctx)
368 parents = self.parents(ctx)
368 if full or not parents:
369 if full or not parents:
369 files = copyfiles = ctx.manifest()
370 files = copyfiles = ctx.manifest()
370 if parents:
371 if parents:
371 if self._changescache[0] == rev:
372 if self._changescache[0] == rev:
372 m, a, r = self._changescache[1]
373 m, a, r = self._changescache[1]
373 else:
374 else:
374 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
375 m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3]
375 if not full:
376 if not full:
376 files = m + a + r
377 files = m + a + r
377 copyfiles = m + a
378 copyfiles = m + a
378 # getcopies() is also run for roots and before filtering so missing
379 # getcopies() is also run for roots and before filtering so missing
379 # revlogs are detected early
380 # revlogs are detected early
380 copies = self.getcopies(ctx, parents, copyfiles)
381 copies = self.getcopies(ctx, parents, copyfiles)
381 changes = [(f, rev) for f in files if f not in self.ignored]
382 changes = [(f, rev) for f in files if f not in self.ignored]
382 changes.sort()
383 changes.sort()
383 return changes, copies
384 return changes, copies
384
385
385 def getcopies(self, ctx, parents, files):
386 def getcopies(self, ctx, parents, files):
386 copies = {}
387 copies = {}
387 for name in files:
388 for name in files:
388 if name in self.ignored:
389 if name in self.ignored:
389 continue
390 continue
390 try:
391 try:
391 copysource, _copynode = ctx.filectx(name).renamed()
392 copysource, _copynode = ctx.filectx(name).renamed()
392 if copysource in self.ignored:
393 if copysource in self.ignored:
393 continue
394 continue
394 # Ignore copy sources not in parent revisions
395 # Ignore copy sources not in parent revisions
395 found = False
396 found = False
396 for p in parents:
397 for p in parents:
397 if copysource in p:
398 if copysource in p:
398 found = True
399 found = True
399 break
400 break
400 if not found:
401 if not found:
401 continue
402 continue
402 copies[name] = copysource
403 copies[name] = copysource
403 except TypeError:
404 except TypeError:
404 pass
405 pass
405 except error.LookupError, e:
406 except error.LookupError, e:
406 if not self.ignoreerrors:
407 if not self.ignoreerrors:
407 raise
408 raise
408 self.ignored.add(name)
409 self.ignored.add(name)
409 self.ui.warn(_('ignoring: %s\n') % e)
410 self.ui.warn(_('ignoring: %s\n') % e)
410 return copies
411 return copies
411
412
412 def getcommit(self, rev):
413 def getcommit(self, rev):
413 ctx = self.changectx(rev)
414 ctx = self.changectx(rev)
414 parents = [p.hex() for p in self.parents(ctx)]
415 parents = [p.hex() for p in self.parents(ctx)]
415 if self.saverev:
416 if self.saverev:
416 crev = rev
417 crev = rev
417 else:
418 else:
418 crev = None
419 crev = None
419 return commit(author=ctx.user(),
420 return commit(author=ctx.user(),
420 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
421 date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
421 desc=ctx.description(), rev=crev, parents=parents,
422 desc=ctx.description(), rev=crev, parents=parents,
422 branch=ctx.branch(), extra=ctx.extra(),
423 branch=ctx.branch(), extra=ctx.extra(),
423 sortkey=ctx.rev())
424 sortkey=ctx.rev())
424
425
425 def gettags(self):
426 def gettags(self):
426 # This will get written to .hgtags, filter non global tags out.
427 # This will get written to .hgtags, filter non global tags out.
427 tags = [t for t in self.repo.tagslist()
428 tags = [t for t in self.repo.tagslist()
428 if self.repo.tagtype(t[0]) == 'global']
429 if self.repo.tagtype(t[0]) == 'global']
429 return dict([(name, hex(node)) for name, node in tags
430 return dict([(name, hex(node)) for name, node in tags
430 if self.keep(node)])
431 if self.keep(node)])
431
432
432 def getchangedfiles(self, rev, i):
433 def getchangedfiles(self, rev, i):
433 ctx = self.changectx(rev)
434 ctx = self.changectx(rev)
434 parents = self.parents(ctx)
435 parents = self.parents(ctx)
435 if not parents and i is None:
436 if not parents and i is None:
436 i = 0
437 i = 0
437 changes = [], ctx.manifest().keys(), []
438 changes = [], ctx.manifest().keys(), []
438 else:
439 else:
439 i = i or 0
440 i = i or 0
440 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
441 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
441 changes = [[f for f in l if f not in self.ignored] for l in changes]
442 changes = [[f for f in l if f not in self.ignored] for l in changes]
442
443
443 if i == 0:
444 if i == 0:
444 self._changescache = (rev, changes)
445 self._changescache = (rev, changes)
445
446
446 return changes[0] + changes[1] + changes[2]
447 return changes[0] + changes[1] + changes[2]
447
448
448 def converted(self, rev, destrev):
449 def converted(self, rev, destrev):
449 if self.convertfp is None:
450 if self.convertfp is None:
450 self.convertfp = open(self.repo.join('shamap'), 'a')
451 self.convertfp = open(self.repo.join('shamap'), 'a')
451 self.convertfp.write('%s %s\n' % (destrev, rev))
452 self.convertfp.write('%s %s\n' % (destrev, rev))
452 self.convertfp.flush()
453 self.convertfp.flush()
453
454
454 def before(self):
455 def before(self):
455 self.ui.debug('run hg source pre-conversion action\n')
456 self.ui.debug('run hg source pre-conversion action\n')
456
457
457 def after(self):
458 def after(self):
458 self.ui.debug('run hg source post-conversion action\n')
459 self.ui.debug('run hg source post-conversion action\n')
459
460
460 def hasnativeorder(self):
461 def hasnativeorder(self):
461 return True
462 return True
462
463
463 def hasnativeclose(self):
464 def hasnativeclose(self):
464 return True
465 return True
465
466
466 def lookuprev(self, rev):
467 def lookuprev(self, rev):
467 try:
468 try:
468 return hex(self.repo.lookup(rev))
469 return hex(self.repo.lookup(rev))
469 except error.RepoError:
470 except error.RepoError:
470 return None
471 return None
471
472
472 def getbookmarks(self):
473 def getbookmarks(self):
473 return bookmarks.listbookmarks(self.repo)
474 return bookmarks.listbookmarks(self.repo)
474
475
475 def checkrevformat(self, revstr, mapname='splicemap'):
476 def checkrevformat(self, revstr, mapname='splicemap'):
476 """ Mercurial, revision string is a 40 byte hex """
477 """ Mercurial, revision string is a 40 byte hex """
477 self.checkhexformat(revstr, mapname)
478 self.checkhexformat(revstr, mapname)
General Comments 0
You need to be logged in to leave comments. Login now