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
24
from paste.httpexceptions import HTTPNotFound, HTTPSeeOther
25
from paste.request import path_info_pop, parse_querystring
27
from turbogears import controllers
28
from cherrypy import NotFound
29
from configobj import ConfigObj
27
31
from loggerhead import util
28
from loggerhead.templatefunctions import templatefunctions
29
from loggerhead.zptsupport import load_template
32
class BufferingWriter(object):
34
def __init__(self, writefunc, buf_limit):
38
self.writefunc = writefunc
39
self.buf_limit = buf_limit
42
self.writefunc(''.join(self.buf))
46
def write(self, data):
48
self.buflen += len(data)
49
self.bytes += len(data)
50
if self.buflen > self.buf_limit:
54
class TemplatedBranchView(object):
59
def __init__(self, branch, history_callable):
61
self._history_callable = history_callable
67
if self.__history is not None:
69
self.__history = self._history_callable()
72
def parse_args(self, environ):
73
kwargs = dict(parse_querystring(environ))
74
util.set_context(kwargs)
77
arg = path_info_pop(environ)
84
path = unicode('/'.join(args[1:]), 'utf-8')
89
def add_template_values(self, values):
91
'static_url': self._branch.static_url,
92
'branch': self._branch,
32
from loggerhead.branchview import BranchView
33
from loggerhead.history import History, is_branch
35
log = logging.getLogger("loggerhead.controllers")
38
def cherrypy_friendly(s):
40
convert a config section name into a name that pleases cherrypy.
42
return re.sub(r'[^\w\d_]', '_', s)
45
class Project (object):
46
def __init__(self, name, config):
48
self.friendly_name = config.get('name', name)
49
self.description = config.get('description', '')
50
self.long_description = config.get('long_description', '')
54
for view_name in config.sections:
55
log.debug('Configuring (project %s) branch %s...', name, view_name)
56
self._add_view(view_name, config[view_name], config[view_name].get('folder'))
58
self._auto_folder = config.get('auto_publish_folder', None)
60
if self._auto_folder is not None:
61
self._recheck_auto_folders()
63
def _recheck_auto_folders(self):
64
if self._auto_folder is None:
67
# scan a folder for bazaar branches, and add them automatically
68
for path, folders, filenames in os.walk(self._auto_folder):
69
for folder in folders:
70
folder = os.path.join(path, folder)
72
auto_list.append(folder)
74
if auto_list == self._auto_list:
75
# nothing has changed; do nothing.
79
log.debug('Rescanning auto-folder for project %s ...', self.name)
81
for folder in auto_list:
82
view_name = os.path.basename(folder)
83
log.debug('Auto-configuring (project %s) branch %s...', self.name, view_name)
84
self._add_view(view_name, ConfigObj(), folder)
85
self._auto_list = auto_list
87
def _add_view(self, view_name, view_config, folder):
88
c_view_name = cherrypy_friendly(view_name)
89
view = BranchView(self.name, c_view_name, view_name, folder, view_config, self._config)
90
self._views.append(view)
91
setattr(self, c_view_name, view)
93
views = property(lambda self: self._views)
96
class Root (controllers.RootController):
97
def __init__(self, config):
100
for project_name in self._config.sections:
101
c_project_name = cherrypy_friendly(project_name)
102
project = Project(c_project_name, self._config[project_name])
103
self._projects.append(project)
104
setattr(self, c_project_name, project)
106
@turbogears.expose(template='loggerhead.templates.browse')
108
for p in self._projects:
109
p._recheck_auto_folders()
111
'projects': self._projects,
94
'url': self._branch.context_url,
96
values.update(templatefunctions)
98
def __call__(self, environ, start_response):
100
if environ.get('loggerhead.as_json') and not self.supports_json:
102
path = self.parse_args(environ)
104
values = self.get_values(path, self.kwargs, headers)
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
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))
122
self.add_template_values(values)
123
template = load_template(self.template_path)
124
template.expand_into(w, **values)
127
'Rendering %s: %.3f secs, %s bytes' % (
128
self.__class__.__name__, time.time() - z, w.bytes))
135
if len(self.args) > 0 and self.args != ['']:
137
revid = h.fix_revid(self.args[0])
138
except bzrlib.errors.NoSuchRevision:
113
'title': self._config.get('title', ''),
116
def _check_rebuild(self):
117
for p in self._projects:
123
# for use in profiling the very-slow get_change() method:
124
#h = Root.bazaar.bzr_dev.get_history()
125
#w = list(h.get_revision_history())
126
#h._get_changes_profiled(w[:100])