1#!/usr/bin/env python3
2
3import argparse
4import subprocess
5import shutil
6import os
7import sys
8from pathlib import Path
9
10def run(argsv):
11    commands = [[]]
12    SEPARATOR = ';;;'
13
14    # Generate CMD parameters
15    parser = argparse.ArgumentParser(description='Wrapper for add_custom_command')
16    parser.add_argument('-d', '--directory', type=str, metavar='D', required=True, help='Working directory to cwd to')
17    parser.add_argument('-o', '--outputs', nargs='+', metavar='O', required=True, help='Expected output files')
18    parser.add_argument('-O', '--original-outputs', nargs='*', metavar='O', default=[], help='Output files expected by CMake')
19    parser.add_argument('commands', nargs=argparse.REMAINDER, help='A "{}" seperated list of commands'.format(SEPARATOR))
20
21    # Parse
22    args = parser.parse_args(argsv)
23
24    dummy_target = None
25    if len(args.outputs) == 1 and len(args.original_outputs) == 0:
26        dummy_target = args.outputs[0]
27    elif len(args.outputs) != len(args.original_outputs):
28        print('Length of output list and original output list differ')
29        sys.exit(1)
30
31    for i in args.commands:
32        if i == SEPARATOR:
33            commands += [[]]
34            continue
35
36        i = i.replace('"', '')  # Remove lefover quotes
37        commands[-1] += [i]
38
39    # Execute
40    for i in commands:
41        # Skip empty lists
42        if not i:
43            continue
44
45        cmd = []
46        stdout = None
47        stderr = None
48        capture_file = ''
49
50        for j in i:
51            if j in ['>', '>>']:
52                stdout = subprocess.PIPE
53                continue
54            elif j in ['&>', '&>>']:
55                stdout = subprocess.PIPE
56                stderr = subprocess.STDOUT
57                continue
58
59            if stdout is not None or stderr is not None:
60                capture_file += j
61            else:
62                cmd += [j]
63
64        try:
65            os.makedirs(args.directory, exist_ok=True)
66
67            res = subprocess.run(cmd, stdout=stdout, stderr=stderr, cwd=args.directory, check=True)
68            if capture_file:
69                out_file = Path(args.directory) / capture_file
70                out_file.write_bytes(res.stdout)
71        except subprocess.CalledProcessError:
72            sys.exit(1)
73
74    if dummy_target:
75        with open(dummy_target, 'a'):
76            os.utime(dummy_target, None)
77        sys.exit(0)
78
79    # Copy outputs
80    zipped_outputs = zip(args.outputs, args.original_outputs)
81    for expected, generated in zipped_outputs:
82        do_copy = False
83        if not os.path.exists(expected):
84            if not os.path.exists(generated):
85                print('Unable to find generated file. This can cause the build to fail:')
86                print(generated)
87                do_copy = False
88            else:
89                do_copy = True
90        elif os.path.exists(generated):
91            if os.path.getmtime(generated) > os.path.getmtime(expected):
92                do_copy = True
93
94        if do_copy:
95            if os.path.exists(expected):
96                os.remove(expected)
97            shutil.copyfile(generated, expected)
98
99if __name__ == '__main__':
100    sys.run(sys.argv[1:])
101