/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.40.10 by Parth Malwankar
assigned copyright to canonical
1
# Copyright (C) 2010 Canonical Ltd
7211.14.6 by Jelmer Vernooij
Fix source tests.
2
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
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
7211.14.6 by Jelmer Vernooij
Fix source tests.
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
16
0.40.147 by Jelmer Vernooij
Fix compatibility with newer versions of bzr: don't use relative imports in lazy imports, and import features from bzrlib.tests.features.
17
from __future__ import absolute_import
18
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
19
import re
0.47.1 by Martin
Implement whole text search for fast failure on no match
20
7211.14.5 by Jelmer Vernooij
Fix tests.
21
from .lazy_import import lazy_import
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
22
lazy_import(globals(), """
0.40.83 by Parth Malwankar
added support for -F/--fixed-string.
23
from fnmatch import fnmatch
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
24
6667.2.1 by Jelmer Vernooij
Some cleanup; s/BzrDir/ControlDir/, remove some unused imports.
25
from breezy._termcolor import color_string, FG
0.43.4 by Parth Malwankar
initial support for color for fixed string grep.
26
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
27
from breezy import (
7211.14.2 by Jelmer Vernooij
Move GrepOptions to breezy.grep.
28
    diff,
29
    )
30
""")
31
from . import (
6667.2.1 by Jelmer Vernooij
Some cleanup; s/BzrDir/ControlDir/, remove some unused imports.
32
    controldir,
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
33
    errors,
7211.14.2 by Jelmer Vernooij
Move GrepOptions to breezy.grep.
34
    osutils,
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
35
    revision as _mod_revision,
0.40.47 by Parth Malwankar
fixes bug #531336. binary files are now skipped.
36
    trace,
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
37
    )
7211.14.2 by Jelmer Vernooij
Move GrepOptions to breezy.grep.
38
from .revisionspec import (
6800.1.5 by Jelmer Vernooij
Fix more imports.
39
    RevisionSpec,
40
    RevisionSpec_revid,
41
    RevisionSpec_revno,
42
    )
7211.14.2 by Jelmer Vernooij
Move GrepOptions to breezy.grep.
43
from .sixish import (
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
44
    BytesIO,
45
    )
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
46
0.40.83 by Parth Malwankar
added support for -F/--fixed-string.
47
_user_encoding = osutils.get_user_encoding()
48
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
49
0.40.95 by Parth Malwankar
faster mainline rev grep
50
class _RevisionNotLinear(Exception):
51
    """Raised when a revision is not on left-hand history."""
52
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
53
7211.14.2 by Jelmer Vernooij
Move GrepOptions to breezy.grep.
54
class GrepOptions(object):
55
    """Container to pass around grep options.
56
57
    This class is used as a container to pass around user option and
58
    some other params (like outf) to processing functions. This makes
59
    it easier to add more options as grep evolves.
60
    """
61
    verbose = False
62
    ignore_case = False
63
    no_recursive = False
64
    from_root = False
65
    null = False
66
    levels = None
67
    line_number = False
68
    path_list = None
69
    revision = None
70
    pattern = None
71
    include = None
72
    exclude = None
73
    fixed_string = False
74
    files_with_matches = False
75
    files_without_match = False
76
    color = None
77
    diff = False
78
79
    # derived options
80
    recursive = None
81
    eol_marker = None
82
    patternc = None
83
    sub_patternc = None
84
    print_revno = None
85
    fixed_string = None
86
    outf = None
87
    show_color = False
88
89
0.40.95 by Parth Malwankar
faster mainline rev grep
90
def _rev_on_mainline(rev_tuple):
91
    """returns True is rev tuple is on mainline"""
92
    if len(rev_tuple) == 1:
93
        return True
94
    return rev_tuple[1] == 0 and rev_tuple[2] == 0
95
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
96
0.40.100 by Parth Malwankar
removed dependency on log._graph_view_revisions
97
# NOTE: _linear_view_revisions is basided on
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
98
# breezy.log._linear_view_revisions.
0.40.100 by Parth Malwankar
removed dependency on log._graph_view_revisions
99
# This should probably be a common public API
0.40.95 by Parth Malwankar
faster mainline rev grep
100
def _linear_view_revisions(branch, start_rev_id, end_rev_id):
0.40.106 by Parth Malwankar
fixed error in dotted rev reverse search.
101
    # requires that start is older than end
0.40.95 by Parth Malwankar
faster mainline rev grep
102
    repo = branch.repository
6531.3.6 by Jelmer Vernooij
Use iter_lefthand_ancestry rather than removed iter_reverse_revision_history.
103
    graph = repo.get_graph()
6531.3.7 by Jelmer Vernooij
Formatting.
104
    for revision_id in graph.iter_lefthand_ancestry(
105
            end_rev_id, (_mod_revision.NULL_REVISION, )):
0.40.95 by Parth Malwankar
faster mainline rev grep
106
        revno = branch.revision_id_to_dotted_revno(revision_id)
107
        revno_str = '.'.join(str(n) for n in revno)
108
        if revision_id == start_rev_id:
109
            yield revision_id, revno_str, 0
110
            break
111
        yield revision_id, revno_str, 0
112
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
113
0.40.100 by Parth Malwankar
removed dependency on log._graph_view_revisions
114
# NOTE: _graph_view_revisions is copied from
6622.1.34 by Jelmer Vernooij
Rename brzlib => breezy.
115
# breezy.log._graph_view_revisions.
0.40.100 by Parth Malwankar
removed dependency on log._graph_view_revisions
116
# This should probably be a common public API
117
def _graph_view_revisions(branch, start_rev_id, end_rev_id,
118
                          rebase_initial_depths=True):
119
    """Calculate revisions to view including merges, newest to oldest.
120
121
    :param branch: the branch
122
    :param start_rev_id: the lower revision-id
123
    :param end_rev_id: the upper revision-id
124
    :param rebase_initial_depth: should depths be rebased until a mainline
125
      revision is found?
126
    :return: An iterator of (revision_id, dotted_revno, merge_depth) tuples.
127
    """
0.40.106 by Parth Malwankar
fixed error in dotted rev reverse search.
128
    # requires that start is older than end
