def test_branch_last_revision_info_rewind(self): """A branch's tip can be set to a revision that is an ancestor of the current tip, but only if allow_overwrite_descendant is passed. """ self.make_tree_with_two_commits() rev_id_utf8 = u'\xc8'.encode('utf-8') self.assertEqual( (2, 'rev-2'), self.tree.branch.last_revision_info()) # If allow_overwrite_descendant flag is 0, then trying to set the tip # to an older revision ID has no effect. branch_token, repo_token = self.lock_branch() response = self.request.execute( '', branch_token, repo_token, rev_id_utf8, 0, 0) self.assertEqual( SuccessfulSmartServerResponse(('ok', 2, 'rev-2')), response) self.assertEqual( (2, 'rev-2'), self.tree.branch.last_revision_info()) # If allow_overwrite_descendant flag is 1, then setting the tip to an # ancestor works. response = self.request.execute( '', branch_token, repo_token, rev_id_utf8, 0, 1) self.assertEqual( SuccessfulSmartServerResponse(('ok', 1, rev_id_utf8)), response) self.unlock_branch() self.assertEqual( (1, rev_id_utf8), self.tree.branch.last_revision_info())
def do_bzrdir_request(self): """Open a branch at path and return the reference or format. This version introduced in 2.1. Differences to SmartServerRequestOpenBranchV2: * can return 2-element ('nobranch', extra), where 'extra' is a string with an explanation like 'location is a repository'. Previously a 'nobranch' response would never have more than one element. """ 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: # Stringify the exception so that its .detail attribute will be # filled out. str(e) resp = ('nobranch', ) detail = e.detail if detail: if detail.startswith(': '): detail = detail[2:] resp += (detail, ) return FailedSmartServerResponse(resp)
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_repository_request(self, repository): """Return the result of repository.is_shared(). :param repository: The repository to query in. :return: A smart server response of ('yes', ) if the repository is shared, and ('no', ) if it is not. """ if repository.is_shared(): return SuccessfulSmartServerResponse(('yes', )) else: return SuccessfulSmartServerResponse(('no', ))
def do_bzrdir_request(self, name=None): """Check whether there is a working tree present. New in 2.5.0. :return: If there is a working tree present, 'yes'. Otherwise 'no'. """ if self._bzrdir.has_workingtree(): return SuccessfulSmartServerResponse(('yes', )) else: return SuccessfulSmartServerResponse(('no', ))
def do_repository_request(self, repository, revision_id): """Return ok if a specific revision is in the repository at path. :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 the revision is present. ('no', ) if it is missing. """ if repository.has_revision(revision_id): return SuccessfulSmartServerResponse(('yes', )) else: return SuccessfulSmartServerResponse(('no', ))
def do_repository_request(self, repository): pack_collection = getattr(repository, '_pack_collection', None) if pack_collection is None: # This is a not a pack repo, so asking for an autopack is just a # no-op. return SuccessfulSmartServerResponse(('ok',)) repository.lock_write() try: repository._pack_collection.autopack() finally: repository.unlock() return SuccessfulSmartServerResponse(('ok',))
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 do_repository_request(self, repository): """Return the result of repository.make_working_trees(). Introduced in bzr 2.5.0. :param repository: The repository to query in. :return: A smart server response of ('yes', ) if the repository uses working trees, and ('no', ) if it is not. """ if repository.make_working_trees(): return SuccessfulSmartServerResponse(('yes', )) else: return SuccessfulSmartServerResponse(('no', ))
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, str_bool_new_value): if str_bool_new_value == 'True': new_value = True else: new_value = False repository.set_make_working_trees(new_value) return SuccessfulSmartServerResponse(('ok',))
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_repository_request(self, body_bytes): repository = self._repository revision_ids = set(self._revision_ids) include_missing = 'include-missing:' in revision_ids if include_missing: revision_ids.remove('include-missing:') body_lines = body_bytes.split('\n') search_result, error = self.recreate_search_from_recipe( repository, body_lines) if error is not None: return error # TODO might be nice to start up the search again; but thats not # written or tested yet. client_seen_revs = set(search_result.get_keys()) # Always include the requested ids. client_seen_revs.difference_update(revision_ids) repo_graph = repository.get_graph() result = self._expand_requested_revs(repo_graph, revision_ids, client_seen_revs, include_missing) # sorting trivially puts lexographically similar revision ids together. # Compression FTW. lines = [] for revision, parents in sorted(result.items()): lines.append(' '.join((revision, ) + tuple(parents))) return SuccessfulSmartServerResponse( ('ok', ), bz2.compress('\n'.join(lines)))
def do(self, path, network_name): """Create a branch in the bzr dir at path. This operates precisely like 'bzrdir.create_branch'. If a bzrdir is not present, an exception is propogated rather than 'no branch' because these are different conditions (and this method should only be called after establishing that a bzr dir exists anyway). This is the initial version of this method introduced to the smart server for 1.13. :param path: The path to the bzrdir. :param network_name: The network name of the branch type to create. :return: ('ok', branch_format, repo_path, rich_root, tree_ref, external_lookup, repo_format) """ bzrdir = BzrDir.open_from_transport( self.transport_from_client_path(path)) format = branch.network_format_registry.get(network_name) bzrdir.branch_format = format result = format.initialize(bzrdir, name="") rich_root, tree_ref, external_lookup = self._format_to_capabilities( result.repository._format) branch_format = result._format.network_name() repo_format = result.repository._format.network_name() repo_path = self._repo_relpath(bzrdir.root_transport, result.repository) # branch format, repo relpath, rich_root, tree_ref, external_lookup, # repo_network_name return SuccessfulSmartServerResponse( ('ok', branch_format, repo_path, rich_root, tree_ref, external_lookup, repo_format))
def do_with_branch(self, branch): """Return branch.last_revision_info(). The revno is encoded in decimal, the revision_id is encoded as utf8. """ revno, last_revision = branch.last_revision_info() return SuccessfulSmartServerResponse(('ok', str(revno), last_revision))
def do(self, path, network_name, shared): """Create a repository in the bzr dir at path. This operates precisely like 'bzrdir.create_repository'. If a bzrdir is not present, an exception is propagated rather than 'no branch' because these are different conditions (and this method should only be called after establishing that a bzr dir exists anyway). This is the initial version of this method introduced to the smart server for 1.13. :param path: The path to the bzrdir. :param network_name: The network name of the repository type to create. :param shared: The value to pass create_repository for the shared parameter. :return: (ok, rich_root, tree_ref, external_lookup, network_name) """ bzrdir = BzrDir.open_from_transport( self.transport_from_client_path(path)) shared = shared == 'True' format = repository.network_format_registry.get(network_name) bzrdir.repository_format = format result = format.initialize(bzrdir, shared=shared) rich_root, tree_ref, external_lookup = self._format_to_capabilities( result._format) return SuccessfulSmartServerResponse( ('ok', rich_root, tree_ref, external_lookup, result._format.network_name()))
class SmartServerBranchRequestLockWrite(SmartServerBranchRequest): 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))) if repo_token is None: repo_token = '' else: branch.repository.leave_lock_in_place() branch.leave_lock_in_place() branch.unlock() return SuccessfulSmartServerResponse(('ok', branch_token, repo_token))
def do_with_branch(self, branch): """Get the revision history for the branch. The revision list is returned as the body content, with each revision utf8 encoded and \x00 joined. """ return SuccessfulSmartServerResponse( ('ok', ), ('\x00'.join(branch.revision_history())))
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 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, 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))
class SmartServerRepositoryUnlock(SmartServerRepositoryRequest): def do_repository_request(self, repository, token): try: repository.lock_write(token=token) except errors.TokenMismatch, e: return FailedSmartServerResponse(('TokenMismatch', )) repository.dont_leave_lock_in_place() repository.unlock() return SuccessfulSmartServerResponse(('ok', ))
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_with_locked_branch(self, branch, value_dict, name, section): utf8_dict = bencode.bdecode(value_dict) value_dict = {} for key, value in utf8_dict.items(): value_dict[key.decode('utf8')] = value.decode('utf8') if not section: section = None branch._get_config().set_option(value_dict, name, section) return SuccessfulSmartServerResponse(())
def do_end(self): self.queue.put(StopIteration) if self.insert_thread is not None: self.insert_thread.join() if not self.insert_ok: exc_info = self.insert_exception raise exc_info[0], exc_info[1], exc_info[2] write_group_tokens, missing_keys = self.insert_result if write_group_tokens or missing_keys: # bzip needed? missing keys should typically be a small set. # Should this be a streaming body response ? missing_keys = sorted(missing_keys) bytes = bencode.bencode((write_group_tokens, missing_keys)) self.repository.unlock() return SuccessfulSmartServerResponse(('missing-basis', bytes)) else: self.repository.unlock() return SuccessfulSmartServerResponse(('ok', ))
def do(self, path): """Initialize a bzrdir at path. The default format of the server is used. :return: SmartServerResponse(('ok', )) """ target_transport = self.transport_from_client_path(path) BzrDirFormat.get_default_format().initialize_on_transport( target_transport) return SuccessfulSmartServerResponse(('ok', ))
def do_with_branch(self, branch): """Return the heads-to-fetch for a Branch as two bencoded lists. See Branch.heads_to_fetch. New in 2.4. """ must_fetch, if_present_fetch = branch.heads_to_fetch() return SuccessfulSmartServerResponse( (list(must_fetch), list(if_present_fetch)))
def do_with_branch(self, branch): """Return the content of branch.conf The body is not utf8 decoded - its the literal bytestream from disk. """ try: content = branch.control_transport.get_bytes('branch.conf') except errors.NoSuchFile: content = '' return SuccessfulSmartServerResponse(('ok', ), content)
def do_repository_request(self, repository): """Return the serializer format for this repository. New in 2.5.0. :param repository: The repository to query :return: A smart server response ('ok', FORMAT) """ serializer = repository.get_serializer_format() return SuccessfulSmartServerResponse(('ok', serializer))
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))