~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/controllers/__init__.py

  • Committer: John Arbash Meinel
  • Date: 2010-05-10 19:36:37 UTC
  • mto: This revision was merged to the branch mainline in revision 419.
  • Revision ID: john@arbash-meinel.com-20100510193637-4vmxsw7ha5wz0pi2
Allow running the loggerhead test suite using 'bzr selftest'

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#
 
2
# Copyright (C) 2008  Canonical Ltd.
2
3
# Copyright (C) 2006  Robey Pointer <robey@lag.net>
3
4
# Copyright (C) 2006  Goffredo Baroncelli <kreijack@inwind.it>
4
5
#
15
16
# You should have received a copy of the GNU General Public License
16
17
# along with this program; if not, write to the Free Software
17
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
#
19
 
 
20
 
import logging
21
 
import os
22
 
import re
23
 
 
24
 
import turbogears
25
 
from turbogears import controllers
26
 
from configobj import ConfigObj
 
19
 
 
20
import time
 
21
 
 
22
from paste.request import path_info_pop, parse_querystring
27
23
 
28
24
from loggerhead import util
29
 
from loggerhead.branchview import BranchView
30
 
from loggerhead.history import is_branch
31
25
from loggerhead.templatefunctions import templatefunctions
32
 
 
33
 
log = logging.getLogger("loggerhead.controllers")
34
 
 
35
 
 
36
 
def cherrypy_friendly(s):
37
 
    """
38
 
    convert a config section name into a name that pleases cherrypy.
39
 
    """
40
 
    return re.sub(r'[^\w\d_]', '_', s)
41
 
 
42
 
 
43
 
class Project (object):
44
 
    def __init__(self, name, config, root_config):
45
 
        self.name = name
46
 
        self.friendly_name = config.get('name', name)
47
 
        self.description = config.get('description', '')
48
 
        self.long_description = config.get('long_description', '')
49
 
        self._config = config
50
 
        self._root_config = root_config
51
 
        
52
 
        self._views = []
53
 
        for view_name in config.sections:
54
 
            log.debug('Configuring (project %s) branch %s...', name, view_name)
55
 
            self._add_view(view_name, config[view_name], config[view_name].get('folder'))
56
 
        
57
 
        self._auto_folder = config.get('auto_publish_folder', None)
58
 
        self._auto_list = []
59
 
        if self._auto_folder is not None:
60
 
            self._recheck_auto_folders()
61
 
    
62
 
    def _recheck_auto_folders(self):
63
 
        if self._auto_folder is None:
64
 
            return
65
 
        auto_list = []
66
 
        # scan a folder for bazaar branches, and add them automatically
67
 
        for path, folders, filenames in os.walk(self._auto_folder):
68
 
            for folder in folders:
69
 
                folder = os.path.join(path, folder)
70
 
                if is_branch(folder):
71
 
                    auto_list.append(folder)
72
 
        auto_list.sort()
73
 
        if auto_list == self._auto_list:
74
 
            # nothing has changed; do nothing.
75
 
            return
76
 
 
77
 
        # rebuild views:
78
 
        log.debug('Rescanning auto-folder for project %s ...', self.name)
79
 
        self._views = []
80
 
        for folder in auto_list:
81
 
            view_name = os.path.basename(folder)
82
 
            log.debug('Auto-configuring (project %s) branch %s...', self.name, view_name)
83
 
            self._add_view(view_name, ConfigObj(), folder)
84
 
        self._auto_list = auto_list
85
 
        
86
 
    def _add_view(self, view_name, view_config, folder):
87
 
        c_view_name = cherrypy_friendly(view_name)
88
 
        view = BranchView(
89
 
            self.name, c_view_name, view_name, folder, view_config,
90
 
            self._config, self._root_config)
91
 
        self._views.append(view)
92
 
        setattr(self, c_view_name, view)
93
 
        
94
 
    views = property(lambda self: self._views)
95
 
 
96
 
 
97
 
class Root (controllers.RootController):
98
 
    def __init__(self, config):
99
 
        self._projects = []
100
 
        self._config = config
101
 
        for project_name in self._config.sections:
102
 
            c_project_name = cherrypy_friendly(project_name)