0.40.100 by Parth Malwankar
removed dependency on log._graph_view_revisions
129
    view_revisions = branch.iter_merge_sorted_revisions(
130
        start_revision_id=end_rev_id, stop_revision_id=start_rev_id,
131
        stop_rule="with-merges")
132
    if not rebase_initial_depths:
133
        for (rev_id, merge_depth, revno, end_of_merge
134
             ) in view_revisions:
135
            yield rev_id, '.'.join(map(str, revno)), merge_depth
136
    else:
137
        # We're following a development line starting at a merged revision.
138
        # We need to adjust depths down by the initial depth until we find
139
        # a depth less than it. Then we use that depth as the adjustment.
140
        # If and when we reach the mainline, depth adjustment ends.
141
        depth_adjustment = None
142
        for (rev_id, merge_depth, revno, end_of_merge
143
             ) in view_revisions:
144
            if depth_adjustment is None:
145
                depth_adjustment = merge_depth
146
            if depth_adjustment:
147
                if merge_depth < depth_adjustment:
148
                    # From now on we reduce the depth adjustement, this can be
149
                    # surprising for users. The alternative requires two passes
150
                    # which breaks the fast display of the first revision
151
                    # though.
152
                    depth_adjustment = merge_depth
153
                merge_depth -= depth_adjustment
154
            yield rev_id, '.'.join(map(str, revno)), merge_depth
155
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
156
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
157
def compile_pattern(pattern, flags=0):
158
    try:
7169.2.2 by Martin
Fix bp.grep test
159
        return re.compile(pattern, flags)
6619.3.2 by Jelmer Vernooij
Apply 2to3 except fix.
160
    except re.error as e:
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
161
        raise errors.BzrError("Invalid pattern: '%s'" % pattern)
7169.2.2 by Martin
Fix bp.grep test
162
    return None
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
163
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
164
0.40.86 by Parth Malwankar
the check for implicit fixed_string now allows for spaces.
165
def is_fixed_string(s):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
166
    if re.match("^([A-Za-z0-9_]|\\s)*$", s):
0.40.86 by Parth Malwankar
the check for implicit fixed_string now allows for spaces.
167
        return True
168
    return False
0.41.11 by Parth Malwankar
moved top level grep code to versioned_grep.
169
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
170
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
171
class _GrepDiffOutputter(object):
172
    """Precalculate formatting based on options given for diff grep.
173
    """
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
174
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
175
    def __init__(self, opts):
0.48.8 by Parth Malwankar
colored header for diff grep output
176
        self.opts = opts
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
177
        self.outf = opts.outf
178
        if opts.show_color:
179
            if opts.fixed_string:
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
180
                self._old = opts.pattern
181
                self._new = color_string(opts.pattern, FG.BOLD_RED)
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
182
                self.get_writer = self._get_writer_fixed_highlighted
183
            else:
184
                flags = opts.patternc.flags
7143.15.2 by Jelmer Vernooij
Run autopep8.
185
                self._sub = re.compile(
186
                    opts.pattern.join(("((?:", ")+)")), flags).sub
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
187
                self._highlight = color_string("\\1", FG.BOLD_RED)
188
                self.get_writer = self._get_writer_regexp_highlighted
189
        else:
190
            self.get_writer = self._get_writer_plain
191
0.48.8 by Parth Malwankar
colored header for diff grep output
192
    def get_file_header_writer(self):
193
        """Get function for writing file headers"""
194
        write = self.outf.write
195
        eol_marker = self.opts.eol_marker
7143.15.2 by Jelmer Vernooij
Run autopep8.
196
0.48.8 by Parth Malwankar
colored header for diff grep output
197
        def _line_writer(line):
198
            write(line + eol_marker)
7143.15.2 by Jelmer Vernooij
Run autopep8.
199
0.48.8 by Parth Malwankar
colored header for diff grep output
200
        def _line_writer_color(line):
201
            write(FG.BOLD_MAGENTA + line + FG.NONE + eol_marker)
202
        if self.opts.show_color:
203
            return _line_writer_color
204
        else:
205
            return _line_writer
206
        return _line_writer
207
208
    def get_revision_header_writer(self):
209
        """Get function for writing revno lines"""
210
        write = self.outf.write
211
        eol_marker = self.opts.eol_marker
7143.15.2 by Jelmer Vernooij
Run autopep8.
212
0.48.8 by Parth Malwankar
colored header for diff grep output
213
        def _line_writer(line):
214
            write(line + eol_marker)
7143.15.2 by Jelmer Vernooij
Run autopep8.
215
0.48.8 by Parth Malwankar
colored header for diff grep output
216
        def _line_writer_color(line):
217
            write(FG.BOLD_BLUE + line + FG.NONE + eol_marker)
218
        if self.opts.show_color:
219
            return _line_writer_color
220
        else:
221
            return _line_writer
222
        return _line_writer
223
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
224
    def _get_writer_plain(self):
225
        """Get function for writing uncoloured output"""
226
        write = self.outf.write
0.48.8 by Parth Malwankar
colored header for diff grep output
227
        eol_marker = self.opts.eol_marker
7143.15.2 by Jelmer Vernooij
Run autopep8.
228
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
229
        def _line_writer(line):
0.48.8 by Parth Malwankar
colored header for diff grep output
230
            write(line + eol_marker)
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
231
        return _line_writer
232
233
    def _get_writer_regexp_highlighted(self):
234
        """Get function for writing output with regexp match highlighted"""
235
        _line_writer = self._get_writer_plain()
236
        sub, highlight = self._sub, self._highlight
7143.15.2 by Jelmer Vernooij
Run autopep8.
237
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
238
        def _line_writer_regexp_highlighted(line):
239
            """Write formatted line with matched pattern highlighted"""
240
            return _line_writer(line=sub(highlight, line))
241
        return _line_writer_regexp_highlighted
242
243
    def _get_writer_fixed_highlighted(self):
244
        """Get function for writing output with search string highlighted"""
245
        _line_writer = self._get_writer_plain()
246
        old, new = self._old, self._new
7143.15.2 by Jelmer Vernooij
Run autopep8.
247
0.48.7 by Parth Malwankar
initial outputter support for diff_grep
248
        def _line_writer_fixed_highlighted(line):
249
            """Write formatted line with string searched for highlighted"""
250
            return _line_writer(line=line.replace(old, new))
251
        return _line_writer_fixed_highlighted
252
253
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
254
def grep_diff(opts):
255
    wt, branch, relpath = \
6667.2.1 by Jelmer Vernooij
Some cleanup; s/BzrDir/ControlDir/, remove some unused imports.
256
        controldir.ControlDir.open_containing_tree_or_branch('.')
6754.8.4 by Jelmer Vernooij
Use new context stuff.
257
    with branch.lock_read():
0.48.3 by Parth Malwankar
for grep_diff, if rev is not specified, last is used as start.
258
        if opts.revision:
259
            start_rev = opts.revision[0]
260
        else:
0.48.9 by Parth Malwankar
added inital test for 'grep -p'
261
            # if no revision is sepcified for diff grep we grep all changesets.
262
            opts.revision = [RevisionSpec.from_string('revno:1'),
7143.15.2 by Jelmer Vernooij
Run autopep8.
263
                             RevisionSpec.from_string('last:1')]
0.48.3 by Parth Malwankar
for grep_diff, if rev is not specified, last is used as start.
264
            start_rev = opts.revision[0]
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
265
        start_revid = start_rev.as_revision_id(branch)
6973.14.6 by Jelmer Vernooij
Fix some more tests.
266
        if start_revid == b'null:':
0.48.4 by Parth Malwankar
diff grep now works.
267
            return
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
268
        srevno_tuple = branch.revision_id_to_dotted_revno(start_revid)
269
        if len(opts.revision) == 2:
270
            end_rev = opts.revision[1]
271
            end_revid = end_rev.as_revision_id(branch)
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
272
            if end_revid is None:
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
273
                end_revno, end_revid = branch.last_revision_info()
274
            erevno_tuple = branch.revision_id_to_dotted_revno(end_revid)
275
7143.15.2 by Jelmer Vernooij
Run autopep8.
276
            grep_mainline = (_rev_on_mainline(srevno_tuple)
277
                             and _rev_on_mainline(erevno_tuple))
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
278
279
            # ensure that we go in reverse order
280
            if srevno_tuple > erevno_tuple:
281
                srevno_tuple, erevno_tuple = erevno_tuple, srevno_tuple
282
                start_revid, end_revid = end_revid, start_revid
283
284
            # Optimization: Traversing the mainline in reverse order is much
285
            # faster when we don't want to look at merged revs. We try this
286
            # with _linear_view_revisions. If all revs are to be grepped we
287
            # use the slower _graph_view_revisions
7143.15.2 by Jelmer Vernooij
Run autopep8.
288
            if opts.levels == 1 and grep_mainline:
289
                given_revs = _linear_view_revisions(
290
                    branch, start_revid, end_revid)
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
291
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
292
                given_revs = _graph_view_revisions(
293
                    branch, start_revid, end_revid)
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
294
        else:
295
            # We do an optimization below. For grepping a specific revison
296
            # We don't need to call _graph_view_revisions which is slow.
297
            # We create the start_rev_tuple for only that specific revision.
298
            # _graph_view_revisions is used only for revision range.
299
            start_revno = '.'.join(map(str, srevno_tuple))
300
            start_rev_tuple = (start_revid, start_revno, 0)
301
            given_revs = [start_rev_tuple]
302
        repo = branch.repository
7143.15.2 by Jelmer Vernooij
Run autopep8.
303
        diff_pattern = re.compile(
304
            b"^[+\\-].*(" + opts.pattern.encode(_user_encoding) + b")")
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
305
        file_pattern = re.compile(b"=== (modified|added|removed) file '.*'")
0.48.8 by Parth Malwankar
colored header for diff grep output
306
        outputter = _GrepDiffOutputter(opts)
307
        writeline = outputter.get_writer()
308
        writerevno = outputter.get_revision_header_writer()
309
        writefileheader = outputter.get_file_header_writer()
0.48.11 by Parth Malwankar
unicode decode fix for diff grep.
310
        file_encoding = _user_encoding
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
311
        for revid, revno, merge_depth in given_revs:
312
            if opts.levels == 1 and merge_depth != 0:
313
                # with level=1 show only top level
314
                continue
315
7143.15.2 by Jelmer Vernooij
Run autopep8.
316
            rev_spec = RevisionSpec_revid.from_string(
317
                "revid:" + revid.decode('utf-8'))
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
318
            new_rev = repo.get_revision(revid)
319
            new_tree = rev_spec.as_tree(branch)
320
            if len(new_rev.parent_ids) == 0:
321
                ancestor_id = _mod_revision.NULL_REVISION
322
            else:
323
                ancestor_id = new_rev.parent_ids[0]
324
            old_tree = repo.revision_tree(ancestor_id)
6621.22.2 by Martin
Use BytesIO or StringIO from bzrlib.sixish
325
            s = BytesIO()
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
326
            diff.show_diff_trees(old_tree, new_tree, s,
7143.15.2 by Jelmer Vernooij
Run autopep8.
327
                                 old_label='', new_label='')
0.48.4 by Parth Malwankar
diff grep now works.
328
            display_revno = True
329
            display_file = False
330
            file_header = None
331
            text = s.getvalue()
0.48.6 by Parth Malwankar
removed fixed_string condition for diff grep
332
            for line in text.splitlines():
333
                if file_pattern.search(line):
334
                    file_header = line
335
                    display_file = True
0.48.11 by Parth Malwankar
unicode decode fix for diff grep.
336
                elif diff_pattern.search(line):
0.48.6 by Parth Malwankar
removed fixed_string condition for diff grep
337
                    if display_revno:
0.48.10 by Parth Malwankar
more tests for 'grep --diff'
338
                        writerevno("=== revno:%s ===" % (revno,))
0.48.6 by Parth Malwankar
removed fixed_string condition for diff grep
339
                        display_revno = False
340
                    if display_file:
7143.15.2 by Jelmer Vernooij
Run autopep8.
341
                        writefileheader(
342
                            "  %s" % (file_header.decode(file_encoding, 'replace'),))
0.48.6 by Parth Malwankar
removed fixed_string condition for diff grep
343
                        display_file = False
