##// END OF EJS Templates
convert: add config option for disabling ancestor parent checks...
Durham Goode -
r25742:d859123e default
parent child Browse files
Show More
@@ -1,425 +1,430 b''
1 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
1 # Copyright 2007 Bryan O'Sullivan <bos@serpentine.com>
2 # Copyright 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
2 # Copyright 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
3 #
3 #
4 # This software may be used and distributed according to the terms of the
4 # This software may be used and distributed according to the terms of the
5 # GNU General Public License version 2 or any later version.
5 # GNU General Public License version 2 or any later version.
6
6
7 import posixpath
7 import posixpath
8 import shlex
8 import shlex
9 from mercurial.i18n import _
9 from mercurial.i18n import _
10 from mercurial import util, error
10 from mercurial import util, error
11 from common import SKIPREV, converter_source
11 from common import SKIPREV, converter_source
12
12
13 def rpairs(path):
13 def rpairs(path):
14 '''Yield tuples with path split at '/', starting with the full path.
14 '''Yield tuples with path split at '/', starting with the full path.
15 No leading, trailing or double '/', please.
15 No leading, trailing or double '/', please.
16 >>> for x in rpairs('foo/bar/baz'): print x
16 >>> for x in rpairs('foo/bar/baz'): print x
17 ('foo/bar/baz', '')
17 ('foo/bar/baz', '')
18 ('foo/bar', 'baz')
18 ('foo/bar', 'baz')
19 ('foo', 'bar/baz')
19 ('foo', 'bar/baz')
20 ('.', 'foo/bar/baz')
20 ('.', 'foo/bar/baz')
21 '''
21 '''
22 i = len(path)
22 i = len(path)
23 while i != -1:
23 while i != -1:
24 yield path[:i], path[i + 1:]
24 yield path[:i], path[i + 1:]
25 i = path.rfind('/', 0, i)
25 i = path.rfind('/', 0, i)
26 yield '.', path
26 yield '.', path
27
27
28 def normalize(path):
28 def normalize(path):
29 ''' We use posixpath.normpath to support cross-platform path format.
29 ''' We use posixpath.normpath to support cross-platform path format.
30 However, it doesn't handle None input. So we wrap it up. '''
30 However, it doesn't handle None input. So we wrap it up. '''
31 if path is None:
31 if path is None:
32 return None
32 return None
33 return posixpath.normpath(path)
33 return posixpath.normpath(path)
34
34
35 class filemapper(object):
35 class filemapper(object):
36 '''Map and filter filenames when importing.
36 '''Map and filter filenames when importing.
37 A name can be mapped to itself, a new name, or None (omit from new
37 A name can be mapped to itself, a new name, or None (omit from new
38 repository).'''
38 repository).'''
39
39
40 def __init__(self, ui, path=None):
40 def __init__(self, ui, path=None):
41 self.ui = ui
41 self.ui = ui
42 self.include = {}
42 self.include = {}
43 self.exclude = {}
43 self.exclude = {}
44 self.rename = {}
44 self.rename = {}
45 if path:
45 if path:
46 if self.parse(path):
46 if self.parse(path):
47 raise util.Abort(_('errors in filemap'))
47 raise util.Abort(_('errors in filemap'))
48
48
49 def parse(self, path):
49 def parse(self, path):
50 errs = 0
50 errs = 0
51 def check(name, mapping, listname):
51 def check(name, mapping, listname):
52 if not name:
52 if not name:
53 self.ui.warn(_('%s:%d: path to %s is missing\n') %
53 self.ui.warn(_('%s:%d: path to %s is missing\n') %
54 (lex.infile, lex.lineno, listname))
54 (lex.infile, lex.lineno, listname))
55 return 1
55 return 1
56 if name in mapping:
56 if name in mapping:
57 self.ui.warn(_('%s:%d: %r already in %s list\n') %
57 self.ui.warn(_('%s:%d: %r already in %s list\n') %
58 (lex.infile, lex.lineno, name, listname))
58 (lex.infile, lex.lineno, name, listname))
59 return 1
59 return 1
60 if (name.startswith('/') or
60 if (name.startswith('/') or
61 name.endswith('/') or
61 name.endswith('/') or
62 '//' in name):
62 '//' in name):
63 self.ui.warn(_('%s:%d: superfluous / in %s %r\n') %
63 self.ui.warn(_('%s:%d: superfluous / in %s %r\n') %
64 (lex.infile, lex.lineno, listname, name))
64 (lex.infile, lex.lineno, listname, name))
65 return 1
65 return 1
66 return 0
66 return 0
67 lex = shlex.shlex(open(path), path, True)
67 lex = shlex.shlex(open(path), path, True)
68 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
68 lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?'
69 cmd = lex.get_token()
69 cmd = lex.get_token()
70 while cmd:
70 while cmd:
71 if cmd == 'include':
71 if cmd == 'include':
72 name = normalize(lex.get_token())
72 name = normalize(lex.get_token())
73 errs += check(name, self.exclude, 'exclude')
73 errs += check(name, self.exclude, 'exclude')
74 self.include[name] = name
74 self.include[name] = name
75 elif cmd == 'exclude':
75 elif cmd == 'exclude':
76 name = normalize(lex.get_token())
76 name = normalize(lex.get_token())
77 errs += check(name, self.include, 'include')
77 errs += check(name, self.include, 'include')
78 errs += check(name, self.rename, 'rename')
78 errs += check(name, self.rename, 'rename')
79 self.exclude[name] = name
79 self.exclude[name] = name
80 elif cmd == 'rename':
80 elif cmd == 'rename':
81 src = normalize(lex.get_token())
81 src = normalize(lex.get_token())
82 dest = normalize(lex.get_token())
82 dest = normalize(lex.get_token())
83 errs += check(src, self.exclude, 'exclude')
83 errs += check(src, self.exclude, 'exclude')
84 self.rename[src] = dest
84 self.rename[src] = dest
85 elif cmd == 'source':
85 elif cmd == 'source':
86 errs += self.parse(normalize(lex.get_token()))
86 errs += self.parse(normalize(lex.get_token()))
87 else:
87 else:
88 self.ui.warn(_('%s:%d: unknown directive %r\n') %
88 self.ui.warn(_('%s:%d: unknown directive %r\n') %
89 (lex.infile, lex.lineno, cmd))
89 (lex.infile, lex.lineno, cmd))
90 errs += 1
90 errs += 1
91 cmd = lex.get_token()
91 cmd = lex.get_token()
92 return errs
92 return errs
93
93
94 def lookup(self, name, mapping):
94 def lookup(self, name, mapping):
95 name = normalize(name)
95 name = normalize(name)
96 for pre, suf in rpairs(name):
96 for pre, suf in rpairs(name):
97 try:
97 try:
98 return mapping[pre], pre, suf
98 return mapping[pre], pre, suf
99 except KeyError:
99 except KeyError:
100 pass
100 pass
101 return '', name, ''
101 return '', name, ''
102
102
103 def __call__(self, name):
103 def __call__(self, name):
104 if self.include:
104 if self.include:
105 inc = self.lookup(name, self.include)[0]
105 inc = self.lookup(name, self.include)[0]
106 else:
106 else:
107 inc = name
107 inc = name
108 if self.exclude:
108 if self.exclude:
109 exc = self.lookup(name, self.exclude)[0]
109 exc = self.lookup(name, self.exclude)[0]
110 else:
110 else:
111 exc = ''
111 exc = ''
112 if (not self.include and exc) or (len(inc) <= len(exc)):
112 if (not self.include and exc) or (len(inc) <= len(exc)):
113 return None
113 return None
114 newpre, pre, suf = self.lookup(name, self.rename)
114 newpre, pre, suf = self.lookup(name, self.rename)
115 if newpre:
115 if newpre:
116 if newpre == '.':
116 if newpre == '.':
117 return suf
117 return suf
118 if suf:
118 if suf:
119 if newpre.endswith('/'):
119 if newpre.endswith('/'):
120 return newpre + suf
120 return newpre + suf
121 return newpre + '/' + suf
121 return newpre + '/' + suf
122 return newpre
122 return newpre
123 return name
123 return name
124
124
125 def active(self):
125 def active(self):
126 return bool(self.include or self.exclude or self.rename)
126 return bool(self.include or self.exclude or self.rename)
127
127
128 # This class does two additional things compared to a regular source:
128 # This class does two additional things compared to a regular source:
129 #
129 #
130 # - Filter and rename files. This is mostly wrapped by the filemapper
130 # - Filter and rename files. This is mostly wrapped by the filemapper
131 # class above. We hide the original filename in the revision that is
131 # class above. We hide the original filename in the revision that is
132 # returned by getchanges to be able to find things later in getfile.
132 # returned by getchanges to be able to find things later in getfile.
133 #
133 #
134 # - Return only revisions that matter for the files we're interested in.
134 # - Return only revisions that matter for the files we're interested in.
135 # This involves rewriting the parents of the original revision to
135 # This involves rewriting the parents of the original revision to
136 # create a graph that is restricted to those revisions.
136 # create a graph that is restricted to those revisions.
137 #
137 #
138 # This set of revisions includes not only revisions that directly
138 # This set of revisions includes not only revisions that directly
139 # touch files we're interested in, but also merges that merge two
139 # touch files we're interested in, but also merges that merge two
140 # or more interesting revisions.
140 # or more interesting revisions.
141
141
142 class filemap_source(converter_source):
142 class filemap_source(converter_source):
143 def __init__(self, ui, baseconverter, filemap):
143 def __init__(self, ui, baseconverter, filemap):
144 super(filemap_source, self).__init__(ui)
144 super(filemap_source, self).__init__(ui)
145 self.base = baseconverter
145 self.base = baseconverter
146 self.filemapper = filemapper(ui, filemap)
146 self.filemapper = filemapper(ui, filemap)
147 self.commits = {}
147 self.commits = {}
148 # if a revision rev has parent p in the original revision graph, then
148 # if a revision rev has parent p in the original revision graph, then
149 # rev will have parent self.parentmap[p] in the restricted graph.
149 # rev will have parent self.parentmap[p] in the restricted graph.
150 self.parentmap = {}
150 self.parentmap = {}
151 # self.wantedancestors[rev] is the set of all ancestors of rev that
151 # self.wantedancestors[rev] is the set of all ancestors of rev that
152 # are in the restricted graph.
152 # are in the restricted graph.
153 self.wantedancestors = {}
153 self.wantedancestors = {}
154 self.convertedorder = None
154 self.convertedorder = None
155 self._rebuilt = False
155 self._rebuilt = False
156 self.origparents = {}
156 self.origparents = {}
157 self.children = {}
157 self.children = {}
158 self.seenchildren = {}
158 self.seenchildren = {}
159 # experimental config: convert.ignoreancestorcheck
160 self.ignoreancestorcheck = self.ui.configbool('convert',
161 'ignoreancestorcheck')
159
162
160 def before(self):
163 def before(self):
161 self.base.before()
164 self.base.before()
162
165
163 def after(self):
166 def after(self):
164 self.base.after()
167 self.base.after()
165
168
166 def setrevmap(self, revmap):
169 def setrevmap(self, revmap):
167 # rebuild our state to make things restartable
170 # rebuild our state to make things restartable
168 #
171 #
169 # To avoid calling getcommit for every revision that has already
172 # To avoid calling getcommit for every revision that has already
170 # been converted, we rebuild only the parentmap, delaying the
173 # been converted, we rebuild only the parentmap, delaying the
171 # rebuild of wantedancestors until we need it (i.e. until a
174 # rebuild of wantedancestors until we need it (i.e. until a
172 # merge).
175 # merge).
173 #
176 #
174 # We assume the order argument lists the revisions in
177 # We assume the order argument lists the revisions in
175 # topological order, so that we can infer which revisions were
178 # topological order, so that we can infer which revisions were
176 # wanted by previous runs.
179 # wanted by previous runs.
177 self._rebuilt = not revmap
180 self._rebuilt = not revmap
178 seen = {SKIPREV: SKIPREV}
181 seen = {SKIPREV: SKIPREV}
179 dummyset = set()
182 dummyset = set()
180 converted = []
183 converted = []
181 for rev in revmap.order:
184 for rev in revmap.order:
182 mapped = revmap[rev]
185 mapped = revmap[rev]
183 wanted = mapped not in seen
186 wanted = mapped not in seen
184 if wanted:
187 if wanted:
185 seen[mapped] = rev
188 seen[mapped] = rev
186 self.parentmap[rev] = rev
189 self.parentmap[rev] = rev
187 else:
190 else:
188 self.parentmap[rev] = seen[mapped]
191 self.parentmap[rev] = seen[mapped]
189 self.wantedancestors[rev] = dummyset
192 self.wantedancestors[rev] = dummyset
190 arg = seen[mapped]
193 arg = seen[mapped]
191 if arg == SKIPREV:
194 if arg == SKIPREV:
192 arg = None
195 arg = None
193 converted.append((rev, wanted, arg))
196 converted.append((rev, wanted, arg))
194 self.convertedorder = converted
197 self.convertedorder = converted
195 return self.base.setrevmap(revmap)
198 return self.base.setrevmap(revmap)
196
199
197 def rebuild(self):
200 def rebuild(self):
198 if self._rebuilt:
201 if self._rebuilt:
199 return True
202 return True
200 self._rebuilt = True
203 self._rebuilt = True
201 self.parentmap.clear()
204 self.parentmap.clear()
202 self.wantedancestors.clear()
205 self.wantedancestors.clear()
203 self.seenchildren.clear()
206 self.seenchildren.clear()
204 for rev, wanted, arg in self.convertedorder:
207 for rev, wanted, arg in self.convertedorder:
205 if rev not in self.origparents:
208 if rev not in self.origparents:
206 try:
209 try:
207 self.origparents[rev] = self.getcommit(rev).parents
210 self.origparents[rev] = self.getcommit(rev).parents
208 except error.RepoLookupError:
211 except error.RepoLookupError:
209 self.ui.debug("unknown revmap source: %s\n" % rev)
212 self.ui.debug("unknown revmap source: %s\n" % rev)
210 continue
213 continue
211 if arg is not None:
214 if arg is not None:
212 self.children[arg] = self.children.get(arg, 0) + 1
215 self.children[arg] = self.children.get(arg, 0) + 1
213
216
214 for rev, wanted, arg in self.convertedorder:
217 for rev, wanted, arg in self.convertedorder:
215 try:
218 try:
216 parents = self.origparents[rev]
219 parents = self.origparents[rev]
217 except KeyError:
220 except KeyError:
218 continue # unknown revmap source
221 continue # unknown revmap source
219 if wanted:
222 if wanted:
220 self.mark_wanted(rev, parents)
223 self.mark_wanted(rev, parents)
221 else:
224 else:
222 self.mark_not_wanted(rev, arg)
225 self.mark_not_wanted(rev, arg)
223 self._discard(arg, *parents)
226 self._discard(arg, *parents)
224
227
225 return True
228 return True
226
229
227 def getheads(self):
230 def getheads(self):
228 return self.base.getheads()
231 return self.base.getheads()
229
232
230 def getcommit(self, rev):
233 def getcommit(self, rev):
231 # We want to save a reference to the commit objects to be able
234 # We want to save a reference to the commit objects to be able
232 # to rewrite their parents later on.
235 # to rewrite their parents later on.
233 c = self.commits[rev] = self.base.getcommit(rev)
236 c = self.commits[rev] = self.base.getcommit(rev)
234 for p in c.parents:
237 for p in c.parents:
235 self.children[p] = self.children.get(p, 0) + 1
238 self.children[p] = self.children.get(p, 0) + 1
236 return c
239 return c
237
240
238 def _cachedcommit(self, rev):
241 def _cachedcommit(self, rev):
239 if rev in self.commits:
242 if rev in self.commits:
240 return self.commits[rev]
243 return self.commits[rev]
241 return self.base.getcommit(rev)
244 return self.base.getcommit(rev)
242
245
243 def _discard(self, *revs):
246 def _discard(self, *revs):
244 for r in revs:
247 for r in revs:
245 if r is None:
248 if r is None:
246 continue
249 continue
247 self.seenchildren[r] = self.seenchildren.get(r, 0) + 1
250 self.seenchildren[r] = self.seenchildren.get(r, 0) + 1
248 if self.seenchildren[r] == self.children[r]:
251 if self.seenchildren[r] == self.children[r]:
249 self.wantedancestors.pop(r, None)
252 self.wantedancestors.pop(r, None)
250 self.parentmap.pop(r, None)
253 self.parentmap.pop(r, None)
251 del self.seenchildren[r]
254 del self.seenchildren[r]
252 if self._rebuilt:
255 if self._rebuilt:
253 del self.children[r]
256 del self.children[r]
254
257
255 def wanted(self, rev, i):
258 def wanted(self, rev, i):
256 # Return True if we're directly interested in rev.
259 # Return True if we're directly interested in rev.
257 #
260 #
258 # i is an index selecting one of the parents of rev (if rev
261 # i is an index selecting one of the parents of rev (if rev
259 # has no parents, i is None). getchangedfiles will give us
262 # has no parents, i is None). getchangedfiles will give us
260 # the list of files that are different in rev and in the parent
263 # the list of files that are different in rev and in the parent
261 # indicated by i. If we're interested in any of these files,
264 # indicated by i. If we're interested in any of these files,
262 # we're interested in rev.
265 # we're interested in rev.
263 try:
266 try:
264 files = self.base.getchangedfiles(rev, i)
267 files = self.base.getchangedfiles(rev, i)
265 except NotImplementedError:
268 except NotImplementedError:
266 raise util.Abort(_("source repository doesn't support --filemap"))
269 raise util.Abort(_("source repository doesn't support --filemap"))
267 for f in files:
270 for f in files:
268 if self.filemapper(f):
271 if self.filemapper(f):
269 return True
272 return True
270 return False
273 return False
271
274
272 def mark_not_wanted(self, rev, p):
275 def mark_not_wanted(self, rev, p):
273 # Mark rev as not interesting and update data structures.
276 # Mark rev as not interesting and update data structures.
274
277
275 if p is None:
278 if p is None:
276 # A root revision. Use SKIPREV to indicate that it doesn't
279 # A root revision. Use SKIPREV to indicate that it doesn't
277 # map to any revision in the restricted graph. Put SKIPREV
280 # map to any revision in the restricted graph. Put SKIPREV
278 # in the set of wanted ancestors to simplify code elsewhere
281 # in the set of wanted ancestors to simplify code elsewhere
279 self.parentmap[rev] = SKIPREV
282 self.parentmap[rev] = SKIPREV
280 self.wantedancestors[rev] = set((SKIPREV,))
283 self.wantedancestors[rev] = set((SKIPREV,))
281 return
284 return
282
285
283 # Reuse the data from our parent.
286 # Reuse the data from our parent.
284 self.parentmap[rev] = self.parentmap[p]
287 self.parentmap[rev] = self.parentmap[p]
285 self.wantedancestors[rev] = self.wantedancestors[p]
288 self.wantedancestors[rev] = self.wantedancestors[p]
286
289
287 def mark_wanted(self, rev, parents):
290 def mark_wanted(self, rev, parents):
288 # Mark rev ss wanted and update data structures.
291 # Mark rev ss wanted and update data structures.
289
292
290 # rev will be in the restricted graph, so children of rev in
293 # rev will be in the restricted graph, so children of rev in
291 # the original graph should still have rev as a parent in the
294 # the original graph should still have rev as a parent in the
292 # restricted graph.
295 # restricted graph.
293 self.parentmap[rev] = rev
296 self.parentmap[rev] = rev
294
297
295 # The set of wanted ancestors of rev is the union of the sets
298 # The set of wanted ancestors of rev is the union of the sets
296 # of wanted ancestors of its parents. Plus rev itself.
299 # of wanted ancestors of its parents. Plus rev itself.
297 wrev = set()
300 wrev = set()
298 for p in parents:
301 for p in parents:
299 if p in self.wantedancestors:
302 if p in self.wantedancestors:
300 wrev.update(self.wantedancestors[p])
303 wrev.update(self.wantedancestors[p])
301 else:
304 else:
302 self.ui.warn(_('warning: %s parent %s is missing\n') %
305 self.ui.warn(_('warning: %s parent %s is missing\n') %
303 (rev, p))
306 (rev, p))
304 wrev.add(rev)
307 wrev.add(rev)
305 self.wantedancestors[rev] = wrev
308 self.wantedancestors[rev] = wrev
306
309
307 def getchanges(self, rev, full):
310 def getchanges(self, rev, full):
308 parents = self.commits[rev].parents
311 parents = self.commits[rev].parents
309 if len(parents) > 1:
312 if len(parents) > 1 and not self.ignoreancestorcheck:
310 self.rebuild()
313 self.rebuild()
311
314
312 # To decide whether we're interested in rev we:
315 # To decide whether we're interested in rev we:
313 #
316 #
314 # - calculate what parents rev will have if it turns out we're
317 # - calculate what parents rev will have if it turns out we're
315 # interested in it. If it's going to have more than 1 parent,
318 # interested in it. If it's going to have more than 1 parent,
316 # we're interested in it.
319 # we're interested in it.
317 #
320 #
318 # - otherwise, we'll compare it with the single parent we found.
321 # - otherwise, we'll compare it with the single parent we found.
319 # If any of the files we're interested in is different in the
322 # If any of the files we're interested in is different in the
320 # the two revisions, we're interested in rev.
323 # the two revisions, we're interested in rev.
321
324
322 # A parent p is interesting if its mapped version (self.parentmap[p]):
325 # A parent p is interesting if its mapped version (self.parentmap[p]):
323 # - is not SKIPREV
326 # - is not SKIPREV
324 # - is still not in the list of parents (we don't want duplicates)
327 # - is still not in the list of parents (we don't want duplicates)
325 # - is not an ancestor of the mapped versions of the other parents or
328 # - is not an ancestor of the mapped versions of the other parents or
326 # there is no parent in the same branch than the current revision.
329 # there is no parent in the same branch than the current revision.
327 mparents = []
330 mparents = []
328 knownparents = set()
331 knownparents = set()
329 branch = self.commits[rev].branch
332 branch = self.commits[rev].branch
330 hasbranchparent = False
333 hasbranchparent = False
331 for i, p1 in enumerate(parents):
334 for i, p1 in enumerate(parents):
332 mp1 = self.parentmap[p1]
335 mp1 = self.parentmap[p1]
333 if mp1 == SKIPREV or mp1 in knownparents:
336 if mp1 == SKIPREV or mp1 in knownparents:
334 continue
337 continue
335 isancestor = any(p2 for p2 in parents
338
336 if p1 != p2 and mp1 != self.parentmap[p2]
339 isancestor = (not self.ignoreancestorcheck and
337 and mp1 in self.wantedancestors[p2])
340 any(p2 for p2 in parents
341 if p1 != p2 and mp1 != self.parentmap[p2]
342 and mp1 in self.wantedancestors[p2]))
338 if not isancestor and not hasbranchparent and len(parents) > 1:
343 if not isancestor and not hasbranchparent and len(parents) > 1:
339 # This could be expensive, avoid unnecessary calls.
344 # This could be expensive, avoid unnecessary calls.
340 if self._cachedcommit(p1).branch == branch:
345 if self._cachedcommit(p1).branch == branch:
341 hasbranchparent = True
346 hasbranchparent = True
342 mparents.append((p1, mp1, i, isancestor))
347 mparents.append((p1, mp1, i, isancestor))
343 knownparents.add(mp1)
348 knownparents.add(mp1)
344 # Discard parents ancestors of other parents if there is a
349 # Discard parents ancestors of other parents if there is a
345 # non-ancestor one on the same branch than current revision.
350 # non-ancestor one on the same branch than current revision.
346 if hasbranchparent:
351 if hasbranchparent:
347 mparents = [p for p in mparents if not p[3]]
352 mparents = [p for p in mparents if not p[3]]
348 wp = None
353 wp = None
349 if mparents:
354 if mparents:
350 wp = max(p[2] for p in mparents)
355 wp = max(p[2] for p in mparents)
351 mparents = [p[1] for p in mparents]
356 mparents = [p[1] for p in mparents]
352 elif parents:
357 elif parents:
353 wp = 0
358 wp = 0
354
359
355 self.origparents[rev] = parents
360 self.origparents[rev] = parents
356
361
357 closed = False
362 closed = False
358 if 'close' in self.commits[rev].extra:
363 if 'close' in self.commits[rev].extra:
359 # A branch closing revision is only useful if one of its
364 # A branch closing revision is only useful if one of its
360 # parents belong to the branch being closed
365 # parents belong to the branch being closed
361 pbranches = [self._cachedcommit(p).branch for p in mparents]
366 pbranches = [self._cachedcommit(p).branch for p in mparents]
362 if branch in pbranches:
367 if branch in pbranches:
363 closed = True
368 closed = True
364
369
365 if len(mparents) < 2 and not closed and not self.wanted(rev, wp):
370 if len(mparents) < 2 and not closed and not self.wanted(rev, wp):
366 # We don't want this revision.
371 # We don't want this revision.
367 # Update our state and tell the convert process to map this
372 # Update our state and tell the convert process to map this
368 # revision to the same revision its parent as mapped to.
373 # revision to the same revision its parent as mapped to.
369 p = None
374 p = None
370 if parents:
375 if parents:
371 p = parents[wp]
376 p = parents[wp]
372 self.mark_not_wanted(rev, p)
377 self.mark_not_wanted(rev, p)
373 self.convertedorder.append((rev, False, p))
378 self.convertedorder.append((rev, False, p))
374 self._discard(*parents)
379 self._discard(*parents)
375 return self.parentmap[rev]
380 return self.parentmap[rev]
376
381
377 # We want this revision.
382 # We want this revision.
378 # Rewrite the parents of the commit object
383 # Rewrite the parents of the commit object
379 self.commits[rev].parents = mparents
384 self.commits[rev].parents = mparents
380 self.mark_wanted(rev, parents)
385 self.mark_wanted(rev, parents)
381 self.convertedorder.append((rev, True, None))
386 self.convertedorder.append((rev, True, None))
382 self._discard(*parents)
387 self._discard(*parents)
383
388
384 # Get the real changes and do the filtering/mapping. To be
389 # Get the real changes and do the filtering/mapping. To be
385 # able to get the files later on in getfile, we hide the
390 # able to get the files later on in getfile, we hide the
386 # original filename in the rev part of the return value.
391 # original filename in the rev part of the return value.
387 changes, copies, cleanp2 = self.base.getchanges(rev, full)
392 changes, copies, cleanp2 = self.base.getchanges(rev, full)
388 files = {}
393 files = {}
389 ncleanp2 = set(cleanp2)
394 ncleanp2 = set(cleanp2)
390 for f, r in changes:
395 for f, r in changes:
391 newf = self.filemapper(f)
396 newf = self.filemapper(f)
392 if newf and (newf != f or newf not in files):
397 if newf and (newf != f or newf not in files):
393 files[newf] = (f, r)
398 files[newf] = (f, r)
394 if newf != f:
399 if newf != f:
395 ncleanp2.discard(f)
400 ncleanp2.discard(f)
396 files = sorted(files.items())
401 files = sorted(files.items())
397
402
398 ncopies = {}
403 ncopies = {}
399 for c in copies:
404 for c in copies:
400 newc = self.filemapper(c)
405 newc = self.filemapper(c)
401 if newc:
406 if newc:
402 newsource = self.filemapper(copies[c])
407 newsource = self.filemapper(copies[c])
403 if newsource:
408 if newsource:
404 ncopies[newc] = newsource
409 ncopies[newc] = newsource
405
410
406 return files, ncopies, ncleanp2
411 return files, ncopies, ncleanp2
407
412
408 def getfile(self, name, rev):
413 def getfile(self, name, rev):
409 realname, realrev = rev
414 realname, realrev = rev
410 return self.base.getfile(realname, realrev)
415 return self.base.getfile(realname, realrev)
411
416
412 def gettags(self):
417 def gettags(self):
413 return self.base.gettags()
418 return self.base.gettags()
414
419
415 def hasnativeorder(self):
420 def hasnativeorder(self):
416 return self.base.hasnativeorder()
421 return self.base.hasnativeorder()
417
422
418 def lookuprev(self, rev):
423 def lookuprev(self, rev):
419 return self.base.lookuprev(rev)
424 return self.base.lookuprev(rev)
420
425
421 def getbookmarks(self):
426 def getbookmarks(self):
422 return self.base.getbookmarks()
427 return self.base.getbookmarks()
423
428
424 def converted(self, rev, sinkrev):
429 def converted(self, rev, sinkrev):
425 self.base.converted(rev, sinkrev)
430 self.base.converted(rev, sinkrev)
General Comments 0
You need to be logged in to leave comments. Login now