def _as_revision_id(self, context_branch): path, numstring = self.spec.rsplit(':', 1) try: index = int(numstring) - 1 except ValueError: self._raise_invalid(numstring, context_branch) tree, file_path = workingtree.WorkingTree.open_containing(path) tree.lock_read() try: file_id = tree.path2id(file_path) if file_id is None: raise errors.InvalidRevisionSpec( self.user_spec, context_branch, "File '%s' is not versioned." % file_path) revision_ids = [r for (r, l) in tree.annotate_iter(file_id)] finally: tree.unlock() try: revision_id = revision_ids[index] except IndexError: self._raise_invalid(numstring, context_branch) if revision_id == revision.CURRENT_REVISION: raise errors.InvalidRevisionSpec( self.user_spec, context_branch, 'Line %s has not been committed.' % numstring) return revision_id
def _lookup(self, branch): loc = self.spec.find(':') if loc == -1: revno_spec = self.spec branch_spec = None else: revno_spec = self.spec[:loc] branch_spec = self.spec[loc + 1:] if revno_spec == '': if not branch_spec: raise errors.InvalidRevisionSpec( self.user_spec, branch, 'cannot have an empty revno and no branch') revno = None else: try: revno = int(revno_spec) dotted = False except ValueError: # dotted decimal. This arguably should not be here # but the from_string method is a little primitive # right now - RBC 20060928 try: match_revno = tuple( (int(number) for number in revno_spec.split('.'))) except ValueError, e: raise errors.InvalidRevisionSpec(self.user_spec, branch, e) dotted = True
def _match_on(self, branch, revs): r = RevisionSpec.from_string(self.spec)._match_on(branch, revs) if r.revno == 0: raise errors.InvalidRevisionSpec(self.user_spec, branch, 'cannot go before the null: revision') if r.revno is None: # We need to use the repository history here rev = branch.repository.get_revision(r.rev_id) if not rev.parent_ids: revno = 0 revision_id = revision.NULL_REVISION else: revision_id = rev.parent_ids[0] try: revno = revs.index(revision_id) + 1 except ValueError: revno = None else: revno = r.revno - 1 try: revision_id = branch.get_rev_id(revno, revs) except errors.NoSuchRevision: raise errors.InvalidRevisionSpec(self.user_spec, branch) return RevisionInfo(branch, revno, revision_id)
def _match_on(self, branch, revs): """Spec for date revisions: date:value value can be 'yesterday', 'today', 'tomorrow' or a YYYY-MM-DD string. matches the first entry after a given date (either at midnight or at a specified time). """ # XXX: This doesn't actually work # So the proper way of saying 'give me all entries for today' is: # -r date:yesterday..date:today today = datetime.datetime.fromordinal(datetime.date.today().toordinal()) if self.spec.lower() == 'yesterday': dt = today - datetime.timedelta(days=1) elif self.spec.lower() == 'today': dt = today elif self.spec.lower() == 'tomorrow': dt = today + datetime.timedelta(days=1) else: m = self._date_re.match(self.spec) if not m or (not m.group('date') and not m.group('time')): raise errors.InvalidRevisionSpec(self.user_spec, branch, 'invalid date') try: if m.group('date'): year = int(m.group('year')) month = int(m.group('month')) day = int(m.group('day')) else: year = today.year month = today.month day = today.day if m.group('time'): hour = int(m.group('hour')) minute = int(m.group('minute')) if m.group('second'): second = int(m.group('second')) else: second = 0 else: hour, minute, second = 0,0,0 except ValueError: raise errors.InvalidRevisionSpec(self.user_spec, branch, 'invalid date') dt = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=minute, second=second) branch.lock_read() try: rev = bisect.bisect(_RevListToTimestamps(revs, branch), dt) finally: branch.unlock() if rev == len(revs): raise errors.InvalidRevisionSpec(self.user_spec, branch) else: return RevisionInfo(branch, rev + 1)
def _match_on_and_check(self, branch, revs): info = self._match_on(branch, revs) if info: return info elif info == (None, None): # special case - nothing supplied return info elif self.prefix: raise errors.InvalidRevisionSpec(self.user_spec, branch) else: raise errors.InvalidRevisionSpec(self.spec, branch)
def _match_on(self, branch, revs): """Run the lookup and see what we can get.""" # First, see if it's a revno if self._revno_regex.match(self.spec) is not None: try: return self._try_spectype(RevisionSpec_revno, branch) except RevisionSpec_revno.dwim_catchable_exceptions: pass # Next see what has been registered for objgetter in self._possible_revspecs: rs_class = objgetter.get_obj() try: return self._try_spectype(rs_class, branch) except rs_class.dwim_catchable_exceptions: pass # Try the old (deprecated) dwim list: for rs_class in dwim_revspecs: try: return self._try_spectype(rs_class, branch) except rs_class.dwim_catchable_exceptions: pass # Well, I dunno what it is. Note that we don't try to keep track of the # first of last exception raised during the DWIM tries as none seems # really relevant. raise errors.InvalidRevisionSpec(self.spec, branch)
class RevisionSpec_last(RevisionSpec): """Selects the nth revision from the end.""" help_txt = """Selects the nth revision from the end. Supply a positive number to get the nth revision from the end. This is the same as supplying negative numbers to the 'revno:' spec. Examples:: last:1 -> return the last revision last:3 -> return the revision 2 before the end. """ prefix = 'last:' def _match_on(self, branch, revs): revno, revision_id = self._revno_and_revision_id(branch) return RevisionInfo(branch, revno, revision_id) def _revno_and_revision_id(self, context_branch): last_revno, last_revision_id = context_branch.last_revision_info() if self.spec == '': if not last_revno: raise errors.NoCommits(context_branch) return last_revno, last_revision_id try: offset = int(self.spec) except ValueError, e: raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e) if offset <= 0: raise errors.InvalidRevisionSpec( self.user_spec, context_branch, 'you must supply a positive value') revno = last_revno - offset + 1 try: revision_id = context_branch.get_rev_id(revno) except errors.NoSuchRevision: raise errors.InvalidRevisionSpec(self.user_spec, context_branch) return revno, revision_id
def _revno_and_revision_id(self, context_branch): last_revno, last_revision_id = context_branch.last_revision_info() if self.spec == '': if not last_revno: raise errors.NoCommits(context_branch) return last_revno, last_revision_id try: offset = int(self.spec) except ValueError, e: raise errors.InvalidRevisionSpec(self.user_spec, context_branch, e)
def _as_revision_id(self, context_branch): base_revspec = RevisionSpec.from_string(self.spec) base_revision_id = base_revspec.as_revision_id(context_branch) if base_revision_id == revision.NULL_REVISION: raise errors.InvalidRevisionSpec(self.user_spec, context_branch, 'cannot go before the null: revision') context_repo = context_branch.repository context_repo.lock_read() try: parent_map = context_repo.get_parent_map([base_revision_id]) finally: context_repo.unlock() if base_revision_id not in parent_map: # Ghost, or unknown revision id raise errors.InvalidRevisionSpec(self.user_spec, context_branch, 'cannot find the matching revision') parents = parent_map[base_revision_id] if len(parents) < 1: raise errors.InvalidRevisionSpec(self.user_spec, context_branch, 'No parents for revision.') return parents[0]
def _as_revision_id(self, context_branch): revspec = RevisionSpec.from_string(self.spec) if revspec.get_branch() is None: spec_branch = context_branch else: spec_branch = _mod_branch.Branch.open(revspec.get_branch()) revision_id = revspec.as_revision_id(spec_branch) graph = context_branch.repository.get_graph() result = graph.find_lefthand_merger(revision_id, context_branch.last_revision()) if result is None: raise errors.InvalidRevisionSpec(self.user_spec, context_branch) return result
def _raise_invalid(self, numstring, context_branch): raise errors.InvalidRevisionSpec(self.user_spec, context_branch, 'No such line: %s' % numstring)
class RevisionSpec_revno(RevisionSpec): """Selects a revision using a number.""" help_txt = """Selects a revision using a number. Use an integer to specify a revision in the history of the branch. Optionally a branch can be specified. A negative number will count from the end of the branch (-1 is the last revision, -2 the previous one). If the negative number is larger than the branch's history, the first revision is returned. Examples:: revno:1 -> return the first revision of this branch revno:3:/path/to/branch -> return the 3rd revision of the branch '/path/to/branch' revno:-1 -> The last revision in a branch. -2:http://other/branch -> The second to last revision in the remote branch. -1000000 -> Most likely the first revision, unless your history is very long. """ prefix = 'revno:' def _match_on(self, branch, revs): """Lookup a revision by revision number""" branch, revno, revision_id = self._lookup(branch) return RevisionInfo(branch, revno, revision_id) def _lookup(self, branch): loc = self.spec.find(':') if loc == -1: revno_spec = self.spec branch_spec = None else: revno_spec = self.spec[:loc] branch_spec = self.spec[loc + 1:] if revno_spec == '': if not branch_spec: raise errors.InvalidRevisionSpec( self.user_spec, branch, 'cannot have an empty revno and no branch') revno = None else: try: revno = int(revno_spec) dotted = False except ValueError: # dotted decimal. This arguably should not be here # but the from_string method is a little primitive # right now - RBC 20060928 try: match_revno = tuple( (int(number) for number in revno_spec.split('.'))) except ValueError, e: raise errors.InvalidRevisionSpec(self.user_spec, branch, e) dotted = True if branch_spec: # the user has overriden the branch to look in. branch = _mod_branch.Branch.open(branch_spec) if dotted: try: revision_id = branch.dotted_revno_to_revision_id( match_revno, _cache_reverse=True) except errors.NoSuchRevision: raise errors.InvalidRevisionSpec(self.user_spec, branch) else: # there is no traditional 'revno' for dotted-decimal revnos. # so for API compatibility we return None. return branch, None, revision_id else: last_revno, last_revision_id = branch.last_revision_info() if revno < 0: # if get_rev_id supported negative revnos, there would not be a # need for this special case. if (-revno) >= last_revno: revno = 1 else: revno = last_revno + revno + 1 try: revision_id = branch.get_rev_id(revno) except errors.NoSuchRevision: raise errors.InvalidRevisionSpec(self.user_spec, branch) return branch, revno, revision_id
def _match_on(self, branch, revs): if self.spec == "bork": return RevisionInfo.from_revision_id(branch, "r1") else: raise errors.InvalidRevisionSpec(self.spec, branch)