#!/usr/bin/env python3 from __future__ import annotations import argparse import subprocess import shutil import sys from pathlib import Path import typing as T def run(argsv: T.List[str]) -> int: commands: 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=f'A "{SEPARATOR}" separated list of commands') # 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 leftover 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:]))