~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/controllers/__init__.py

  • Committer: Robey Pointer
  • Date: 2007-01-14 01:22:51 UTC
  • Revision ID: robey@lag.net-20070114012251-4r9icwoouak09zog
try john's idea of implementing _get_deltas_for_revisions_with_trees().
i don't think it helps a lot, but it's clearly less redundant.

Show diffs side-by-side

added added

removed removed

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