예제 #1
0
    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())
예제 #2
0
    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)
예제 #3
0
 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', ))
예제 #4
0
    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', ))
예제 #5
0
    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', ))
예제 #6
0
    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', ))
예제 #7
0
 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',))
예제 #8
0
 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', ))
예제 #9
0
    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', ))
예제 #10
0
 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', ))
예제 #11
0
 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',))
예제 #12
0
    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))
예제 #13
0
    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)))
예제 #14
0
    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))
예제 #15
0
 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))
예제 #16
0
    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()))
예제 #17
0
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))
예제 #18
0
    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())))
예제 #19
0
 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', ))
예제 #20
0
 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')))
예제 #21
0
    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))
예제 #22
0
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', ))
예제 #23
0
 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', ))
예제 #24
0
 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(())
예제 #25
0
 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', ))
예제 #26
0
    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', ))
예제 #27
0
    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)))
예제 #28
0
    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)
예제 #29
0
    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))
예제 #30
0
    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))