~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: 2010-09-24 08:18:19 UTC
  • mfrom: (5365.6.10 annotate-revspec)
  • Revision ID: pqm@pqm.ubuntu.com-20100924081819-5b3m10xulgg6d3cv
(spiv) Add 'mainline' and 'annotate' revision specs. (Aaron Bentley) (Andrew
 Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
""")
25
25
 
26
26
from bzrlib import (
 
27
    branch as _mod_branch,
27
28
    errors,
28
29
    osutils,
29
30
    registry,
30
31
    revision,
31
32
    symbol_versioning,
32
33
    trace,
 
34
    workingtree,
33
35
    )
34
36
 
35
37
 
444
446
 
445
447
 
446
448
 
447
 
class RevisionSpec_revid(RevisionSpec):
 
449
class RevisionIDSpec(RevisionSpec):
 
450
 
 
451
    def _match_on(self, branch, revs):
 
452
        revision_id = self.as_revision_id(branch)
 
453
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
 
454
 
 
455
 
 
456
class RevisionSpec_revid(RevisionIDSpec):
448
457
    """Selects a revision using the revision id."""
449
458
 
450
459
    help_txt = """Selects a revision using the revision id.
459
468
 
460
469
    prefix = 'revid:'
461
470
 
462
 
    def _match_on(self, branch, revs):
 
471
    def _as_revision_id(self, context_branch):
463
472
        # self.spec comes straight from parsing the command line arguments,
464
473
        # so we expect it to be a Unicode string. Switch it to the internal
465
474
        # representation.
466
 
        revision_id = osutils.safe_revision_id(self.spec, warn=False)
467
 
        return RevisionInfo.from_revision_id(branch, revision_id, revs)
468
 
 
469
 
    def _as_revision_id(self, context_branch):
470
475
        return osutils.safe_revision_id(self.spec, warn=False)
471
476
 
472
477
 
896
901
            self._get_submit_location(context_branch))
897
902
 
898
903
 
 
904
class RevisionSpec_annotate(RevisionIDSpec):
 
905
 
 
906
    prefix = 'annotate:'
 
907
 
 
908
    help_txt = """Select the revision that last modified the specified line.
 
909
 
 
910
    Select the revision that last modified the specified line.  Line is
 
911
    specified as path:number.  Path is a relative path to the file.  Numbers
 
912
    start at 1, and are relative to the current version, not the last-
 
913
    committed version of the file.
 
914
    """
 
915
 
 
916
    def _raise_invalid(self, numstring, context_branch):
 
917
        raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
918
            'No such line: %s' % numstring)
 
919
 
 
920
    def _as_revision_id(self, context_branch):
 
921
        path, numstring = self.spec.rsplit(':', 1)
 
922
        try:
 
923
            index = int(numstring) - 1
 
924
        except ValueError:
 
925
            self._raise_invalid(numstring, context_branch)
 
926
        tree, file_path = workingtree.WorkingTree.open_containing(path)
 
927
        tree.lock_read()
 
928
        try:
 
929
            file_id = tree.path2id(file_path)
 
930
            if file_id is None:
 
931
                raise errors.InvalidRevisionSpec(self.user_spec,
 
932
                    context_branch, "File '%s' is not versioned." %
 
933
                    file_path)
 
934
            revision_ids = [r for (r, l) in tree.annotate_iter(file_id)]
 
935
        finally:
 
936
            tree.unlock()
 
937
        try:
 
938
            revision_id = revision_ids[index]
 
939
        except IndexError:
 
940
            self._raise_invalid(numstring, context_branch)
 
941
        if revision_id == revision.CURRENT_REVISION:
 
942
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
 
943
                'Line %s has not been committed.' % numstring)
 
944
        return revision_id
 
945
 
 
946
 
 
947
class RevisionSpec_mainline(RevisionIDSpec):
 
948
 
 
949
    help_txt = """Select mainline revision that merged the specified revision.
 
950
 
 
951
    Select the revision that merged the specified revision into mainline.
 
952
    """
 
953
 
 
954
    prefix = 'mainline:'
 
955
 
 
956
    def _as_revision_id(self, context_branch):
 
957
        revspec = RevisionSpec.from_string(self.spec)
 
958
        if revspec.get_branch() is None:
 
959
            spec_branch = context_branch
 
960
        else:
 
961
            spec_branch = _mod_branch.Branch.open(revspec.get_branch())
 
962
        revision_id = revspec.as_revision_id(spec_branch)
 
963
        graph = context_branch.repository.get_graph()
 
964
        result = graph.find_lefthand_merger(revision_id,
 
965
                                            context_branch.last_revision())
 
966
        if result is None:
 
967
            raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
 
968
        return result
 
969
 
 
970
 
899
971
# The order in which we want to DWIM a revision spec without any prefix.
900
972
# revno is always tried first and isn't listed here, this is used by
901
973
# RevisionSpec_dwim._match_on
920
992
_register_revspec(RevisionSpec_ancestor)
921
993
_register_revspec(RevisionSpec_branch)
922
994
_register_revspec(RevisionSpec_submit)
 
995
_register_revspec(RevisionSpec_annotate)
 
996
_register_revspec(RevisionSpec_mainline)
923
997
 
924
998
# classes in this list should have a "prefix" attribute, against which
925
999
# string specs are matched