~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revisionspec.py

  • Committer: John Arbash Meinel
  • Date: 2008-08-25 21:50:11 UTC
  • mfrom: (0.11.3 tools)
  • mto: This revision was merged to the branch mainline in revision 3659.
  • Revision ID: john@arbash-meinel.com-20080825215011-de9esmzgkue3e522
Merge in Lukáš's helper scripts.
Update the packaging documents to describe how to do the releases
using bzr-builddeb to package all distro platforms
simultaneously.

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)
103
105
        try:
104
106
            revno = revs.index(revision_id) + 1
105
107
        except ValueError:
133
135
    """
134
136
 
135
137
    prefix = None
 
138
    wants_revision_history = True
136
139
 
137
140
    def __new__(cls, spec, _internal=False):
138
141
        if _internal:
158
161
 
159
162
        if spec is None:
160
163
            return RevisionSpec(None, _internal=True)
161
 
 
162
 
        assert isinstance(spec, basestring), \
163
 
            "You should only supply strings not %s" % (type(spec),)
164
 
 
165
164
        for spectype in SPEC_TYPES:
166
165
            if spec.startswith(spectype.prefix):
167
166
                trace.mutter('Returning RevisionSpec %s for %s',
201
200
 
202
201
    def _match_on(self, branch, revs):
203
202
        trace.mutter('Returning RevisionSpec._match_on: None')
204
 
        return RevisionInfo(branch, 0, None)
 
203
        return RevisionInfo(branch, None, None)
205
204
 
206
205
    def _match_on_and_check(self, branch, revs):
207
206
        info = self._match_on(branch, revs)
208
207
        if info:
209
208
            return info
210
 
        elif info == (0, None):
211
 
            # special case - the empty tree
 
209
        elif info == (None, None):
 
210
            # special case - nothing supplied
212
211
            return info
213
212
        elif self.prefix:
214
213
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
217
216
 
218
217
    def in_history(self, branch):
219
218
        if branch:
220
 
            revs = branch.revision_history()
 
219
            if self.wants_revision_history:
 
220
                revs = branch.revision_history()
 
221
            else:
 
222
                revs = None
221
223
        else:
222
224
            # this should never trigger.
223
225
            # TODO: make it a deprecated code path. RBC 20060928
233
235
    # will do what you expect.
234
236
    in_store = in_history
235
237
    in_branch = in_store
236
 
        
 
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
 
237
255
    def __repr__(self):
238
256
        # this is mostly for helping with testing
239
257
        return '<%s %s>' % (self.__class__.__name__,
278
296
                                   your history is very long.
279
297
    """
280
298
    prefix = 'revno:'
 
299
    wants_revision_history = False
281
300
 
282
301
    def _match_on(self, branch, revs):
283
302
        """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):
284
307
        loc = self.spec.find(':')
285
308
        if loc == -1:
286
309
            revno_spec = self.spec
315
338
            # the branch object.
316
339
            from bzrlib.branch import Branch
317
340
            branch = Branch.open(branch_spec)
318
 
            # Need to use a new revision history
319
 
            # because we are using a specific branch
320
 
            revs = branch.revision_history()
 
341
            revs_or_none = None
321
342
 
322
343
        if dotted:
323
344
            branch.lock_read()
329
350
            finally:
330
351
                branch.unlock()
331
352
            if len(revisions) != 1:
332
 
                return RevisionInfo(branch, None, None)
 
353
                return branch, None, None
333
354
            else:
334
355
                # there is no traditional 'revno' for dotted-decimal revnos.
335
356
                # so for  API compatability we return None.
336
 
                return RevisionInfo(branch, None, revisions[0])
 
357
                return branch, None, revisions[0]
337
358
        else:
 
359
            last_revno, last_revision_id = branch.last_revision_info()
338
360
            if revno < 0:
339
361
                # if get_rev_id supported negative revnos, there would not be a
340
362
                # need for this special case.
341
 
                if (-revno) >= len(revs):
 
363
                if (-revno) >= last_revno:
342
364
                    revno = 1
343
365
                else:
344
 
                    revno = len(revs) + revno + 1
 
366
                    revno = last_revno + revno + 1
345
367
            try:
346
 
                revision_id = branch.get_rev_id(revno, revs)
 
368
                revision_id = branch.get_rev_id(revno, revs_or_none)
347
369
            except errors.NoSuchRevision:
348
370
                raise errors.InvalidRevisionSpec(self.user_spec, branch)
349
 
        return RevisionInfo(branch, revno, revision_id)
350
 
        
 
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
 
351
378
    def needs_branch(self):
352
379
        return self.spec.find(':') == -1
353
380
 
374
401
    Examples::
375
402
 
376
403
      revid:aaaa@bbbb-123456789 -> Select revision 'aaaa@bbbb-123456789'
377
 
    """    
 
404
    """
 
405
 
378
406
    prefix = 'revid:'
379
407
 
380
408
    def _match_on(self, branch, revs):
384
412
        revision_id = osutils.safe_revision_id(self.spec, warn=False)
385
413
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
386
414
 
 
415
    def _as_revision_id(self, context_branch):
 
416
        return osutils.safe_revision_id(self.spec, warn=False)
 
417
 
387
418
SPEC_TYPES.append(RevisionSpec_revid)
388
419
 
389
420
 
398
429
 
399
430
      last:1        -> return the last revision
400
431
      last:3        -> return the revision 2 before the end.
401
 
    """    
 
