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
23
from paste.httpexceptions import HTTPNotFound
24
from paste.request import path_info_pop, parse_querystring
27
from turbogears import controllers
28
from cherrypy import NotFound
29
from configobj import ConfigObj
26
31
from loggerhead import util
27
from loggerhead.templatefunctions import templatefunctions
28
from loggerhead.zptsupport import load_template
31
class BufferingWriter(object):
33
def __init__(self, writefunc, buf_limit):
37
self.writefunc = writefunc
38
self.buf_limit = buf_limit
41
self.writefunc(''.join(self.buf))
45
def write(self, data):
47
self.buflen += len(data)
48
self.bytes += len(data)
49
if self.buflen > self.buf_limit:
53
class TemplatedBranchView(object):
57
def __init__(self, branch, history_callable):
59
self._history_callable = history_callable
65
if self.__history is not None:
67
self.__history = self._history_callable()
70
def __call__(self, environ, start_response):
72
kwargs = dict(parse_querystring(environ))
73
util.set_context(kwargs)
76
arg = path_info_pop(environ)
83
path = unicode('/'.join(args[1:]), 'utf-8')
87
'static_url': self._branch.static_url,
88
'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,
90
'url': self._branch.context_url,
113
'title': self._config.get('title', ''),
92
vals.update(templatefunctions)
95
vals.update(self.get_values(path, kwargs, headers))
97
self.log.info('Getting information for %s: %.3f secs' % (
98
self.__class__.__name__, time.time() - z))
99
if 'Content-Type' not in headers:
100
headers['Content-Type'] = 'text/html'
101
writer = start_response("200 OK", headers.items())
102
if environ.get('REQUEST_METHOD') == 'HEAD':
103
# No content for a HEAD request
105
template = load_template(self.template_path)
107
w = BufferingWriter(writer, 8192)
108
template.expand_into(w, **vals)
111
'Rendering %s: %.3f secs, %s bytes' % (
112
self.__class__.__name__, time.time() - z, w.bytes))
119
if len(self.args) > 0 and self.args != ['']:
121
revid = h.fix_revid(self.args[0])
122
except bzrlib.errors.NoSuchRevision:
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])