Skip to content

Instantly share code, notes, and snippets.

@pfultz2
Last active October 28, 2019 13:59
Show Gist options
  • Save pfultz2/b61696f2e5830ecb1f5cc410fd695612 to your computer and use it in GitHub Desktop.
Save pfultz2/b61696f2e5830ecb1f5cc410fd695612 to your computer and use it in GitHub Desktop.
Python script to reduce using creduce
import argparse, contextlib, multiprocessing, os, tempfile, shutil, subprocess
@contextlib.contextmanager
def mkdtemp():
d = tempfile.mkdtemp()
yield d
shutil.rmtree(d, ignore_errors=True)
def print_lines(lines):
for line in lines:
print line
def write_to(file, lines):
content = list((line + "\n" for line in lines))
if (len(content) > 0):
with open(file, 'w') as f:
f.writelines(content)
def make_executable(p):
os.chmod(p, 509)
def quote(s):
text = s.replace("'", "'\"'\"'")
return "'{}'".format(text)
class ScriptBuilder:
def __init__(self):
self.commands = ['#!/bin/bash', '', 'rm -rf .tmp.output', '']
def blank(self):
self.commands.append('')
def add_command(self, cmd, save=False):
if save:
self.commands.append(cmd + ' |& tee .tmp.output')
else:
self.commands.append(cmd)
def grep(self, text, file=None):
self.add_command("grep -q -F {} {}".format(quote(text), file or '.tmp.output'))
def check(self, equal_zero=False, result=1):
op = 'eq' if equal_zero else 'ne'
cmds = ['RES=$?',
'if [ $RES -{} "0" ]; then'.format(op),
' exit {}'.format(result),
'fi']
self.commands.extend(cmds)
def write(self, p):
write_to(p, self.commands)
make_executable(p)
def show(self):
print_lines(self.commands)
parser = argparse.ArgumentParser()
parser.add_argument('--file', '-f', help='file to reduce', required=True)
parser.add_argument('--text', '-t', help='expected output text')
parser.add_argument('--keep', '-k', help='text to keep in source file')
parser.add_argument('--check', '-c', action='append', help='command to check syntax')
parser.add_argument('--dry-run', '-d', action='store_true', default=False, help='dry run')
parser.add_argument('--no-cache', action='store_true', default=False, help="Don't cache behavior of passes")
parser.add_argument('--no-give-up', action='store_true', default=False, help="Don't give up on a pass that hasn't made progress for 50000 iterations")
parser.add_argument('--sllooww', action='store_true', default=False, help="Try harder to reduce, but perhaps take a long time to do so")
parser.add_argument('command')
parser.add_argument('args', nargs=argparse.REMAINDER)
args = parser.parse_args()
file = os.path.basename(args.file)
sb = ScriptBuilder()
if args.keep:
sb.grep(args.keep, file=file)
sb.check()
sb.blank()
for check in args.check or []:
sb.add_command(check+' '+file)
sb.check()
sb.blank()
command = ' '.join([os.path.abspath(args.command)]+args.args+[file])
sb.add_command(command, save=args.text)
if args.text:
sb.grep(args.text)
else:
sb.check(equal_zero=True)
sb.show()
with mkdtemp() as d:
script = os.path.join(d, 'reduce.sh')
sb.write(script)
if args.dry_run:
subprocess.check_call([script], cwd=d)
else:
creduce = ['creduce', '--n', str(multiprocessing.cpu_count())]
if args.no_cache:
creduce.append("--no-cache")
if args.no_give_up:
creduce.append("--no-give-up")
if args.sllooww:
creduce.append("--sllooww")
subprocess.check_call(creduce + [script, args.file])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment