예제 #1
0
 def do(self, path, *args):
     """Open a BzrDir at path, and return `self.do_bzrdir_request(*args)`."""
     try:
         self._bzrdir = BzrDir.open_from_transport(
             self.transport_from_client_path(path))
     except errors.NotBranchError, e:
         return FailedSmartServerResponse(('nobranch', ))
예제 #2
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))
예제 #3
0
 def recreate_search(self, repository, recipe_bytes):
     lines = recipe_bytes.split('\n')
     start_keys = set(lines[0].split(' '))
     exclude_keys = set(lines[1].split(' '))
     revision_count = int(lines[2])
     repository.lock_read()
     try:
         search = repository.get_graph()._make_breadth_first_searcher(
             start_keys)
         while True:
             try:
                 next_revs = search.next()
             except StopIteration:
                 break
             search.stop_searching_any(exclude_keys.intersection(next_revs))
         search_result = search.get_result()
         if search_result.get_recipe()[2] != revision_count:
             # we got back a different amount of data than expected, this
             # gets reported as NoSuchRevision, because less revisions
             # indicates missing revisions, and more should never happen as
             # the excludes list considers ghosts and ensures that ghost
             # filling races are not a problem.
             return (None, FailedSmartServerResponse(('NoSuchRevision', )))
         return (search, None)
     finally:
         repository.unlock()
예제 #4
0
 def test_NoSuchRevision(self):
     """If the revision_id is not present, the verb returns NoSuchRevision.
     """
     revision_id = 'non-existent revision'
     self.assertEqual(
         FailedSmartServerResponse(('NoSuchRevision', revision_id)),
         self.set_last_revision(revision_id, 1))
예제 #5
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)
예제 #6
0
    def recreate_search_from_recipe(self, repository, lines,
        discard_excess=False):
        """Recreate a specific revision search (vs a from-tip search).

        :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.
        """
        start_keys = set(lines[0].split(' '))
        exclude_keys = set(lines[1].split(' '))
        revision_count = int(lines[2])
        repository.lock_read()
        try:
            search = repository.get_graph()._make_breadth_first_searcher(
                start_keys)
            while True:
                try:
                    next_revs = search.next()
                except StopIteration:
                    break
                search.stop_searching_any(exclude_keys.intersection(next_revs))
            (started_keys, excludes, included_keys) = search.get_state()
            if (not discard_excess and len(included_keys) != revision_count):
                # we got back a different amount of data than expected, this
                # gets reported as NoSuchRevision, because less revisions
                # indicates missing revisions, and more should never happen as
                # the excludes list considers ghosts and ensures that ghost
                # filling races are not a problem.
                return (None, FailedSmartServerResponse(('NoSuchRevision',)))
            search_result = vf_search.SearchResult(started_keys, excludes,
                len(included_keys), included_keys)
            return (search_result, None)
        finally:
            repository.unlock()
예제 #7
0
 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))
예제 #8
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')))
예제 #9
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))
예제 #10
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', ))
예제 #11
0
 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',))
예제 #12
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', ))
예제 #13
0
 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))
예제 #14
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', ))
예제 #15
0
    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', ))
예제 #16
0
 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:
예제 #17
0
 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())
예제 #18
0
    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', ))
예제 #19
0
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', ))
예제 #20
0
 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))
예제 #21
0
 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)))
예제 #22
0
    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))
예제 #23
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', ))
예제 #24
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)))
예제 #25
0
 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))
예제 #26
0
 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', ))
예제 #27
0
 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))
예제 #28
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', ))
예제 #29
0
 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
예제 #30
0
    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.