~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/apps/config.py

  • Committer: Michael Hudson
  • Date: 2009-06-25 03:39:27 UTC
  • mfrom: (366.1.3 tags-info)
  • Revision ID: michael.hudson@canonical.com-20090625033927-lg3pjtb8a88ankug
merge lp:~zigarn/loggerhead/tags-info with some tweaks from me

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# A server that recreates (modulo cherrypy bugs :) the url parsing
2
 
# from the old, loggerhead.conf approach.
 
1
"""A server that uses a loggerhead.conf file.
3
2
 
4
 
# It's all a bit horrible really.
 
3
We recreate the branch discovery and url scheme of the old branchview
 
4
code.  It's all a bit horrible really.
 
5
"""
5
6
 
6
7
import logging
7
8
import os
8
9
import posixpath
9
10
 
10
 
from configobj import ConfigObj
 
11
import bzrlib.lru_cache
 
12
 
 
13
from bzrlib.util.configobj.configobj import ConfigObj
11
14
 
12
15
from paste.request import path_info_pop
13
16
from paste import httpexceptions
14
17
from paste.wsgiwrappers import WSGIResponse
15
18
 
16
19
from loggerhead.apps.branch import BranchWSGIApp
17
 
from loggerhead.apps import favicon_app, static_app
 
20
from loggerhead.apps import favicon_app, static_app, robots_app
18
21
from loggerhead.templatefunctions import templatefunctions
19
22
from loggerhead.zptsupport import load_template
20
23
from loggerhead import util
23
26
 
24
27
from loggerhead.history import is_branch
25
28
 
26
 
class Project (object):
27
 
    def __init__(self, name, config, root_config):
 
29
 
 
30
class Project(object):
 
31
    """A project contains the branches.
 
32
 
 
33
    There is some complication because we don't want to hold on to the
 
34
    branches when they are not being browsed."""
 
35
 
 
36
    def __init__(self, name, config, root_config, graph_cache):
28
37
        self.name = name
29
38
        self.friendly_name = config.get('name', name)
30
39
        self.description = config.get('description', '')
31
40
        self.long_description = config.get('long_description', '')
32
41
        self._config = config
33
42
        self._root_config = root_config
 
43
        self.graph_cache = graph_cache
34
44
 
35
 
        self.views = []
36
 
        self.views_by_name = {}
 
45
        self.view_names = []
 
46
        self.view_data_by_name = {}
37
47
        for view_name in config.sections:
38
48
            log.debug('Configuring (project %s) branch %s...', name, view_name)