0.48.11 by Parth Malwankar
unicode decode fix for diff grep.
344
                    line = line.decode(file_encoding, 'replace')
345
                    writeline("    %s" % (line,))
0.48.2 by Parth Malwankar
intermediate checkin. we now show diff with -p option.
346
347
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
348
def versioned_grep(opts):
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
349
    wt, branch, relpath = \
6667.2.1 by Jelmer Vernooij
Some cleanup; s/BzrDir/ControlDir/, remove some unused imports.
350
        controldir.ControlDir.open_containing_tree_or_branch('.')
6754.8.4 by Jelmer Vernooij
Use new context stuff.
351
    with branch.lock_read():
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
352
        start_rev = opts.revision[0]
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
353
        start_revid = start_rev.as_revision_id(branch)
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
354
        if start_revid is None:
0.40.95 by Parth Malwankar
faster mainline rev grep
355
            start_rev = RevisionSpec_revno.from_string("revno:1")
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
356
            start_revid = start_rev.as_revision_id(branch)
357
        srevno_tuple = branch.revision_id_to_dotted_revno(start_revid)
0.40.88 by Parth Malwankar
updated to avoid relocking.
358
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
359
        if len(opts.revision) == 2:
360
            end_rev = opts.revision[1]
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
361
            end_revid = end_rev.as_revision_id(branch)
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
362
            if end_revid is None:
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
363
                end_revno, end_revid = branch.last_revision_info()
364
            erevno_tuple = branch.revision_id_to_dotted_revno(end_revid)
0.40.95 by Parth Malwankar
faster mainline rev grep
365
7143.15.2 by Jelmer Vernooij
Run autopep8.
366
            grep_mainline = (_rev_on_mainline(srevno_tuple)
367
                             and _rev_on_mainline(erevno_tuple))
0.40.106 by Parth Malwankar
fixed error in dotted rev reverse search.
368
369
            # ensure that we go in reverse order
370
            if srevno_tuple > erevno_tuple:
371
                srevno_tuple, erevno_tuple = erevno_tuple, srevno_tuple
372
                start_revid, end_revid = end_revid, start_revid
0.40.97 by Parth Malwankar
fixed caching bug for rev range.
373
0.40.95 by Parth Malwankar
faster mainline rev grep
374
            # Optimization: Traversing the mainline in reverse order is much
375
            # faster when we don't want to look at merged revs. We try this
376
            # with _linear_view_revisions. If all revs are to be grepped we
377
            # use the slower _graph_view_revisions
6531.3.9 by Jelmer Vernooij
Remove broken tests..
378
            if opts.levels == 1 and grep_mainline:
7143.15.2 by Jelmer Vernooij
Run autopep8.
379
                given_revs = _linear_view_revisions(
380
                    branch, start_revid, end_revid)
0.40.95 by Parth Malwankar
faster mainline rev grep
381
            else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
382
                given_revs = _graph_view_revisions(
383
                    branch, start_revid, end_revid)
0.40.88 by Parth Malwankar
updated to avoid relocking.
384
        else:
0.40.94 by Parth Malwankar
code cleanup. moved start_rev_tuple into if cond that uses it.
385
            # We do an optimization below. For grepping a specific revison
386
            # We don't need to call _graph_view_revisions which is slow.
387
            # We create the start_rev_tuple for only that specific revision.
388
            # _graph_view_revisions is used only for revision range.
389
            start_revno = '.'.join(map(str, srevno_tuple))
390
            start_rev_tuple = (start_revid, start_revno, 0)
0.40.88 by Parth Malwankar
updated to avoid relocking.
391
            given_revs = [start_rev_tuple]
392
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
393
        # GZ 2010-06-02: Shouldn't be smuggling this on opts, but easy for now
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
394
        opts.outputter = _Outputter(opts, use_cache=True)
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
395
0.40.88 by Parth Malwankar
updated to avoid relocking.
396
        for revid, revno, merge_depth in given_revs:
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
397
            if opts.levels == 1 and merge_depth != 0:
0.40.88 by Parth Malwankar
updated to avoid relocking.
398
                # with level=1 show only top level
399
                continue
400
7143.15.2 by Jelmer Vernooij
Run autopep8.
401
            rev = RevisionSpec_revid.from_string(
402
                "revid:" + revid.decode('utf-8'))
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
403
            tree = rev.as_tree(branch)
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
404
            for path in opts.path_list:
6874.2.5 by Jelmer Vernooij
Fix grep.
405
                tree_path = osutils.pathjoin(relpath, path)
406
                if not tree.has_filename(tree_path):
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
407
                    trace.warning("Skipped unknown file '%s'.", path)
0.41.11 by Parth Malwankar
moved top level grep code to versioned_grep.
408
                    continue
409
410
                if osutils.isdir(path):
411
                    path_prefix = path
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
412
                    dir_grep(tree, path, relpath, opts, revno, path_prefix)
0.41.11 by Parth Malwankar
moved top level grep code to versioned_grep.
413
                else:
7143.15.2 by Jelmer Vernooij
Run autopep8.
414
                    versioned_file_grep(
415
                        tree, tree_path, '.', path, opts, revno)
0.41.11 by Parth Malwankar
moved top level grep code to versioned_grep.
416
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
417
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
418
def workingtree_grep(opts):
7143.15.2 by Jelmer Vernooij
Run autopep8.
419
    revno = opts.print_revno = None  # for working tree set revno to None
0.40.69 by Parth Malwankar
reduced lock/unlock
420
421
    tree, branch, relpath = \
6667.2.1 by Jelmer Vernooij
Some cleanup; s/BzrDir/ControlDir/, remove some unused imports.
422
        controldir.ControlDir.open_containing_tree_or_branch('.')
