~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/controllers/__init__.py

  • Committer: Marius Kruger
  • Date: 2008-09-06 20:17:56 UTC
  • mto: This revision was merged to the branch mainline in revision 219.
  • Revision ID: amanic@gmail.com-20080906201756-ocqnga9vu1uj425t
Add alternative insallation notes and mention the --prefix option in README.txt

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
18
 
20
 
import logging
21
 
import os
22
19
import re
 
20
import time
23
21
 
24
 
import turbogears
25
 
from turbogears import controllers
26
 
from configobj import ConfigObj
 
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
 
 
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):
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
 
        
50
 
        self._views = []
51
 
        for view_name in config.sections:
52
 
            log.debug('Configuring (project %s) branch %s...', name, view_name)
53
 
            self._add_view(view_name, config[view_name], config[view_name].get('folder'))
54
 
        
55
 
        self._auto_folder = config.get('auto_publish_folder', None)
56
 
        self._auto_list = []
57
 
        if self._auto_folder is not None:
58
 
            self._recheck_auto_folders()
59
 
    
60
 
    def _recheck_auto_folders(self):
61
 
        if self._auto_folder is None:
62
 
            return
63
 
        auto_list = []
64
 
        # scan a folder for bazaar branches, and add them automatically
65
 
        for path, folders, filenames in os.walk(self._auto_folder):
66
 
            for folder in folders:
67
 
                folder = os.path.join(path, folder)
68
 
                if is_branch(folder):
69
 
                    auto_list.append(folder)
70
 
        auto_list.sort()
71
 
        if auto_list == self._auto_list:
72
 
            # nothing has changed; do nothing.
73
 
            return
74
 
 
75
 
        # rebuild views:
76
 
        log.debug('Rescanning auto-folder for project %s ...', self.name)
77
 
        self._views = []
78
 
        for folder in auto_list:
79
 
            view_name = os.path.basename(folder)
80
 
            log.debug('Auto-configuring (project %s) branch %s...', self.name, view_name)
81
 
            self._add_view(view_name, ConfigObj(), folder)
82
 
        self._auto_list = auto_list
83
 
        
84
 
    def _add_view(self, view_name, view_config, folder):
85
 
        c_view_name = cherrypy_friendly(view_name)
86
 
        view = BranchView(self.name, c_view_name, view_name, folder, view_config, self._config)
87
 
        self._views.append(view)
88
 
        setattr(self, c_view_name, view)
89
 
        
90
 
    views = property(lambda self: self._views)
91
 
 
92
 
 
93
 
class Root (controllers.RootController):
94
 
    def __init__(self, config):
95
 
        self._projects = []
96
 
        self._config = config
97
 
        for project_name in self._config.sections:
98
 
            c_project_name = cherrypy_friendly(project_name)
99
 
            project = Project(c_project_name, self._config[project_name])
100
 
            self._projects.append(project)
101
 
            setattr(self, c_project_name, project)
102
 
        
103
 
    @turbogears.expose(template='loggerhead.templates.browse')
104
 
    def index(self):
105
 
        for p in self._projects:
106
 
            p._recheck_auto_folders()
107
 
        return {
108
 
            'projects': self._projects,
 
25
from loggerhead.templatefunctions import templatefunctions
 
26
from loggerhead.zptsupport import load_template
 
27
 
 
28
class BufferingWriter(object):
 
29
 
 
30
    def __init__(self, writefunc, buf_limit):
 
31
        self.bytes = 0
 
32
        self.buf = []
 
33
        self.buflen = 0
 
34
        self.writefunc = writefunc
 
35
        self.bytes_saved = 0
 
36
        self.buf_limit = buf_limit
 
37
 
 
38
    def flush(self):
 
39
        chunk = ''.join(self.buf)
 
40
        chunk = re.sub(r'\s*\n\s*', '\n', chunk)
 
41
        chunk = re.sub(r'[ \t]+', ' ', chunk)
 
42
        self.bytes_saved += self.buflen - len(chunk)
 
43
        self.writefunc(chunk)
 
44
        self.buf = []
 
45
        self.buflen = 0
 
46
 
 
47
    def write(self, data):
 
48
        self.buf.append(data)
 
49
        self.buflen += len(data)
 
50
        self.bytes += len(data)
 
51
        if self.buflen > self.buf_limit:
 
52
            self.flush()
 
53
 
 
54
class TemplatedBranchView(object):
 
55
 
 
56
    template_path = None
 
57
 
 
58
    def __init__(self, branch, history):
 
59
        self._branch = branch
 
60
        self._history = history
 
61
        self.log = branch.log
 
62
 
 
63
    def __call__(self, environ, start_response):
 
64
        z = time.time()
 
65
        h = self._history
 
66
        kw = dict(parse_querystring(environ))
 
67
        util.set_context(kw)
 
68
        args = []
 
69
        while 1:
 
70
            arg = path_info_pop(environ)
 
71
            if arg is None:
 
72
                break
 
73
            args.append(arg)
 
74
 
 
75
        vals = {
 
76
            'branch': self._branch,
109
77
            'util': util,
110
 
            'title': self._config.get('title', ''),
 
78
            'history': h,
 
79
            'url': self._branch.context_url,
111
80
        }
112
 
 
113
 
    def _check_rebuild(self):
114
 
        for p in self._projects:
115
 
            for v in p.views:
116
 
                v.check_rebuild()
117
 
 
118
 
 
119
 
 
120
 
# for use in profiling the very-slow get_change() method:
121
 
#h = Root.bazaar.bzr_dev.get_history()
122
 
#w = list(h.get_revision_history())
123
 
#h._get_changes_profiled(w[:100])
124
 
 
 
81
        vals.update(templatefunctions)
 
82
        headers = {}
 
83
        vals.update(self.get_values(h, args, kw, headers))
 
84
 
 
85
        self.log.info('Getting information for %s: %r secs' % (
 
86
            self.__class__.__name__, time.time() - z,))
 
87
        if 'Content-Type' not in headers:
 
88
            headers['Content-Type'] = 'text/html'
 
89
        writer = start_response("200 OK", headers.items())
 
90
        template = load_template(self.template_path)
 
91
        z = time.time()
 
92
        w = BufferingWriter(writer, 8192)
 
93
        template.expand_into(w, **vals)
 
94
        w.flush()
 
95
        self.log.info('Rendering %s: %r secs, %s bytes, %s (%2.1f%%) bytes saved' % (
 
96
            self.__class__.__name__, time.time() - z, w.bytes, w.bytes_saved, 100.0*w.bytes_saved/w.bytes))
 
97
        return []