2
# Copyright (C) 2006 Robey Pointer <robey@lag.net>
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
collection of configuration and objects related to a bazaar branch.
29
from cherrypy import HTTPRedirect
31
from loggerhead import util
32
from loggerhead.changecache import ChangeCache, FileChangeCache
33
from loggerhead.history import History
34
from loggerhead.textindex import TextIndex
35
from loggerhead.controllers.changelog_ui import ChangeLogUI
36
from loggerhead.controllers.atom_ui import AtomUI
37
from loggerhead.controllers.revision_ui import RevisionUI
38
from loggerhead.controllers.inventory_ui import InventoryUI
39
from loggerhead.controllers.annotate_ui import AnnotateUI
40
from loggerhead.controllers.download_ui import DownloadUI
41
from loggerhead.controllers.bundle_ui import BundleUI
44
with_history_lock = util.with_lock('_history_lock', 'History')
47
class BranchView (object):
48
def __init__(self, group_name, name, subfolder, absfolder, config, project_config):
49
self._group_name = group_name
51
self._folder = subfolder
52
self._absfolder = absfolder
54
self._project_config = project_config
55
self.log = logging.getLogger('loggerhead.%s' % (name,))
58
self._history_lock = threading.RLock()
62
self.changes = ChangeLogUI(self)
63
self.revision = RevisionUI(self)
64
self.files = InventoryUI(self)
65
self.annotate = AnnotateUI(self)
66
self.download = DownloadUI(self)
67
self.atom = AtomUI(self)
68
self.bundle = BundleUI(self)
70
# force history object to be loaded:
73
turbogears.startup.call_on_shutdown.append(self.close)
77
# it's important that we cleanly detach the history, so the cache
78
# files can be closed correctly and hopefully remain uncorrupted.
79
# this should also stop any ongoing indexing.
80
self._history.detach()
84
config = property(lambda self: self._config)
86
name = property(lambda self: self._name)
88
group_name = property(lambda self: self._group_name)
90
def _get_friendly_name(self):
91
name = self._config.get('branch_name', None)
94
# try branch-specific config?
95
name = self.get_history().get_config().get_nickname()
100
friendly_name = property(_get_friendly_name)
102
def _get_description(self):
103
description = self._config.get('description', None)
104
if description is not None:
106
# try branch-specific config?
107
description = self.get_history().get_config().get_user_option('description')
110
description = property(_get_description)
112
def _get_branch_url(self):
113
url = self._config.get('url', None)
116
# try to assemble one from the project, if an url_prefix was defined.
117
url = self._project_config.get('url_prefix', None)
119
return posixpath.join(url, self._folder) + '/'
120
# try branch-specific config?
121
url = self.get_history().get_config().get_user_option('public_branch')
124
branch_url = property(_get_branch_url)
128
raise HTTPRedirect(self.url('/changes'))
131
def get_history(self):
133
get an up-to-date History object, safely. each page-view calls this
134
method, and normally it will get the same History object as on previous
135
calls. but if the bazaar branch on-disk has been updated since this
136
History was created, a new object will be created and returned.
140
if (self._history is None) or self._history.out_of_date():
141
self.log.debug('Reload branch history...')
142
if self._history is not None:
143
self._history.detach()
144
_history = self._history = History.from_folder(
145
self._absfolder, self._name)
146
cache_path = self._config.get('cachepath', None)
147
if cache_path is None:
148
# try the project config
149
cache_path = self._project_config.get('cachepath', None)
150
if cache_path is not None:
151
_history.use_cache(ChangeCache(_history, cache_path))
152
_history.use_file_cache(FileChangeCache(_history, cache_path))
153
_history.use_search_index(TextIndex(_history, cache_path))
156
def check_rebuild(self):
157
h = self.get_history()
161
def url(self, elements, **kw):
162
"build an url relative to this branch"
163
if not isinstance(elements, list):
164
elements = [elements]
165
if elements[0].startswith('/'):
166
elements[0] = elements[0][1:]
167
elements = [urllib.quote(x) for x in elements]
168
return turbogears.url([ '/' + self.group_name, self.name ] + elements, **kw)
170
def context_url(self, elements, **kw):
171
"build an url relative to this branch, bringing along browsing context"
172
return self.url(elements, **util.get_context(**kw))
174
def last_updated(self):
175
h = self.get_history()
176
change = h.get_changes([ h.last_revid ])[0]