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
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
self._history = History.from_folder(self._absfolder, self._name)
145
cache_path = self._config.get('cachepath', None)
146
if cache_path is None:
147
# try the project config
148
cache_path = self._project_config.get('cachepath', None)
149
if cache_path is not None:
150
self._history.use_cache(ChangeCache(self._history, cache_path))
151
self._history.use_search_index(TextIndex(self._history, cache_path))
154
def check_rebuild(self):
155
h = self.get_history()
159
def url(self, elements, **kw):
160
if not isinstance(elements, list):
161
elements = [elements]
162
if elements[0].startswith('/'):
163
elements[0] = elements[0][1:]
164
elements = [urllib.quote(x) for x in elements]
165
return turbogears.url([ '/' + self.group_name, self.name ] + elements, **kw)
167
def last_updated(self):
168
h = self.get_history()
169
change = h.get_changes([ h.last_revid ])[0]