166
172
spectype.__name__, spec)
167
173
return spectype(spec, _internal=True)
169
for spectype in SPEC_TYPES:
170
if spec.startswith(spectype.prefix):
171
trace.mutter('Returning RevisionSpec %s for %s',
172
spectype.__name__, spec)
173
return spectype(spec, _internal=True)
174
175
# Otherwise treat it as a DWIM, build the RevisionSpec object and
175
176
# wait for _match_on to be called.
176
177
return RevisionSpec_dwim(spec, _internal=True)
333
345
# really relevant.
334
346
raise errors.InvalidRevisionSpec(self.spec, branch)
349
def append_possible_revspec(cls, revspec):
350
"""Append a possible DWIM revspec.
352
:param revspec: Revision spec to try.
354
cls._possible_revspecs.append(registry._ObjectGetter(revspec))
357
def append_possible_lazy_revspec(cls, module_name, member_name):
358
"""Append a possible lazily loaded DWIM revspec.
360
:param module_name: Name of the module with the revspec
361
:param member_name: Name of the revspec within the module
363
cls._possible_revspecs.append(
364
registry._LazyObjectGetter(module_name, member_name))
337
367
class RevisionSpec_revno(RevisionSpec):
338
368
"""Selects a revision using a number."""
460
497
prefix = 'revid:'
462
def _match_on(self, branch, revs):
499
def _as_revision_id(self, context_branch):
463
500
# self.spec comes straight from parsing the command line arguments,
464
501
# so we expect it to be a Unicode string. Switch it to the internal
465
502
# 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):
470
503
return osutils.safe_revision_id(self.spec, warn=False)
813
846
revision_b = other_branch.last_revision()
814
847
if revision_b in (None, revision.NULL_REVISION):
815
848
raise errors.NoCommits(other_branch)
816
# pull in the remote revisions so we can diff
817
branch.fetch(other_branch, revision_b)
850
branch = other_branch
853
# pull in the remote revisions so we can diff
854
branch.fetch(other_branch, revision_b)
855
except errors.ReadOnlyError:
856
branch = other_branch
819
858
revno = branch.revision_id_to_revno(revision_b)
820
859
except errors.NoSuchRevision:
884
929
self._get_submit_location(context_branch))
932
class RevisionSpec_annotate(RevisionIDSpec):
936
help_txt = """Select the revision that last modified the specified line.
938
Select the revision that last modified the specified line. Line is
939
specified as path:number. Path is a relative path to the file. Numbers
940
start at 1, and are relative to the current version, not the last-
941
committed version of the file.
944
def _raise_invalid(self, numstring, context_branch):
945
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
946
'No such line: %s' % numstring)
948
def _as_revision_id(self, context_branch):
949
path, numstring = self.spec.rsplit(':', 1)
951
index = int(numstring) - 1
953
self._raise_invalid(numstring, context_branch)
954
tree, file_path = workingtree.WorkingTree.open_containing(path)
957
file_id = tree.path2id(file_path)
959
raise errors.InvalidRevisionSpec(self.user_spec,
960
context_branch, "File '%s' is not versioned." %
962
revision_ids = [r for (r, l) in tree.annotate_iter(file_id)]
966
revision_id = revision_ids[index]
968
self._raise_invalid(numstring, context_branch)
969
if revision_id == revision.CURRENT_REVISION:
970
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
971
'Line %s has not been committed.' % numstring)
975
class RevisionSpec_mainline(RevisionIDSpec):
977
help_txt = """Select mainline revision that merged the specified revision.
979
Select the revision that merged the specified revision into mainline.
984
def _as_revision_id(self, context_branch):
985
revspec = RevisionSpec.from_string(self.spec)
986
if revspec.get_branch() is None:
987
spec_branch = context_branch
989
spec_branch = _mod_branch.Branch.open(revspec.get_branch())
990
revision_id = revspec.as_revision_id(spec_branch)
991
graph = context_branch.repository.get_graph()
992
result = graph.find_lefthand_merger(revision_id,
993
context_branch.last_revision())
995
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
887
999
# The order in which we want to DWIM a revision spec without any prefix.
888
1000
# revno is always tried first and isn't listed here, this is used by
889
1001
# RevisionSpec_dwim._match_on
891
RevisionSpec_tag, # Let's try for a tag
892
RevisionSpec_revid, # Maybe it's a revid?
893
RevisionSpec_date, # Perhaps a date?
894
RevisionSpec_branch, # OK, last try, maybe it's a branch
1002
dwim_revspecs = symbol_versioning.deprecated_list(
1003
symbol_versioning.deprecated_in((2, 4, 0)), "dwim_revspecs", [])
1005
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_tag)
1006
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_revid)
1007
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_date)
1008
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_branch)
898
1010
revspec_registry = registry.Registry()
899
1011
def _register_revspec(revspec):
908
1020
_register_revspec(RevisionSpec_ancestor)
909
1021
_register_revspec(RevisionSpec_branch)
910
1022
_register_revspec(RevisionSpec_submit)
912
# classes in this list should have a "prefix" attribute, against which
913
# string specs are matched
914
SPEC_TYPES = symbol_versioning.deprecated_list(
915
symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])
1023
_register_revspec(RevisionSpec_annotate)
1024
_register_revspec(RevisionSpec_mainline)