~bzr-pqm/bzr/bzr.dev

3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
1
# Copyright (C) 2008 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
17
"""Rule-based definition of preferences for selected files in selected branches.
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
18
3398.1.22 by Ian Clatworthy
minor tweaks
19
See ``bzr help rules`` for details.
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
20
"""
21
22
from bzrlib import (
23
    config,
3398.1.30 by Ian Clatworthy
test unknown rules detection
24
    errors,
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
25
    globbing,
26
    osutils,
27
    )
3398.1.6 by Ian Clatworthy
get properties_filename() test passing
28
from bzrlib.util.configobj import configobj
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
29
30
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
31
# Name of the file holding rules in a tree
32
RULES_TREE_FILENAME = ".bzrrules"
33
3398.1.28 by Ian Clatworthy
add namespace for rules
34
# Namespace prefix for per file preferences
3398.1.32 by Ian Clatworthy
namespace keyword changed to name
35
FILE_PREFS_PREFIX = 'name '
3398.1.28 by Ian Clatworthy
add namespace for rules
36
FILE_PREFS_PREFIX_LEN = len(FILE_PREFS_PREFIX)
37
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
38
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
39
class _RulesSearcher(object):
40
    """An object that provides rule-based preferences."""
3398.1.13 by Ian Clatworthy
rename properties to attributes
41
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
42
    def get_items(self, path):
43
        """Return the preferences for a path as name,value tuples.
3398.1.13 by Ian Clatworthy
rename properties to attributes
44
45
        :param path: tree relative path
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
46
        :return: () if no rule matched, otherwise a sequence of name,value
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
47
          tuples.
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
48
        """
49
        raise NotImplementedError(self.get_items)
50
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
51
    def get_selected_items(self, path, names):
52
        """Return selected preferences for a path as name,value tuples.
53
54
        :param path: tree relative path
55
        :param names: the list of preferences to lookup
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
56
        :return: () if no rule matched, otherwise a sequence of name,value
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
57
          tuples. The sequence is the same length as names,
58
          tuple order matches the order in names, and
59
          undefined preferences are given the value None.
60
        """
61
        raise NotImplementedError(self.get_selected_items)
62
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
63
64
class _IniBasedRulesSearcher(_RulesSearcher):
65
66
    def __init__(self, inifile):
67
        """Construct a _RulesSearcher based on an ini file.
68
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
69
        The content will be decoded as utf-8.
70
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
71
        :param inifile: the name of the file or a sequence of lines.
72
        """
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
73
        options = {'encoding': 'utf-8'}
74
        self._cfg = configobj.ConfigObj(inifile, options=options)
3398.1.28 by Ian Clatworthy
add namespace for rules
75
        sections = self._cfg.keys()
76
        patterns = [s[FILE_PREFS_PREFIX_LEN:] for s in sections
77
            if s.startswith(FILE_PREFS_PREFIX)]
78
        if len(patterns) < len(sections):
79
            unknowns = [s for s in sections
80
                if not s.startswith(FILE_PREFS_PREFIX)]
3398.1.30 by Ian Clatworthy
test unknown rules detection
81
            raise errors.UnknownRules(unknowns)
3398.1.28 by Ian Clatworthy
add namespace for rules
82
        elif patterns:
3398.1.17 by Ian Clatworthy
search less when files not present
83
            self._globster = globbing._OrderedGlobster(patterns)
84
        else:
85
            self._globster = None
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
86
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
87
    def get_items(self, path):
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
88
        """See _RulesSearcher.get_items."""
3398.1.17 by Ian Clatworthy
search less when files not present
89
        if self._globster is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
90
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
91
        pat = self._globster.match(path)
92
        if pat is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
93
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
94
        else:
95
            all = self._cfg[FILE_PREFS_PREFIX + pat]
96
            return tuple(all.items())
97
98
    def get_selected_items(self, path, names):
99
        """See _RulesSearcher.get_selected_items."""
100
        if self._globster is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
101
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
102
        pat = self._globster.match(path)
103
        if pat is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
104
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
105
        else:
106
            all = self._cfg[FILE_PREFS_PREFIX + pat]
107
            return tuple((k, all.get(k)) for k in names)
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
108
109
110
class _StackedRulesSearcher(_RulesSearcher):
111
112
    def __init__(self, searchers):
113
        """Construct a _RulesSearcher based on a stack of other ones.
114
115
        :param searchers: a sequence of searchers.
116
        """
117
        self.searchers = searchers
118
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
119
    def get_items(self, path):
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
120
        """See _RulesSearcher.get_items."""
3398.1.18 by Ian Clatworthy
add tests for _StackedRulesSearcher
121
        for searcher in self.searchers:
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
122
            result = searcher.get_items(path)
123
            if result:
124
                return result
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
125
        return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
126
127
    def get_selected_items(self, path, names):
128
        """See _RulesSearcher.get_selected_items."""
129
        for searcher in self.searchers:
130
            result = searcher.get_selected_items(path, names)
131
            if result:
132
                return result
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
133
        return ()
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
134
135
136
def rules_filename():
137
    """Return the default rules filename."""
3398.1.23 by Ian Clatworthy
update doc to reflect file naming per poolie's review
138
    return osutils.pathjoin(config.config_dir(), 'rules')
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
139
140
141
# The object providing default rules
142
_per_user_searcher = _IniBasedRulesSearcher(rules_filename())