From a9daa1abd5769377df5ea0d1831cd99662577803 Mon Sep 17 00:00:00 2001 From: Paul Fultz II Date: Sun, 18 Jul 2021 00:51:01 -0500 Subject: [PATCH] Add creduce.py script to run creduce (#3341) --- tools/creduce.py | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 tools/creduce.py diff --git a/tools/creduce.py b/tools/creduce.py new file mode 100644 index 000000000..0ab9f5b99 --- /dev/null +++ b/tools/creduce.py @@ -0,0 +1,107 @@ +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 + ' 2>&1 | 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', action='append', help='expected output text') +parser.add_argument('--keep', '-k', action='append', 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('--timeout', action='store', default=300, help='Interestingness test timeout in seconds') +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', '--slow', 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() +for keep in args.keep or []: + sb.grep(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: + for t in args.text: + sb.grep(t) + sb.check() +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: + shutil.copy(args.file, d) + subprocess.check_call([script], cwd=d) + else: + creduce = ['creduce', '--n', str(multiprocessing.cpu_count())] + creduce.append("--timeout") + creduce.append(str(args.timeout)) + 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])