202
204
def _match_on(self, branch, revs):
203
205
trace.mutter('Returning RevisionSpec._match_on: None')
204
return RevisionInfo(branch, 0, None)
206
return RevisionInfo(branch, None, None)
206
208
def _match_on_and_check(self, branch, revs):
207
209
info = self._match_on(branch, revs)
210
elif info == (0, None):
211
# special case - the empty tree
212
elif info == (None, None):
213
# special case - nothing supplied
213
215
elif self.prefix:
214
216
raise errors.InvalidRevisionSpec(self.user_spec, branch)
233
235
# will do what you expect.
234
236
in_store = in_history
235
237
in_branch = in_store
239
def as_revision_id(self, context_branch):
240
"""Return just the revision_id for this revisions spec.
242
Some revision specs require a context_branch to be able to determine
243
their value. Not all specs will make use of it.
245
return self._as_revision_id(context_branch)
247
def _as_revision_id(self, context_branch):
248
"""Implementation of as_revision_id()
250
Classes should override this function to provide appropriate
251
functionality. The default is to just call '.in_history().rev_id'
253
return self.in_history(context_branch).rev_id
237
255
def __repr__(self):
238
256
# this is mostly for helping with testing
239
257
return '<%s %s>' % (self.__class__.__name__,
282
300
def _match_on(self, branch, revs):
283
301
"""Lookup a revision by revision number"""
302
branch, revno, revision_id = self._lookup(branch, revs)
303
return RevisionInfo(branch, revno, revision_id)
305
def _lookup(self, branch, revs_or_none):
284
306
loc = self.spec.find(':')
286
308
revno_spec = self.spec
331
351
if len(revisions) != 1:
332
return RevisionInfo(branch, None, None)
352
return branch, None, None
334
354
# there is no traditional 'revno' for dotted-decimal revnos.
335
355
# so for API compatability we return None.
336
return RevisionInfo(branch, None, revisions[0])
356
return branch, None, revisions[0]
358
last_revno, last_revision_id = branch.last_revision_info()
339
360
# if get_rev_id supported negative revnos, there would not be a
340
361
# need for this special case.
341
if (-revno) >= len(revs):
362
if (-revno) >= last_revno:
344
revno = len(revs) + revno + 1
365
revno = last_revno + revno + 1
346
revision_id = branch.get_rev_id(revno, revs)
367
revision_id = branch.get_rev_id(revno, revs_or_none)
347
368
except errors.NoSuchRevision:
348
369
raise errors.InvalidRevisionSpec(self.user_spec, branch)
349
return RevisionInfo(branch, revno, revision_id)
370
return branch, revno, revision_id
372
def _as_revision_id(self, context_branch):
373
# We would have the revno here, but we don't really care
374
branch, revno, revision_id = self._lookup(context_branch, None)
351
377
def needs_branch(self):
352
378
return self.spec.find(':') == -1
384
411
revision_id = osutils.safe_revision_id(self.spec, warn=False)
385
412
return RevisionInfo.from_revision_id(branch, revision_id, revs)
414
def _as_revision_id(self, context_branch):
415
return osutils.safe_revision_id(self.spec, warn=False)
387
417
SPEC_TYPES.append(RevisionSpec_revid)
399
429
last:1 -> return the last revision
400
430
last:3 -> return the revision 2 before the end.
405
435
def _match_on(self, branch, revs):
436
revno, revision_id = self._revno_and_revision_id(branch, revs)
437
return RevisionInfo(branch, revno, revision_id)
439
def _revno_and_revision_id(self, context_branch, revs_or_none):
440
last_revno, last_revision_id = context_branch.last_revision_info()
406
442
if self.spec == '':
408
raise errors.NoCommits(branch)
409
return RevisionInfo(branch, len(revs), revs[-1])
444
raise errors.NoCommits(context_branch)
445
return last_revno, last_revision_id
412
448
offset = int(self.spec)
413
449
except ValueError, e:
414
raise errors.InvalidRevisionSpec(self.user_spec, branch, e)
450
raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
417
raise errors.InvalidRevisionSpec(self.user_spec, branch,
453
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
418
454
'you must supply a positive value')
419
revno = len(revs) - offset + 1
456
revno = last_revno - offset + 1
421
revision_id = branch.get_rev_id(revno, revs)
458
revision_id = context_branch.get_rev_id(revno, revs_or_none)
422
459
except errors.NoSuchRevision:
423
raise errors.InvalidRevisionSpec(self.user_spec, branch)
424
return RevisionInfo(branch, revno, revision_id)
460
raise errors.InvalidRevisionSpec(self.user_spec, context_branch)
461
return revno, revision_id
463
def _as_revision_id(self, context_branch):
464
# We compute the revno as part of the process, but we don't really care
466
revno, revision_id = self._revno_and_revision_id(context_branch, None)
426
469
SPEC_TYPES.append(RevisionSpec_last)
475
518
return RevisionInfo(branch, revno, revision_id)
520
def _as_revision_id(self, context_branch):
521
base_revspec = RevisionSpec.from_string(self.spec)
522
base_revision_id = base_revspec.as_revision_id(context_branch)
523
if base_revision_id == revision.NULL_REVISION:
524
raise errors.InvalidRevisionSpec(self.user_spec, branch,
525
'cannot go before the null: revision')
526
context_repo = context_branch.repository
527
context_repo.lock_read()
529
parent_map = context_repo.get_parent_map([base_revision_id])
531
context_repo.unlock()
532
if base_revision_id not in parent_map:
533
# Ghost, or unknown revision id
534
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
535
'cannot find the matching revision')
536
parents = parent_map[base_revision_id]
538
raise errors.InvalidRevisionSpec(self.user_spec, context_branch,
539
'No parents for revision.')
477
542
SPEC_TYPES.append(RevisionSpec_before)
629
697
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
630
698
return self._find_revision_info(branch, self.spec)
700
def _as_revision_id(self, context_branch):
701
return self._find_revision_id(context_branch, self.spec)
633
704
def _find_revision_info(branch, other_location):
705
revision_id = RevisionSpec_ancestor._find_revision_id(branch,
708
revno = branch.revision_id_to_revno(revision_id)
709
except errors.NoSuchRevision:
711
return RevisionInfo(branch, revno, revision_id)
714
def _find_revision_id(branch, other_location):
634
715
from bzrlib.branch import Branch
636
other_branch = Branch.open(other_location)
637
revision_a = branch.last_revision()
638
revision_b = other_branch.last_revision()
639
for r, b in ((revision_a, branch), (revision_b, other_branch)):
640
if r in (None, revision.NULL_REVISION):
641
raise errors.NoCommits(b)
642
revision_source = revision.MultipleRevisionSources(
643
branch.repository, other_branch.repository)
644
graph = branch.repository.get_graph(other_branch.repository)
645
revision_a = revision.ensure_null(revision_a)
646
revision_b = revision.ensure_null(revision_b)
647
if revision.NULL_REVISION in (revision_a, revision_b):
648
rev_id = revision.NULL_REVISION
650
rev_id = graph.find_unique_lca(revision_a, revision_b)
719
revision_a = revision.ensure_null(branch.last_revision())
720
if revision_a == revision.NULL_REVISION:
721
raise errors.NoCommits(branch)
722
other_branch = Branch.open(other_location)
723
other_branch.lock_read()
725
revision_b = revision.ensure_null(other_branch.last_revision())
726
if revision_b == revision.NULL_REVISION:
727
raise errors.NoCommits(other_branch)
728
graph = branch.repository.get_graph(other_branch.repository)
729
rev_id = graph.find_unique_lca(revision_a, revision_b)
731
other_branch.unlock()
651
732
if rev_id == revision.NULL_REVISION:
652
733
raise errors.NoCommonAncestor(revision_a, revision_b)
654
revno = branch.revision_id_to_revno(rev_id)
655
except errors.NoSuchRevision:
657
return RevisionInfo(branch, revno, rev_id)
660
739
SPEC_TYPES.append(RevisionSpec_ancestor)
686
765
except errors.NoSuchRevision:
688
767
return RevisionInfo(branch, revno, revision_b)
769
def _as_revision_id(self, context_branch):
770
from bzrlib.branch import Branch
771
other_branch = Branch.open(self.spec)
772
last_revision = other_branch.last_revision()
773
last_revision = revision.ensure_null(last_revision)
774
if last_revision == revision.NULL_REVISION:
775
raise errors.NoCommits(other_branch)
690
778
SPEC_TYPES.append(RevisionSpec_branch)
712
800
prefix = 'submit:'
714
def _match_on(self, branch, revs):
715
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
802
def _get_submit_location(self, branch):
716
803
submit_location = branch.get_submit_branch()
717
804
location_type = 'submit branch'
718
805
if submit_location is None:
721
808
if submit_location is None:
722
809
raise errors.NoSubmitBranch(branch)
723
810
trace.note('Using %s %s', location_type, submit_location)
724
return self._find_revision_info(branch, submit_location)
811
return submit_location
813
def _match_on(self, branch, revs):
814
trace.mutter('matching ancestor: on: %s, %s', self.spec, branch)
815
return self._find_revision_info(branch,
816
self._get_submit_location(branch))
818
def _as_revision_id(self, context_branch):
819
return self._find_revision_id(context_branch,
820
self._get_submit_location(context_branch))
727
823
SPEC_TYPES.append(RevisionSpec_submit)