From 320908419788ca67f81cb869bed7249dab1be8a4 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Thu, 2 Nov 2017 22:13:18 -0700 Subject: remove serve-storage and HTTP storage driver This functionality is now better fulfilled by using an off-the-shelf network file system technology to share the BE object directory. This has the advantage of a more comprehensive and integrated security model as well. --- libbe/command/help.py | 29 +--- libbe/command/serve_storage.py | 328 ------------------------------------ libbe/storage/__init__.py | 7 +- libbe/storage/http.py | 368 ----------------------------------------- libbe/ui/command_line.py | 3 +- libbe/util/wsgi.py | 1 - 6 files changed, 4 insertions(+), 732 deletions(-) delete mode 100644 libbe/command/serve_storage.py delete mode 100644 libbe/storage/http.py (limited to 'libbe') diff --git a/libbe/command/help.py b/libbe/command/help.py index 6a04117..3af7769 100644 --- a/libbe/command/help.py +++ b/libbe/command/help.py @@ -33,28 +33,6 @@ may or may not be versioned. If you're using BE to track bugs in your local software, you'll probably be using an on-disk storage based on the VCS you use to version the storage. See `be help init` for details about automatic VCS-detection. - -While most users will be using local storage, BE also supports remote -storage servers. This allows projects to publish their local -repository in a way that's directly accessible to remote users. The -remote users can then use a local BE client to interact with the -remote repository, without having to create a local copy of the -repository. The remote server will be running something like: - - $ be serve-storage --host 123.123.123.123 --port 54321 - -And the local client can run: - - $ be --repo http://123.123.123.123:54321 list - -or whichever command they like. - -Because the storage server serves repositories at the `Storage` level, -it can be inefficient. For example, `be list` will have to transfer -the data for all the bugs in a repository over the wire. The storage -server can also be harder to lock down, because users with write -access can potentially store data that cannot be parsed by BE. For a -more efficient server, see `be serve-commands`. """, ## 'server': """A server for remote BE command execution @@ -64,9 +42,7 @@ particular project is to clone the project repository. They can then use their local BE client to browse the repository and make changes, before pushing their changes back upstream. For the average user seeking to file a bug or comment, this can be too much work. One way -to simplify the process is to use a storage server (see `be help -repo`), but this is not always ideal. A more robust approach is to -use a command server. +to simplify the process is to use a command server. The remote server will be running something like: @@ -79,8 +55,7 @@ And the local client can run: or whichever command they like. The command line arguments are parsed locally, and then POSTed to the command server, where the command is executed. The output of the command is returned to the client for -display. This requires much less traffic over the wire than running -the same command via a storage server. +display. """, } diff --git a/libbe/command/serve_storage.py b/libbe/command/serve_storage.py deleted file mode 100644 index 1d8d0dd..0000000 --- a/libbe/command/serve_storage.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright (C) 2010-2012 Chris Ball -# W. Trevor King -# -# This file is part of Bugs Everywhere. -# -# Bugs Everywhere is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 2 of the License, or (at your option) any -# later version. -# -# Bugs Everywhere is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# Bugs Everywhere. If not, see . - -"""Define the :py:class:`Serve` serving BE Storage over HTTP. - -See Also --------- -:py:mod:`libbe.storage.http` : the associated client -""" - -import logging -import os.path - -import libbe -import libbe.command -import libbe.command.util -import libbe.util.http -import libbe.util.subproc -import libbe.util.wsgi -import libbe.version - -if libbe.TESTING: - import copy - import doctest - import StringIO - import sys - import unittest - import wsgiref.validate - try: - import cherrypy.test.webtest - cherrypy_test_webtest = True - except ImportError: - cherrypy_test_webtest = None - - import libbe.bugdir - import libbe.util.wsgi - - -class ServerApp (libbe.util.wsgi.WSGI_AppObject, - libbe.util.wsgi.WSGI_DataObject): - """WSGI server for a BE Storage instance over HTTP. - - RESTful_ WSGI request handler for serving the - libbe.storage.http.HTTP backend with GET, POST, and HEAD commands. - For more information on authentication and REST, see John - Calcote's `Open Sourcery article`_ - - .. _RESTful: http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm - .. _Open Sourcery article: http://jcalcote.wordpress.com/2009/08/10/restful-authentication/ - - This serves files from a connected storage instance, usually - a VCS-based repository located on the local machine. - - Notes - ----- - - The GET and HEAD requests are identical except that the HEAD - request omits the actual content of the file. - """ - server_version = 'BE-storage-server/' + libbe.version.version() - - def __init__(self, storage=None, notify=False, **kwargs): - super(ServerApp, self).__init__( - urls=[ - (r'^add/?', self.add), - (r'^exists/?', self.exists), - (r'^remove/?', self.remove), - (r'^ancestors/?', self.ancestors), - (r'^children/?', self.children), - (r'^get/(.+)', self.get), - (r'^set/(.+)', self.set), - (r'^commit/?', self.commit), - (r'^revision-id/?', self.revision_id), - (r'^changed/?', self.changed), - (r'^version/?', self.version), - ], - **kwargs) - self.storage = storage - self.notify = notify - - # handlers - def add(self, environ, start_response): - data = self.post_data(environ) - source = 'post' - id = self.data_get_id(data, source=source) - parent = self.data_get_string( - data, 'parent', default=None, source=source) - directory = self.data_get_boolean( - data, 'directory', default=False, source=source) - self.storage.add(id, parent=parent, directory=directory) - if self.notify: - self._notify(environ, 'add', id, - [('parent', parent), ('directory', directory)]) - return self.ok_response(environ, start_response, None) - - def exists(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - id = self.data_get_id(data, source=source) - revision = self.data_get_string( - data, 'revision', default=None, source=source) - content = str(self.storage.exists(id, revision)) - return self.ok_response(environ, start_response, content) - - def remove(self, environ, start_response): - data = self.post_data(environ) - source = 'post' - id = self.data_get_id(data, source=source) - recursive = self.data_get_boolean( - data, 'recursive', default=False, source=source) - if recursive == True: - self.storage.recursive_remove(id) - else: - self.storage.remove(id) - if self.notify: - self._notify(environ, 'remove', id, [('recursive', recursive)]) - return self.ok_response(environ, start_response, None) - - def ancestors(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - id = self.data_get_id(data, source=source) - revision = self.data_get_string( - data, 'revision', default=None, source=source) - content = '\n'.join(self.storage.ancestors(id, revision))+'\n' - return self.ok_response(environ, start_response, content) - - def children(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - id = self.data_get_id(data, default=None, source=source) - revision = self.data_get_string( - data, 'revision', default=None, source=source) - content = '\n'.join(self.storage.children(id, revision)) - return self.ok_response(environ, start_response, content) - - def get(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - try: - id = environ['be-server.url_args'][0] - except: - raise libbe.util.wsgi.HandlerError(404, 'Not Found') - revision = self.data_get_string( - data, 'revision', default=None, source=source) - content = self.storage.get(id, revision=revision) - be_version = self.storage.storage_version(revision) - return self.ok_response(environ, start_response, content, - headers=[('X-BE-Version', be_version)]) - - def set(self, environ, start_response): - data = self.post_data(environ) - try: - id = environ['be-server.url_args'][0] - except: - raise libbe.util.wsgi.HandlerError(404, 'Not Found') - if not 'value' in data: - raise libbe.util.wsgi.HandlerError(406, 'Missing query key value') - value = data['value'] - self.storage.set(id, value) - if self.notify: - self._notify(environ, 'set', id, [('value', value)]) - return self.ok_response(environ, start_response, None) - - def commit(self, environ, start_response): - data = self.post_data(environ) - if not 'summary' in data: - raise libbe.util.wsgi.HandlerError( - 406, 'Missing query key summary') - summary = data['summary'] - if not 'body' in data or data['body'] == 'None': - data['body'] = None - body = data['body'] - if not 'allow_empty' in data \ - or data['allow_empty'] == 'True': - allow_empty = True - else: - allow_empty = False - try: - revision = self.storage.commit(summary, body, allow_empty) - except libbe.storage.EmptyCommit, e: - raise libbe.util.wsgi.HandlerError( - libbe.util.http.HTTP_USER_ERROR, 'EmptyCommit') - if self.notify: - self._notify(environ, 'commit', id, - [('allow_empty', allow_empty), ('summary', summary), - ('body', body)]) - return self.ok_response(environ, start_response, revision) - - def revision_id(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - index = int(self.data_get_string( - data, 'index', default=libbe.util.wsgi.HandlerError, - source=source)) - content = self.storage.revision_id(index) - return self.ok_response(environ, start_response, content) - - def changed(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - revision = self.data_get_string( - data, 'revision', default=None, source=source) - add,mod,rem = self.storage.changed(revision) - content = '\n\n'.join(['\n'.join(p) for p in (add,mod,rem)]) - return self.ok_response(environ, start_response, content) - - def version(self, environ, start_response): - data = self.query_data(environ) - source = 'query' - revision = self.data_get_string( - data, 'revision', default=None, source=source) - content = self.storage.storage_version(revision) - return self.ok_response(environ, start_response, content) - - def _notify(self, environ, command, id, params): - message = self._format_notification(environ, command, id, params) - self._submit_notification(message) - - def _format_notification(self, environ, command, id, params): - key_length = len('command') - for key,value in params: - if len(key) > key_length and '\n' not in str(value): - key_length = len(key) - key_length += 1 - lines = [] - multi_line_params = [] - for key,value in [('address', environ.get('REMOTE_ADDR', '-')), - ('command', command), ('id', id)]+params: - v = str(value) - if '\n' in v: - multi_line_params.append((key,v)) - continue - lines.append('%*.*s %s' % (key_length, key_length, key+':', v)) - lines.append('') - for key,value in multi_line_params: - lines.extend(['=== START %s ===' % key, v, - '=== STOP %s ===' % key, '']) - lines.append('') - return '\n'.join(lines) - - def _submit_notification(self, message): - libbe.util.subproc.invoke(self.notify, stdin=message, shell=True) - - -class ServeStorage (libbe.util.wsgi.ServerCommand): - """Serve bug directory storage over HTTP. - - This allows you to run local `be` commands interfacing with remote - data, transmitting file reads/writes/etc. over the network. - - :py:class:`~libbe.command.base.Command` wrapper around - :py:class:`ServerApp`. - """ - - name = 'serve-storage' - - def _get_app(self, logger, storage, **kwargs): - return ServerApp( - logger=logger, storage=storage, notify=kwargs.get('notify', False)) - - def _long_help(self): - return """ -Example usage:: - - $ be serve-storage - -And in another terminal (or after backgrounding the server):: - - $ be --repo http://localhost:8000/ list - -If you bind your server to a public interface, take a look at the -``--read-only`` option so other people can't mess with your repository. -""" - - -# alias for libbe.command.base.get_command_class() -Serve_storage = ServeStorage - - -if libbe.TESTING: - class ServerAppTestCase (libbe.util.wsgi.WSGITestCase): - def setUp(self): - super(ServerAppTestCase, self).setUp() - self.bd = libbe.bugdir.SimpleBugDir(memory=False) - self.app = ServerApp(self.bd.storage, logger=self.logger) - - def tearDown(self): - self.bd.cleanup() - super(ServerAppTestCase, self).tearDown() - - def test_add_get(self): - try: - self.getURL(self.app, '/add/', method='GET') - except libbe.util.wsgi.HandlerError as e: - self.failUnless(e.code == 404, e) - else: - self.fail('GET /add/ did not raise 404') - - def test_add_post(self): - self.getURL(self.app, '/add/', method='POST', - data_dict={'id':'123456', 'parent':'abc123', - 'directory':'True'}) - self.failUnless(self.status == '200 OK', self.status) - self.failUnless(self.response_headers == [], - self.response_headers) - self.failUnless(self.exc_info is None, self.exc_info) - # Note: other methods tested in libbe.storage.http - - # TODO: integration tests on Serve? - - unitsuite =unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) - suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()]) diff --git a/libbe/storage/__init__.py b/libbe/storage/__init__.py index ccadb9c..01885e9 100644 --- a/libbe/storage/__init__.py +++ b/libbe/storage/__init__.py @@ -23,7 +23,6 @@ data. Also define assorted implementations for the Storage classes: * :py:mod:`libbe.storage.vcs` -* :py:mod:`libbe.storage.http` Also define an assortment of storage-related tools and utilities: @@ -53,10 +52,6 @@ STORAGE_VERSIONS = ['Bugs Everywhere Tree 1 0', # the current version STORAGE_VERSION = STORAGE_VERSIONS[-1] -def get_http_storage(location): - import http - return http.HTTP(location) - def get_vcs_storage(location): import vcs s = vcs.detect_vcs(location) @@ -68,7 +63,7 @@ def get_storage(location): Return a Storage instance from a repo location string. """ if location.startswith('http://') or location.startswith('https://'): - return get_http_storage(location) + raise ConnectionError('HTTP URLs are no longer supported') return get_vcs_storage(location) __all__ = [ConnectionError, InvalidStorageVersion, InvalidID, diff --git a/libbe/storage/http.py b/libbe/storage/http.py deleted file mode 100644 index 030349d..0000000 --- a/libbe/storage/http.py +++ /dev/null @@ -1,368 +0,0 @@ -# Copyright (C) 2010-2012 Chris Ball -# W. Trevor King -# -# This file is part of Bugs Everywhere. -# -# Bugs Everywhere is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free -# Software Foundation, either version 2 of the License, or (at your option) any -# later version. -# -# Bugs Everywhere is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -# more details. -# -# You should have received a copy of the GNU General Public License along with -# Bugs Everywhere. If not, see . - -"""Define an HTTP-based :py:class:`~libbe.storage.base.VersionedStorage` -implementation. - -See Also --------- -:py:mod:`libbe.command.serve_storage` : the associated server -""" - -from __future__ import absolute_import -import sys -import urllib -import urlparse - -import libbe -import libbe.version -import libbe.util.http -from libbe.util.http import HTTP_VALID, HTTP_USER_ERROR -from . import base - -from libbe import TESTING - -if TESTING == True: - import copy - import doctest - import StringIO - import unittest - - import libbe.bugdir - import libbe.command.serve_storage - import libbe.util.http - import libbe.util.wsgi - - -class HTTP (base.VersionedStorage): - """:py:class:`~libbe.storage.base.VersionedStorage` implementation over - HTTP. - - Uses GET to retrieve information and POST to set information. - """ - name = 'HTTP' - user_agent = 'BE-HTTP-Storage' - - def __init__(self, repo, *args, **kwargs): - repo,self.uname,self.password = self.parse_repo(repo) - base.VersionedStorage.__init__(self, repo, *args, **kwargs) - - def parse_repo(self, repo): - """Grab username and password (if any) from the repo URL. - - Examples - -------- - - >>> s = HTTP('http://host.com/path/to/repo') - >>> s.repo - 'http://host.com/path/to/repo' - >>> s.uname == None - True - >>> s.password == None - True - >>> s.parse_repo('http://joe:secret@host.com/path/to/repo') - ('http://host.com/path/to/repo', 'joe', 'secret') - """ - scheme,netloc,path,params,query,fragment = urlparse.urlparse(repo) - parts = netloc.split('@', 1) - if len(parts) == 2: - uname,password = parts[0].split(':') - repo = urlparse.urlunparse( - (scheme, parts[1], path, params, query, fragment)) - else: - uname,password = (None, None) - return (repo, uname, password) - - def get_post_url(self, url, get=True, data_dict=None, headers=[]): - if self.uname != None and self.password != None: - headers.append(('Authorization','Basic %s' % \ - ('%s:%s' % (self.uname, self.password)).encode('base64'))) - return libbe.util.http.get_post_url( - url, get, data_dict=data_dict, headers=headers, - agent=self.user_agent) - - def storage_version(self, revision=None): - """Return the storage format for this backend.""" - return libbe.storage.STORAGE_VERSION - - def _init(self): - """Create a new storage repository.""" - raise base.NotSupported( - 'init', 'Cannot initialize this repository format.') - - def _destroy(self): - """Remove the storage repository.""" - raise base.NotSupported( - 'destroy', 'Cannot destroy this repository format.') - - def _connect(self): - self.check_storage_version() - - def _disconnect(self): - pass - - def _add(self, id, parent=None, directory=False): - url = urlparse.urljoin(self.repo, 'add') - page,final_url,info = self.get_post_url( - url, get=False, - data_dict={'id':id, 'parent':parent, 'directory':directory}) - - def _exists(self, id, revision=None): - url = urlparse.urljoin(self.repo, 'exists') - page,final_url,info = self.get_post_url( - url, get=True, - data_dict={'id':id, 'revision':revision}) - if page == 'True': - return True - return False - - def _remove(self, id): - url = urlparse.urljoin(self.repo, 'remove') - page,final_url,info = self.get_post_url( - url, get=False, - data_dict={'id':id, 'recursive':False}) - - def _recursive_remove(self, id): - url = urlparse.urljoin(self.repo, 'remove') - page,final_url,info = self.get_post_url( - url, get=False, - data_dict={'id':id, 'recursive':True}) - - def _ancestors(self, id=None, revision=None): - url = urlparse.urljoin(self.repo, 'ancestors') - page,final_url,info = self.get_post_url( - url, get=True, - data_dict={'id':id, 'revision':revision}) - return page.strip('\n').splitlines() - - def _children(self, id=None, revision=None): - url = urlparse.urljoin(self.repo, 'children') - page,final_url,info = self.get_post_url( - url, get=True, - data_dict={'id':id, 'revision':revision}) - return page.strip('\n').splitlines() - - def _get(self, id, default=base.InvalidObject, revision=None): - url = urlparse.urljoin(self.repo, '/'.join(['get', id])) - try: - page,final_url,info = self.get_post_url( - url, get=True, - data_dict={'revision':revision}) - except libbe.util.http.HTTPError, e: - if not (hasattr(e.error, 'code') and e.error.code in HTTP_VALID): - raise - elif default == base.InvalidObject: - raise base.InvalidID(id) - return default - version = info['X-BE-Version'] - if version != libbe.storage.STORAGE_VERSION: - raise base.InvalidStorageVersion( - version, libbe.storage.STORAGE_VERSION) - return page - - def _set(self, id, value): - url = urlparse.urljoin(self.repo, '/'.join(['set', id])) - try: - page,final_url,info = self.get_post_url( - url, get=False, - data_dict={'value':value}) - except libbe.util.http.HTTPError, e: - if not (hasattr(e.error, 'code') and e.error.code in HTTP_VALID): - raise - if e.error.code == HTTP_USER_ERROR \ - and not 'InvalidID' in str(e.error): - raise base.InvalidDirectory( - 'Directory %s cannot have data' % id) - raise base.InvalidID(id) - - def _commit(self, summary, body=None, allow_empty=False): - url = urlparse.urljoin(self.repo, 'commit') - try: - page,final_url,info = self.get_post_url( - url, get=False, - data_dict={'summary':summary, 'body':body, - 'allow_empty':allow_empty}) - except libbe.util.http.HTTPError, e: - if not (hasattr(e.error, 'code') and e.error.code in HTTP_VALID): - raise - if e.error.code == HTTP_USER_ERROR: - raise base.EmptyCommit - raise base.InvalidID(id) - return page.rstrip('\n') - - def revision_id(self, index=None): - """Return the name of the th revision. - - The choice of which branch to follow when crossing - branches/merges is not defined. Revision indices start at 1; - ID 0 is the blank repository. - - Return None if index==None. - - Raises - ------ - InvalidRevision - If the specified revision does not exist. - """ - if index == None: - return None - try: - if int(index) != index: - raise base.InvalidRevision(index) - except ValueError: - raise base.InvalidRevision(index) - url = urlparse.urljoin(self.repo, 'revision-id') - try: - page,final_url,info = self.get_post_url( - url, get=True, - data_dict={'index':index}) - except libbe.util.http.HTTPError, e: - if not (hasattr(e.error, 'code') and e.error.code in HTTP_VALID): - raise - if e.error.code == HTTP_USER_ERROR: - raise base.InvalidRevision(index) - raise base.InvalidID(id) - return page.rstrip('\n') - - def changed(self, revision=None): - url = urlparse.urljoin(self.repo, 'changed') - page,final_url,info = self.get_post_url( - url, get=True, - data_dict={'revision':revision}) - lines = page.strip('\n') - new,mod,rem = [p.splitlines() for p in page.split('\n\n')] - return (new, mod, rem) - - def check_storage_version(self): - version = self.storage_version() - if version != libbe.storage.STORAGE_VERSION: - raise base.InvalidStorageVersion( - version, libbe.storage.STORAGE_VERSION) - - def storage_version(self, revision=None): - url = urlparse.urljoin(self.repo, 'version') - page,final_url,info = self.get_post_url( - url, get=True, data_dict={'revision':revision}) - return page.rstrip('\n') - -if TESTING == True: - class TestingHTTP (HTTP): - name = 'TestingHTTP' - def __init__(self, repo, *args, **kwargs): - self._storage_backend = base.VersionedStorage(repo) - app = libbe.command.serve_storage.ServerApp( - storage=self._storage_backend) - self.app = libbe.util.wsgi.BEExceptionApp(app=app) - HTTP.__init__(self, repo='http://localhost:8000/', *args, **kwargs) - self.intitialized = False - # duplicated from libbe.util.wsgi.WSGITestCase - self.default_environ = { - 'REQUEST_METHOD': 'GET', # 'POST', 'HEAD' - 'REMOTE_ADDR': '192.168.0.123', - 'SCRIPT_NAME':'', - 'PATH_INFO': '', - #'QUERY_STRING':'', # may be empty or absent - #'CONTENT_TYPE':'', # may be empty or absent - #'CONTENT_LENGTH':'', # may be empty or absent - 'SERVER_NAME':'example.com', - 'SERVER_PORT':'80', - 'SERVER_PROTOCOL':'HTTP/1.1', - 'wsgi.version':(1,0), - 'wsgi.url_scheme':'http', - 'wsgi.input':StringIO.StringIO(), - 'wsgi.errors':StringIO.StringIO(), - 'wsgi.multithread':False, - 'wsgi.multiprocess':False, - 'wsgi.run_once':False, - } - def getURL(self, app, path='/', method='GET', data=None, - scheme='http', environ={}): - # duplicated from libbe.util.wsgi.WSGITestCase - env = copy.copy(self.default_environ) - env['PATH_INFO'] = path - env['REQUEST_METHOD'] = method - env['scheme'] = scheme - if data != None: - enc_data = urllib.urlencode(data) - if method == 'POST': - env['CONTENT_LENGTH'] = len(enc_data) - env['wsgi.input'] = StringIO.StringIO(enc_data) - else: - assert method in ['GET', 'HEAD'], method - env['QUERY_STRING'] = enc_data - for key,value in environ.items(): - env[key] = value - try: - result = app(env, self.start_response) - except libbe.util.wsgi.HandlerError as e: - raise libbe.util.http.HTTPError(error=e, url=path, msg=str(e)) - return ''.join(result) - def start_response(self, status, response_headers, exc_info=None): - self.status = status - self.response_headers = response_headers - self.exc_info = exc_info - def get_post_url(self, url, get=True, data_dict=None, headers=[]): - if get == True: - method = 'GET' - else: - method = 'POST' - scheme,netloc,path,params,query,fragment = urlparse.urlparse(url) - environ = {} - for header_name,header_value in headers: - environ['HTTP_%s' % header_name] = header_value - output = self.getURL( - self.app, path, method, data_dict, scheme, environ) - if self.status != '200 OK': - class __estr (object): - def __init__(self, string): - self.string = string - self.code = int(string.split()[0]) - def __str__(self): - return self.string - error = __estr(self.status) - raise libbe.util.http.HTTPError( - error=error, url=url, msg=output) - info = dict(self.response_headers) - return (output, url, info) - def _init(self): - try: - HTTP._init(self) - raise AssertionError - except base.NotSupported: - pass - self._storage_backend._init() - def _destroy(self): - try: - HTTP._destroy(self) - raise AssertionError - except base.NotSupported: - pass - self._storage_backend._destroy() - def _connect(self): - self._storage_backend._connect() - HTTP._connect(self) - def _disconnect(self): - HTTP._disconnect(self) - self._storage_backend._disconnect() - - - base.make_versioned_storage_testcase_subclasses( - TestingHTTP, sys.modules[__name__]) - - unitsuite =unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) - suite = unittest.TestSuite([unitsuite, doctest.DocTestSuite()]) diff --git a/libbe/ui/command_line.py b/libbe/ui/command_line.py index 614366d..5d4d80a 100644 --- a/libbe/ui/command_line.py +++ b/libbe/ui/command_line.py @@ -379,8 +379,7 @@ def main(): ui.setup_command(command) if command.name in [ - 'new', 'comment', 'commit', 'html', 'import-xml', 'serve-storage', - 'serve-commands']: + 'new', 'comment', 'commit', 'html', 'import-xml', 'serve-commands']: paginate = 'never' else: paginate = 'auto' diff --git a/libbe/util/wsgi.py b/libbe/util/wsgi.py index 956fa5c..c509a48 100644 --- a/libbe/util/wsgi.py +++ b/libbe/util/wsgi.py @@ -20,7 +20,6 @@ See Also -------- -:py:mod:`libbe.command.serve_storage` and :py:mod:`libbe.command.serve_commands`. """ -- cgit