168
166
spectype.__name__, spec)
169
167
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)
171
174
# Otherwise treat it as a DWIM, build the RevisionSpec object and
172
175
# wait for _match_on to be called.
173
176
return RevisionSpec_dwim(spec, _internal=True)
314
312
"""Run the lookup and see what we can get."""
316
314
# First, see if it's a revno
317
if self._revno_regex.match(self.spec) is not None:
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:
319
320
return self._try_spectype(RevisionSpec_revno, branch)
320
321
except RevisionSpec_revno.dwim_catchable_exceptions:
323
324
# Next see what has been registered
324
for objgetter in self._possible_revspecs:
325
rs_class = objgetter.get_obj()
327
return self._try_spectype(rs_class, branch)
328
except rs_class.dwim_catchable_exceptions:
331
# Try the old (deprecated) dwim list:
332
325
for rs_class in dwim_revspecs:
334
327
return self._try_spectype(rs_class, branch)
340
333
# really relevant.
341
334
raise errors.InvalidRevisionSpec(self.spec, branch)
344
def append_possible_revspec(cls, revspec):
345
"""Append a possible DWIM revspec.
347
:param revspec: Revision spec to try.
349
cls._possible_revspecs.append(registry._ObjectGetter(revspec))
352
def append_possible_lazy_revspec(cls, module_name, member_name):
353
"""Append a possible lazily loaded DWIM revspec.
355
:param module_name: Name of the module with the revspec
356
:param member_name: Name of the revspec within the module
358
cls._possible_revspecs.append(
359
registry._LazyObjectGetter(module_name, member_name))
362
337
class RevisionSpec_revno(RevisionSpec):
363
338
"""Selects a revision using a number."""
492
460
prefix = 'revid:'
494
def _as_revision_id(self, context_branch):
462
def _match_on(self, branch, revs):
495
463
# self.spec comes straight from parsing the command line arguments,
496
464
# so we expect it to be a Unicode string. Switch it to the internal
497
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):
498
470
return osutils.safe_revision_id(self.spec, warn=False)
841
813
revision_b = other_branch.last_revision()
842
814
if revision_b in (None, revision.NULL_REVISION):
843
815
raise errors.NoCommits(other_branch)
845
branch = other_branch
848
# pull in the remote revisions so we can diff
849
branch.fetch(other_branch, revision_b)
850
except errors.ReadOnlyError:
851
branch = other_branch
816
# pull in the remote revisions so we can diff
817
branch.fetch(other_branch, revision_b)
853
819
revno = branch.revision_id_to_revno(revision_b)
854
820
except errors.NoSuchRevision:
925
884
self._get_submit_location(context_branch))
928
class RevisionSpec_annotate(RevisionIDSpec):
932
help_txt = """Select the revision that last modified the specified line.
934
Select the revision that last modified the specified line. Line is
935
specified as path:number. Path is a relative path to the file. Numbers
936
start at 1, and are relative to the current version, not the last-
937
committed version of the file.
940
def _raise_invalid(self, numstring, context_branch):
941
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
942
'No such line: %s' % numstring)
944
def _as_revision_id(self, context_branch):
945
path, numstring = self.spec.rsplit(':', 1)
947
index = int(numstring) - 1
949
self._raise_invalid(numstring, context_branch)
950
tree, file_path = workingtree.WorkingTree.open_containing(path)
953
file_id = tree.path2id(file_path)
955
raise errors.InvalidRevisionSpec(self.user_spec,
956
context_branch, "File '%s' is not versioned." %
958
revision_ids = [r for (r, l) in tree.annotate_iter(file_id)]
962
revision_id = revision_ids[index]
964
self._raise_invalid(numstring, context_branch)
965
if revision_id == revision.CURRENT_REVISION:
966
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
967
'Line %s has not been committed.' % numstring)
971
class RevisionSpec_mainline(RevisionIDSpec):
973
help_txt = """Select mainline revision that merged the specified revision.
975
Select the revision that merged the specified revision into mainline.
980
def _as_revision_id(self, context_branch):
981
revspec = RevisionSpec.from_string(self.spec)
982
if revspec.get_branch() is None:
983
spec_branch = context_branch
985
spec_branch = _mod_branch.Branch.open(revspec.get_branch())
986
revision_id = revspec.as_revision_id(spec_branch)
987
graph = context_branch.repository.get_graph()
988
result = graph.find_lefthand_merger(revision_id,
989
context_branch.last_revision())
991
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
995
887
# The order in which we want to DWIM a revision spec without any prefix.
996
888
# revno is always tried first and isn't listed here, this is used by
997
889
# RevisionSpec_dwim._match_on
998
dwim_revspecs = symbol_versioning.deprecated_list(
999
symbol_versioning.deprecated_in((2, 4, 0)), "dwim_revspecs", [])
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
1001
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_tag)
1002
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_revid)
1003
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_date)
1004
RevisionSpec_dwim.append_possible_revspec(RevisionSpec_branch)
1006
898
revspec_registry = registry.Registry()
1007
899
def _register_revspec(revspec):
1016
908
_register_revspec(RevisionSpec_ancestor)
1017
909
_register_revspec(RevisionSpec_branch)
1018
910
_register_revspec(RevisionSpec_submit)
1019
_register_revspec(RevisionSpec_annotate)
1020
_register_revspec(RevisionSpec_mainline)
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", [])