/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/plugins/grep/grep.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-16 19:47:19 UTC
  • mfrom: (7178 work)
  • mto: This revision was merged to the branch mainline in revision 7179.
  • Revision ID: jelmer@jelmer.uk-20181116194719-m5ut2wfuze5x9s1p
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
from __future__ import absolute_import
18
18
 
19
19
import re
20
 
import sys
21
20
 
22
21
from ...lazy_import import lazy_import
23
22
lazy_import(globals(), """
121
120
 
122
121
 
123
122
def compile_pattern(pattern, flags=0):
124
 
    patternc = None
125
123
    try:
126
 
        # use python's re.compile as we need to catch re.error in case of bad pattern
127
 
        lazy_regex.reset_compile()
128
 
        patternc = re.compile(pattern, flags)
 
124
        return re.compile(pattern, flags)
129
125
    except re.error as e:
130
126
        raise errors.BzrError("Invalid pattern: '%s'" % pattern)
131
 
    return patternc
 
127
    return None
132
128
 
133
129
 
134
130
def is_fixed_string(s):
151
147
                self.get_writer = self._get_writer_fixed_highlighted
152
148
            else:
153
149
                flags = opts.patternc.flags
154
 
                self._sub = re.compile(opts.pattern.join(("((?:", ")+)")), flags).sub
 
150
                self._sub = re.compile(
 
151
                    opts.pattern.join(("((?:", ")+)")), flags).sub
155
152
                self._highlight = color_string("\\1", FG.BOLD_RED)
156
153
                self.get_writer = self._get_writer_regexp_highlighted
157
154
        else:
161
158
        """Get function for writing file headers"""
162
159
        write = self.outf.write
163
160
        eol_marker = self.opts.eol_marker
 
161
 
164
162
        def _line_writer(line):
165
163
            write(line + eol_marker)
 
164
 
166
165
        def _line_writer_color(line):
167
166
            write(FG.BOLD_MAGENTA + line + FG.NONE + eol_marker)
168
167
        if self.opts.show_color:
175
174
        """Get function for writing revno lines"""
176
175
        write = self.outf.write
177
176
        eol_marker = self.opts.eol_marker
 
177
 
178
178
        def _line_writer(line):
179
179
            write(line + eol_marker)
 
180
 
180
181
        def _line_writer_color(line):
181
182
            write(FG.BOLD_BLUE + line + FG.NONE + eol_marker)
182
183
        if self.opts.show_color:
189
190
        """Get function for writing uncoloured output"""
190
191
        write = self.outf.write
191
192
        eol_marker = self.opts.eol_marker
 
193
 
192
194
        def _line_writer(line):
193
195
            write(line + eol_marker)
194
196
        return _line_writer
197
199
        """Get function for writing output with regexp match highlighted"""
198
200
        _line_writer = self._get_writer_plain()
199
201
        sub, highlight = self._sub, self._highlight
 
202
 
200
203
        def _line_writer_regexp_highlighted(line):
201
204
            """Write formatted line with matched pattern highlighted"""
202
205
            return _line_writer(line=sub(highlight, line))
206
209
        """Get function for writing output with search string highlighted"""
207
210
        _line_writer = self._get_writer_plain()
208
211
        old, new = self._old, self._new
 
212
 
209
213
        def _line_writer_fixed_highlighted(line):
210
214
            """Write formatted line with string searched for highlighted"""
211
215
            return _line_writer(line=line.replace(old, new))
221
225
        else:
222
226
            # if no revision is sepcified for diff grep we grep all changesets.
223
227
            opts.revision = [RevisionSpec.from_string('revno:1'),
224
 
                RevisionSpec.from_string('last:1')]
 
228
                             RevisionSpec.from_string('last:1')]
225
229
            start_rev = opts.revision[0]
226
230
        start_revid = start_rev.as_revision_id(branch)
227
231
        if start_revid == b'null:':
234
238
                end_revno, end_revid = branch.last_revision_info()
235
239
            erevno_tuple = branch.revision_id_to_dotted_revno(end_revid)
236
240
 
237
 
            grep_mainline = (_rev_on_mainline(srevno_tuple) and
238
 
                _rev_on_mainline(erevno_tuple))
 
241
            grep_mainline = (_rev_on_mainline(srevno_tuple)
 
242
                             and _rev_on_mainline(erevno_tuple))
239
243
 
240
244
            # ensure that we go in reverse order
241
245
            if srevno_tuple > erevno_tuple:
246
250
            # faster when we don't want to look at merged revs. We try this
247
251
            # with _linear_view_revisions. If all revs are to be grepped we
248
252
            # use the slower _graph_view_revisions
249
 
            if opts.levels==1 and grep_mainline:
250
 
                given_revs = _linear_view_revisions(branch, start_revid, end_revid)
 
253
            if opts.levels == 1 and grep_mainline:
 
254
                given_revs = _linear_view_revisions(
 
255
                    branch, start_revid, end_revid)
251
256
            else:
252
 
                given_revs = _graph_view_revisions(branch, start_revid, end_revid)
 
257
                given_revs = _graph_view_revisions(
 
258
                    branch, start_revid, end_revid)
253
259
        else:
254
260
            # We do an optimization below. For grepping a specific revison
255
261
            # We don't need to call _graph_view_revisions which is slow.
259
265
            start_rev_tuple = (start_revid, start_revno, 0)
260
266
            given_revs = [start_rev_tuple]
261
267
        repo = branch.repository
262
 
        diff_pattern = re.compile(b"^[+\\-].*(" + opts.pattern.encode(_user_encoding) + b")")
 
268
        diff_pattern = re.compile(
 
269
            b"^[+\\-].*(" + opts.pattern.encode(_user_encoding) + b")")
263
270
        file_pattern = re.compile(b"=== (modified|added|removed) file '.*'")
264
271
        outputter = _GrepDiffOutputter(opts)
265
272
        writeline = outputter.get_writer()
271
278
                # with level=1 show only top level
272
279
                continue
273
280
 
274
 
            rev_spec = RevisionSpec_revid.from_string("revid:"+revid.decode('utf-8'))
 
281
            rev_spec = RevisionSpec_revid.from_string(
 
282
                "revid:" + revid.decode('utf-8'))
275
283
            new_rev = repo.get_revision(revid)
276
284
            new_tree = rev_spec.as_tree(branch)
277
285
            if len(new_rev.parent_ids) == 0:
281
289
            old_tree = repo.revision_tree(ancestor_id)
282
290
            s = BytesIO()
283
291
            diff.show_diff_trees(old_tree, new_tree, s,
284
 
                old_label='', new_label='')
 
292
                                 old_label='', new_label='')
285
293
            display_revno = True
286
294
            display_file = False
287
295
            file_header = None
295
303
                        writerevno("=== revno:%s ===" % (revno,))
296
304
                        display_revno = False
297
305
                    if display_file:
298
 
                        writefileheader("  %s" % (file_header.decode(file_encoding, 'replace'),))
 
306
                        writefileheader(
 
307
                            "  %s" % (file_header.decode(file_encoding, 'replace'),))
299
308
                        display_file = False
300
309
                    line = line.decode(file_encoding, 'replace')
301
310
                    writeline("    %s" % (line,))
319
328
                end_revno, end_revid = branch.last_revision_info()
320
329
            erevno_tuple = branch.revision_id_to_dotted_revno(end_revid)
321
330
 
322
 
            grep_mainline = (_rev_on_mainline(srevno_tuple) and
323
 
                _rev_on_mainline(erevno_tuple))
 
331
            grep_mainline = (_rev_on_mainline(srevno_tuple)
 
332
                             and _rev_on_mainline(erevno_tuple))
324
333
 
325
334
            # ensure that we go in reverse order
326
335
            if srevno_tuple > erevno_tuple:
332
341
            # with _linear_view_revisions. If all revs are to be grepped we
333
342
            # use the slower _graph_view_revisions
334
343
            if opts.levels == 1 and grep_mainline:
335
 
                given_revs = _linear_view_revisions(branch, start_revid, end_revid)
 
344
                given_revs = _linear_view_revisions(
 
345
                    branch, start_revid, end_revid)
336
346
            else:
337
 
                given_revs = _graph_view_revisions(branch, start_revid, end_revid)
 
347
                given_revs = _graph_view_revisions(
 
348
                    branch, start_revid, end_revid)
338
349
        else:
339
350
            # We do an optimization below. For grepping a specific revison
340
351
            # We don't need to call _graph_view_revisions which is slow.
352
363
                # with level=1 show only top level
353
364
                continue
354
365
 
355
 
            rev = RevisionSpec_revid.from_string("revid:"+revid.decode('utf-8'))
 
366
            rev = RevisionSpec_revid.from_string(
 
367
                "revid:" + revid.decode('utf-8'))
356
368
            tree = rev.as_tree(branch)
357
369
            for path in opts.path_list:
358
370
                tree_path = osutils.pathjoin(relpath, path)
364
376
                    path_prefix = path
365
377
                    dir_grep(tree, path, relpath, opts, revno, path_prefix)
366
378
                else:
367
 
                    versioned_file_grep(tree, tree_path, '.', path, opts, revno)
 
379
                    versioned_file_grep(
 
380
                        tree, tree_path, '.', path, opts, revno)
368
381
 
369
382
 
370
383
def workingtree_grep(opts):
371
 
    revno = opts.print_revno = None # for working tree set revno to None
 
384
    revno = opts.print_revno = None  # for working tree set revno to None
372
385
 
373
386
    tree, branch, relpath = \
374
387
        controldir.ControlDir.open_containing_tree_or_branch('.')
375
388
    if not tree:
376
389
        msg = ('Cannot search working tree. Working tree not found.\n'
377
 
            'To search for specific revision in history use the -r option.')
 
390
               'To search for specific revision in history use the -r option.')
378
391
        raise errors.BzrCommandError(msg)
379
392
 
380
393
    # GZ 2010-06-02: Shouldn't be smuggling this on opts, but easy for now
417
430
    #                for a good reason, otherwise cache might want purging.
418
431
    outputter = opts.outputter
419
432
    for fp, fc, fkind, fid, entry in tree.list_files(include_root=False,
420
 
        from_dir=from_dir, recursive=opts.recursive):
 
433
                                                     from_dir=from_dir, recursive=opts.recursive):
421
434
 
422
435
        if _skip_file(opts.include, opts.exclude, fp):
423
436
            continue
428
441
                # If old result is valid, print results immediately.
429
442
                # Otherwise, add file info to to_grep so that the
430
443
                # loop later will get chunks and grep them
431
 
                cache_id = tree.get_file_revision(tree_path, fid)
 
444
                cache_id = tree.get_file_revision(tree_path)
432
445
                if cache_id in outputter.cache:
433
446
                    # GZ 2010-06-05: Not really sure caching and re-outputting
434
447
                    #                the old path is really the right thing,
451
464
                    with open(path_for_file, 'rb') as f:
452
465
                        _file_grep(f.read(), fp, opts, revno, path_prefix)
453
466
 
454
 
    if revno is not None: # grep versioned files
 
467
    if revno is not None:  # grep versioned files
455
468
        for (path, tree_path), chunks in tree.iter_files_bytes(to_grep):
456
469
            path = _make_display_path(relpath, path)
457
470
            _file_grep(b''.join(chunks), path, opts, revno, path_prefix,
458
 
                tree.get_file_revision(tree_path))
 
471
                       tree.get_file_revision(tree_path))
459
472
 
460
473
 
461
474
def _make_display_path(relpath, path):
473
486
    return path
474
487
 
475
488
 
476
 
def versioned_file_grep(tree, tree_path, relpath, path, opts, revno, path_prefix = None):
 
489
def versioned_file_grep(tree, tree_path, relpath, path, opts, revno, path_prefix=None):
477
490
    """Create a file object for the specified id and pass it on to _file_grep.
478
491
    """
479
492
 
496
509
            trace.warning("Binary file '%s' skipped.", path)
497
510
        return
498
511
 
499
 
    file.seek(0) # search from beginning
 
512
    file.seek(0)  # search from beginning
500
513
 
501
514
    found = False
502
515
    if opts.fixed_string:
505
518
            if pattern in line:
506
519
                found = True
507
520
                break
508
 
    else: # not fixed_string
 
521
    else:  # not fixed_string
509
522
        for line in file:
510
523
            if opts.patternc.search(line):
511
524
                found = True
512
525
                break
513
526
 
514
527
    if (opts.files_with_matches and found) or \
515
 
        (opts.files_without_match and not found):
 
528
            (opts.files_without_match and not found):
516
529
        if path_prefix and path_prefix != '.':
517
530
            # user has passed a dir arg, show that as result prefix
518
531
            path = osutils.pathjoin(path_prefix, path)
525
538
    The idea here is to do this work only once per run, and finally return a
526
539
    function that will do the minimum amount possible for each match.
527
540
    """
 
541
 
528
542
    def __init__(self, opts, use_cache=False):
529
543
        self.outf = opts.outf
530
544
        if use_cache:
547
561
                self.get_writer = self._get_writer_fixed_highlighted
548
562
            else:
549
563
                flags = opts.patternc.flags
550
 
                self._sub = re.compile(opts.pattern.join(("((?:", ")+)")), flags).sub
 
564
                self._sub = re.compile(
 
565
                    opts.pattern.join(("((?:", ")+)")), flags).sub
551
566
                self._highlight = color_string("\\1", FG.BOLD_RED)
552
567
                self.get_writer = self._get_writer_regexp_highlighted
553
568
            path_start = FG.MAGENTA
578
593
    def _get_writer_plain(self, path, revno, cache_id):
579
594
        """Get function for writing uncoloured output"""
580
595
        per_line = self._format_perline
581
 
        start = self._format_initial % {"path":path, "revno":revno}
 
596
        start = self._format_initial % {"path": path, "revno": revno}
582
597
        write = self.outf.write
583
598
        if self.cache is not None and cache_id is not None:
584
599
            result_list = []
585
600
            self.cache[cache_id] = path, result_list
586
601
            add_to_cache = result_list.append
 
602
 
587
603
            def _line_cache_and_writer(**kwargs):
588
604
                """Write formatted line and cache arguments"""
589
605
                end = per_line % kwargs
590
606
                add_to_cache(end)
591
607
                write(start + end)
592
608
            return _line_cache_and_writer
 
609
 
593
610
        def _line_writer(**kwargs):
594
611
            """Write formatted line from arguments given by underlying opts"""
595
612
            write(start + per_line % kwargs)
598
615
    def write_cached_lines(self, cache_id, revno):
599
616
        """Write cached results out again for new revision"""
600
617
        cached_path, cached_matches = self.cache[cache_id]
601
 
        start = self._format_initial % {"path":cached_path, "revno":revno}
 
618
        start = self._format_initial % {"path": cached_path, "revno": revno}
602
619
        write = self.outf.write
603
620
        for end in cached_matches:
604
621
            write(start + end)
607
624
        """Get function for writing output with regexp match highlighted"""
608
625
        _line_writer = self._get_writer_plain(path, revno, cache_id)
609
626
        sub, highlight = self._sub, self._highlight
 
627
 
610
628
        def _line_writer_regexp_highlighted(line, **kwargs):
611
629
            """Write formatted line with matched pattern highlighted"""
612
630
            return _line_writer(line=sub(highlight, line), **kwargs)
616
634
        """Get function for writing output with search string highlighted"""
617
635
        _line_writer = self._get_writer_plain(path, revno, cache_id)
618
636
        old, new = self._old, self._new
 
637
 
619
638
        def _line_writer_fixed_highlighted(line, **kwargs):
620
639
            """Write formatted line with string searched for highlighted"""
621
640
            return _line_writer(line=line.replace(old, new), **kwargs)
672
691
            for index, line in enumerate(file_text.splitlines()):
673
692
                if pattern in line:
674
693
                    line = line.decode(file_encoding, 'replace')
675
 
                    writeline(lineno=index+start, line=line)
 
694
                    writeline(lineno=index + start, line=line)
676
695
        else:
677
696
            for line in file_text.splitlines():
678
697
                if pattern in line:
700
719
            for index, line in enumerate(file_text.splitlines()):
701
720
                if search(line):
702
721
                    line = line.decode(file_encoding, 'replace')
703
 
                    writeline(lineno=index+start, line=line)
 
722
                    writeline(lineno=index + start, line=line)
704
723
        else:
705
724
            for line in file_text.splitlines():
706
725
                if search(line):
707
726
                    line = line.decode(file_encoding, 'replace')
708
727
                    writeline(line=line)
709