17
17
"""The WSGI application for serving a Bazaar branch."""
25
from bzrlib.hooks import Hooks
26
import bzrlib.lru_cache
25
from breezy.hooks import Hooks
26
import breezy.lru_cache
27
from breezy.sixish import viewitems
28
from breezy import urlutils
28
30
from paste import request
29
31
from paste import httpexceptions
31
from loggerhead.apps import static_app
32
from loggerhead.controllers.annotate_ui import AnnotateUI
33
from loggerhead.controllers.view_ui import ViewUI
34
from loggerhead.controllers.atom_ui import AtomUI
35
from loggerhead.controllers.changelog_ui import ChangeLogUI
36
from loggerhead.controllers.diff_ui import DiffUI
37
from loggerhead.controllers.download_ui import DownloadUI, DownloadTarballUI
38
from loggerhead.controllers.filediff_ui import FileDiffUI
39
from loggerhead.controllers.inventory_ui import InventoryUI
40
from loggerhead.controllers.revision_ui import RevisionUI
41
from loggerhead.controllers.revlog_ui import RevLogUI
42
from loggerhead.controllers.search_ui import SearchUI
43
from loggerhead.history import History
44
from loggerhead import util
33
from ..apps import static_app
34
from ..controllers.annotate_ui import AnnotateUI
35
from ..controllers.view_ui import ViewUI
36
from ..controllers.atom_ui import AtomUI
37
from ..controllers.changelog_ui import ChangeLogUI
38
from ..controllers.diff_ui import DiffUI
39
from ..controllers.download_ui import DownloadUI, DownloadTarballUI
40
from ..controllers.filediff_ui import FileDiffUI
41
from ..controllers.inventory_ui import InventoryUI
42
from ..controllers.revision_ui import RevisionUI
43
from ..controllers.revlog_ui import RevLogUI
44
from ..controllers.search_ui import SearchUI
45
from ..history import History
47
49
_DEFAULT = object()
63
65
self.branch_link = branch_link # Currently only used in Launchpad
64
66
self.log = logging.getLogger('loggerhead.%s' % (friendly_name,))
65
67
if graph_cache is None:
66
graph_cache = bzrlib.lru_cache.LRUCache(10)
68
graph_cache = breezy.lru_cache.LRUCache(10)
67
69
self.graph_cache = graph_cache
68
70
self.is_root = is_root
69
71
self.served_url = served_url
84
86
# Only import the cache if we're going to use it.
85
87
# This makes sqlite optional
87
from loggerhead.changecache import RevInfoDiskCache
89
from ..changecache import RevInfoDiskCache
88
90
except ImportError:
89
91
self.log.debug("Couldn't load python-sqlite,"
90
92
" continuing without using a cache")
92
94
revinfo_disk_cache = RevInfoDiskCache(cache_path)
94
96
self.branch, self.graph_cache,
95
revinfo_disk_cache=revinfo_disk_cache, cache_key=self.friendly_name)
97
revinfo_disk_cache=revinfo_disk_cache,
98
cache_key=(self.friendly_name.encode('utf-8') if self.friendly_name else None))
100
# Before the addition of this method, clicking to sort by date from
101
# within a branch caused a jump up to the top of that branch.
102
def sort_url(self, *args, **kw):
103
if isinstance(args[0], list):
106
for k, v in viewitems(kw):
108
qs.append('%s=%s' % (k, urlutils.quote(v)))
110
path_info = self._path_info.strip('/').split('?')[0]
111
path_info += '?' + qs
112
return self._url_base + '/' + path_info
97
114
def url(self, *args, **kw):
98
115
if isinstance(args[0], list):
101
for k, v in kw.iteritems():
118
for k, v in viewitems(kw):
102
119
if v is not None:
103
qs.append('%s=%s' % (k, urllib.quote(v)))
120
qs.append('%s=%s' % (k, urlutils.quote(v)))
104
121
qs = '&'.join(qs)
105
path_info = urllib.quote(
106
unicode('/'.join(args)).encode('utf-8'), safe='/~:')
122
path_info = urlutils.quote('/'.join(args), safe='/~:')
108
124
path_info += '?' + qs
109
125
return self._url_base + path_info
147
163
return change.date
149
165
def public_branch_url(self):
150
return self.branch.get_config().get_user_option('public_branch')
166
return self.branch.get_public_branch()
152
168
def lookup_app(self, environ):
153
169
# Check again if the branch is blocked from being served, this is
154
170
# mostly for tests. It's already checked in apps/transport.py
155
if self.branch.get_config().get_user_option('http_serve') == 'False':
171
if not self.branch.get_config().get_user_option_as_bool('http_serve', default=True):
156
172
raise httpexceptions.HTTPNotFound()
157
173
self._url_base = environ['SCRIPT_NAME']
174
self._path_info = environ['PATH_INFO']
158
175
self._static_url_base = environ.get('loggerhead.static.url')
159
176
if self._static_url_base is None:
160
177
self._static_url_base = self._url_base
164
181
if public_branch is not None:
165
182
self.served_url = public_branch
167
# Loggerhead only supports serving .bzr/ on local branches, so
168
# we shouldn't suggest something that won't work.
170
util.local_path_from_url(self.branch.base)
171
self.served_url = self.url([])
172
except bzrlib.errors.InvalidURL:
173
self.served_url = None
184
self.served_url = wsgiref.util.application_uri(environ)
174
185
for hook in self.hooks['controller']:
175
186
controller = hook(self, environ)
176
187
if controller is not None:
190
201
raise httpexceptions.HTTPNotFound()
192
203
def app(self, environ, start_response):
193
self.branch.lock_read()
204
with self.branch.lock_read():
196
206
c = self.lookup_app(environ)
197
207
return c(environ, start_response)
210
218
def __init__(self):
211
219
"""Create the default hooks.
213
Hooks.__init__(self, "bzrlib.plugins.loggerhead.apps.branch",
221
Hooks.__init__(self, "breezy.plugins.loggerhead.apps.branch",
214
222
"BranchWSGIApp.hooks")
215
223
self.add_hook('controller',
216
224
"Invoked when looking for the controller to use for a "