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