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:
52 import tempfile, sys, os, re
55 def grep_parse(filename):
56 """parse grep output lines in given file into a dict of
57 (filename, lineno) : text"""
59 for line in open(filename):
62 m = re.match(r"(?P<filename>.*?)(?P<sep>[-:])(?P<lineno>\d+)(?P=sep)(?P<line>.*\n)$", line)
64 print "couldn't parse grep result line %r" % line
66 filename, lineno, text = (m.group('filename'), int(m.group('lineno')),
68 if (filename,lineno) in parse:
69 raise ValueError("multiple results found for %s:%s" %
71 parse[(filename, lineno)] = text
76 for arg in sys.argv[1:]:
77 if arg == "--sort-text":
78 options['sort-text'] = True
80 passthru_args.append(arg)
82 tf = tempfile.NamedTemporaryFile(prefix="grepedit_")
85 cmd = ("grep --with-filename --line-number --binary-files=without-match %s > %s" %
86 (" ".join(['"%s"' % s.replace("\\","\\\\").replace('"','\\"')
87 for s in passthru_args]),tf.name))
90 originals = grep_parse(tf.name)
92 if options.get('sort-text', False):
93 orig = [(v,k) for k,v in originals.items()]
95 f = open(tf.name, "w")
96 for text, (filename,lineno) in orig:
97 f.write("%s:%s:%s" % (filename, lineno, text))
100 os.system("%s %s" % (os.getenv("EDITOR"), tf.name))
102 corrections = grep_parse(tf.name)
104 files = Set([filename for filename,lineno in corrections.keys()])
105 for orig_filename in files:
106 (copy_fd, copy_filename) = tempfile.mkstemp(
107 dir=os.path.dirname(orig_filename),
108 prefix="_%s_tmp_grepedit" % os.path.basename(orig_filename))
111 for lineno,line in enumerate(open(orig_filename)):
112 lineno = lineno + 1 # grep is 1-based
113 key = orig_filename,lineno
114 if key in corrections:
115 if line != originals[key]:
116 print "%s:%s has changed since the grep command ran- not modifying this line" % key
118 print repr(originals[key])
119 elif corrections[key] == line:
122 print "%s:%s substituting new line" % key
123 line = corrections[key]
125 os.write(copy_fd, line)
129 os.rename(copy_filename, orig_filename)
131 print "no changes made in file %s" % orig_filename
132 os.unlink(copy_filename)