def _fetch_revisions(self, to_revnum, pb=None): """Fetch information about all revisions in the remote repository until to_revnum. :param to_revnum: End of range to fetch information for """ assert isinstance(self.saved_maxrevnum, int) if to_revnum <= self.saved_maxrevnum and self.saved_minrevnum == 0: return # Try to fetch log data in lumps, if possible. if self._latest_revnum is None: self._latest_revnum = self.actual._transport.get_latest_revnum() assert isinstance(self._latest_revnum, int) to_revnum = max(min(self._latest_revnum, to_revnum+MAX_OVERHEAD_FETCH), to_revnum) # Subversion 1.4 clients and servers can only deliver a limited set of # revprops if self._transport.has_capability("log-revprops"): todo_revprops = None else: todo_revprops = ["svn:author", "svn:log", "svn:date"] rcvr = CachingLogWalkerUpdater(self, todo_revprops is None) try: try: # The get_log bounds are inclusive at both ends, so the total # number of revisions requested is A - B. rcvr.total = to_revnum - self.saved_maxrevnum # Try to keep the cache consistent by closing any holes early # in the history if self.saved_minrevnum: rcvr.total += self.saved_minrevnum self.mutter("get_log %d->%d", self.saved_minrevnum, 0) self.actual._transport.get_log(rcvr, [u""], self.saved_minrevnum - 1, 0, 0, True, True, False, todo_revprops) if self.saved_minrevnum: raise bzrsvn_errors.IncompleteRepositoryHistory( "first available revision: %d" % self.saved_minrevnum) if to_revnum > self.saved_maxrevnum: self.mutter("get_log %d->%d", to_revnum, self.saved_maxrevnum) self.actual._transport.get_log(rcvr, [u""], to_revnum, self.saved_maxrevnum, 0, True, True, False, todo_revprops) if to_revnum > self.saved_maxrevnum and to_revnum > 0: raise bzrsvn_errors.IncompleteRepositoryHistory( "last available revision: %d" % self.saved_maxrevnum) except subvertpy.SubversionException as e: msg, num = e.args if num == subvertpy.ERR_FS_NO_SUCH_REVISION: raise NoSuchRevision(branch=self, revision="Revision number %d: %s" % (to_revnum, msg)) raise finally: rcvr.finished() self.cache.commit()
def _real_get_properties(self, path, revnum): try: (_, _, props) = self.log._transport.get_dir(path, revnum) except SubversionException as e: if e.args[1] == ERR_FS_NO_SUCH_REVISION: raise NoSuchRevision(self, revnum) raise return props
def iter_changes(self, prefixes, from_revnum, to_revnum=0, limit=0, pb=None): """Return iterator over all the revisions between revnum and 0 named path or inside path. :param prefixes: Prefixes to report about (in from_revnum) :param from_revnum: Start revision. :param to_revnum: End revision. :return: An iterator that yields tuples with (paths, revnum, revprops) where paths is a dictionary with all changes that happened in revnum. """ assert from_revnum >= 0 and to_revnum >= 0 # Subversion 1.4 clients and servers can only deliver a limited set of revprops if self._transport.has_capability("log-revprops"): todo_revprops = None else: todo_revprops = ["svn:author", "svn:log", "svn:date"] try: iterator = self._transport.iter_log(prefixes, from_revnum, to_revnum, limit, True, False, False, revprops=todo_revprops) for (changed_paths, revnum, known_revprops, has_children) in iterator: if revnum == 0 and changed_paths is None: revpaths = changes.REV0_CHANGES elif isinstance(changed_paths, dict): revpaths = strip_slashes(changed_paths) else: revpaths = {} if todo_revprops is None: revprops = known_revprops if revprops is None: revprops = {} else: revprops = lazy_dict(known_revprops, self._transport.revprop_list, revnum) yield (revpaths, revnum, revprops) except subvertpy.SubversionException as e: msg, num = e.args if num == subvertpy.ERR_FS_NO_SUCH_REVISION: raise NoSuchRevision(branch=self, revision="Revision number %d" % from_revnum) raise
def revision_id_to_revno(self, revision_id): """Given a revision id, return its revno""" if is_null(revision_id): return 0 revmeta_history = self._revision_meta_history() # FIXME: Maybe we can parse revision_id as a bzr-svn roundtripped # revision? for revmeta, hidden, mapping in revmeta_history: if hidden: continue if revmeta.get_revision_id(mapping) == revision_id: return revmeta.get_revno(mapping) raise NoSuchRevision(self, revision_id)
def generate_revision_id(self, revnum): """Generate a new revision id for a revision on this branch.""" assert isinstance(revnum, int) revmeta_history = self._revision_meta_history() take_next = False for revmeta, hidden, mapping in revmeta_history: if revmeta.metarev.revnum == revnum or take_next: if hidden: take_next = True continue return revmeta.get_revision_id(mapping) if revmeta.metarev.revnum < revnum: break if take_next: return NULL_REVISION raise NoSuchRevision(self, revnum)
def get_rev_id(self, revno, history=None): """Find the revision id of the specified revno.""" if revno == 0: return NULL_REVISION last_revno = self.revno() if revno <= 0 or revno > last_revno: raise NoSuchRevision(self, revno) count = last_revno - revno for (revmeta, hidden, mapping) in self._revision_meta_history(): if hidden: continue if count == 0: if revmeta.get_revno(mapping) != revno: raise AssertionError( "Expected %d, was (%r,%r) %d" % (revno, revmeta, mapping, revmeta.get_revno(mapping))) return revmeta.get_revision_id(mapping) count -= 1 raise AssertionError
def find_latest_change(self, path, revnum): """Find latest revision that touched path. :param path: Path to check for changes :param revnum: First revision to check """ assert isinstance(path, text_type) assert isinstance(revnum, int) and revnum >= 0 try: return self._transport.iter_log([path], revnum, 0, 2, True, False, False, []).next()[1] except subvertpy.SubversionException as e: msg, num = e.args if num == subvertpy.ERR_FS_NO_SUCH_REVISION: raise NoSuchRevision(branch=self, revision="Revision number %d" % revnum) if num == subvertpy.ERR_FS_NOT_FOUND: return None raise
def get_revision_paths(self, revnum): """Obtain dictionary with all the changes in a particular revision. :param revnum: Subversion revision number :returns: dictionary with paths as keys and (action, copyfrom_path, copyfrom_rev) as values. """ # To make the existing code happy: if revnum == 0: return changes.REV0_CHANGES try: log_iter = self._transport.iter_log([u""], revnum, revnum, 1, True, True, False, []) return strip_slashes(log_iter.next()[0]) except subvertpy.SubversionException as e: msg, num = e.args if num == subvertpy.ERR_FS_NO_SUCH_REVISION: raise NoSuchRevision(branch=self, revision="Revision number %d" % revnum) raise
def get_branch_revnum(self, revid, layout, project=None): if revid in self._cache: return self._cache[revid] last_revnum = self.actual.repos.get_latest_revnum() if self._nonexistant_revnum is not None: if last_revnum <= self._nonexistant_revnum: if revid in self._nonexistant: raise NoSuchRevision(self, revid) try: ret = self.actual.get_branch_revnum(revid, layout, project) except NoSuchRevision: if self._nonexistant_revnum != last_revnum: self._nonexistant_revnum = last_revnum self._nonexistant = set() self._nonexistant.add(revid) raise else: self._cache[revid] = ret return ret
def get_branch_revnum(self, revid, layout, project=None): """Find the (branch, revnum) tuple for a revision id. :return: Tuple with foreign revision id and mapping. """ last_revnum = self.repos.get_latest_revnum() fileprops_to_revnum = last_revnum with ui.ui_factory.nested_progress_bar() as pb: for entry_revid, branch, revnum, mapping in self.discover_revprop_revids( last_revnum, 0, pb=pb): if revid == entry_revid: return (self.repos.uuid, branch, revnum), mapping fileprops_to_revnum = min(fileprops_to_revnum, revnum) for entry_revid, branch, min_revno, max_revno, mapping in self.discover_fileprop_revids( layout, fileprops_to_revnum, 0, project, pb=pb): if revid == entry_revid: (foreign_revid, mapping_name) = self.bisect_fileprop_revid_revnum( revid, branch, min_revno, max_revno) return (foreign_revid, mapping_name) raise NoSuchRevision(self, revid)
def copy_content(self, revision_id=None, pb=None, project=None, mapping=None, limit=None, lossy=False, exclude_non_mainline=None): """See InterRepository.copy_content.""" with self.source.lock_read(), self.target.lock_write(): graph = self.get_graph() if revision_id is not None: heads = [revision_id] else: heads = graph.heads(self.source.all_revision_ids()) exclude_non_mainline = False todo = [] # Go back over the LHS parent until we reach a revid we know for head in heads: try: for revid in graph.iter_lefthand_ancestry(head, (NULL_REVISION, None)): if self._target_has_revision(revid): break todo.append(revid) except RevisionNotPresent as e: raise NoSuchRevision(self.source, e.revision_id) todo.reverse() if limit is not None: # FIXME: This only considers mainline revisions. # Properly keeping track of how many revisions have been # pushed will be fairly complicated though, so for the # moment this is reasonable enough (and passes tests). todo = todo[:limit] mutter("pushing %r into svn", todo) base_foreign_info = None layout = self.target.get_layout() for rev in self.source.get_revisions(todo): if pb is not None: pb.update("pushing revisions", todo.index(rev.revision_id), len(todo)) mutter('pushing %r', rev.revision_id) if base_foreign_info is None: if rev.parent_ids: base_revid = rev.parent_ids[0] else: base_revid = NULL_REVISION base_foreign_info = self._get_foreign_revision_info( base_revid) (base_foreign_revid, base_mapping) = base_foreign_info if base_foreign_revid is None: target_project = None else: (_, target_project, _, _) = layout.parse( base_foreign_revid[1]) bp = determine_branch_path(rev, layout, target_project) mutter("pushing revision include %r to %s", rev.revision_id, bp) target_config = self._get_branch_config(bp) can_push_merged = layout.push_merged_revisions(target_project) if exclude_non_mainline is None: push_merged = can_push_merged and ( target_config.get('push_merged_revisions')) else: push_merged = (not exclude_non_mainline) if push_merged and not can_push_merged: raise BzrError( "Unable to push merged revisions, layout " "does not provide branch path") append_revisions_only = target_config.get('append_revisions_only') if append_revisions_only is None: append_revisions_only = True root_action = self._get_root_action(bp, rev.parent_ids, overwrite=False, append_revisions_only=append_revisions_only, create_prefix=True) (pushed_revid, base_foreign_info) = self.push_revision_inclusive( bp, target_config, rev, push_metadata=not lossy, push_merged=push_merged, root_action=root_action, layout=layout, project=target_project, base_foreign_info=base_foreign_info)
def revision_id_to_revno(s, r): raise NoSuchRevision(s, r)