~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-12-20 16:16:34 UTC
  • mfrom: (3123.5.18 hardlinks)
  • Revision ID: pqm@pqm.ubuntu.com-20071220161634-2kcjb650o21ydko4
Accelerate build_tree using similar workingtrees (abentley)

Show diffs side-by-side

added added

removed removed

Lines of Context:
100
100
 
101
101
        Use this if you don't know or care what the revno is.
102
102
        """
103
 
        if revision_id == revision.NULL_REVISION:
104
 
            return RevisionInfo(branch, 0, revision_id)
105
103
        try:
106
104
            revno = revs.index(revision_id) + 1
107
105
        except ValueError:
135
133
    """
136
134
 
137
135
    prefix = None
138
 
    wants_revision_history = True
139
136
 
140
137
    def __new__(cls, spec, _internal=False):
141
138
        if _internal:
161
158
 
162
159
        if spec is None:
163
160
            return RevisionSpec(None, _internal=True)
 
161
 
 
162
        assert isinstance(spec, basestring), \
 
163
            "You should only supply strings not %s" % (type(spec),)
 
164
 
164
165
        for spectype in SPEC_TYPES:
165
166
            if spec.startswith(spectype.prefix):
166
167
                trace.mutter('Returning RevisionSpec %s for %s',
200
201
 
201
202
    def _match_on(self, branch, revs):
202
203
        trace.mutter('Returning RevisionSpec._match_on: None')
203
 
        return RevisionInfo(branch, None, None)
 
204
        return RevisionInfo(branch, 0, None)
204
205
 
205
206
    def _match_on_and_check(self, branch, revs):
206
207
        info = self._match_on(branch, revs)
207
208
        if info:
208
209
            return info
209
 
        elif info == (None, None):
210
 
            # special case - nothing supplied
 
210
        elif info == (0, None):
 
211
            # special case - the empty tree
211
212
            return info
212
213
        elif self.prefix:
213
214
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
216
217
 
217
218
    def in_history(self, branch):
218
219
        if branch:
219
 
            if self.wants_revision_history:
220
 
                revs = branch.revision_history()
221
 
            else:
222
 
                revs = None
 
220
            revs = branch.revision_history()
223
221
        else:
224
222
            # this should never trigger.
225
223
            # TODO: make it a deprecated code path. RBC 20060928
235
233
    # will do what you expect.
236
234
    in_store = in_history
237
235
    in_branch = in_store
238
 
 
239
 
    def as_revision_id(self, context_branch):
240
 
        """Return just the revision_id for this revisions spec.
241
 
 
242
 
        Some revision specs require a context_branch to be able to determine
243
 
        their value. Not all specs will make use of it.
244
 
        """
245
 
        return self._as_revision_id(context_branch)
246
 
 
247
 
    def _as_revision_id(self, context_branch):
248
 
        """Implementation of as_revision_id()
249
 
 
250
 
        Classes should override this function to provide appropriate
251
 
        functionality. The default is to just call '.in_history().rev_id'
252
 
        """
253
 
        return self.in_history(context_branch).rev_id
254
 
 
 
236
        
255
237
    def __repr__(self):
256
238
        # this is mostly for helping with testing
257
239
        return '<%s %s>' % (self.__class__.__name__,
296
278
                                   your history is very long.
297
279
    """
298
280
    prefix = 'revno:'
299
 
    wants_revision_history = False
300
281
 
301
282
    def _match_on(self, branch, revs):
302
283
        """Lookup a revision by revision number"""
303
 
        branch, revno, revision_id = self._lookup(branch, revs)
304
 
        return RevisionInfo(branch, revno, revision_id)
305
 
 
306
 
    def _lookup(self, branch, revs_or_none):
307
284
        loc = self.spec.find(':')
308
285
        if loc == -1:
309
286
            revno_spec = self.spec
338
315
            # the branch object.
339
316
            from bzrlib.branch import Branch
340
317
            branch = Branch.open(branch_spec)
341
 
            revs_or_none = None
 
318
            # Need to use a new revision history
 
319
            # because we are using a specific branch
 
320
            revs = branch.revision_history()
342
321
 
343
322
        if dotted:
344
323
            branch.lock_read()
350
329
            finally:
351
330
                branch.unlock()
352
331
            if len(revisions) != 1:
353
 
                return branch, None, None
 
332
                return RevisionInfo(branch, None, None)
354
333
            else:
355
334
                # there is no traditional 'revno' for dotted-decimal revnos.
356
335
                # so for  API compatability we return None.
357
 
                return branch, None, revisions[0]
 
336
                return RevisionInfo(branch, None, revisions[0])
358
337
        else:
359
 
            last_revno, last_revision_id = branch.last_revision_info()
360
338
            if revno < 0:
361
339
                # if get_rev_id supported negative revnos, there would not be a
362
340
                # need for this special case.
363
 
                if (-revno) >= last_revno:
 
341
                if (-revno) >= len(revs):
364
342
                    revno = 1
365
343
                else:
366
 
                    revno = last_revno + revno + 1
 
344
                    revno = len(revs) + revno + 1
367
345
            try:
368
 
                revision_id = branch.get_rev_id(revno, revs_or_none)
 
346
                revision_id = branch.get_rev_id(revno, revs)
369
347
            except errors.NoSuchRevision:
370
348
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
371
 
        return branch, revno, revision_id
372
 
 
373
 
    def _as_revision_id(self, context_branch):
374
 
        # We would have the revno here, but we don't really care
375
 
        branch, revno, revision_id = self._lookup(context_branch, None)
376
 
        return revision_id
377
 
 
 
349
        return RevisionInfo(branch, revno, revision_id)
 
350
        
378
351
    def needs_branch(self):
379
352
        return self.spec.find(':') == -1
380
353
 
401
374
    Examples::
402
375
 
403
376
      revid:aaaa@bbbb-123456789 -> Select revision 'aaaa@bbbb-123456789'
404
 
    """
405
 
 
 
377
    """    
406
378
    prefix = 'revid:'
407
379
 
408
380
    def _match_on(self, branch, revs):
412
384
        revision_id = osutils.safe_revision_id(self.spec, warn=False)
413
385
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
414
386
 
415
 
    def _as_revision_id(self, context_branch):
416
 
        return osutils.safe_revision_id(self.spec, warn=False)
417
 
 
418
387
SPEC_TYPES.append(RevisionSpec_revid)
419
388
 
420
389
 
429
398
 
430
399
      last:1        -> return the last revision
431
400
      last:3        -> return the revision 2 before the end.
432
 
    """
 
401
    """    
433
402
 
434
403
    prefix = 'last:'
435
404
 
436
405
    def _match_on(self, branch, revs):
437
 
        revno, revision_id = self._revno_and_revision_id(branch, revs)
438
 
        return RevisionInfo(branch, revno, revision_id)
439
 
 
440
 
    def _revno_and_revision_id(self, context_branch, revs_or_none):
441
 
        last_revno, last_revision_id = context_branch.last_revision_info()
442
 
 
443
406
        if self.spec == '':
444
 
            if not last_revno:
445
 
                raise errors.NoCommits(context_branch)
446
 
            return last_revno, last_revision_id
 
407
            if not revs:
 
408
                raise errors.NoCommits(branch)
 
409
            return RevisionInfo(branch, len(revs), revs[-1])
447
410
 
448
411
        try:
449
412
            offset = int(self.spec)
450
413
        except ValueError, e:
451
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
 
414
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
452
415
 
453
416
        if offset <= 0:
454
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
417
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
455
418
                                             'you must supply a positive value')
456
 
 
457
 
        revno = last_revno - offset + 1
 
419
        revno = len(revs) - offset + 1
458
420
        try:
459
 
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
 
421
            revision_id = branch.get_rev_id(revno, revs)
460
422
        except errors.NoSuchRevision:
461
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
462
 
        return revno, revision_id
463
 
 
464
 
    def _as_revision_id(self, context_branch):
465
 
        # We compute the revno as part of the process, but we don't really care
466
 
        # about it.
467
 
        revno, revision_id = self._revno_and_revision_id(context_branch, None)
468
 
        return revision_id
 
423
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
424
        return RevisionInfo(branch, revno, revision_id)
469
425
 
470
426
SPEC_TYPES.append(RevisionSpec_last)
471
427
 
518
474
                                                 branch)
519
475
        return RevisionInfo(branch, revno, revision_id)
520
476
 
521
 
    def _as_revision_id(self, context_branch):
522
 
        base_revspec = RevisionSpec.from_string(self.spec)
523
 
        base_revision_id = base_revspec.as_revision_id(context_branch)
524
 
        if base_revision_id == revision.NULL_REVISION:
525
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
526
 
                                         'cannot go before the null: revision')
527
 
        context_repo = context_branch.repository
528
 
        context_repo.lock_read()
529
 
        try:
530
 
            parent_map = context_repo.get_parent_map([base_revision_id])
531
 
        finally:
532
 
            context_repo.unlock()
533
 
        if base_revision_id not in parent_map:
534
 
            # Ghost, or unknown revision id
535
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
536
 
                'cannot find the matching revision')
537
 
        parents = parent_map[base_revision_id]
538
 
        if len(parents) < 1:
539
 
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
540
 
                'No parents for revision.')
541
 
        return parents[0]
542
 
 
543
477
SPEC_TYPES.append(RevisionSpec_before)
544
478
 
545
479
 
559
493
            branch.tags.lookup_tag(self.spec),
560
494
            revs)
561
495
 
562
 
    def _as_revision_id(self, context_branch):
563
 
        return context_branch.tags.lookup_tag(self.spec)
564
 
 
565
496
SPEC_TYPES.append(RevisionSpec_tag)
566
497
 
567
498
 
596
527
 
597
528
    One way to display all the changes since yesterday would be::
598
529
 
599
 
        bzr log -r date:yesterday..
 
530
        bzr log -r date:yesterday..-1
600
531
 
601
532
    Examples::
602
533
 
665
596
        finally:
666
597
            branch.unlock()
667
598
        if rev == len(revs):
668
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
 
599
            return RevisionInfo(branch, None)
669
600
        else:
670
601
            return RevisionInfo(branch, rev + 1)
671
602
 
698
629
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
699
630
        return self._find_revision_info(branch, self.spec)
700
631
 
701
 
    def _as_revision_id(self, context_branch):
702
 
        return self._find_revision_id(context_branch, self.spec)
703
 
 
704
632
    @staticmethod
705
633
    def _find_revision_info(branch, other_location):
706
 
        revision_id = RevisionSpec_ancestor._find_revision_id(branch,
707
 
                                                              other_location)
708
 
        try:
709
 
            revno = branch.revision_id_to_revno(revision_id)
710
 
        except errors.NoSuchRevision:
711
 
            revno = None
712
 
        return RevisionInfo(branch, revno, revision_id)
713
 
 
714
 
    @staticmethod
715
 
    def _find_revision_id(branch, other_location):
716
634
        from bzrlib.branch import Branch
717
635
 
 
636
        other_branch = Branch.open(other_location)
 
637
        revision_a = branch.last_revision()
 
638
        revision_b = other_branch.last_revision()
 
639
        for r, b in ((revision_a, branch), (revision_b, other_branch)):
 
640
            if r in (None, revision.NULL_REVISION):
 
641
                raise errors.NoCommits(b)
718
642
        branch.lock_read()
 
643
        other_branch.lock_read()
719
644
        try:
720
 
            revision_a = revision.ensure_null(branch.last_revision())
721
 
            if revision_a == revision.NULL_REVISION:
722
 
                raise errors.NoCommits(branch)
723
 
            other_branch = Branch.open(other_location)
724
 
            other_branch.lock_read()
725
 
            try:
726
 
                revision_b = revision.ensure_null(other_branch.last_revision())
727
 
                if revision_b == revision.NULL_REVISION:
728
 
                    raise errors.NoCommits(other_branch)
729
 
                graph = branch.repository.get_graph(other_branch.repository)
 
645
            revision_source = revision.MultipleRevisionSources(
 
646
                    branch.repository, other_branch.repository)
 
647
            graph = branch.repository.get_graph(other_branch.repository)
 
648
            revision_a = revision.ensure_null(revision_a)
 
649
            revision_b = revision.ensure_null(revision_b)
 
650
            if revision.NULL_REVISION in (revision_a, revision_b):
 
651
                rev_id = revision.NULL_REVISION
 
652
            else:
730
653
                rev_id = graph.find_unique_lca(revision_a, revision_b)
731
 
            finally:
732
 
                other_branch.unlock()
733
 
            if rev_id == revision.NULL_REVISION:
734
 
                raise errors.NoCommonAncestor(revision_a, revision_b)
735
 
            return rev_id
 
654
                if rev_id == revision.NULL_REVISION:
 
655
                    raise errors.NoCommonAncestor(revision_a, revision_b)
 
656
            try:
 
657
                revno = branch.revision_id_to_revno(rev_id)
 
658
            except errors.NoSuchRevision:
 
659
                revno = None
 
660
            return RevisionInfo(branch, revno, rev_id)
736
661
        finally:
737
662
            branch.unlock()
 
663
            other_branch.unlock()
738
664
 
739
665
 
740
666
SPEC_TYPES.append(RevisionSpec_ancestor)
766
692
        except errors.NoSuchRevision:
767
693
            revno = None
768
694
        return RevisionInfo(branch, revno, revision_b)
769
 
 
770
 
    def _as_revision_id(self, context_branch):
771
 
        from bzrlib.branch import Branch
772
 
        other_branch = Branch.open(self.spec)
773
 
        last_revision = other_branch.last_revision()
774
 
        last_revision = revision.ensure_null(last_revision)
775
 
        context_branch.fetch(other_branch, last_revision)
776
 
        if last_revision == revision.NULL_REVISION:
777
 
            raise errors.NoCommits(other_branch)
778
 
        return last_revision
779
 
 
 
695
        
780
696
SPEC_TYPES.append(RevisionSpec_branch)
781
697
 
782
698
 
787
703
 
788
704
    Diffing against this shows all the changes that were made in this branch,
789
705
    and is a good predictor of what merge will do.  The submit branch is
790
 
    used by the bundle and merge directive commands.  If no submit branch
 
706
    used by the bundle and merge directive comands.  If no submit branch
791
707
    is specified, the parent branch is used instead.
792
708
 
793
709
    The common ancestor is the last revision that existed in both
801
717
 
802
718
    prefix = 'submit:'
803
719
 
804
 
    def _get_submit_location(self, branch):
 
720
    def _match_on(self, branch, revs):
 
721
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
805
722
        submit_location = branch.get_submit_branch()
806
723
        location_type = 'submit branch'
807
724
        if submit_location is None:
810
727
        if submit_location is None:
811
728
            raise errors.NoSubmitBranch(branch)
812
729
        trace.note('Using %s %s', location_type, submit_location)
813
 
        return submit_location
814
 
 
815
 
    def _match_on(self, branch, revs):
816
 
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
817
 
        return self._find_revision_info(branch,
818
 
            self._get_submit_location(branch))
819
 
 
820
 
    def _as_revision_id(self, context_branch):
821
 
        return self._find_revision_id(context_branch,
822
 
            self._get_submit_location(context_branch))
 
730
        return self._find_revision_info(branch, submit_location)
823
731
 
824
732
 
825
733
SPEC_TYPES.append(RevisionSpec_submit)