~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/apps/branch.py

  • Committer: Michael Hudson
  • Date: 2009-06-24 05:11:14 UTC
  • Revision ID: michael.hudson@canonical.com-20090624051114-abvpljiyh796pv0b
brainlessly break up main() into smaller functions

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008, 2009 Canonical Ltd.
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
#
 
17
"""The WSGI application for serving a Bazaar branch."""
 
18
 
 
19
import logging
 
20
import urllib
 
21
import sys
 
22
 
 
23
import bzrlib.branch
 
24
import bzrlib.lru_cache
 
25
 
 
26
from paste import request
 
27
from paste import httpexceptions
 
28
 
 
29
from loggerhead.apps import static_app
 
30
from loggerhead.controllers.annotate_ui import AnnotateUI
 
31
from loggerhead.controllers.atom_ui import AtomUI
 
32
from loggerhead.controllers.changelog_ui import ChangeLogUI
 
33
from loggerhead.controllers.diff_ui import DiffUI
 
34
from loggerhead.controllers.download_ui import DownloadUI
 
35
from loggerhead.controllers.filediff_ui import FileDiffUI
 
36
from loggerhead.controllers.inventory_ui import InventoryUI
 
37
from loggerhead.controllers.revision_ui import RevisionUI
 
38
from loggerhead.controllers.revlog_ui import RevLogUI
 
39
from loggerhead.controllers.search_ui import SearchUI
 
40
from loggerhead.history import History
 
41
from loggerhead import util
 
42
 
 
43
 
 
44
_DEFAULT = object()
 
45
 
 
46
class BranchWSGIApp(object):
 
47
 
 
48
    def __init__(self, branch, friendly_name=None, config={},
 
49
                 graph_cache=None, branch_link=None, is_root=False,
 
50
                 served_url=_DEFAULT, use_cdn=False):
 
51
        self.branch = branch
 
52
        self._config = config
 
53
        self.friendly_name = friendly_name
 
54
        self.branch_link = branch_link  # Currently only used in Launchpad
 
55
        self.log = logging.getLogger('loggerhead.%s' % friendly_name)
 
56
        if graph_cache is None:
 
57
            graph_cache = bzrlib.lru_cache.LRUCache(10)
 
58
        self.graph_cache = graph_cache
 
59
        self.is_root = is_root
 
60
        self.served_url = served_url
 
61
        self.use_cdn = use_cdn
 
62
 
 
63
    def get_history(self):
 
64
        file_cache = None
 
65
        revinfo_disk_cache = None
 
66
        cache_path = self._config.get('cachepath', None)
 
67
        if cache_path is not None:
 
68
            # Only import the cache if we're going to use it.
 
69
            # This makes sqlite optional
 
70
            try:
 
71
                from loggerhead.changecache import (
 
72
                    FileChangeCache, RevInfoDiskCache)
 
73
            except ImportError:
 
74
                self.log.debug("Couldn't load python-sqlite,"
 
75
                               " continuing without using a cache")
 
76
            else:
 
77
                file_cache = FileChangeCache(cache_path)
 
78
                revinfo_disk_cache = RevInfoDiskCache(cache_path)
 
79
        return History(
 
80
            self.branch, self.graph_cache, file_cache=file_cache,
 
81
            revinfo_disk_cache=revinfo_disk_cache, cache_key=self.friendly_name)
 
82
 
 
83
    def url(self, *args, **kw):
 
84
        if isinstance(args[0], list):
 
85
            args = args[0]
 
86
        qs = []
 
87
        for k, v in kw.iteritems():
 
88
            if v is not None:
 
89
                qs.append('%s=%s'%(k, urllib.quote(v)))
 
90
        qs = '&'.join(qs)
 
91
        return request.construct_url(
 
92
            self._environ, script_name=self._url_base,
 
93
            path_info=unicode('/'.join(args)).encode('utf-8'),
 
94
            querystring=qs)
 
95
 
 
96
    def context_url(self, *args, **kw):
 
97
        kw = util.get_context(**kw)
 
98
        return self.url(*args, **kw)
 
99
 
 
100
    def static_url(self, path):
 
101
        return self._static_url_base + path
 
102
 
 
103
    def yui_url(self, path):
 
104
        if self.use_cdn:
 
105
            base = 'http://yui.yahooapis.com/3.0.0pr2/build/'
 
106
        else:
 
107
            base = self.static_url('/static/javascript/yui/build/')
 
108
        return base + path
 
109
 
 
110
    controllers_dict = {
 
111
        '+filediff': FileDiffUI,
 
112
        '+revlog': RevLogUI,
 
113
        'annotate': AnnotateUI,
 
114
        'atom': AtomUI,
 
115
        'changes': ChangeLogUI,
 
116
        'diff': DiffUI,
 
117
        'download': DownloadUI,
 
118
        'files': InventoryUI,
 
119
        'revision': RevisionUI,
 
120
        'search': SearchUI,
 
121
        }
 
122
 
 
123
    def last_updated(self):
 
124
        h = self.get_history()
 
125
        change = h.get_changes([h.last_revid])[0]
 
126
        return change.date
 
127
 
 
128
    def public_branch_url(self):
 
129
        return self.branch.get_config().get_user_option('public_branch')
 
130
 
 
131
    def app(self, environ, start_response):
 
132
        # Check again if the branch is blocked from being served, this is
 
133
        # mostly for tests. It's already checked in apps/transport.py
 
134
        if self.branch.get_config().get_user_option('http_serve') == 'False':
 
135
            raise httpexceptions.HTTPNotFound()
 
136
        self._url_base = environ['SCRIPT_NAME']
 
137
        self._static_url_base = environ.get('loggerhead.static.url')
 
138
        if self._static_url_base is None:
 
139
            self._static_url_base = self._url_base
 
140
        self._environ = environ
 
141
        if self.served_url is _DEFAULT:
 
142
            public_branch = self.public_branch_url()
 
143
            if public_branch is not None:
 
144
                self.served_url = public_branch
 
145
            else:
 
146
                # Loggerhead only supports serving .bzr/ on local branches, so
 
147
                # we shouldn't suggest something that won't work.
 
148
                if self.branch.base.startswith('file://'):
 
149
                    self.served_url = self.url([])
 
150
                else:
 
151
                    self.served_url = None
 
152
        path = request.path_info_pop(environ)
 
153
        if not path:
 
154
            raise httpexceptions.HTTPMovedPermanently(
 
155
                self._url_base + '/changes')
 
156
        if path == 'static':
 
157
            return static_app(environ, start_response)
 
158
        cls = self.controllers_dict.get(path)
 
159
        if cls is None:
 
160
            raise httpexceptions.HTTPNotFound()
 
161
        self.branch.lock_read()
 
162
        try:
 
163
            try:
 
164
                c = cls(self, self.get_history)
 
165
                return c(environ, start_response)
 
166
            except:
 
167
                environ['exc_info'] = sys.exc_info()
 
168
                environ['branch'] = self
 
169
                raise
 
170
        finally:
 
171
            self.branch.unlock()