166
167
spectype.__name__, spec)
167
168
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
170
# Otherwise treat it as a DWIM, build the RevisionSpec object and
175
171
# wait for _match_on to be called.
176
172
return RevisionSpec_dwim(spec, _internal=True)
312
313
"""Run the lookup and see what we can get."""
314
315
# First, see if it's a revno
316
if _revno_regex is None:
317
_revno_regex = re.compile(r'^(?:(\d+(\.\d+)*)|-\d+)(:.*)?$')
318
if _revno_regex.match(self.spec) is not None:
316
if self._revno_regex.match(self.spec) is not None:
320
318
return self._try_spectype(RevisionSpec_revno, branch)
321
319
except RevisionSpec_revno.dwim_catchable_exceptions:
324
322
# Next see what has been registered
323
for objgetter in self._possible_revspecs:
324
rs_class = objgetter.get_obj()
326
return self._try_spectype(rs_class, branch)
327
except rs_class.dwim_catchable_exceptions:
330
# Try the old (deprecated) dwim list:
325
331
for rs_class in dwim_revspecs:
327
333
return self._try_spectype(rs_class, branch)
333
339
# really relevant.
334
340
raise errors.InvalidRevisionSpec(self.spec, branch)
343
def append_possible_revspec(cls, revspec):
344
"""Append a possible DWIM revspec.
346
:param revspec: Revision spec to try.
348
cls._possible_revspecs.append(registry._ObjectGetter(revspec))
351
def append_possible_lazy_revspec(cls, module_name, member_name):
352
"""Append a possible lazily loaded DWIM revspec.
354
:param module_name: Name of the module with the revspec
355
:param member_name: Name of the revspec within the module
357
cls._possible_revspecs.append(
358
registry._LazyObjectGetter(module_name, member_name))
337
361
class RevisionSpec_revno(RevisionSpec):
338
362
"""Selects a revision using a number."""
460
491
prefix = 'revid:'
462
def _match_on(self, branch, revs):
493
def _as_revision_id(self, context_branch):
463
494
# self.spec comes straight from parsing the command line arguments,
464
495
# so we expect it to be a Unicode string. Switch it to the internal
465
496
# 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
497
return osutils.safe_revision_id(self.spec, warn=False)
896
923
self._get_submit_location(context_branch))
926
class RevisionSpec_annotate(RevisionIDSpec):
930
help_txt = """Select the revision that last modified the specified line.
932
Select the revision that last modified the specified line. Line is
933
specified as path:number. Path is a relative path to the file. Numbers
934
start at 1, and are relative to the current version, not the last-
935
committed version of the file.
938
def _raise_invalid(self, numstring, context_branch):
939
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
940
'No such line: %s' % numstring)
942
def _as_revision_id(self, context_branch):
943
path, numstring = self.spec.rsplit(':', 1)
945
index = int(numstring) - 1
947
self._raise_invalid(numstring, context_branch)
948
tree, file_path = workingtree.WorkingTree.open_containing(path)
951
file_id = tree.path2id(file_path)
953
raise errors.InvalidRevisionSpec(self.user_spec,
954
context_branch, "File '%s' is not versioned." %
956
revision_ids = [r for (r, l) in tree.annotate_iter(file_id)]
960
revision_id = revision_ids[index]
962
self._raise_invalid(numstring, context_branch)
963
if revision_id == revision.CURRENT_REVISION:
964
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
965
'Line %s has not been committed.' % numstring)
969
class RevisionSpec_mainline(RevisionIDSpec):
971
help_txt = """Select mainline revision that merged the specified revision.
973
Select the revision that merged the specified revision into mainline.
978
def _as_revision_id(self, context_branch):
979
revspec = RevisionSpec.from_string(self.spec)
980
if revspec.get_branch() is None:
981
spec_branch = context_branch
983
spec_branch = _mod_branch.Branch.open(revspec.get_branch())
984
revision_id = revspec.as_revision_id(spec_branch)
985
graph = context_branch.repository.get_graph()
986
result = graph.find_lefthand_merger(revision_id,
987
context_branch.last_revision())
989
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
899
993
# The order in which we want to DWIM a revision spec without any prefix.
900
994
# revno is always tried first and isn't listed here, this is used by
901
995
# RevisionSpec_dwim._match_on
903
RevisionSpec_tag, # Let's try for a tag
904
RevisionSpec_revid, # Maybe it's a revid?
905
RevisionSpec_date, # Perhaps a date?
906
RevisionSpec_branch, # OK, last try, maybe it's a branch
996
dwim_revspecs = symbol_versioning.deprecated_list(
997
symbol_versioning.deprecated_in((2, 4, 0)), "dwim_revspecs", [])
999
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_tag)
1000
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_revid)
1001
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_date)
1002
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_branch)
910
1004
revspec_registry = registry.Registry()
911
1005
def _register_revspec(revspec):
920
1014
_register_revspec(RevisionSpec_ancestor)
921
1015
_register_revspec(RevisionSpec_branch)
922
1016
_register_revspec(RevisionSpec_submit)
924
# classes in this list should have a "prefix" attribute, against which
925
# string specs are matched
926
SPEC_TYPES = symbol_versioning.deprecated_list(
927
symbol_versioning.deprecated_in((1, 12, 0)), "SPEC_TYPES", [])
1017
_register_revspec(RevisionSpec_annotate)
1018
_register_revspec(RevisionSpec_mainline)