/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/ignores.py

Warn if a config variable can't be interpreted as a boolean

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Lists of ignore files, etc."""
 
18
 
 
19
import errno
 
20
 
 
21
import bzrlib
 
22
from bzrlib import (
 
23
    atomicfile,
 
24
    config,
 
25
    globbing,
 
26
    )
 
27
 
 
28
from trace import warning
 
29
 
 
30
# This was the full ignore list for bzr 0.8
 
31
# please keep these sorted (in C locale order) to aid merging
 
32
OLD_DEFAULTS = [
 
33
    '#*#',
 
34
    '*$',
 
35
    '*,v',
 
36
    '*.BAK',
 
37
    '*.a',
 
38
    '*.bak',
 
39
    '*.elc',
 
40
    '*.exe',
 
41
    '*.la',
 
42
    '*.lo',
 
43
    '*.o',
 
44
    '*.obj',
 
45
    '*.orig',
 
46
    '*.py[oc]',
 
47
    '*.so',
 
48
    '*.tmp',
 
49
    '*~',
 
50
    '.#*',
 
51
    '.*.sw[nop]',
 
52
    '.*.tmp',
 
53
    # Our setup tests dump .python-eggs in the bzr source tree root
 
54
    './.python-eggs',
 
55
    '.DS_Store',
 
56
    '.arch-ids',
 
57
    '.arch-inventory',
 
58
    '.bzr.log',
 
59
    '.del-*',
 
60
    '.git',
 
61
    '.hg',
 
62
    '.jamdeps'
 
63
    '.libs',
 
64
    '.make.state',
 
65
    '.sconsign*',
 
66
    '.svn',
 
67
    '.sw[nop]',    # vim editing nameless file
 
68
    '.tmp*',
 
69
    'BitKeeper',
 
70
    'CVS',
 
71
    'CVS.adm',
 
72
    'RCS',
 
73
    'SCCS',
 
74
    'TAGS',
 
75
    '_darcs',
 
76
    'aclocal.m4',
 
77
    'autom4te*',
 
78
    'config.h',
 
79
    'config.h.in',
 
80
    'config.log',
 
81
    'config.status',
 
82
    'config.sub',
 
83
    'stamp-h',
 
84
    'stamp-h.in',
 
85
    'stamp-h1',
 
86
    '{arch}',
 
87
]
 
88
 
 
89
 
 
90
# ~/.bazaar/ignore will be filled out using
 
91
# this ignore list, if it does not exist
 
92
# please keep these sorted (in C locale order) to aid merging
 
93
USER_DEFAULTS = [
 
94
    '*.a',
 
95
    '*.o',
 
96
    '*.py[co]',
 
97
    '*.so',
 
98
    '*.sw[nop]',
 
99
    '*~',
 
100
    '.#*',
 
101
    '[#]*#',
 
102
]
 
103
 
 
104
 
 
105
 
 
106
def parse_ignore_file(f):
 
107
    """Read in all of the lines in the file and turn it into an ignore list
 
108
    
 
109
    Continue in the case of utf8 decoding errors, and emit a warning when 
 
110
    such and error is found. Optimise for the common case -- no decoding 
 
111
    errors.
 
112
    """
 
113
    ignored = set()
 
114
    ignore_file = f.read()
 
115
    try:
 
116
        # Try and parse whole ignore file at once.
 
117
        unicode_lines = ignore_file.decode('utf8').split('\n')
 
118
    except UnicodeDecodeError:
 
119
        # Otherwise go though line by line and pick out the 'good'
 
120
        # decodable lines
 
121
        lines = ignore_file.split('\n')
 
122
        unicode_lines = []    
 
123
        for line_number, line in enumerate(lines):
 
124
            try:
 
125
                unicode_lines.append(line.decode('utf-8'))
 
126
            except UnicodeDecodeError:
 
127
                # report error about line (idx+1)
 
128
                warning('.bzrignore: On Line #%d, malformed utf8 character. '
 
129
                        'Ignoring line.' % (line_number+1))
 
130
    
 
131
    # Append each line to ignore list if it's not a comment line
 
132
    for line in unicode_lines:
 
133
        line = line.rstrip('\r\n')
 
134
        if not line or line.startswith('#'):
 
135
            continue
 
136
        ignored.add(globbing.normalize_pattern(line))
 
137
    return ignored
 
138
 
 
139
 
 
140
def get_user_ignores():
 
141
    """Get the list of user ignored files, possibly creating it."""
 
142
    path = config.user_ignore_config_filename()
 
143
    patterns = set(USER_DEFAULTS)
 
144
    try:
 
145
        f = open(path, 'rb')
 
146
    except (IOError, OSError), e:
 
147
        # open() shouldn't return an IOError without errno, but just in case
 
148
        err = getattr(e, 'errno', None)
 
149
        if err not in (errno.ENOENT,):
 
150
            raise
 
151
        # Create the ignore file, and just return the default
 
152
        # We want to ignore if we can't write to the file
 
153
        # since get_* should be a safe operation
 
154
        try:
 
155
            _set_user_ignores(USER_DEFAULTS)
 
156
        except (IOError, OSError), e:
 
157
            if e.errno not in (errno.EPERM,):
 
158
                raise
 
159
        return patterns
 
160
 
 
161
    try:
 
162
        return parse_ignore_file(f)
 
163
    finally:
 
164
        f.close()
 
165
 
 
166
 
 
167
def _set_user_ignores(patterns):
 
168
    """Fill out the user ignore file with the given patterns
 
