cmd/contentreplace.py
Ethan Dalool 4a9051e617
Big migrations and linting.
With pathclass.glob_many, we can clean up and feel more confident
about many programs that use pipeable to take glob patterns.

Added return 0 to all programs that didn't have it, so we have
consistent and explicit command line return values.

Other linting and whitespace.
2021-09-23 23:42:45 -07:00

92 lines
2.8 KiB
Python

import argparse
import codecs
import pyperclip
import re
import sys
from voussoirkit import interactive
from voussoirkit import pathclass
from voussoirkit import pipeable
from voussoirkit import spinal
from voussoirkit import vlogging
log = vlogging.getLogger(__name__, 'contentreplace')
def contentreplace(file, replace_from, replace_to, autoyes=False, do_regex=False):
file = pathclass.Path(file)
with file.open('r', encoding='utf-8') as f:
content = f.read()
if do_regex:
occurances = len(re.findall(replace_from, content, flags=re.MULTILINE))
else:
occurances = content.count(replace_from)
print(f'{file.absolute_path}: Found {occurances} occurences.')
if occurances == 0:
return
if not (autoyes or interactive.getpermission('Replace?')):
return
if do_regex:
content = re.sub(replace_from, replace_to, content, flags=re.MULTILINE)
else:
content = content.replace(replace_from, replace_to)
with file.open('w', encoding='utf-8') as f:
f.write(content)
@pipeable.ctrlc_return1
def contentreplace_argparse(args):
files = spinal.walk(
glob_filenames=args.filename_glob,
recurse=args.recurse,
)
if args.clip_prompt:
replace_from = input('Ready from')
if not replace_from:
replace_from = pyperclip.paste()
replace_to = input('Ready to')
if not replace_to:
replace_to = pyperclip.paste()
else:
replace_from = codecs.decode(args.replace_from, 'unicode_escape')
if args.do_regex:
replace_to = args.replace_to
else:
replace_to = codecs.decode(args.replace_to, 'unicode_escape')
for file in files:
try:
contentreplace(
file,
replace_from,
replace_to,
autoyes=args.autoyes,
do_regex=args.do_regex,
)
except UnicodeDecodeError:
log.error('%s encountered unicode decode error.', file.absolute_path)
return 0
@vlogging.main_decorator
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('filename_glob')
parser.add_argument('replace_from')
parser.add_argument('replace_to')
parser.add_argument('-y', '--yes', dest='autoyes', action='store_true', help='accept results without confirming')
parser.add_argument('--recurse', action='store_true')
parser.add_argument('--regex', dest='do_regex', action='store_true')
parser.add_argument('--clip_prompt', '--clip-prompt', action='store_true')
parser.set_defaults(func=contentreplace_argparse)
args = parser.parse_args(argv)
return args.func(args)
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))