103
 
            project = Project(
104
 
                c_project_name, self._config[project_name], self._config)
105
 
            self._projects.append(project)
106
 
            setattr(self, c_project_name, project)
107
 
        
108
 
    @turbogears.expose(template='zpt:loggerhead.templates.browse')
109
 
    def index(self):
110
 
        for p in self._projects:
111
 
            p._recheck_auto_folders()
 
26
from loggerhead.zptsupport import load_template
 
27
 
 
28
 
 
29
class BufferingWriter(object):
 
30
 
 
31
    def __init__(self, writefunc, buf_limit):
 
32
        self.bytes = 0
 
33
        self.buf = []
 
34
        self.buflen = 0
 
35
        self.writefunc = writefunc
 
36
        self.buf_limit = buf_limit
 
37
 
 
38
    def flush(self):
 
39
        self.writefunc(''.join(self.buf))
 
40
        self.buf = []
 
41
        self.buflen = 0
 
42
 
 
43
    def write(self, data):
 
44
        self.buf.append(data)
 
45
        self.buflen += len(data)
 
46
        self.bytes += len(data)
 
47
        if self.buflen > self.buf_limit:
 
48
            self.flush()
 
49
 
 
50
 
 
51
class TemplatedBranchView(object):
 
52
 
 
53
    template_path = None
 
54
 
 
55
    def __init__(self, branch, history_callable):
 
56
        self._branch = branch
 
57
        self._history_callable = history_callable
 
58
        self.__history = None
 
59
        self.log = branch.log
 
60
 
 
61
    @property
 
62
    def _history(self):
 
63
        if self.__history is not None:
 
64
            return self.__history
 
65
        self.__history = self._history_callable()
 
66
        return self.__history
 
67
 
 
68
    def __call__(self, environ, start_response):
 
69
        z = time.time()
 
70
        kwargs = dict(parse_querystring(environ))
 
71
        util.set_context(kwargs)
 
72
        args = []
 
73
        while True:
 
74
            arg = path_info_pop(environ)
 
75
            if arg is None:
 
76
                break
 
77
            args.append(arg)
 
78
 
 
79
        path = None
 
80
        if len(args) > 1:
 
81
            path = unicode('/'.join(args[1:]), 'utf-8')
 
82
        self.args = args
 
83
 
112
84
        vals = {
113
 
            'projects': self._projects,
 
85
            'static_url': self._branch.static_url,
 
86
            'branch': self._branch,
114
87
            'util': util,
115
 
            'title': self._config.get('title', None),
 
88
            'url': self._branch.context_url,
116
89
        }
117
90
        vals.update(templatefunctions)
118
 
        return vals
119
 
 
120
 
    def _check_rebuild(self):
121
 
        for p in self._projects:
122
 
            for v in p.views:
123
 
                v.check_rebuild()
124
 
 
125
 
 
126
 
 
127
 
# for use in profiling the very-slow get_change() method:
128
 
#h = Root.bazaar.bzr_dev.get_history()
129
 
#w = list(h.get_revision_history())
130
 
#h._get_changes_profiled(w[:100])
131
 
 
 
91
        headers = {}
 
92
 
 
93
        vals.update(self.get_values(path, kwargs, headers))
 
94
 
 
95
        self.log.info('Getting information for %s: %r secs' % (
 
96
            self.__class__.__name__, time.time() - z))
 
97
        if 'Content-Type' not in headers:
 
98
            headers['Content-Type'] = 'text/html'
 
99
        writer = start_response("200 OK", headers.items())
 
100
        template = load_template(self.template_path)
 
101
        z = time.time()
 
102
        w = BufferingWriter(writer, 8192)
 
103
        template.expand_into(w, **vals)
 
104
        w.flush()
 
105
        self.log.info(
 
106
            'Rendering %s: %r secs, %s bytes' % (
 
107
                self.__class__.__name__, time.time() - z, w.bytes))
 
108
        return []
 
109
 
 
110
    def get_revid(self):
 
111
        h = self._history
 
112
        if h is None:
 
113
            return None
 
114
        if len(self.args) > 0 and self.args != ['']:
 
115
            return h.fix_revid(self.args[0])
 
116
        else:
 
117
            return h.last_revid