~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/controllers/__init__.py

  • Committer: Martin Albisetti
  • Date: 2008-06-17 17:12:59 UTC
  • mfrom: (160 trunk)
  • mto: (157.1.3 loggerhead)
  • mto: This revision was merged to the branch mainline in revision 187.
  • Revision ID: argentina@gmail.com-20080617171259-m1i55wka7k7cuaqv
MergeĀ fromĀ trunk

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
#
18
19
 
 
20
import logging
 
21
import os
19
22
import re
20
 
import time
21
23
 
22
 
from paste.request import path_info_pop, parse_querystring
 
24
import turbogears
 
25
from turbogears import controllers
 
26
from configobj import ConfigObj
23
27
 
24
28
from loggerhead import util
 
29
from loggerhead.branchview import BranchView
 
30
from loggerhead.history import is_branch
25
31
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
 
 
 
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()
75
112
        vals = {
76
 
            'branch': self._branch,
 
113
            'projects': self._projects,
77
114
            'util': util,
78
 
            'history': h,
79
 
            'url': self._branch.context_url,
 
115
            'title': self._config.get('title', None),
80
116
        }
81
117
        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 []
 
118
        return vals