##// END OF EJS Templates
convert: replace revision references in messages if they are >= short hashes...
Mads Kiilerich -
r23972:c408bf3b stable
parent child Browse files
Show More
@@ -1,478 +1,478 b''
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, exchange
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]{12,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 exchange.pull(self.repo, prepo,
116 exchange.pull(self.repo, prepo,
117 [prepo.lookup(h) for h in heads])
117 [prepo.lookup(h) for h in heads])
118 self.before()
118 self.before()
119
119
120 def _rewritetags(self, source, revmap, data):
120 def _rewritetags(self, source, revmap, data):
121 fp = cStringIO.StringIO()
121 fp = cStringIO.StringIO()
122 for line in data.splitlines():
122 for line in data.splitlines():
123 s = line.split(' ', 1)
123 s = line.split(' ', 1)
124 if len(s) != 2:
124 if len(s) != 2:
125 continue
125 continue
126 revid = revmap.get(source.lookuprev(s[0]))
126 revid = revmap.get(source.lookuprev(s[0]))
127 if not revid:
127 if not revid:
128 continue
128 continue
129 fp.write('%s %s\n' % (revid, s[1]))
129 fp.write('%s %s\n' % (revid, s[1]))
130 return fp.getvalue()
130 return fp.getvalue()
131
131
132 def putcommit(self, files, copies, parents, commit, source, revmap, full):
132 def putcommit(self, files, copies, parents, commit, source, revmap, full):
133 files = dict(files)
133 files = dict(files)
134 def getfilectx(repo, memctx, f):
134 def getfilectx(repo, memctx, f):
135 try:
135 try:
136 v = files[f]
136 v = files[f]
137 except KeyError:
137 except KeyError:
138 return None
138 return None
139 data, mode = source.getfile(f, v)
139 data, mode = source.getfile(f, v)
140 if data is None:
140 if data is None:
141 return None
141 return None
142 if f == '.hgtags':
142 if f == '.hgtags':
143 data = self._rewritetags(source, revmap, data)
143 data = self._rewritetags(source, revmap, data)
144 return context.memfilectx(self.repo, f, data, 'l' in mode,
144 return context.memfilectx(self.repo, f, data, 'l' in mode,
145 'x' in mode, copies.get(f))
145 'x' in mode, copies.get(f))
146
146
147 pl = []
147 pl = []
148 for p in parents:
148 for p in parents:
149 if p not in pl:
149 if p not in pl:
150 pl.append(p)
150 pl.append(p)
151 parents = pl
151 parents = pl
152 nparents = len(parents)
152 nparents = len(parents)
153 if self.filemapmode and nparents == 1:
153 if self.filemapmode and nparents == 1:
154 m1node = self.repo.changelog.read(bin(parents[0]))[0]
154 m1node = self.repo.changelog.read(bin(parents[0]))[0]
155 parent = parents[0]
155 parent = parents[0]
156
156
157 if len(parents) < 2:
157 if len(parents) < 2:
158 parents.append(nullid)
158 parents.append(nullid)
159 if len(parents) < 2:
159 if len(parents) < 2:
160 parents.append(nullid)
160 parents.append(nullid)
161 p2 = parents.pop(0)
161 p2 = parents.pop(0)
162
162
163 text = commit.desc
163 text = commit.desc
164
164
165 sha1s = re.findall(sha1re, text)
165 sha1s = re.findall(sha1re, text)
166 for sha1 in sha1s:
166 for sha1 in sha1s:
167 oldrev = source.lookuprev(sha1)
167 oldrev = source.lookuprev(sha1)
168 newrev = revmap.get(oldrev)
168 newrev = revmap.get(oldrev)
169 if newrev is not None:
169 if newrev is not None:
170 text = text.replace(sha1, newrev[:len(sha1)])
170 text = text.replace(sha1, newrev[:len(sha1)])
171
171
172 extra = commit.extra.copy()
172 extra = commit.extra.copy()
173
173
174 for label in ('source', 'transplant_source', 'rebase_source'):
174 for label in ('source', 'transplant_source', 'rebase_source'):
175 node = extra.get(label)
175 node = extra.get(label)
176
176
177 if node is None:
177 if node is None:
178 continue
178 continue
179
179
180 # Only transplant stores its reference in binary
180 # Only transplant stores its reference in binary
181 if label == 'transplant_source':
181 if label == 'transplant_source':
182 node = hex(node)
182 node = hex(node)
183
183
184 newrev = revmap.get(node)
184 newrev = revmap.get(node)
185 if newrev is not None:
185 if newrev is not None:
186 if label == 'transplant_source':
186 if label == 'transplant_source':
187 newrev = bin(newrev)
187 newrev = bin(newrev)
188
188
189 extra[label] = newrev
189 extra[label] = newrev
190
190
191 if self.branchnames and commit.branch:
191 if self.branchnames and commit.branch:
192 extra['branch'] = commit.branch
192 extra['branch'] = commit.branch
193 if commit.rev:
193 if commit.rev:
194 extra['convert_revision'] = commit.rev
194 extra['convert_revision'] = commit.rev
195
195
196 while parents:
196 while parents:
197 p1 = p2
197 p1 = p2
198 p2 = parents.pop(0)
198 p2 = parents.pop(0)
199 fileset = set(files)
199 fileset = set(files)
200 if full:
200 if full:
201 fileset.update(self.repo[p1])
201 fileset.update(self.repo[p1])
202 fileset.update(self.repo[p2])
202 fileset.update(self.repo[p2])
203 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
203 ctx = context.memctx(self.repo, (p1, p2), text, fileset,
204 getfilectx, commit.author, commit.date, extra)
204 getfilectx, commit.author, commit.date, extra)
205 self.repo.commitctx(ctx)
205 self.repo.commitctx(ctx)
206 text = "(octopus merge fixup)\n"
206 text = "(octopus merge fixup)\n"
207 p2 = hex(self.repo.changelog.tip())
207 p2 = hex(self.repo.changelog.tip())
208
208
209 if self.filemapmode and nparents == 1:
209 if self.filemapmode and nparents == 1:
210 man = self.repo.manifest
210 man = self.repo.manifest
211 mnode = self.repo.changelog.read(bin(p2))[0]
211 mnode = self.repo.changelog.read(bin(p2))[0]
212 closed = 'close' in commit.extra
212 closed = 'close' in commit.extra
213 if not closed and not man.cmp(m1node, man.revision(mnode)):
213 if not closed and not man.cmp(m1node, man.revision(mnode)):
214 self.ui.status(_("filtering out empty revision\n"))
214 self.ui.status(_("filtering out empty revision\n"))
215 self.repo.rollback(force=True)
215 self.repo.rollback(force=True)
216 return parent
216 return parent
217 return p2
217 return p2
218
218
219 def puttags(self, tags):
219 def puttags(self, tags):
220 try:
220 try:
221 parentctx = self.repo[self.tagsbranch]
221 parentctx = self.repo[self.tagsbranch]
222 tagparent = parentctx.node()
222 tagparent = parentctx.node()
223 except error.RepoError:
223 except error.RepoError:
224 parentctx = None
224 parentctx = None
225 tagparent = nullid
225 tagparent = nullid
226
226
227 oldlines = set()
227 oldlines = set()
228 for branch, heads in self.repo.branchmap().iteritems():
228 for branch, heads in self.repo.branchmap().iteritems():
229 for h in heads:
229 for h in heads:
230 if '.hgtags' in self.repo[h]:
230 if '.hgtags' in self.repo[h]:
231 oldlines.update(
231 oldlines.update(
232 set(self.repo[h]['.hgtags'].data().splitlines(True)))
232 set(self.repo[h]['.hgtags'].data().splitlines(True)))
233 oldlines = sorted(list(oldlines))
233 oldlines = sorted(list(oldlines))
234
234
235 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])
236 if newlines == oldlines:
236 if newlines == oldlines:
237 return None, None
237 return None, None
238
238
239 # 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
240 oldtags = set()
240 oldtags = set()
241 newtags = set()
241 newtags = set()
242 for line in oldlines:
242 for line in oldlines:
243 s = line.strip().split(' ', 1)
243 s = line.strip().split(' ', 1)
244 if len(s) != 2:
244 if len(s) != 2:
245 continue
245 continue
246 oldtags.add(s[1])
246 oldtags.add(s[1])
247 for line in newlines:
247 for line in newlines:
248 s = line.strip().split(' ', 1)
248 s = line.strip().split(' ', 1)
249 if len(s) != 2:
249 if len(s) != 2:
250 continue
250 continue
251 if s[1] not in oldtags:
251 if s[1] not in oldtags:
252 newtags.add(s[1].strip())
252 newtags.add(s[1].strip())
253
253
254 if not newtags:
254 if not newtags:
255 return None, None
255 return None, None
256
256
257 data = "".join(newlines)
257 data = "".join(newlines)
258 def getfilectx(repo, memctx, f):
258 def getfilectx(repo, memctx, f):
259 return context.memfilectx(repo, f, data, False, False, None)
259 return context.memfilectx(repo, f, data, False, False, None)
260
260
261 self.ui.status(_("updating tags\n"))
261 self.ui.status(_("updating tags\n"))
262 date = "%s 0" % int(time.mktime(time.gmtime()))
262 date = "%s 0" % int(time.mktime(time.gmtime()))
263 extra = {'branch': self.tagsbranch}
263 extra = {'branch': self.tagsbranch}
264 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
264 ctx = context.memctx(self.repo, (tagparent, None), "update tags",
265 [".hgtags"], getfilectx, "convert-repo", date,
265 [".hgtags"], getfilectx, "convert-repo", date,
266 extra)
266 extra)
267 self.repo.commitctx(ctx)
267 self.repo.commitctx(ctx)
268 return hex(self.repo.changelog.tip()), hex(tagparent)
268 return hex(self.repo.changelog.tip()), hex(tagparent)
269
269
270 def setfilemapmode(self, active):
270 def setfilemapmode(self, active):
271 self.filemapmode = active
271 self.filemapmode = active
272
272
273 def putbookmarks(self, updatedbookmark):
273 def putbookmarks(self, updatedbookmark):
274 if not len(updatedbookmark):
274 if not len(updatedbookmark):
275 return
275 return
276
276
277 self.ui.status(_("updating bookmarks\n"))
277 self.ui.status(_("updating bookmarks\n"))
278 destmarks = self.repo._bookmarks
278 destmarks = self.repo._bookmarks
279 for bookmark in updatedbookmark:
279 for bookmark in updatedbookmark:
280 destmarks[bookmark] = bin(updatedbookmark[bookmark])
280 destmarks[bookmark] = bin(updatedbookmark[bookmark])
281 destmarks.write()
281 destmarks.write()
282
282
283 def hascommitfrommap(self, rev):
283 def hascommitfrommap(self, rev):
284 # 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
285 return rev in self.repo or self.clonebranches
285 return rev in self.repo or self.clonebranches
286
286
287 def hascommitforsplicemap(self, rev):
287 def hascommitforsplicemap(self, rev):
288 if rev not in self.repo and self.clonebranches:
288 if rev not in self.repo and self.clonebranches:
289 raise util.Abort(_('revision %s not found in destination '
289 raise util.Abort(_('revision %s not found in destination '
290 'repository (lookups with clonebranches=true '
290 'repository (lookups with clonebranches=true '
291 'are not implemented)') % rev)
291 'are not implemented)') % rev)
292 return rev in self.repo
292 return rev in self.repo
293
293
294 class mercurial_source(converter_source):
294 class mercurial_source(converter_source):
295 def __init__(self, ui, path, rev=None):
295 def __init__(self, ui, path, rev=None):
296 converter_source.__init__(self, ui, path, rev)
296 converter_source.__init__(self, ui, path, rev)
297 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
297 self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False)
298 self.ignored = set()
298 self.ignored = set()
299 self.saverev = ui.configbool('convert', 'hg.saverev', False)
299 self.saverev = ui.configbool('convert', 'hg.saverev', False)
300 try:
300 try:
301 self.repo = hg.repository(self.ui, path)
301 self.repo = hg.repository(self.ui, path)
302 # 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
303 # repo, but some other bogus compatible-looking url
303 # repo, but some other bogus compatible-looking url
304 if not self.repo.local():
304 if not self.repo.local():
305 raise error.RepoError
305 raise error.RepoError
306 except error.RepoError:
306 except error.RepoError:
307 ui.traceback()
307 ui.traceback()
308 raise NoRepo(_("%s is not a local Mercurial repository") % path)
308 raise NoRepo(_("%s is not a local Mercurial repository") % path)
309 self.lastrev = None
309 self.lastrev = None
310 self.lastctx = None
310 self.lastctx = None
311 self._changescache = None, None
311 self._changescache = None, None
312 self.convertfp = None
312 self.convertfp = None
313 # Restrict converted revisions to startrev descendants
313 # Restrict converted revisions to startrev descendants
314 startnode = ui.config('convert', 'hg.startrev')
314 startnode = ui.config('convert', 'hg.startrev')
315 hgrevs = ui.config('convert', 'hg.revs')
315 hgrevs = ui.config('convert', 'hg.revs')
316 if hgrevs is None:
316 if hgrevs is None:
317 if startnode is not None:
317 if startnode is not None:
318 try:
318 try:
319 startnode = self.repo.lookup(startnode)
319 startnode = self.repo.lookup(startnode)
320 except error.RepoError:
320 except error.RepoError:
321 raise util.Abort(_('%s is not a valid start revision')
321 raise util.Abort(_('%s is not a valid start revision')
322 % startnode)
322 % startnode)
323 startrev = self.repo.changelog.rev(startnode)
323 startrev = self.repo.changelog.rev(startnode)
324 children = {startnode: 1}
324 children = {startnode: 1}
325 for r in self.repo.changelog.descendants([startrev]):
325 for r in self.repo.changelog.descendants([startrev]):
326 children[self.repo.changelog.node(r)] = 1
326 children[self.repo.changelog.node(r)] = 1
327 self.keep = children.__contains__
327 self.keep = children.__contains__
328 else:
328 else:
329 self.keep = util.always
329 self.keep = util.always
330 if rev:
330 if rev:
331 self._heads = [self.repo[rev].node()]
331 self._heads = [self.repo[rev].node()]
332 else:
332 else:
333 self._heads = self.repo.heads()
333 self._heads = self.repo.heads()
334 else:
334 else:
335 if rev or startnode is not None:
335 if rev or startnode is not None:
336 raise util.Abort(_('hg.revs cannot be combined with '
336 raise util.Abort(_('hg.revs cannot be combined with '
337 'hg.startrev or --rev'))
337 'hg.startrev or --rev'))
338 nodes = set()
338 nodes = set()
339 parents = set()
339 parents = set()
340 for r in scmutil.revrange(self.repo, [hgrevs]):
340 for r in scmutil.revrange(self.repo, [hgrevs]):
341 ctx = self.repo[r]
341 ctx = self.repo[r]
342 nodes.add(ctx.node())
342 nodes.add(ctx.node())
343 parents.update(p.node() for p in ctx.parents())
343 parents.update(p.node() for p in ctx.parents())
344 self.keep = nodes.__contains__
344 self.keep = nodes.__contains__
345 self._heads = nodes - parents
345 self._heads = nodes - parents
346
346
347 def changectx(self, rev):
347 def changectx(self, rev):
348 if self.lastrev != rev:
348 if self.lastrev != rev:
349 self.lastctx = self.repo[rev]
349 self.lastctx = self.repo[rev]
350 self.lastrev = rev
350 self.lastrev = rev
351 return self.lastctx
351 return self.lastctx
352
352
353 def parents(self, ctx):
353 def parents(self, ctx):
354 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())]
355
355
356 def getheads(self):
356 def getheads(self):
357 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)]
358
358
359 def getfile(self, name, rev):
359 def getfile(self, name, rev):
360 try:
360 try:
361 fctx = self.changectx(rev)[name]
361 fctx = self.changectx(rev)[name]
362 return fctx.data(), fctx.flags()
362 return fctx.data(), fctx.flags()
363 except error.LookupError:
363 except error.LookupError:
364 return None, None
364 return None, None
365
365
366 def getchanges(self, rev, full):
366 def getchanges(self, rev, full):
367 ctx = self.changectx(rev)
367 ctx = self.changectx(rev)
368 parents = self.parents(ctx)
368 parents = self.parents(ctx)
369 if full or not parents:
369 if full or not parents:
370 files = copyfiles = ctx.manifest()
370 files = copyfiles = ctx.manifest()
371 if parents:
371 if parents:
372 if self._changescache[0] == rev:
372 if self._changescache[0] == rev:
373 m, a, r = self._changescache[1]
373 m, a, r = self._changescache[1]
374 else:
374 else:
375 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]
376 if not full:
376 if not full:
377 files = m + a + r
377 files = m + a + r
378 copyfiles = m + a
378 copyfiles = m + a
379 # getcopies() is also run for roots and before filtering so missing
379 # getcopies() is also run for roots and before filtering so missing
380 # revlogs are detected early
380 # revlogs are detected early
381 copies = self.getcopies(ctx, parents, copyfiles)
381 copies = self.getcopies(ctx, parents, copyfiles)
382 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]
383 changes.sort()
383 changes.sort()
384 return changes, copies
384 return changes, copies
385
385
386 def getcopies(self, ctx, parents, files):
386 def getcopies(self, ctx, parents, files):
387 copies = {}
387 copies = {}
388 for name in files:
388 for name in files:
389 if name in self.ignored:
389 if name in self.ignored:
390 continue
390 continue
391 try:
391 try:
392 copysource, _copynode = ctx.filectx(name).renamed()
392 copysource, _copynode = ctx.filectx(name).renamed()
393 if copysource in self.ignored:
393 if copysource in self.ignored:
394 continue
394 continue
395 # Ignore copy sources not in parent revisions
395 # Ignore copy sources not in parent revisions
396 found = False
396 found = False
397 for p in parents:
397 for p in parents:
398 if copysource in p:
398 if copysource in p:
399 found = True
399 found = True
400 break
400 break
401 if not found:
401 if not found:
402 continue
402 continue
403 copies[name] = copysource
403 copies[name] = copysource
404 except TypeError:
404 except TypeError:
405 pass
405 pass
406 except error.LookupError, e:
406 except error.LookupError, e:
407 if not self.ignoreerrors:
407 if not self.ignoreerrors:
408 raise
408 raise
409 self.ignored.add(name)
409 self.ignored.add(name)
410 self.ui.warn(_('ignoring: %s\n') % e)
410 self.ui.warn(_('ignoring: %s\n') % e)
411 return copies
411 return copies
412
412
413 def getcommit(self, rev):
413 def getcommit(self, rev):
414 ctx = self.changectx(rev)
414 ctx = self.changectx(rev)
415 parents = [p.hex() for p in self.parents(ctx)]
415 parents = [p.hex() for p in self.parents(ctx)]
416 if self.saverev:
416 if self.saverev:
417 crev = rev
417 crev = rev
418 else:
418 else:
419 crev = None
419 crev = None
420 return commit(author=ctx.user(),
420 return commit(author=ctx.user(),
421 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'),
422 desc=ctx.description(), rev=crev, parents=parents,
422 desc=ctx.description(), rev=crev, parents=parents,
423 branch=ctx.branch(), extra=ctx.extra(),
423 branch=ctx.branch(), extra=ctx.extra(),
424 sortkey=ctx.rev())
424 sortkey=ctx.rev())
425
425
426 def gettags(self):
426 def gettags(self):
427 # This will get written to .hgtags, filter non global tags out.
427 # This will get written to .hgtags, filter non global tags out.
428 tags = [t for t in self.repo.tagslist()
428 tags = [t for t in self.repo.tagslist()
429 if self.repo.tagtype(t[0]) == 'global']
429 if self.repo.tagtype(t[0]) == 'global']
430 return dict([(name, hex(node)) for name, node in tags
430 return dict([(name, hex(node)) for name, node in tags
431 if self.keep(node)])
431 if self.keep(node)])
432
432
433 def getchangedfiles(self, rev, i):
433 def getchangedfiles(self, rev, i):
434 ctx = self.changectx(rev)
434 ctx = self.changectx(rev)
435 parents = self.parents(ctx)
435 parents = self.parents(ctx)
436 if not parents and i is None:
436 if not parents and i is None:
437 i = 0
437 i = 0
438 changes = [], ctx.manifest().keys(), []
438 changes = [], ctx.manifest().keys(), []
439 else:
439 else:
440 i = i or 0
440 i = i or 0
441 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
441 changes = self.repo.status(parents[i].node(), ctx.node())[:3]
442 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]
443
443
444 if i == 0:
444 if i == 0:
445 self._changescache = (rev, changes)
445 self._changescache = (rev, changes)
446
446
447 return changes[0] + changes[1] + changes[2]
447 return changes[0] + changes[1] + changes[2]
448
448
449 def converted(self, rev, destrev):
449 def converted(self, rev, destrev):
450 if self.convertfp is None:
450 if self.convertfp is None:
451 self.convertfp = open(self.repo.join('shamap'), 'a')
451 self.convertfp = open(self.repo.join('shamap'), 'a')
452 self.convertfp.write('%s %s\n' % (destrev, rev))
452 self.convertfp.write('%s %s\n' % (destrev, rev))
453 self.convertfp.flush()
453 self.convertfp.flush()
454
454
455 def before(self):
455 def before(self):
456 self.ui.debug('run hg source pre-conversion action\n')
456 self.ui.debug('run hg source pre-conversion action\n')
457
457
458 def after(self):
458 def after(self):
459 self.ui.debug('run hg source post-conversion action\n')
459 self.ui.debug('run hg source post-conversion action\n')
460
460
461 def hasnativeorder(self):
461 def hasnativeorder(self):
462 return True
462 return True
463
463
464 def hasnativeclose(self):
464 def hasnativeclose(self):
465 return True
465 return True
466
466
467 def lookuprev(self, rev):
467 def lookuprev(self, rev):
468 try:
468 try:
469 return hex(self.repo.lookup(rev))
469 return hex(self.repo.lookup(rev))
470 except (error.RepoError, error.LookupError):
470 except (error.RepoError, error.LookupError):
471 return None
471 return None
472
472
473 def getbookmarks(self):
473 def getbookmarks(self):
474 return bookmarks.listbookmarks(self.repo)
474 return bookmarks.listbookmarks(self.repo)
475
475
476 def checkrevformat(self, revstr, mapname='splicemap'):
476 def checkrevformat(self, revstr, mapname='splicemap'):
477 """ Mercurial, revision string is a 40 byte hex """
477 """ Mercurial, revision string is a 40 byte hex """
478 self.checkhexformat(revstr, mapname)
478 self.checkhexformat(revstr, mapname)
General Comments 0
You need to be logged in to leave comments. Login now