~bzr-pqm/bzr/bzr.dev

5452.4.3 by John Arbash Meinel
Merge bzr.dev to resolve bzr-2.3.txt (aka NEWS)
1
# Copyright (C) 2008, 2009, 2010 Canonical Ltd
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
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
6379.6.7 by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear.
22
from __future__ import absolute_import
23
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
24
from bzrlib import (
25
    config,
4913.5.24 by Gordon Tyler
Added cmdline.split function, which replaces commands.shlex_split_unicode.
26
    cmdline,
3398.1.30 by Ian Clatworthy
test unknown rules detection
27
    errors,
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
28
    globbing,
29
    osutils,
30
    )
3398.1.6 by Ian Clatworthy
get properties_filename() test passing
31
from bzrlib.util.configobj import configobj
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
32
33
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
34
# Name of the file holding rules in a tree
35
RULES_TREE_FILENAME = ".bzrrules"
36
3398.1.28 by Ian Clatworthy
add namespace for rules
37
# Namespace prefix for per file preferences
3398.1.32 by Ian Clatworthy
namespace keyword changed to name
38
FILE_PREFS_PREFIX = 'name '
3398.1.28 by Ian Clatworthy
add namespace for rules
39
FILE_PREFS_PREFIX_LEN = len(FILE_PREFS_PREFIX)
40
4324.4.1 by Marius Kruger
Make it possible to blackboxtest rules
41
# The object providing default rules
42
_per_user_searcher = None
43
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
44
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
45
class _RulesSearcher(object):
46
    """An object that provides rule-based preferences."""
3398.1.13 by Ian Clatworthy
rename properties to attributes
47
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
48
    def get_items(self, path):
49
        """Return the preferences for a path as name,value tuples.
3398.1.13 by Ian Clatworthy
rename properties to attributes
50
51
        :param path: tree relative path
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
52
        :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
53
          tuples.
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
54
        """
55
        raise NotImplementedError(self.get_items)
56
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
57
    def get_selected_items(self, path, names):
58
        """Return selected preferences for a path as name,value tuples.
59
60
        :param path: tree relative path
61
        :param names: the list of preferences to lookup
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
62
        :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
63
          tuples. The sequence is the same length as names,
64
          tuple order matches the order in names, and
65
          undefined preferences are given the value None.
66
        """
67
        raise NotImplementedError(self.get_selected_items)
68
5802.4.1 by Martin Pool
Add and test _RulesSearcher.get_single_value
69
    def get_single_value(self, path, preference_name):
70
        """Get a single preference for a single file.
71
        
72
        :returns: The string preference value, or None.
73
        """
74
        for key, value in self.get_selected_items(path, [preference_name]):
75
            return value
76
        return None
77
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
78
79
class _IniBasedRulesSearcher(_RulesSearcher):
80
81
    def __init__(self, inifile):
82
        """Construct a _RulesSearcher based on an ini file.
83
3398.1.24 by Ian Clatworthy
make iter_search_rules a tree method
84
        The content will be decoded as utf-8.
85
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
86
        :param inifile: the name of the file or a sequence of lines.
87
        """
5519.2.1 by Max Bowsher
Fix a slightly odd style of ConfigObj construction to match the prevailing style in bzrlib.
88
        self._cfg = configobj.ConfigObj(inifile, encoding='utf-8')
3398.1.28 by Ian Clatworthy
add namespace for rules
89
        sections = self._cfg.keys()
3946.1.1 by Ian Clatworthy
Multi-glob rules (Marius Kruger)
90
        patterns = []
3943.3.1 by Marius Kruger
add test and support for multi-glob rules
91
        self.pattern_to_section = {}
92
        for s in sections:
93
            if s.startswith(FILE_PREFS_PREFIX):
4913.5.24 by Gordon Tyler
Added cmdline.split function, which replaces commands.shlex_split_unicode.
94
                file_patterns = cmdline.split(s[FILE_PREFS_PREFIX_LEN:])
3943.3.1 by Marius Kruger
add test and support for multi-glob rules
95
                patterns.extend(file_patterns)
96
                for fp in file_patterns:
97
                    self.pattern_to_section[fp] = s
3398.1.28 by Ian Clatworthy
add namespace for rules
98
        if len(patterns) < len(sections):
99
            unknowns = [s for s in sections
100
                if not s.startswith(FILE_PREFS_PREFIX)]
3398.1.30 by Ian Clatworthy
test unknown rules detection
101
            raise errors.UnknownRules(unknowns)
3398.1.28 by Ian Clatworthy
add namespace for rules
102
        elif patterns:
3398.1.17 by Ian Clatworthy
search less when files not present
103
            self._globster = globbing._OrderedGlobster(patterns)
104
        else:
105
            self._globster = None
3398.1.3 by Ian Clatworthy
first cut at PropertiesProvider class
106
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
107
    def get_items(self, path):
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
108
        """See _RulesSearcher.get_items."""
3398.1.17 by Ian Clatworthy
search less when files not present
109
        if self._globster is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
110
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
111
        pat = self._globster.match(path)
112
        if pat is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
113
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
114
        else:
3943.3.1 by Marius Kruger
add test and support for multi-glob rules
115
            all = self._cfg[self.pattern_to_section[pat]]
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
116
            return tuple(all.items())
117
118
    def get_selected_items(self, path, names):
119
        """See _RulesSearcher.get_selected_items."""
120
        if self._globster is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
121
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
122
        pat = self._globster.match(path)
123
        if pat is None:
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
124
            return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
125
        else:
3943.3.1 by Marius Kruger
add test and support for multi-glob rules
126
            all = self._cfg[self.pattern_to_section[pat]]
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
127
            return tuple((k, all.get(k)) for k in names)
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
128
129
130
class _StackedRulesSearcher(_RulesSearcher):
131
132
    def __init__(self, searchers):
133
        """Construct a _RulesSearcher based on a stack of other ones.
134
135
        :param searchers: a sequence of searchers.
136
        """
137
        self.searchers = searchers
138
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
139
    def get_items(self, path):
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
140
        """See _RulesSearcher.get_items."""
3398.1.18 by Ian Clatworthy
add tests for _StackedRulesSearcher
141
        for searcher in self.searchers:
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
142
            result = searcher.get_items(path)
143
            if result:
144
                return result
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
145
        return ()
3398.1.34 by Ian Clatworthy
changed API design as requested by jam during review
146
147
    def get_selected_items(self, path, names):
148
        """See _RulesSearcher.get_selected_items."""
149
        for searcher in self.searchers:
150
            result = searcher.get_selected_items(path, names)
151
            if result:
152
                return result
3564.1.1 by Ian Clatworthy
RuleSearchers need to return () instead of []
153
        return ()
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
154
155
156
def rules_filename():
157
    """Return the default rules filename."""
3398.1.23 by Ian Clatworthy
update doc to reflect file naming per poolie's review
158
    return osutils.pathjoin(config.config_dir(), 'rules')
3398.1.15 by Ian Clatworthy
search branch.rules and bazaar.rules for preferences
159
160
4324.4.1 by Marius Kruger
Make it possible to blackboxtest rules
161
def reset_rules():
162
    global _per_user_searcher
163
    _per_user_searcher = _IniBasedRulesSearcher(rules_filename())
164
165
reset_rules()