3 # Copyright 2005 Drew Perttula
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 """sometimes we grep for something in a bunch of files, and then we
20 want to make edits to the lines that were returned from the grep. It's
21 a hassle to edit all the files; this program puts the match lines in a
22 temp file for easy editing all at once.
24 EDITOR is used on the temporary file.
26 The cmdline arguments to grepedit are the same as those to grep. Do
27 not use arguments that alter the output line format; -C is ok.
29 grepedit also reads the following arguments:
31 --sort-text sort lines by the text part of the line (this probably
32 doesn't make sense with -C)
36 The grep output usually looks like this:
37 ez_setup.py:136: import setuptools
38 ez_setup.py:138: import tempfile, shutil
40 Output might be like this with -C 2:
42 ez_setup.py-174- '''Update our built-in md5 registry'''
44 ez_setup.py:176: import re
45 ez_setup.py:177: from md5 import md5
47 ez_setup.py-179- for name in filenames:
60 def grep_parse(filename):
61 """parse grep output lines in given file into a dict of
62 (filename, lineno) : text"""
64 for line in open(filename):
68 r"(?P<filename>.*?)(?P<sep>[-:])(?P<lineno>\d+)(?P=sep)(?P<line>.*\n)$",
72 print("couldn't parse grep result line %r" % line)
74 filename, lineno, text = (
76 int(m.group("lineno")),
79 if (filename, lineno) in parse:
80 raise ValueError("multiple results found for %s:%s" % (filename, lineno))
81 parse[(filename, lineno)] = text
87 for arg in sys.argv[1:]:
88 if arg == "--sort-text":
89 options["sort-text"] = True
91 passthru_args.append(arg)
93 tf = tempfile.NamedTemporaryFile(prefix="grepedit_")
96 cmd = "grep --with-filename --line-number --binary-files=without-match %s > %s" % (
98 ['"%s"' % s.replace("\\", "\\\\").replace('"', '\\"') for s in passthru_args]
104 originals = grep_parse(tf.name)
106 if options.get("sort-text", False):
107 orig = [(v, k) for k, v in list(originals.items())]
109 f = open(tf.name, "w")
110 for text, (filename, lineno) in orig:
111 f.write("%s:%s:%s" % (filename, lineno, text))
114 os.system("%s %s" % (os.getenv("EDITOR"), tf.name))
116 corrections = grep_parse(tf.name)
118 files = Set([filename for filename, lineno in list(corrections.keys())])
119 for orig_filename in files:
120 (copy_fd, copy_filename) = tempfile.mkstemp(
121 dir=os.path.dirname(orig_filename),
122 prefix="_%s_tmp_grepedit" % os.path.basename(orig_filename),
126 for lineno, line in enumerate(open(orig_filename)):
127 lineno = lineno + 1 # grep is 1-based
128 key = orig_filename, lineno
129 if key in corrections:
130 if line != originals[key]:
132 "%s:%s has changed since the grep command ran- "
133 "not modifying this line" % key
136 print(repr(originals[key]))
137 elif corrections[key] == line:
140 print("%s:%s substituting new line" % key)
141 line = corrections[key]
143 os.write(copy_fd, line)
147 os.rename(copy_filename, orig_filename)
149 print("no changes made in file %s" % orig_filename)
150 os.unlink(copy_filename)