0.40.130 by Parth Malwankar
grep in a branch with no tree does not throw stack trace (#572658)
423
    if not tree:
0.40.131 by Parth Malwankar
bzr grep now allows grepping with -r even when no tree exists.
424
        msg = ('Cannot search working tree. Working tree not found.\n'
7143.15.2 by Jelmer Vernooij
Run autopep8.
425
               'To search for specific revision in history use the -r option.')
0.40.130 by Parth Malwankar
grep in a branch with no tree does not throw stack trace (#572658)
426
        raise errors.BzrCommandError(msg)
427
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
428
    # GZ 2010-06-02: Shouldn't be smuggling this on opts, but easy for now
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
429
    opts.outputter = _Outputter(opts)
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
430
6754.8.4 by Jelmer Vernooij
Use new context stuff.
431
    with tree.lock_read():
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
432
        for path in opts.path_list:
0.40.69 by Parth Malwankar
reduced lock/unlock
433
            if osutils.isdir(path):
434
                path_prefix = path
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
435
                dir_grep(tree, path, relpath, opts, revno, path_prefix)
0.40.69 by Parth Malwankar
reduced lock/unlock
436
            else:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
437
                with open(path, 'rb') as f:
438
                    _file_grep(f.read(), path, opts, revno)
0.41.11 by Parth Malwankar
moved top level grep code to versioned_grep.
439
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
440
0.40.74 by Parth Malwankar
optimization. --include/exclude are checked before reading the file.
441
def _skip_file(include, exclude, path):
442
    if include and not _path_in_glob_list(path, include):
443
        return True
444
    if exclude and _path_in_glob_list(path, exclude):
445
        return True
446
    return False
447
448
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
449
def dir_grep(tree, path, relpath, opts, revno, path_prefix):
0.40.60 by Parth Malwankar
'binary file skipped' warning is only shown with --verbose flag
450
    # setup relpath to open files relative to cwd
451
    rpath = relpath
452
    if relpath:
6809.1.1 by Martin
Apply 2to3 ws_comma fixer
453
        rpath = osutils.pathjoin('..', relpath)
0.40.60 by Parth Malwankar
'binary file skipped' warning is only shown with --verbose flag
454
455
    from_dir = osutils.pathjoin(relpath, path)
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
456
    if opts.from_root:
0.40.60 by Parth Malwankar
'binary file skipped' warning is only shown with --verbose flag
457
        # start searching recursively from root
6874.2.1 by Jelmer Vernooij
Make Tree.iter_files_bytes() take paths rather than file_ids.
458
        from_dir = None
459
        recursive = True
0.40.60 by Parth Malwankar
'binary file skipped' warning is only shown with --verbose flag
460
0.40.85 by Parth Malwankar
optimized versioned grep to use iter_files_bytes.
461
    to_grep = []
0.40.92 by Parth Malwankar
performance tweaks to core cached result print loop.
462
    to_grep_append = to_grep.append
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
463
    # GZ 2010-06-05: The cache dict used to be recycled every call to dir_grep
464
    #                and hits manually refilled. Could do this again if it was
465
    #                for a good reason, otherwise cache might want purging.
466
    outputter = opts.outputter
7143.19.7 by Jelmer Vernooij
merge trunk
467
    for fp, fc, fkind, entry in tree.list_files(
468
            include_root=False, from_dir=from_dir, recursive=opts.recursive):
0.40.69 by Parth Malwankar
reduced lock/unlock
469
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
470
        if _skip_file(opts.include, opts.exclude, fp):
0.40.74 by Parth Malwankar
optimization. --include/exclude are checked before reading the file.
471
            continue
472
7143.19.5 by Jelmer Vernooij
Undo removal of kind.
473
        if fc == 'V' and fkind == 'file':
6928.1.1 by Jelmer Vernooij
Pass in correct paths in grep.
474
            tree_path = osutils.pathjoin(from_dir if from_dir else '', fp)
475
            if revno is not None:
0.40.90 by Parth Malwankar
significant speedup for revision range grep by caching old result.
476
                # If old result is valid, print results immediately.
477
                # Otherwise, add file info to to_grep so that the
478
                # loop later will get chunks and grep them
7141.7.1 by Jelmer Vernooij
Get rid of file_ids in most of Tree.
479
                cache_id = tree.get_file_revision(tree_path)
0.46.11 by Martin
Add method to outputter for writing cached lines
480
                if cache_id in outputter.cache:
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
481
                    # GZ 2010-06-05: Not really sure caching and re-outputting
482
                    #                the old path is really the right thing,
483
                    #                but it's what the old code seemed to do
0.46.11 by Martin
Add method to outputter for writing cached lines
484
                    outputter.write_cached_lines(cache_id, revno)
0.40.90 by Parth Malwankar
significant speedup for revision range grep by caching old result.
485
                else:
6928.1.1 by Jelmer Vernooij
Pass in correct paths in grep.
486
                    to_grep_append((tree_path, (fp, tree_path)))
0.40.69 by Parth Malwankar
reduced lock/unlock
487
            else:
488
                # we are grepping working tree.
6531.3.8 by Jelmer Vernooij
Move color feature into bzrlib.tests.features.
489
                if from_dir is None:
0.40.69 by Parth Malwankar
reduced lock/unlock
490
                    from_dir = '.'
491
492
                path_for_file = osutils.pathjoin(tree.basedir, from_dir, fp)
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
493
                if opts.files_with_matches or opts.files_without_match:
0.40.116 by Parth Malwankar
optimization for wtree list-only grep to avoid full file read.
494
                    # Optimize for wtree list-only as we don't need to read the
495
                    # entire file
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
496
                    with open(path_for_file, 'rb', buffering=4096) as file:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
497
                        _file_grep_list_only_wtree(file, fp, opts, path_prefix)
0.40.121 by Parth Malwankar
initial implementation of -L/--files-without-matches. no tests.
498
                else:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
499
                    with open(path_for_file, 'rb') as f:
500
                        _file_grep(f.read(), fp, opts, revno, path_prefix)
0.40.43 by Parth Malwankar
moved cmd_grep._grep_dir to grep.dir_grep
501
7143.15.2 by Jelmer Vernooij
Run autopep8.
502
    if revno is not None:  # grep versioned files
6928.1.1 by Jelmer Vernooij
Pass in correct paths in grep.
503
        for (path, tree_path), chunks in tree.iter_files_bytes(to_grep):
0.40.85 by Parth Malwankar
optimized versioned grep to use iter_files_bytes.
504
            path = _make_display_path(relpath, path)
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
505
            _file_grep(b''.join(chunks), path, opts, revno, path_prefix,
7143.15.2 by Jelmer Vernooij
Run autopep8.
506
                       tree.get_file_revision(tree_path))
0.40.43 by Parth Malwankar
moved cmd_grep._grep_dir to grep.dir_grep
507
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
508
0.41.8 by Parth Malwankar
code cleanup.
509
def _make_display_path(relpath, path):
510
    """Return path string relative to user cwd.
0.40.42 by Parth Malwankar
fix to make grep paths relative to cwd
511
0.41.8 by Parth Malwankar
code cleanup.
512
    Take tree's 'relpath' and user supplied 'path', and return path
513
    that can be displayed to the user.
514
    """
0.40.15 by Parth Malwankar
some fixes and test updates
515
    if relpath:
0.40.52 by Parth Malwankar
code cleanup and documentation
516
        # update path so to display it w.r.t cwd
517
        # handle windows slash separator
0.40.20 by Parth Malwankar
used path functions from bzrlib.osutils
518
        path = osutils.normpath(osutils.pathjoin(relpath, path))
0.40.22 by Parth Malwankar
fixed display path formatting on windows
519
        path = path.replace('\\', '/')
520
        path = path.replace(relpath + '/', '', 1)
0.41.8 by Parth Malwankar
code cleanup.
521
    return path
522
523
7143.15.2 by Jelmer Vernooij
Run autopep8.
524
def versioned_file_grep(tree, tree_path, relpath, path, opts, revno, path_prefix=None):
0.41.10 by Parth Malwankar
code cleanup. added comments. path adjustment is now done
525
    """Create a file object for the specified id and pass it on to _file_grep.
526
    """
527
528
    path = _make_display_path(relpath, path)
6874.2.5 by Jelmer Vernooij
Fix grep.
529
    file_text = tree.get_file_text(tree_path)
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
530
    _file_grep(file_text, path, opts, revno, path_prefix)
0.41.21 by Parth Malwankar
include/exclude working now. tests not added.
531
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
532
0.41.21 by Parth Malwankar
include/exclude working now. tests not added.
533
def _path_in_glob_list(path, glob_list):
534
    for glob in glob_list:
535
        if fnmatch(path, glob):
0.46.19 by Martin
Minor pokes, fixes a bug with working tree optimisation and binary files
536
            return True
537
    return False
0.41.12 by Parth Malwankar
initial support for working tree grep (no test cases yet!)
538
0.40.117 by Parth Malwankar
cosmetic fix. added two lines between top level functions.
539
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
540
def _file_grep_list_only_wtree(file, path, opts, path_prefix=None):
0.40.116 by Parth Malwankar
optimization for wtree list-only grep to avoid full file read.
541
    # test and skip binary files
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
542
    if b'\x00' in file.read(1024):
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
543
        if opts.verbose:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
544
            trace.warning("Binary file '%s' skipped.", path)
0.46.19 by Martin
Minor pokes, fixes a bug with working tree optimisation and binary files
545
        return
0.40.118 by Parth Malwankar
further optimization of _file_grep_list_only_wtree.
546
7143.15.2 by Jelmer Vernooij
Run autopep8.
547
    file.seek(0)  # search from beginning
0.40.118 by Parth Malwankar
further optimization of _file_grep_list_only_wtree.
548
549
    found = False
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
550
    if opts.fixed_string:
551
        pattern = opts.pattern.encode(_user_encoding, 'replace')
0.46.1 by Martin
Make -Fi use regexps for re.IGNORECASE rather than double str.lower
552
        for line in file:
553
            if pattern in line:
554
                found = True
555
                break
7143.15.2 by Jelmer Vernooij
Run autopep8.
556
    else:  # not fixed_string
0.40.116 by Parth Malwankar
optimization for wtree list-only grep to avoid full file read.
557
        for line in file:
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
558
            if opts.patternc.search(line):
0.40.118 by Parth Malwankar
further optimization of _file_grep_list_only_wtree.
559
                found = True
0.40.116 by Parth Malwankar
optimization for wtree list-only grep to avoid full file read.
560
                break
561
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
562
    if (opts.files_with_matches and found) or \
7143.15.2 by Jelmer Vernooij
Run autopep8.
563
            (opts.files_without_match and not found):
0.40.118 by Parth Malwankar
further optimization of _file_grep_list_only_wtree.
564
        if path_prefix and path_prefix != '.':
565
            # user has passed a dir arg, show that as result prefix
566
            path = osutils.pathjoin(path_prefix, path)
0.46.18 by Martin
Fix another, previously existing issue with colour and match-only
567
        opts.outputter.get_writer(path, None, None)()
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
568
569
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
570
class _Outputter(object):
571
    """Precalculate formatting based on options given
572
573
    The idea here is to do this work only once per run, and finally return a
574
    function that will do the minimum amount possible for each match.
0.46.3 by Martin
Start moving formatting setup out of _file_grep, only for files_with_matches so far
575
    """
7143.15.2 by Jelmer Vernooij
Run autopep8.
576
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
577
    def __init__(self, opts, use_cache=False):
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
578
        self.outf = opts.outf
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
579
        if use_cache:
580
            # self.cache is used to cache results for dir grep based on fid.
581
            # If the fid is does not change between results, it means that
582
            # the result will be the same apart from revno. In such a case
583
            # we avoid getting file chunks from repo and grepping. The result
584
            # is just printed by replacing old revno with new one.
585
            self.cache = {}
586
        else:
587
            self.cache = None
0.46.17 by Martin
Fix previously untested issue with colour and match-only, and test a related issue
588
        no_line = opts.files_with_matches or opts.files_without_match
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
589
590
        if opts.show_color:
0.46.17 by Martin
Fix previously untested issue with colour and match-only, and test a related issue
591
            if no_line:
592
                self.get_writer = self._get_writer_plain
593
            elif opts.fixed_string:
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
594
                self._old = opts.pattern
595
                self._new = color_string(opts.pattern, FG.BOLD_RED)
0.46.17 by Martin
Fix previously untested issue with colour and match-only, and test a related issue
596
                self.get_writer = self._get_writer_fixed_highlighted
597
            else:
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
598
                flags = opts.patternc.flags
7143.15.2 by Jelmer Vernooij
Run autopep8.
599
                self._sub = re.compile(
600
                    opts.pattern.join(("((?:", ")+)")), flags).sub
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
601
                self._highlight = color_string("\\1", FG.BOLD_RED)
602
                self.get_writer = self._get_writer_regexp_highlighted
603
            path_start = FG.MAGENTA
0.46.17 by Martin
Fix previously untested issue with colour and match-only, and test a related issue
604
            path_end = FG.NONE
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
605
            sep = color_string(':', FG.BOLD_CYAN)
606
            rev_sep = color_string('~', FG.BOLD_YELLOW)
607
        else:
608
            self.get_writer = self._get_writer_plain
0.46.17 by Martin
Fix previously untested issue with colour and match-only, and test a related issue
609
            path_start = path_end = ""
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
610
            sep = ":"
611
            rev_sep = "~"
612
613
        parts = [path_start, "%(path)s"]
0.46.3 by Martin
Start moving formatting setup out of _file_grep, only for files_with_matches so far
614
        if opts.print_revno:
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
615
            parts.extend([rev_sep, "%(revno)s"])
0.46.13 by Martin
Split format string into two parts for non-cached operations too
616
        self._format_initial = "".join(parts)
617
        parts = []
0.46.17 by Martin
Fix previously untested issue with colour and match-only, and test a related issue
618
        if no_line:
619
            if not opts.print_revno:
620
                parts.append(path_end)
621
        else:
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
622
            if opts.line_number:
0.46.13 by Martin
Split format string into two parts for non-cached operations too
623
                parts.extend([sep, "%(lineno)s"])
624
            parts.extend([sep, "%(line)s"])
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
625
        parts.append(opts.eol_marker)
0.46.19 by Martin
Minor pokes, fixes a bug with working tree optimisation and binary files
626
        self._format_perline = "".join(parts)
0.46.7 by Martin
Move line writing function up the stack so it lasts the whole operation, and clean up some params
627
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
628
    def _get_writer_plain(self, path, revno, cache_id):
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
629
        """Get function for writing uncoloured output"""
0.46.13 by Martin
Split format string into two parts for non-cached operations too
630
        per_line = self._format_perline
7143.15.2 by Jelmer Vernooij
Run autopep8.
631
        start = self._format_initial % {"path": path, "revno": revno}
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
632
        write = self.outf.write
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
633
        if self.cache is not None and cache_id is not None:
634
            result_list = []
635
            self.cache[cache_id] = path, result_list
636
            add_to_cache = result_list.append
7143.15.2 by Jelmer Vernooij
Run autopep8.
637
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
638
            def _line_cache_and_writer(**kwargs):
639
                """Write formatted line and cache arguments"""
0.46.12 by Martin
Split format string for cache to only store a string, not a dict
640
                end = per_line % kwargs
641
                add_to_cache(end)
642
                write(start + end)
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
643
            return _line_cache_and_writer
7143.15.2 by Jelmer Vernooij
Run autopep8.
644
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
645
        def _line_writer(**kwargs):
646
            """Write formatted line from arguments given by underlying opts"""
0.46.13 by Martin
Split format string into two parts for non-cached operations too
647
            write(start + per_line % kwargs)
0.46.8 by Martin
Move pattern highlighting out of _file_grep and into the line writing code
648
        return _line_writer
649
0.46.11 by Martin
Add method to outputter for writing cached lines
650
    def write_cached_lines(self, cache_id, revno):
651
        """Write cached results out again for new revision"""
652
        cached_path, cached_matches = self.cache[cache_id]
7143.15.2 by Jelmer Vernooij
Run autopep8.
653
        start = self._format_initial % {"path": cached_path, "revno": revno}
0.46.11 by Martin
Add method to outputter for writing cached lines
654
        write = self.outf.write
0.46.12 by Martin
Split format string for cache to only store a string, not a dict
655
        for end in cached_matches:
656
            write(start + end)
0.46.11 by Martin
Add method to outputter for writing cached lines
657
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
658
    def _get_writer_regexp_highlighted(self, path, revno, cache_id):
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
659
        """Get function for writing output with regexp match highlighted"""
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
660
        _line_writer = self._get_writer_plain(path, revno, cache_id)
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
661
        sub, highlight = self._sub, self._highlight
7143.15.2 by Jelmer Vernooij
Run autopep8.
662
0.46.8 by Martin
Move pattern highlighting out of _file_grep and into the line writing code
663
        def _line_writer_regexp_highlighted(line, **kwargs):
664
            """Write formatted line with matched pattern highlighted"""
665
            return _line_writer(line=sub(highlight, line), **kwargs)
666
        return _line_writer_regexp_highlighted
667
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
668
    def _get_writer_fixed_highlighted(self, path, revno, cache_id):
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
669
        """Get function for writing output with search string highlighted"""
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
670
        _line_writer = self._get_writer_plain(path, revno, cache_id)
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
671
        old, new = self._old, self._new
7143.15.2 by Jelmer Vernooij
Run autopep8.
672
0.46.9 by Martin
Give in and make formatter a class so path and revno only need to be passed once per file
673
        def _line_writer_fixed_highlighted(line, **kwargs):
674
            """Write formatted line with string searched for highlighted"""
675
            return _line_writer(line=line.replace(old, new), **kwargs)
676
        return _line_writer_fixed_highlighted
0.46.3 by Martin
Start moving formatting setup out of _file_grep, only for files_with_matches so far
677
678
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
679
def _file_grep(file_text, path, opts, revno, path_prefix=None, cache_id=None):
0.41.9 by Parth Malwankar
refactored code towards support for working tree grep.
680
    # test and skip binary files
6977.2.1 by Jelmer Vernooij
Require that get_file implementations are contect managers, simplify file handling in transform.
681
    if b'\x00' in file_text[:1024]:
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
682
        if opts.verbose:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
683
            trace.warning("Binary file '%s' skipped.", path)
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
684
        return
0.41.9 by Parth Malwankar
refactored code towards support for working tree grep.
685
0.40.52 by Parth Malwankar
code cleanup and documentation
686
    if path_prefix and path_prefix != '.':
687
        # user has passed a dir arg, show that as result prefix
688
        path = osutils.pathjoin(path_prefix, path)
689
0.46.21 by Martin
Fix and test bytes/unicode issue but there's more to do in this area
690
    # GZ 2010-06-07: There's no actual guarentee the file contents will be in
691
    #                the user encoding, but we have to guess something and it
692
    #                is a reasonable default without a better mechanism.
693
    file_encoding = _user_encoding
0.46.19 by Martin
Minor pokes, fixes a bug with working tree optimisation and binary files
694
    pattern = opts.pattern.encode(_user_encoding, 'replace')
0.43.8 by Parth Malwankar
added color for regex pattern.
695
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
696
    writeline = opts.outputter.get_writer(path, revno, cache_id)
0.40.9 by Parth Malwankar
factored out grep related code to grep.py
697
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
698
    if opts.files_with_matches or opts.files_without_match:
0.46.2 by Martin
Remove redundant code on files_with_matches path in _file_grep
699
        if opts.fixed_string:
6691.1.5 by Jelmer Vernooij
Drop support for Python <= 2.5.
700
            found = pattern in file_text
0.40.112 by Parth Malwankar
support for -l, --files-with-matches. no tests yet.
701
        else:
0.46.16 by Martin
Save an attribute lookup on regexp object in inner loops
702
            search = opts.patternc.search
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
703
            if b"$" not in pattern:
0.47.2 by Martin
Use whole text search for match only cases where possible as well
704
                found = search(file_text) is not None
705
            else:
706
                for line in file_text.splitlines():
707
                    if search(line):
708
                        found = True
709
                        break
710
                else:
711
                    found = False
0.43.1 by Parth Malwankar
added GrepOptions object for easy parameter passing
712
        if (opts.files_with_matches and found) or \
713
                (opts.files_without_match and not found):
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
714
            writeline()
0.46.19 by Martin
Minor pokes, fixes a bug with working tree optimisation and binary files
715
    elif opts.fixed_string:
0.47.1 by Martin
Implement whole text search for fast failure on no match
716
        # Fast path for no match, search through the entire file at once rather
6619.3.25 by Jelmer Vernooij
Drop some old dependency checks.
717
        # than a line at a time. <http://effbot.org/zone/stringlib.htm>
718
        i = file_text.find(pattern)
719
        if i == -1:
720
            return
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
721
        b = file_text.rfind(b"\n", 0, i) + 1
6619.3.25 by Jelmer Vernooij
Drop some old dependency checks.
722
        if opts.line_number:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
723
            start = file_text.count(b"\n", 0, b) + 1
6619.3.25 by Jelmer Vernooij
Drop some old dependency checks.
724
        file_text = file_text[b:]
0.46.15 by Martin
Swap fixed_string/line_number branches in _file_grep
725
        if opts.line_number:
0.46.5 by Martin
Delete now redundant duplicated loops in _file_grep
726
            for index, line in enumerate(file_text.splitlines()):
727
                if pattern in line:
0.40.137 by Parth Malwankar
(Martin [gz]) Add seperate output formatter
728
                    line = line.decode(file_encoding, 'replace')
7143.15.2 by Jelmer Vernooij
Run autopep8.
729
                    writeline(lineno=index + start, line=line)
0.46.5 by Martin
Delete now redundant duplicated loops in _file_grep
730
        else:
0.46.15 by Martin
Swap fixed_string/line_number branches in _file_grep
731
            for line in file_text.splitlines():
732
                if pattern in line:
0.40.137 by Parth Malwankar
(Martin [gz]) Add seperate output formatter
733
                    line = line.decode(file_encoding, 'replace')
0.46.15 by Martin
Swap fixed_string/line_number branches in _file_grep
734
                    writeline(line=line)
0.40.63 by Parth Malwankar
performance: moved conditionals out of core loop.
735
    else:
0.47.1 by Martin
Implement whole text search for fast failure on no match
736
        # Fast path on no match, the re module avoids bad behaviour in most
737
        # standard cases, but perhaps could try and detect backtracking
738
        # patterns here and avoid whole text search in those cases
0.46.16 by Martin
Save an attribute lookup on regexp object in inner loops
739
        search = opts.patternc.search
7027.9.1 by Jelmer Vernooij
Fix all but one remaining grep tests.
740
        if b"$" not in pattern:
0.47.1 by Martin
Implement whole text search for fast failure on no match
741
            # GZ 2010-06-05: Grr, re.MULTILINE can't save us when searching
742
            #                through revisions as bazaar returns binary mode
743
            #                and trailing \r breaks $ as line ending match
744
            m = search(file_text)
745
            if m is None:
746
                return
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
747
            b = file_text.rfind(b"\n", 0, m.start()) + 1
0.47.1 by Martin
Implement whole text search for fast failure on no match
748
            if opts.line_number:
7027.3.3 by Jelmer Vernooij
Add some more bees; support writing both bytes and unicode strings in build_tree_contents.
749
                start = file_text.count(b"\n", 0, b) + 1
0.47.4 by Martin
Scale back no-match fast path to avoid some behaviour changes with line endings
750
            file_text = file_text[b:]
0.47.3 by Martin
Fix previously untested bug with regexp and line numbers introduced by optimisation
751
        else:
752
            start = 1
0.46.15 by Martin
Swap fixed_string/line_number branches in _file_grep
753
        if opts.line_number:
754
            for index, line in enumerate(file_text.splitlines()):
0.46.16 by Martin
Save an attribute lookup on regexp object in inner loops
755
                if search(line):
0.40.137 by Parth Malwankar
(Martin [gz]) Add seperate output formatter
756
                    line = line.decode(file_encoding, 'replace')
7143.15.2 by Jelmer Vernooij
Run autopep8.
757
                    writeline(lineno=index + start, line=line)
0.40.83 by Parth Malwankar
added support for -F/--fixed-string.
758
        else:
759
            for line in file_text.splitlines():
0.46.16 by Martin
Save an attribute lookup on regexp object in inner loops
760
                if search(line):
0.40.137 by Parth Malwankar
(Martin [gz]) Add seperate output formatter
761
                    line = line.decode(file_encoding, 'replace')
0.46.10 by Martin
Move caching mechanism onto outputter rather than passing around dicts and lists
762
                    writeline(line=line)