~bzr-pqm/bzr/bzr.dev

2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
1
# Copyright (C) 2005, 2006 Canonical Ltd
1836.1.12 by John Arbash Meinel
Move ignores into a file of their own, make DEFAULT_IGNORE a deprecated list. Create deprecated_list in symbol versioning.
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
1836.1.12 by John Arbash Meinel
Move ignores into a file of their own, make DEFAULT_IGNORE a deprecated list. Create deprecated_list in symbol versioning.
16
17
"""Lists of ignore files, etc."""
18
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
19
import errno
20
3528.2.3 by Jelmer Vernooij
use constant for ignore file filename.
21
import bzrlib
2298.8.1 by Kent Gibson
Normalise ignore patterns to use '/' path separator.
22
from bzrlib import (
3528.2.1 by Jelmer Vernooij
Move functionality to add ignores to the ignore file into a separate function.
23
    atomicfile,
2298.8.1 by Kent Gibson
Normalise ignore patterns to use '/' path separator.
24
    config,
25
    globbing,
26
    )
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
27
5119.1.5 by Jason Spashett
Iff character decoding error occurs during processing of .bzrignore, parse line by line to fish out valid utf8 lines.
28
from trace import warning
29
1836.1.12 by John Arbash Meinel
Move ignores into a file of their own, make DEFAULT_IGNORE a deprecated list. Create deprecated_list in symbol versioning.
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',
2135.2.2 by Kent Gibson
Ignore pattern matcher (glob.py) patches:
98
    '*.sw[nop]',
1836.1.12 by John Arbash Meinel
Move ignores into a file of their own, make DEFAULT_IGNORE a deprecated list. Create deprecated_list in symbol versioning.
99
    '*~',
100
    '.#*',
101
    '[#]*#',
102
]
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
103
104
5119.1.5 by Jason Spashett
Iff character decoding error occurs during processing of .bzrignore, parse line by line to fish out valid utf8 lines.
105
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
106
def parse_ignore_file(f):
5119.1.5 by Jason Spashett
Iff character decoding error occurs during processing of .bzrignore, parse line by line to fish out valid utf8 lines.
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
    """
1836.1.30 by John Arbash Meinel
Change ignore functions to use sets instead of lists.
113
    ignored = set()
5119.1.5 by Jason Spashett
Iff character decoding error occurs during processing of .bzrignore, parse line by line to fish out valid utf8 lines.
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:
5119.1.3 by Jason Spashett
Reverse merge 4670..4668
133
        line = line.rstrip('\r\n')
134
        if not line or line.startswith('#'):
135
            continue
136
        ignored.add(globbing.normalize_pattern(line))
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
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()
1836.1.30 by John Arbash Meinel
Change ignore functions to use sets instead of lists.
143
    patterns = set(USER_DEFAULTS)
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
144
    try:
145
        f = open(path, 'rb')
146
    except (IOError, OSError), e:
1836.1.25 by John Arbash Meinel
cleanups suggested by Martin.
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,):
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
150
            raise
151
        # Create the ignore file, and just return the default
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
152
        # We want to ignore if we can't write to the file
153
        # since get_* should be a safe operation
154
        try:
1836.1.31 by John Arbash Meinel
Make set_user_ignores a private function, and update the doc string to recommend it isn't used.
155
            _set_user_ignores(USER_DEFAULTS)
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
156
        except (IOError, OSError), e:
157
            if e.errno not in (errno.EPERM,):
158
                raise
1836.1.13 by John Arbash Meinel
Adding functions for getting user ignores.
159
        return patterns
160
161
    try:
162
        return parse_ignore_file(f)
163
    finally:
164
        f.close()
1836.1.14 by John Arbash Meinel
Adding a helper function that will only add patterns if they are missing.
165
166
1836.1.31 by John Arbash Meinel
Make set_user_ignores a private function, and update the doc string to recommend it isn't used.
167
def _set_user_ignores(patterns):
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
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.
1836.1.31 by John Arbash Meinel
Make set_user_ignores a private function, and update the doc string to recommend it isn't used.
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.
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
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
1836.1.14 by John Arbash Meinel
Adding a helper function that will only add patterns if they are missing.
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
    """
1836.1.30 by John Arbash Meinel
Change ignore functions to use sets instead of lists.
194
    ignored = get_user_ignores()
1836.1.14 by John Arbash Meinel
Adding a helper function that will only add patterns if they are missing.
195
    to_add = []
196
    for ignore in new_ignores:
2298.8.1 by Kent Gibson
Normalise ignore patterns to use '/' path separator.
197
        ignore = globbing.normalize_pattern(ignore)
1836.1.14 by John Arbash Meinel
Adding a helper function that will only add patterns if they are missing.
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
1836.1.28 by John Arbash Meinel
Add a function for adding runtime ignores.
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.
1711.2.105 by John Arbash Meinel
Updated doc
223
    (Such as a conversion script that needs to ignore temporary files,
224
    but does not want to modify the project's ignore list.)
1836.1.28 by John Arbash Meinel
Add a function for adding runtime ignores.
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
3528.2.1 by Jelmer Vernooij
Move functionality to add ignores to the ignore file into a separate function.
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.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
242
    :return:
3528.2.1 by Jelmer Vernooij
Move functionality to add ignores to the ignore file into a separate function.
243
    """
3528.2.3 by Jelmer Vernooij
use constant for ignore file filename.
244
    ifn = tree.abspath(bzrlib.IGNORE_FILENAME)
3528.2.1 by Jelmer Vernooij
Move functionality to add ignores to the ignore file into a separate function.
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'])