432
    """
402
433
 
403
434
    prefix = 'last:'
404
435
 
405
436
    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
 
406
443
        if self.spec == '':
407
 
            if not revs:
408
 
                raise errors.NoCommits(branch)
409
 
            return RevisionInfo(branch, len(revs), revs[-1])
 
444
            if not last_revno:
 
445
                raise errors.NoCommits(context_branch)
 
446
            return last_revno, last_revision_id
410
447
 
411
448
        try:
412
449
            offset = int(self.spec)
413
450
        except ValueError, e:
414
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
 
451
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
415
452
 
416
453
        if offset <= 0:
417
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch,
 
454
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
418
455
                                             'you must supply a positive value')
419
 
        revno = len(revs) - offset + 1
 
456
 
 
457
        revno = last_revno - offset + 1
420
458
        try:
421
 
            revision_id = branch.get_rev_id(revno, revs)
 
459
            revision_id = context_branch.get_rev_id(revno, revs_or_none)
422
460
        except errors.NoSuchRevision:
423
 
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
424
 
        return RevisionInfo(branch, revno, revision_id)
 
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
425
469
 
426
470
SPEC_TYPES.append(RevisionSpec_last)
427
471
 
474
518
                                                 branch)
475
519
        return RevisionInfo(branch, revno, revision_id)
476
520
 
 
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
 
477
543
SPEC_TYPES.append(RevisionSpec_before)
478
544
 
479
545
 
493
559
            branch.tags.lookup_tag(self.spec),
494
560
            revs)
495
561
 
 
562
    def _as_revision_id(self, context_branch):
 
563
        return context_branch.tags.lookup_tag(self.spec)
 
564
 
496
565
SPEC_TYPES.append(RevisionSpec_tag)
497
566
 
498
567
 
527
596
 
528
597
    One way to display all the changes since yesterday would be::
529
598
 
530
 
        bzr log -r date:yesterday..-1
 
599
        bzr log -r date:yesterday..
531
600
 
532
601
    Examples::
533
602
 
596
665
        finally:
597
666
            branch.unlock()
598
667
        if rev == len(revs):
599
 
            return RevisionInfo(branch, None)
 
668
            raise errors.InvalidRevisionSpec(self.user_spec, branch)
600
669
        else:
601
670
            return RevisionInfo(branch, rev + 1)
602
671
 
629
698
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
630
699
        return self._find_revision_info(branch, self.spec)
631
700
 
 
701
    def _as_revision_id(self, context_branch):
 
702
        return self._find_revision_id(context_branch, self.spec)
 
703
 
632
704
    @staticmethod
633
705
    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):
634
716
        from bzrlib.branch import Branch
635
717
 
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)
642
 
        revision_source = revision.MultipleRevisionSources(
643
 
                branch.repository, other_branch.repository)
644
 
        graph = branch.repository.get_graph(other_branch.repository)
645
 
        revision_a = revision.ensure_null(revision_a)
646
 
        revision_b = revision.ensure_null(revision_b)
647
 
        if revision.NULL_REVISION in (revision_a, revision_b):
648
 
            rev_id = revision.NULL_REVISION
649
 
        else:
650
 
            rev_id = graph.find_unique_lca(revision_a, revision_b)
 
718
        branch.lock_read()
 
719
        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)
 
730
                rev_id = graph.find_unique_lca(revision_a, revision_b)
 
731
            finally:
 
732
                other_branch.unlock()
651
733
            if rev_id == revision.NULL_REVISION:
652
734
                raise errors.NoCommonAncestor(revision_a, revision_b)
653
 
        try:
654
 
            revno = branch.revision_id_to_revno(rev_id)
655
 
        except errors.NoSuchRevision:
656
 
            revno = None
657
 
        return RevisionInfo(branch, revno, rev_id)
 
735
            return rev_id
 
736
        finally:
 
737
            branch.unlock()
658
738
 
659
739
 
660
740
SPEC_TYPES.append(RevisionSpec_ancestor)
686
766
        except errors.NoSuchRevision:
687
767
            revno = None
688
768
        return RevisionInfo(branch, revno, revision_b)
689
 
        
 
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
 
690
780
SPEC_TYPES.append(RevisionSpec_branch)
691
781
 
692
782
 
697
787
 
698
788
    Diffing against this shows all the changes that were made in this branch,
699
789
    and is a good predictor of what merge will do.  The submit branch is
700
 
    used by the bundle and merge directive comands.  If no submit branch
 
790
    used by the bundle and merge directive commands.  If no submit branch
701
791
    is specified, the parent branch is used instead.
702
792
 
703
793
    The common ancestor is the last revision that existed in both
711
801
 
712
802
    prefix = 'submit:'
713
803
 
714
 
    def _match_on(self, branch, revs):
715
 
        trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
 
804
    def _get_submit_location(self, branch):
716
805
        submit_location = branch.get_submit_branch()
717
806
        location_type = 'submit branch'
718
807
        if submit_location is None:
721
810
        if submit_location is None:
722
811
            raise errors.NoSubmitBranch(branch)
723
812
        trace.note('Using %s %s', location_type, submit_location)
724
 
        return self._find_revision_info(branch, 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))
725
823
 
726
824
 
727
825
SPEC_TYPES.append(RevisionSpec_submit)