1
"""The WSGI application for serving a Bazaar branch."""
8
import bzrlib.lru_cache
10
from paste import request
11
from paste import httpexceptions
13
from loggerhead.apps import static_app
14
from loggerhead.controllers.annotate_ui import AnnotateUI
15
from loggerhead.controllers.atom_ui import AtomUI
16
from loggerhead.controllers.changelog_ui import ChangeLogUI
17
from loggerhead.controllers.diff_ui import DiffUI
18
from loggerhead.controllers.download_ui import DownloadUI
19
from loggerhead.controllers.filediff_ui import FileDiffUI
20
from loggerhead.controllers.inventory_ui import InventoryUI
21
from loggerhead.controllers.revision_ui import RevisionUI
22
from loggerhead.controllers.revlog_ui import RevLogUI
23
from loggerhead.controllers.search_ui import SearchUI
24
from loggerhead.history import History
25
from loggerhead import util
30
class BranchWSGIApp(object):
32
def __init__(self, branch, friendly_name=None, config={},
33
graph_cache=None, branch_link=None, is_root=False,
34
served_url=_DEFAULT, use_cdn=False):
37
self.friendly_name = friendly_name
38
self.branch_link = branch_link # Currently only used in Launchpad
39
self.log = logging.getLogger('loggerhead.%s' % friendly_name)
40
if graph_cache is None:
41
graph_cache = bzrlib.lru_cache.LRUCache(10)
42
self.graph_cache = graph_cache
43
self.is_root = is_root
44
self.served_url = served_url
45
self.use_cdn = use_cdn
47
def get_history(self):
49
revinfo_disk_cache = None
50
cache_path = self._config.get('cachepath', None)
51
if cache_path is not None:
52
# Only import the cache if we're going to use it.
53
# This makes sqlite optional
55
from loggerhead.changecache import (
56
FileChangeCache, RevInfoDiskCache)
58
self.log.debug("Couldn't load python-sqlite,"
59
" continuing without using a cache")
61
file_cache = FileChangeCache(cache_path)
62
revinfo_disk_cache = RevInfoDiskCache(cache_path)
64
self.branch, self.graph_cache, file_cache=file_cache,
65
revinfo_disk_cache=revinfo_disk_cache, cache_key=self.friendly_name)
67
def url(self, *args, **kw):
68
if isinstance(args[0], list):
71
for k, v in kw.iteritems():
73
qs.append('%s=%s'%(k, urllib.quote(v)))
75
return request.construct_url(
76
self._environ, script_name=self._url_base,
77
path_info=unicode('/'.join(args)).encode('utf-8'),
80
def context_url(self, *args, **kw):
81
kw = util.get_context(**kw)
82
return self.url(*args, **kw)
84
def static_url(self, path):
85
return self._static_url_base + path
87
def yui_url(self, path):
89
base = 'http://yui.yahooapis.com/3.0.0pr2/build/'
91
base = self.static_url('/static/javascript/yui/build/')
95
'+filediff': FileDiffUI,
97
'annotate': AnnotateUI,
99
'changes': ChangeLogUI,
101
'download': DownloadUI,
102
'files': InventoryUI,
103
'revision': RevisionUI,
107
def last_updated(self):
108
h = self.get_history()
109
change = h.get_changes([h.last_revid])[0]
112
def public_branch_url(self):
113
return self.branch.get_config().get_user_option('public_branch')
115
def app(self, environ, start_response):
116
self._url_base = environ['SCRIPT_NAME']
117
self._static_url_base = environ.get('loggerhead.static.url')
118
if self._static_url_base is None:
119
self._static_url_base = self._url_base
120
self._environ = environ
121
if self.served_url is _DEFAULT:
122
public_branch = self.public_branch_url()
123
if public_branch is not None:
124
self.served_url = public_branch
126
# Loggerhead only supports serving .bzr/ on local branches, so
127
# we shouldn't suggest something that won't work.
128
if self.branch.base.startswith('file://'):
129
self.served_url = self.url([])
131
self.served_url = None
132
path = request.path_info_pop(environ)
134
raise httpexceptions.HTTPMovedPermanently(
135
self._url_base + '/changes')
137
return static_app(environ, start_response)
138
cls = self.controllers_dict.get(path)
140
raise httpexceptions.HTTPNotFound()
141
self.branch.lock_read()
144
c = cls(self, self.get_history)
145
return c(environ, start_response)
147
environ['exc_info'] = sys.exc_info()
148
environ['branch'] = self