#!/usr/bin/python # Copyright 2005 Drew Perttula # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """sometimes we grep for something in a bunch of files, and then we want to make edits to the lines that were returned from the grep. It's a hassle to edit all the files; this program puts the match lines in a temp file for easy editing all at once. EDITOR is used on the temporary file. The cmdline arguments to grepedit are the same as those to grep. Do not use arguments that alter the output line format; -C is ok. grepedit also reads the following arguments: --sort-text sort lines by the text part of the line (this probably doesn't make sense with -C) The grep output usually looks like this: ez_setup.py:136: import setuptools ez_setup.py:138: import tempfile, shutil Output might be like this with -C 2: -- ez_setup.py-174- '''Update our built-in md5 registry''' ez_setup.py-175- ez_setup.py:176: import re ez_setup.py:177: from md5 import md5 ez_setup.py-178- ez_setup.py-179- for name in filenames: -- """ import os import re import sys import tempfile from sets import Set def grep_parse(filename): """parse grep output lines in given file into a dict of (filename, lineno) : text""" parse = {} for line in open(filename): if line == "--\n": continue m = re.match( r"(?P.*?)(?P[-:])(?P\d+)(?P=sep)(?P.*\n)$", line, ) if m is None: print("couldn't parse grep result line %r" % line) continue filename, lineno, text = ( m.group("filename"), int(m.group("lineno")), m.group("line"), ) if (filename, lineno) in parse: raise ValueError("multiple results found for %s:%s" % (filename, lineno)) parse[(filename, lineno)] = text return parse options = {} passthru_args = [] for arg in sys.argv[1:]: if arg == "--sort-text": options["sort-text"] = True continue passthru_args.append(arg) tf = tempfile.NamedTemporaryFile(prefix="grepedit_") tf.close() cmd = "grep --with-filename --line-number --binary-files=without-match %s > %s" % ( " ".join( ['"%s"' % s.replace("\\", "\\\\").replace('"', '\\"') for s in passthru_args] ), tf.name, ) os.system(cmd) originals = grep_parse(tf.name) if options.get("sort-text", False): orig = [(v, k) for k, v in list(originals.items())] orig.sort() f = open(tf.name, "w") for text, (filename, lineno) in orig: f.write("%s:%s:%s" % (filename, lineno, text)) f.close() os.system("%s %s" % (os.getenv("EDITOR"), tf.name)) corrections = grep_parse(tf.name) files = Set([filename for filename, lineno in list(corrections.keys())]) for orig_filename in files: (copy_fd, copy_filename) = tempfile.mkstemp( dir=os.path.dirname(orig_filename), prefix="_%s_tmp_grepedit" % os.path.basename(orig_filename), ) any_changes = False for lineno, line in enumerate(open(orig_filename)): lineno = lineno + 1 # grep is 1-based key = orig_filename, lineno if key in corrections: if line != originals[key]: print( "%s:%s has changed since the grep command ran- " "not modifying this line" % key ) print(repr(line)) print(repr(originals[key])) elif corrections[key] == line: pass else: print("%s:%s substituting new line" % key) line = corrections[key] any_changes = True os.write(copy_fd, line) os.close(copy_fd) if any_changes: os.rename(copy_filename, orig_filename) else: print("no changes made in file %s" % orig_filename) os.unlink(copy_filename)