169
 
 
170
    This may raise an error if it doesn't have permission to
 
171
    write to the user ignore file.
 
172
    This is mostly used for testing, since it would be
 
173
    bad form to rewrite a user's ignore list.
 
174
    bzrlib only writes this file if it does not exist.
 
175
    """
 
176
    ignore_path = config.user_ignore_config_filename()
 
177
    config.ensure_config_dir_exists()
 
178
 
 
179
    # Create an empty file
 
180
    f = open(ignore_path, 'wb')
 
181
    try:
 
182
        for pattern in patterns:
 
183
            f.write(pattern.encode('utf8') + '\n')
 
184
    finally:
 
185
        f.close()
 
186
 
 
187
 
 
188
def add_unique_user_ignores(new_ignores):
 
189
    """Add entries to the user's ignore list if not present.
 
190
 
 
191
    :param new_ignores: A list of ignore patterns
 
192
    :return: The list of ignores that were added
 
193
    """
 
194
    ignored = get_user_ignores()
 
195
    to_add = []
 
196
    for ignore in new_ignores:
 
197
        ignore = globbing.normalize_pattern(ignore)
 
198
        if ignore not in ignored:
 
199
            ignored.add(ignore)
 
200
            to_add.append(ignore)
 
201
 
 
202
    if not to_add:
 
203
        return []
 
204
 
 
205
    f = open(config.user_ignore_config_filename(), 'ab')
 
206
    try:
 
207
        for pattern in to_add:
 
208
            f.write(pattern.encode('utf8') + '\n')
 
209
    finally:
 
210
        f.close()
 
211
 
 
212
    return to_add
 
213
 
 
214
 
 
215
_runtime_ignores = set()
 
216
 
 
217
 
 
218
def add_runtime_ignores(ignores):
 
219
    """Add some ignore patterns that only exists in memory.
 
220
 
 
221
    This is used by some plugins that want bzr to ignore files,
 
222
    but don't want to change a users ignore list.
 
223
    (Such as a conversion script that needs to ignore temporary files,
 
224
    but does not want to modify the project's ignore list.)
 
225
 
 
226
    :param ignores: A list or generator of ignore patterns.
 
227
    :return: None
 
228
    """
 
229
    global _runtime_ignores
 
230
    _runtime_ignores.update(set(ignores))
 
231
 
 
232
 
 
233
def get_runtime_ignores():
 
234
    """Get the current set of runtime ignores."""
 
235
    return _runtime_ignores
 
236
 
 
237
 
 
238
def tree_ignores_add_patterns(tree, name_pattern_list):
 
239
    """Retrieve a list of ignores from the ignore file in a tree.
 
240
 
 
241
    :param tree: Tree to retrieve the ignore list from.
 
242
    :return:
 
243
    """
 
244
    ifn = tree.abspath(bzrlib.IGNORE_FILENAME)
 
245
    if tree.has_filename(ifn):
 
246
        f = open(ifn, 'rt')
 
247
        try:
 
248
            igns = f.read().decode('utf-8')
 
249
        finally:
 
250
            f.close()
 
251
    else:
 
252
        igns = ""
 
253
 
 
254
    # TODO: If the file already uses crlf-style termination, maybe
 
255
    # we should use that for the newly added lines?
 
256
 
 
257
    if igns and igns[-1] != '\n':
 
258
        igns += '\n'
 
259
    for name_pattern in name_pattern_list:
 
260
        igns += name_pattern + '\n'
 
261
 
 
262
    f = atomicfile.AtomicFile(ifn, 'wb')
 
263
    try:
 
264
        f.write(igns.encode('utf-8'))
 
265
        f.commit()
 
266
    finally:
 
267
        f.close()
 
268
 
 
269
    if not tree.path2id('.bzrignore'):
 
270
        tree.add(['.bzrignore'])