def do_readlocked_repository_request(self, repository, revision_id): """Return the result of repository.get_revision_graph(revision_id). Deprecated as of bzr 1.4, but supported for older clients. :param repository: The repository to query in. :param revision_id: The utf8 encoded revision_id to get a graph from. :return: A smart server response where the body contains an utf8 encoded flattened list of the revision graph. """ if not revision_id: revision_id = None lines = [] graph = repository.get_graph() if revision_id: search_ids = [revision_id] else: search_ids = repository.all_revision_ids() search = graph._make_breadth_first_searcher(search_ids) transitive_ids = set() map(transitive_ids.update, list(search)) parent_map = graph.get_parent_map(transitive_ids) revision_graph = _strip_NULL_ghosts(parent_map) if revision_id and revision_id not in revision_graph: # Note that we return an empty body, rather than omitting the body. # This way the client knows that it can always expect to find a body # in the response for this method, even in the error case. return FailedSmartServerResponse(('nosuchrevision', revision_id), '') for revision, parents in revision_graph.items(): lines.append(' '.join((revision, ) + tuple(parents))) return SuccessfulSmartServerResponse(('ok', ), '\n'.join(lines))
def do_tip_change_with_locked_branch(self, branch, new_last_revision_id, allow_divergence, allow_overwrite_descendant): """Set the last revision of the branch. New in 1.6. :param new_last_revision_id: the revision ID to set as the last revision of the branch. :param allow_divergence: A flag. If non-zero, change the revision ID even if the new_last_revision_id's ancestry has diverged from the current last revision. If zero, a 'Diverged' error will be returned if new_last_revision_id is not a descendant of the current last revision. :param allow_overwrite_descendant: A flag. If zero and new_last_revision_id is not a descendant of the current last revision, then the last revision will not be changed. If non-zero and there is no divergence, then the last revision is always changed. :returns: on success, a tuple of ('ok', revno, revision_id), where revno and revision_id are the new values of the current last revision info. The revision_id might be different to the new_last_revision_id if allow_overwrite_descendant was not set. """ do_not_overwrite_descendant = not allow_overwrite_descendant try: last_revno, last_rev = branch.last_revision_info() graph = branch.repository.get_graph() if not allow_divergence or do_not_overwrite_descendant: relation = branch._revision_relations(last_rev, new_last_revision_id, graph) if relation == 'diverged' and not allow_divergence: return FailedSmartServerResponse(('Diverged', )) if relation == 'a_descends_from_b' and do_not_overwrite_descendant: return SuccessfulSmartServerResponse( ('ok', last_revno, last_rev)) new_revno = graph.find_distance_to_null(new_last_revision_id, [(last_rev, last_revno)]) branch.set_last_revision_info(new_revno, new_last_revision_id) except errors.GhostRevisionsHaveNoRevno: return FailedSmartServerResponse( ('NoSuchRevision', new_last_revision_id)) return SuccessfulSmartServerResponse( ('ok', new_revno, new_last_revision_id))
def do_tip_change_with_locked_branch(self, branch, new_revno, new_last_revision_id): try: branch.set_last_revision_info(int(new_revno), new_last_revision_id) except errors.NoSuchRevision: return FailedSmartServerResponse( ('NoSuchRevision', new_last_revision_id)) return SuccessfulSmartServerResponse(('ok', ))
def do_with_locked_branch(self, branch, *args): try: return self.do_tip_change_with_locked_branch(branch, *args) except errors.TipChangeRejected, e: msg = e.msg if isinstance(msg, unicode): msg = msg.encode('utf-8') return FailedSmartServerResponse(('TipChangeRejected', msg))
def do_repository_request(self, repository, token=''): # XXX: this probably should not have a token. if token == '': token = None try: token = repository.lock_write(token=token).repository_token except errors.LockContention, e: return FailedSmartServerResponse(('LockContention',))
def test__str__(self): """SmartServerResponses can be stringified.""" self.assertEqual( "<SmartServerResponse status=OK args=('args',) body='body'>", str(SuccessfulSmartServerResponse(('args',), 'body'))) self.assertEqual( "<SmartServerResponse status=ERR args=('args',) body='body'>", str(FailedSmartServerResponse(('args',), 'body')))
def do_tip_change_with_locked_branch(self, branch, new_last_revision_id): if new_last_revision_id == 'null:': branch.set_revision_history([]) else: if not branch.repository.has_revision(new_last_revision_id): return FailedSmartServerResponse( ('NoSuchRevision', new_last_revision_id)) branch.generate_revision_history(new_last_revision_id) return SuccessfulSmartServerResponse(('ok', ))
def do_bzrdir_request(self): """open a branch at path and return the branch reference or branch.""" try: reference_url = self._bzrdir.get_branch_reference() if reference_url is None: return SuccessfulSmartServerResponse(('ok', '')) else: return SuccessfulSmartServerResponse(('ok', reference_url)) except errors.NotBranchError, e: return FailedSmartServerResponse(('nobranch', ))
def do_bzrdir_request(self, name=None): """Destroy the branch with the specified name. New in 2.5.0. :return: On success, 'ok'. """ try: self._bzrdir.destroy_branch(name) except errors.NotBranchError, e: return FailedSmartServerResponse(('nobranch', ))
def body_stream(self, stream, repository): byte_stream = _stream_to_byte_stream(stream, repository._format) try: for bytes in byte_stream: yield bytes except errors.RevisionNotPresent, e: # This shouldn't be able to happen, but as we don't buffer # everything it can in theory happen. repository.unlock() yield FailedSmartServerResponse(('NoSuchRevision', e.revision_id))
def test_not_allow_diverged(self): """If allow_diverged is not passed, then setting a divergent history returns a Diverged error. """ self.make_branch_with_divergent_history() self.assertEqual( FailedSmartServerResponse(('Diverged',)), self.set_last_revision('child-1', 2)) # The branch tip was not changed. self.assertEqual('child-2', self.tree.branch.last_revision())
def do_repository_request(self, repository, lock_token, write_group_tokens): """Abort a write group.""" repository.lock_write(token=lock_token) try: try: repository.resume_write_group(write_group_tokens) except errors.UnresumableWriteGroup, e: return FailedSmartServerResponse( ('UnresumableWriteGroup', e.write_groups, e.reason)) else:
class SmartServerRepositoryLockWrite(SmartServerRepositoryRequest): def do_repository_request(self, repository, token=''): # XXX: this probably should not have a token. if token == '': token = None try: token = repository.lock_write(token=token) except errors.LockContention, e: return FailedSmartServerResponse(('LockContention', )) except errors.UnlockableTransport: return FailedSmartServerResponse(('UnlockableTransport', ))
def do_bzrdir_request(self, name=None): """Destroy the repository. New in 2.5.0. :return: On success, 'ok'. """ try: self._bzrdir.destroy_repository() except errors.NoRepositoryPresent, e: return FailedSmartServerResponse(('norepository', ))
def do_repository_request(self, repository, lock_token): """Start a write group.""" repository.lock_write(token=lock_token) try: repository.start_write_group() try: tokens = repository.suspend_write_group() except errors.UnsuspendableWriteGroup: return FailedSmartServerResponse(('UnsuspendableWriteGroup',)) finally: repository.unlock() return SuccessfulSmartServerResponse(('ok', tokens))
def do_with_branch(self, branch, branch_token='', repo_token=''): if branch_token == '': branch_token = None if repo_token == '': repo_token = None try: repo_token = branch.repository.lock_write(token=repo_token) try: branch_token = branch.lock_write(token=branch_token) finally: # this leaves the repository with 1 lock branch.repository.unlock() except errors.LockContention: return FailedSmartServerResponse(('LockContention', )) except errors.TokenMismatch: return FailedSmartServerResponse(('TokenMismatch', )) except errors.UnlockableTransport: return FailedSmartServerResponse(('UnlockableTransport', )) except errors.LockFailed, e: return FailedSmartServerResponse( ('LockFailed', str(e.lock), str(e.why)))
def do_repository_request(self, repository, revision_id): """Return the result of repository.get_signature_text(). :param repository: The repository to query in. :return: A smart server response of with the signature text as body. """ try: text = repository.get_signature_text(revision_id) except errors.NoSuchRevision, err: return FailedSmartServerResponse( ('nosuchrevision', err.revision))
def do_bzrdir_request(self): """open a branch at path and return the reference or format.""" try: reference_url = self._bzrdir.get_branch_reference() if reference_url is None: br = self._bzrdir.open_branch(ignore_fallbacks=True) format = br._format.network_name() return SuccessfulSmartServerResponse(('branch', format)) else: return SuccessfulSmartServerResponse(('ref', reference_url)) except errors.NotBranchError, e: return FailedSmartServerResponse(('nobranch', ))
def test_TipChangeRejected(self): """If a pre_change_branch_tip hook raises TipChangeRejected, the verb returns TipChangeRejected. """ rejection_message = u'rejection message\N{INTERROBANG}' def hook_that_rejects(params): raise errors.TipChangeRejected(rejection_message) Branch.hooks.install_named_hook( 'pre_change_branch_tip', hook_that_rejects, None) self.assertEqual( FailedSmartServerResponse( ('TipChangeRejected', rejection_message.encode('utf-8'))), self.set_last_revision('null:', 0))
def do_with_branch(self, branch, revid): """Return branch.revision_id_to_revno(). New in 2.5. The revno is encoded in decimal, the revision_id is encoded as utf8. """ try: dotted_revno = branch.revision_id_to_dotted_revno(revid) except errors.NoSuchRevision: return FailedSmartServerResponse(('NoSuchRevision', revid)) return SuccessfulSmartServerResponse(('ok', ) + tuple(map(str, dotted_revno)))
def do_with_branch(self, branch, branch_token, repo_token): try: branch.repository.lock_write(token=repo_token) try: branch.lock_write(token=branch_token) finally: branch.repository.unlock() except errors.TokenMismatch: return FailedSmartServerResponse(('TokenMismatch', )) if repo_token: branch.repository.dont_leave_lock_in_place() branch.dont_leave_lock_in_place() branch.unlock() return SuccessfulSmartServerResponse(('ok', ))
def do_readlocked_repository_request(self, repository, revno, known_pair): """Find the revid for a given revno, given a known revno/revid pair. New in 1.17. """ try: found_flag, result = repository.get_rev_id_for_revno(revno, known_pair) except errors.RevisionNotPresent, err: if err.revision_id != known_pair[1]: raise AssertionError( 'get_rev_id_for_revno raised RevisionNotPresent for ' 'non-initial revision: ' + err.revision_id) return FailedSmartServerResponse( ('nosuchrevision', err.revision_id))
def do(self, path): """try to open a branch at path and return ok/nobranch. If a bzrdir is not present, an exception is propogated rather than 'no branch' because these are different conditions. """ bzrdir = BzrDir.open_from_transport( self.transport_from_client_path(path)) try: reference_url = bzrdir.get_branch_reference() if reference_url is None: return SuccessfulSmartServerResponse(('ok', '')) else: return SuccessfulSmartServerResponse(('ok', reference_url)) except errors.NotBranchError: return FailedSmartServerResponse(('nobranch', ))
def do_repository_request(self, repository, lock_token, write_group_tokens): """Commit a write group.""" repository.lock_write(token=lock_token) try: try: repository.resume_write_group(write_group_tokens) except errors.UnresumableWriteGroup, e: return FailedSmartServerResponse( ('UnresumableWriteGroup', e.write_groups, e.reason)) try: repository.commit_write_group() except: write_group_tokens = repository.suspend_write_group() # FIXME JRV 2011-11-19: What if the write_group_tokens # have changed? raise
def do_repository_request(self, repository, revision_id): """Return ok if a signature is present for a revision. Introduced in bzr 2.5.0. :param repository: The repository to query in. :param revision_id: The utf8 encoded revision_id to lookup. :return: A smart server response of ('yes', ) if a signature for the revision is present, ('no', ) if it is missing. """ try: if repository.has_signature_for_revision_id(revision_id): return SuccessfulSmartServerResponse(('yes', )) else: return SuccessfulSmartServerResponse(('no', )) except errors.NoSuchRevision: return FailedSmartServerResponse( ('nosuchrevision', revision_id))
def do_repository_request(self, repository, to_network_name): """Get a stream for inserting into a to_format repository. The request body is 'search_bytes', a description of the revisions being requested. In 2.3 this verb added support for search_bytes == 'everything'. Older implementations will respond with a BadSearch error, and clients should catch this and fallback appropriately. :param repository: The repository to stream from. :param to_network_name: The network name of the format of the target repository. """ self._to_format = network_format_registry.get(to_network_name) if self._should_fake_unknown(): return FailedSmartServerResponse( ('UnknownMethod', 'Repository.get_stream')) return None # Signal that we want a body.
def do_repository_request(self, repository, revid, committers): """Return the result of repository.gather_stats(). :param repository: The repository to query in. :param revid: utf8 encoded rev id or an empty string to indicate None :param committers: 'yes' or 'no'. :return: A SmartServerResponse ('ok',), a encoded body looking like committers: 1 firstrev: 1234.230 0 latestrev: 345.700 3600 revisions: 2 But containing only fields returned by the gather_stats() call """ if revid == '': decoded_revision_id = None else: decoded_revision_id = revid if committers == 'yes': decoded_committers = True else: decoded_committers = None try: stats = repository.gather_stats(decoded_revision_id, decoded_committers) except errors.NoSuchRevision: return FailedSmartServerResponse(('nosuchrevision', revid)) body = '' if stats.has_key('committers'): body += 'committers: %d\n' % stats['committers'] if stats.has_key('firstrev'): body += 'firstrev: %.3f %d\n' % stats['firstrev'] if stats.has_key('latestrev'): body += 'latestrev: %.3f %d\n' % stats['latestrev'] if stats.has_key('revisions'): body += 'revisions: %d\n' % stats['revisions'] if stats.has_key('size'): body += 'size: %d\n' % stats['size'] return SuccessfulSmartServerResponse(('ok', ), body)
def do(self, path): """try to find a repository from path upwards This operates precisely like 'bzrdir.find_repository'. If a bzrdir is not present, an exception is propagated rather than 'no branch' because these are different conditions. This is the initial version of this method introduced with the smart server. Modern clients will try the V2 method that adds support for the supports_external_lookups attribute. :return: norepository or ok, relpath. """ try: path, rich_root, tree_ref, external_lookup, name = self._find(path) return SuccessfulSmartServerResponse( ('ok', path, rich_root, tree_ref)) except errors.NoRepositoryPresent: return FailedSmartServerResponse(('norepository', ))
def do(self, path): """try to find a repository from path upwards This operates precisely like 'bzrdir.find_repository'. If a bzrdir is not present, an exception is propogated rather than 'no branch' because these are different conditions. This is the third edition of this method introduced in bzr 1.13, which returns information about the network name of the repository format. :return: norepository or ok, relpath, rich_root, tree_ref, external_lookup, network_name. """ try: path, rich_root, tree_ref, external_lookup, name = self._find(path) return SuccessfulSmartServerResponse( ('ok', path, rich_root, tree_ref, external_lookup, name)) except errors.NoRepositoryPresent: return FailedSmartServerResponse(('norepository', ))
def recreate_search(self, repository, search_bytes, discard_excess=False): """Recreate a search from its serialised form. :param discard_excess: If True, and the search refers to data we don't have, just silently accept that fact - the verb calling recreate_search trusts that clients will look for missing things they expected and get it from elsewhere. """ if search_bytes == 'everything': return vf_search.EverythingResult(repository), None lines = search_bytes.split('\n') if lines[0] == 'ancestry-of': heads = lines[1:] search_result = vf_search.PendingAncestryResult(heads, repository) return search_result, None elif lines[0] == 'search': return self.recreate_search_from_recipe(repository, lines[1:], discard_excess=discard_excess) else: return (None, FailedSmartServerResponse(('BadSearch',)))