| #!/usr/bin/env python3 | |
| import argparse | |
| import subprocess | |
| import shutil | |
| import sys | |
| from pathlib import Path | |
| import typing as T | |
| def run(argsv: T.List[str]) -> int: | |
| commands = [[]] # type: T.List[T.List[str]] | |
| SEPARATOR = ';;;' | |
| # Generate CMD parameters | |
| parser = argparse.ArgumentParser(description='Wrapper for add_custom_command') | |
| parser.add_argument('-d', '--directory', type=str, metavar='D', required=True, help='Working directory to cwd to') | |
| parser.add_argument('-o', '--outputs', nargs='+', metavar='O', required=True, help='Expected output files') | |
| parser.add_argument('-O', '--original-outputs', nargs='*', metavar='O', default=[], help='Output files expected by CMake') | |
| parser.add_argument('commands', nargs=argparse.REMAINDER, help='A "{}" seperated list of commands'.format(SEPARATOR)) | |
| # Parse | |
| args = parser.parse_args(argsv) | |
| directory = Path(args.directory) | |
| dummy_target = None | |
| if len(args.outputs) == 1 and len(args.original_outputs) == 0: | |
| dummy_target = Path(args.outputs[0]) | |
| elif len(args.outputs) != len(args.original_outputs): | |
| print('Length of output list and original output list differ') | |
| return 1 | |
| for i in args.commands: | |
| if i == SEPARATOR: | |
| commands += [[]] | |
| continue | |
| i = i.replace('"', '') # Remove lefover quotes | |
| commands[-1] += [i] | |
| # Execute | |
| for i in commands: | |
| # Skip empty lists | |
| if not i: | |
| continue | |
| cmd = [] | |
| stdout = None | |
| stderr = None | |
| capture_file = '' | |
| for j in i: | |
| if j in ['>', '>>']: | |
| stdout = subprocess.PIPE | |
| continue | |
| elif j in ['&>', '&>>']: | |
| stdout = subprocess.PIPE | |
| stderr = subprocess.STDOUT | |
| continue | |
| if stdout is not None or stderr is not None: | |
| capture_file += j | |
| else: | |
| cmd += [j] | |
| try: | |
| directory.mkdir(parents=True, exist_ok=True) | |
| res = subprocess.run(cmd, stdout=stdout, stderr=stderr, cwd=str(directory), check=True) | |
| if capture_file: | |
| out_file = directory / capture_file | |
| out_file.write_bytes(res.stdout) | |
| except subprocess.CalledProcessError: | |
| return 1 | |
| if dummy_target: | |
| dummy_target.touch() | |
| return 0 | |
| # Copy outputs | |
| zipped_outputs = zip([Path(x) for x in args.outputs], [Path(x) for x in args.original_outputs]) | |
| for expected, generated in zipped_outputs: | |
| do_copy = False | |
| if not expected.exists(): | |
| if not generated.exists(): | |
| print('Unable to find generated file. This can cause the build to fail:') | |
| print(generated) | |
| do_copy = False | |
| else: | |
| do_copy = True | |
| elif generated.exists(): | |
| if generated.stat().st_mtime > expected.stat().st_mtime: | |
| do_copy = True | |
| if do_copy: | |
| if expected.exists(): | |
| expected.unlink() | |
| shutil.copyfile(str(generated), str(expected)) | |
| return 0 | |
| if __name__ == '__main__': | |
| sys.exit(run(sys.argv[1:])) |