~loggerhead-team/loggerhead/trunk-rich

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#
# Copyright (C) 2006  Robey Pointer <robey@lag.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#

"""
collection of configuration and objects related to a bazaar branch.
"""

import logging
import posixpath
import threading
import urllib

import turbogears
from cherrypy import HTTPRedirect

from loggerhead import util
from loggerhead.changecache import FileChangeCache
from loggerhead.history import History
from loggerhead.controllers.changelog_ui import ChangeLogUI
from loggerhead.controllers.atom_ui import AtomUI
from loggerhead.controllers.revision_ui import RevisionUI
from loggerhead.controllers.inventory_ui import InventoryUI
from loggerhead.controllers.annotate_ui import AnnotateUI
from loggerhead.controllers.download_ui import DownloadUI
from loggerhead.controllers.bundle_ui import BundleUI


with_history_lock = util.with_lock('_history_lock', 'History')


class BranchView (object):
    def __init__(self, group_name, name, subfolder, absfolder, config,
                 project_config, root_config):
        self._group_name = group_name
        self._name = name
        self._folder = subfolder
        self._absfolder = absfolder
        self._config = config
        self._project_config = project_config
        self._root_config = root_config
        self.log = logging.getLogger('loggerhead.%s' % (name,))

        # branch history
        self._history_lock = threading.RLock()
        self._history = None

        self.changes = ChangeLogUI(self)
        self.revision = RevisionUI(self)
        self.files = InventoryUI(self)
        self.annotate = AnnotateUI(self)
        self.download = DownloadUI(self)
        self.atom = AtomUI(self)
        self.bundle = BundleUI(self)

        # force history object to be loaded:
        self.get_history()

    config = property(lambda self: self._config)

    name = property(lambda self: self._name)

    group_name = property(lambda self: self._group_name)

    def _get_friendly_name(self):
        name = self._config.get('branch_name', None)
        if name is not None:
            return name
        # try branch-specific config?
        name = self.get_history().get_config().get_nickname()
        if name is not None:
            return name
        return self._name

    friendly_name = property(_get_friendly_name)

    def _get_description(self):
        description = self._config.get('description', None)
        if description is not None:
            return description
        # try branch-specific config?
        description = self.get_history().get_config().get_user_option('description')
        return description

    description = property(_get_description)

    def _get_branch_url(self):
        url = self._config.get('url', None)
        if url is not None:
            return url
        # try to assemble one from the project, if an url_prefix was defined.
        url = self._project_config.get('url_prefix', None)
        if url is not None:
            return posixpath.join(url, self._folder) + '/'
        # try branch-specific config?
        url = self.get_history().get_config().get_user_option('public_branch')
        return url

    branch_url = property(_get_branch_url)

    @turbogears.expose()
    def index(self):
        raise HTTPRedirect(self.url('/changes'))

    def get_config_item(self, item, default=None):
        for conf in self._config, self._project_config, self._root_config:
            if item in conf:
                return conf[item]
        return default

    @with_history_lock
    def get_history(self):
        """
        get an up-to-date History object, safely.  each page-view calls this
        method, and normally it will get the same History object as on previous
        calls.  but if the bazaar branch on-disk has been updated since this
        History was created, a new object will be created and returned.
        """
        if (self._history is None) or self._history.out_of_date():
            self.log.debug('Reload branch history...')
            _history = self._history = History.from_folder(
                self._absfolder, self._name)
            cache_path = self._config.get('cachepath', None)
            if cache_path is None:
                # try the project config
                cache_path = self._project_config.get('cachepath', None)
            if cache_path is not None:
                _history.use_file_cache(FileChangeCache(_history, cache_path))
        return self._history

    def url(self, elements, **kw):
        "build an url relative to this branch"
        if not isinstance(elements, list):
            elements = [elements]
        if elements[0].startswith('/'):
            elements[0] = elements[0][1:]
        elements = [urllib.quote(x) for x in elements]
        return turbogears.url([ '/' + self.group_name, self.name ] + elements, **kw)

    def context_url(self, elements, **kw):
        "build an url relative to this branch, bringing along browsing context"
        return self.url(elements, **util.get_context(**kw))

    def last_updated(self):
        h = self.get_history()
        change = h.get_changes([ h.last_revid ])[0]
        return change.date