39
49
            self._add_view(
60
70
            return
61
71
 
62
72
        # rebuild views:
 
73
        self.view_names = []
63
74
        log.debug('Rescanning auto-folder for project %s ...', self.name)
64
 
        self._views = []
65
75
        for folder in auto_list:
66
76
            view_name = os.path.basename(folder)
67
 
            log.debug('Auto-configuring (project %s) branch %s...', self.name, view_name)
 
77
            log.debug('Auto-configuring (project %s) branch %s...',
 
78
                      self.name,
 
79
                      view_name)
68
80
            self._add_view(view_name, ConfigObj(), folder)
69
81
        self._auto_list = auto_list
70
82
 
77
89
            return posixpath.join(url, folder) + '/'
78
90
        return None
79
91
 
80
 
    def _get_description(self, view, view_config):
 
92
    def _get_description(self, view, view_config, history):
81
93
        description = view_config.get('description', None)
82
94
        if description is not None:
83
95
            return description
84
 
        description = view.history._branch.get_config().get_user_option('description')
 
96
        description = history._branch.get_config().get_user_option(
 
97
                          'description')
85
98
        return description
86
99
 
87
100
    def _add_view(self, view_name, view_config, folder):
88
 
        view = BranchWSGIApp(folder, view_name, view_config)
89
 
        friendly_name = view_config.get('branch_name', None)
90
 
        if friendly_name is None:
91
 
            friendly_name = view.history.get_config().get_nickname()
 
101
        b = bzrlib.branch.Branch.open(folder)
 
102
        view = BranchWSGIApp(b, view_name, view_config, self.graph_cache)
 
103
        b.lock_read()
 
104
        try:
 
105
            history = view.get_history()
 
106
            friendly_name = view_config.get('branch_name', None)
92
107
            if friendly_name is None:
93
 
                friendly_name = view_name
94
 
        view.friendly_name = friendly_name
95
 
        view.name = view_name
96
 
        branch_url = self._get_branch_url(view, view_config, view_name)
97
 
        if branch_url is not None:
98
 
            view.branch_url = branch_url
99
 
        view.description = self._get_description(view, view_config)
100
 
        view._src_folder = folder
101
 
        view._view_config = view_config
102
 
        self.views.append(view)
103
 
        self.views_by_name[view_name] = view
 
108
                friendly_name = history.get_config().get_nickname()
 
109
                if friendly_name is None:
 
110
                    friendly_name = view_name
 
111
            branch_url = self._get_branch_url(view, view_config, view_name)
 
112
            description = self._get_description(view, view_config, history)
 
113
            self.view_data_by_name[view_name] = {
 
114
                'branch_path': folder,
 
115
                'config': view_config,
 
116
                'description': description,
 
117
                'friendly_name': friendly_name,
 
118
                'graph_cache': self.graph_cache,
 
119
                'name': view_name,
 
120
                'served_url': branch_url,
 
121
                }
 
122
            self.view_names.append(view_name)
 
123
        finally:
 
124
            b.unlock()
 
125
 
 
126
    def view_named(self, name):
 
127
        view_data = self.view_data_by_name.get(name)
 
128
        if view_data is None:
 
129
            return None
 
130
        view_data = view_data.copy()
 
131
        branch_path = view_data.pop('branch_path')
 
132
        description = view_data.pop('description')
 
133
        name = view_data.pop('name')
 
134
        b = bzrlib.branch.Branch.open(branch_path)
 
135
        b.lock_read()
 
136
        view = BranchWSGIApp(b, **view_data)
 
137
        view.description = description
 
138
        view.name = name
 
139
        return view
104
140
 
105
141
    def call(self, environ, start_response):
106
142
        segment = path_info_pop(environ)
107
143
        if not segment:
108
144
            raise httpexceptions.HTTPNotFound()
109
145
        else:
110
 
            view = self.views_by_name.get(segment)
 
146
            view = self.view_named(segment)
111
147
            if view is None:
112
148
                raise httpexceptions.HTTPNotFound()
113
 
            return view.app(environ, start_response)
 
149
            try:
 
150
                return view.app(environ, start_response)
 
151
            finally:
 
152
                view.branch.unlock()
114
153
 
115
154
 
116
155
class Root(object):
 
156
    """The root of the server -- renders as the browse view,
 
157
    dispatches to Project above for each 'project'."""
117
158
 
118
159
    def __init__(self, config):
119
160
        self.projects = []
120
161
        self.config = config
121
162
        self.projects_by_name = {}
 
163
        graph_cache = bzrlib.lru_cache.LRUCache()
122
164
        for project_name in self.config.sections:
123
 
            project = Project(
124
 
                project_name, self.config[project_name], self.config)
 
165
            project = Project(project_name, self.config[project_name],
 
166
                              self.config, graph_cache)
125
167
            self.projects.append(project)
126
168
            self.projects_by_name[project_name] = project
127
169
 
128
170
    def browse(self, response):
 
171
        # This is insanely complicated because we want to open and
 
172
        # lock all the branches, render the view and then unlock the
 
173
        # branches again.
129
174
        for p in self.projects:
130
175
            p._recheck_auto_folders()
131
 
        class branch:
 
176
 
 
177
        class branch(object):
 
178
 
132
179
            @staticmethod
133
180
            def static_url(path):
134
181
                return self._static_url_base + path
135
 
        vals = {
136
 
            'projects': self.projects,
137
 
            'util': util,
138
 
            'title': self.config.get('title', None),
139
 
            'branch': branch,
140
 
        }
141
 
        vals.update(templatefunctions)
142
 
        response.headers['Content-Type'] = 'text/html'
143
 
        template = load_template('loggerhead.templates.browse')
144
 
        template.expand_into(response, **vals)
 
182
        views_by_project = {}
 
183
        all_views = []
 
184
        try:
 
185
            for p in self.projects:
 
186
                views_by_project[p] = []
 
187
                for vn in p.view_names:
 
188
                    v = p.view_named(vn)
 
189
                    all_views.append(v)
 
190
                    views_by_project[p].append(v)
 
191
            vals = {
 
192
                'projects': self.projects,
 
193
                'util': util,
 
194
                'title': self.config.get('title', None),
 
195
                'branch': branch,
 
196
                'views_by_project': views_by_project,
 
197
            }
 
198
            vals.update(templatefunctions)
 
199
            response.headers['Content-Type'] = 'text/html'
 
200
            template = load_template('loggerhead.templates.browse')
 
201
            template.expand_into(response, **vals)
 
202
        finally:
 
203
            for v in all_views:
 
204
                v.branch.unlock()
145
205
 
146
206
    def __call__(self, environ, start_response):
147
 
        self._static_url_base = environ['loggerhead.static.url'] = environ['SCRIPT_NAME']
 
207
        self._static_url_base = environ['loggerhead.static.url'] = \
 
208
                                environ['SCRIPT_NAME']
148
209
        segment = path_info_pop(environ)
149
210
        if segment is None:
150
211
            raise httpexceptions.HTTPMovedPermanently(
153
214
            response = WSGIResponse()
154
215
            self.browse(response)
155
216
            return response(environ, start_response)
 
217
        elif segment == 'robots.txt':
 
218
            return robots_app(environ, start_response)
156
219
        elif segment == 'static':
157
220
            return static_app(environ, start_response)
158
221
        elif segment == 'favicon.ico':