449
class RevisionIDSpec(RevisionSpec):
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)
456
class RevisionSpec_revid(RevisionIDSpec):
447
class RevisionSpec_revid(RevisionSpec):
457
448
"""Selects a revision using the revision id."""
459
450
help_txt = """Selects a revision using the revision id.
469
460
prefix = 'revid:'
471
def _as_revision_id(self, context_branch):
462
def _match_on(self, branch, revs):
472
463
# self.spec comes straight from parsing the command line arguments,
473
464
# so we expect it to be a Unicode string. Switch it to the internal
474
465
# representation.
466
revision_id = osutils.safe_revision_id(self.spec, warn=False)
467
return RevisionInfo.from_revision_id(branch, revision_id, revs)
469
def _as_revision_id(self, context_branch):
475
470
return osutils.safe_revision_id(self.spec, warn=False)
818
813
revision_b = other_branch.last_revision()
819
814
if revision_b in (None, revision.NULL_REVISION):
820
815
raise errors.NoCommits(other_branch)
822
branch = other_branch
825
# pull in the remote revisions so we can diff
826
branch.fetch(other_branch, revision_b)
827
except errors.ReadOnlyError:
828
branch = other_branch
816
# pull in the remote revisions so we can diff
817
branch.fetch(other_branch, revision_b)
830
819
revno = branch.revision_id_to_revno(revision_b)
831
820
except errors.NoSuchRevision:
901
884
self._get_submit_location(context_branch))
904
class RevisionSpec_annotate(RevisionIDSpec):
908
help_txt = """Select the revision that last modified the specified line.
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.
916
def _raise_invalid(self, numstring, context_branch):
917
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
918
'No such line: %s' % numstring)
920
def _as_revision_id(self, context_branch):
921
path, numstring = self.spec.rsplit(':', 1)
923
index = int(numstring) - 1
925
self._raise_invalid(numstring, context_branch)
926
tree, file_path = workingtree.WorkingTree.open_containing(path)
929
file_id = tree.path2id(file_path)
931
raise errors.InvalidRevisionSpec(self.user_spec,
932
context_branch, "File '%s' is not versioned." %
934
revision_ids = [r for (r, l) in tree.annotate_iter(file_id)]
938
revision_id = revision_ids[index]
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)
947
class RevisionSpec_mainline(RevisionIDSpec):
949
help_txt = """Select mainline revision that merged the specified revision.
951
Select the revision that merged the specified revision into mainline.
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
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())
967
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
971
887
# The order in which we want to DWIM a revision spec without any prefix.
972
888
# revno is always tried first and isn't listed here, this is used by
973
889
# RevisionSpec_dwim._match_on
992
908
_register_revspec(RevisionSpec_ancestor)
993
909
_register_revspec(RevisionSpec_branch)
994
910
_register_revspec(RevisionSpec_submit)
995
_register_revspec(RevisionSpec_annotate)
996
_register_revspec(RevisionSpec_mainline)
998
912
# classes in this list should have a "prefix" attribute, against which
999
913
# string specs are matched