/loggerhead/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/loggerhead/trunk

« back to all changes in this revision

Viewing changes to loggerhead/controllers/__init__.py

[rs=mwhudson] many many improvements to loggerhead -- faster
        templating, leaner HTTP server, less caching, cleaner urls

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# You should have received a copy of the GNU General Public License
16
16
# along with this program; if not, write to the Free Software
17
17
# 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
 
18
 
 
19
import time
 
20
 
 
21
from paste.request import path_info_pop
27
22
 
28
23
from loggerhead import util
29
 
from loggerhead.branchview import BranchView
30
 
from loggerhead.history import is_branch
31
 
 
32
 
log = logging.getLogger("loggerhead.controllers")
33
 
 
34
 
 
35
 
def cherrypy_friendly(s):
36
 
    """
37
 
    convert a config section name into a name that pleases cherrypy.
38
 
    """
39
 
    return re.sub(r'[^\w\d_]', '_', s)
40
 
 
41
 
 
42
 
class Project (object):
43
 
    def __init__(self, name, config, root_config):
44
 
        self.name = name
45
 
        self.friendly_name = config.get('name', name)
46
 
        self.description = config.get('description', '')
47
 
        self.long_description = config.get('long_description', '')
48
 
        self._config = config
49
 
        self._root_config = root_config
50
 
        
51
 
        self._views = []
52
 
        for view_name in config.sections:
53
 
            log.debug('Configuring (project %s) branch %s...', name, view_name)
54
 
            self._add_view(view_name, config[view_name], config[view_name].get('folder'))
55
 
        
56
 
        self._auto_folder = config.get('auto_publish_folder', None)
57
 
        self._auto_list = []
58
 
        if self._auto_folder is not None:
59
 
            self._recheck_auto_folders()
60
 
    
61
 
    def _recheck_auto_folders(self):
62
 
        if self._auto_folder is None:
63
 
            return
64
 
        auto_list = []
65
 
        # scan a folder for bazaar branches, and add them automatically
66
 
        for path, folders, filenames in os.walk(self._auto_folder):
67
 
            for folder in folders:
68
 
                folder = os.path.join(path, folder)
69
 
                if is_branch(folder):
70
 
                    auto_list.append(folder)
71
 
        auto_list.sort()
72
 
        if auto_list == self._auto_list:
73
 
            # nothing has changed; do nothing.
74
 
            return
75
 
 
76
 
        # rebuild views:
77
 
        log.debug('Rescanning auto-folder for project %s ...', self.name)
78
 
        self._views = []
79
 
        for folder in auto_list:
80
 
            view_name = os.path.basename(folder)
81
 
            log.debug('Auto-configuring (project %s) branch %s...', self.name, view_name)
82
 
            self._add_view(view_name, ConfigObj(), folder)
83
 
        self._auto_list = auto_list
84
 
        
85
 
    def _add_view(self, view_name, view_config, folder):
86
 
        c_view_name = cherrypy_friendly(view_name)
87
 
        view = BranchView(
88
 
            self.name, c_view_name, view_name, folder, view_config,
89
 
            self._config, self._root_config)
90
 
        self._views.append(view)
91
 
        setattr(self, c_view_name, view)
92
 
        
93
 
    views = property(lambda self: self._views)
94
 
 
95
 
 
96
 
class Root (controllers.RootController):
97
 
    def __init__(self, config):
98
 
        self._projects = []
99
 
        self._config = config
100
 
        for project_name in self._config.sections:
101
 
            c_project_name = cherrypy_friendly(project_name)
102
 
            project = Project(
103
 
                c_project_name, self._config[project_name], self._config)
104
 
            self._projects.append(project)
105
 
            setattr(self, c_project_name, project)
106
 
        
107
 
    @turbogears.expose(template='loggerhead.templates.browse')
108
 
    def index(self):
109
 
        for p in self._projects:
110
 
            p._recheck_auto_folders()
111
 
        return {
112
 
            'projects': self._projects,
113
 
            'util': util,
114
 
            'title': self._config.get('title', ''),
115
 
        }
116
 
 
117
 
    def _check_rebuild(self):
118
 
        for p in self._projects:
119
 
            for v in p.views:
120
 
                v.check_rebuild()
121
 
 
122
 
 
123
 
 
124
 
# for use in profiling the very-slow get_change() method:
125
 
#h = Root.bazaar.bzr_dev.get_history()
126
 
#w = list(h.get_revision_history())
127
 
#h._get_changes_profiled(w[:100])
 
24
from loggerhead.templatefunctions import templatefunctions
 
25
from loggerhead.zptsupport import load_template
 
26
 
 
27
class TemplatedBranchView(object):
 
28
 
 
29
    template_path = None
 
30
 
 
31
    def __init__(self, branch):
 
32
        self._branch = branch
 
33
        self.log = branch.log
 
34
 
 
35
    def default(self, request, response):
 
36
        z = time.time()
 
37
        h = self._branch.history
 
38
        kw = request.GET
 
39
        util.set_context(kw)
 
40
 
 
41
        h._branch.lock_read()
 
42
        try:
 
43
            args = []
 
44
            while 1:
 
45
                arg = path_info_pop(request.environ)
 
46
                if arg is None:
 
47
                    break
 
48
                args.append(arg)
 
49
 
 
50
            vals = {
 
51
                'branch': self._branch,
 
52
                'util': util,
 
53
                'history': h,
 
54
                'url': self._branch.context_url,
 
55
            }
 
56
            vals.update(templatefunctions)
 
57
            del response.headers['Content-Type']
 
58
            vals.update(self.get_values(h, args, kw, response))
 
59
 
 
60
            self.log.info('/%s: %r secs' % (
 
61
                self.__class__.__name__, time.time() - z,))
 
62
            if 'Content-Type' not in response.headers:
 
63
                response.headers['Content-Type'] = 'text/html'
 
64
            template = load_template(self.template_path)
 
65
            template.expand_into(response, **vals)
 
66
        finally:
 
67
            h._branch.unlock()
128
68