284
285
:return: A dictionary mapping revision_id => dotted revno.
286
last_revision = self.last_revision()
287
revision_graph = repository._old_get_graph(self.repository,
289
merge_sorted_revisions = tsort.merge_sort(
294
287
revision_id_to_revno = dict((rev_id, revno)
295
for seq_num, rev_id, depth, revno, end_of_merge
296
in merge_sorted_revisions)
288
for rev_id, depth, revno, end_of_merge
289
in self.iter_merge_sorted_revisions())
297
290
return revision_id_to_revno
293
def iter_merge_sorted_revisions(self, start_revision_id=None,
294
stop_revision_id=None, stop_rule='exclude', direction='reverse'):
295
"""Walk the revisions for a branch in merge sorted order.
297
Merge sorted order is the output from a merge-aware,
298
topological sort, i.e. all parents come before their
299
children going forward; the opposite for reverse.
301
:param start_revision_id: the revision_id to begin walking from.
302
If None, the branch tip is used.
303
:param stop_revision_id: the revision_id to terminate the walk
304
after. If None, the rest of history is included.
305
:param stop_rule: if stop_revision_id is not None, the precise rule
306
to use for termination:
307
* 'exclude' - leave the stop revision out of the result (default)
308
* 'include' - the stop revision is the last item in the result
309
* 'with-merges' - include the stop revision and all of its
310
merged revisions in the result
311
:param direction: either 'reverse' or 'forward':
312
* reverse means return the start_revision_id first, i.e.
313
start at the most recent revision and go backwards in history
314
* forward returns tuples in the opposite order to reverse.
315
Note in particular that forward does *not* do any intelligent
316
ordering w.r.t. depth as some clients of this API may like.
317
(If required, that ought to be done at higher layers.)
319
:return: an iterator over (revision_id, depth, revno, end_of_merge)
322
* revision_id: the unique id of the revision
323
* depth: How many levels of merging deep this node has been
325
* revno_sequence: This field provides a sequence of
326
revision numbers for all revisions. The format is:
327
(REVNO, BRANCHNUM, BRANCHREVNO). BRANCHNUM is the number of the
328
branch that the revno is on. From left to right the REVNO numbers
329
are the sequence numbers within that branch of the revision.
330
* end_of_merge: When True the next node (earlier in history) is
331
part of a different merge.
333
# Note: depth and revno values are in the context of the branch so
334
# we need the full graph to get stable numbers, regardless of the
336
if self._merge_sorted_revisions_cache is None:
337
last_revision = self.last_revision()
338
graph = self.repository.get_graph()
339
parent_map = dict(((key, value) for key, value in
340
graph.iter_ancestry([last_revision]) if value is not None))
341
revision_graph = repository._strip_NULL_ghosts(parent_map)
342
revs = tsort.merge_sort(revision_graph, last_revision, None,
344
# Drop the sequence # before caching
345
self._merge_sorted_revisions_cache = [r[1:] for r in revs]
347
filtered = self._filter_merge_sorted_revisions(
348
self._merge_sorted_revisions_cache, start_revision_id,
349
stop_revision_id, stop_rule)
350
if direction == 'reverse':
352
if direction == 'forward':
353
return reversed(list(filtered))
355
raise ValueError('invalid direction %r' % direction)
357
def _filter_merge_sorted_revisions(self, merge_sorted_revisions,
358
start_revision_id, stop_revision_id, stop_rule):
359
"""Iterate over an inclusive range of sorted revisions."""
360
rev_iter = iter(merge_sorted_revisions)
361
if start_revision_id is not None:
362
for rev_id, depth, revno, end_of_merge in rev_iter:
363
if rev_id != start_revision_id:
366
# The decision to include the start or not
367
# depends on the stop_rule if a stop is provided
369
iter([(rev_id, depth, revno, end_of_merge)]),
372
if stop_revision_id is None:
373
for rev_id, depth, revno, end_of_merge in rev_iter:
374
yield rev_id, depth, revno, end_of_merge
375
elif stop_rule == 'exclude':
376
for rev_id, depth, revno, end_of_merge in rev_iter:
377
if rev_id == stop_revision_id:
379
yield rev_id, depth, revno, end_of_merge
380
elif stop_rule == 'include':
381
for rev_id, depth, revno, end_of_merge in rev_iter:
382
yield rev_id, depth, revno, end_of_merge
383
if rev_id == stop_revision_id:
385
elif stop_rule == 'with-merges':
386
stop_rev = self.repository.get_revision(stop_revision_id)
387
if stop_rev.parent_ids:
388
left_parent = stop_rev.parent_ids[0]
390
left_parent = _mod_revision.NULL_REVISION
391
for rev_id, depth, revno, end_of_merge in rev_iter:
392
if rev_id == left_parent:
394
yield rev_id, depth, revno, end_of_merge
396
raise ValueError('invalid stop_rule %r' % stop_rule)
299
398
def leave_lock_in_place(self):
300
399
"""Tell this branch object not to release the physical lock when this
301
400
object is unlocked.