|
1 | 1 | #!/usr/bin/env python
|
2 |
| -import glob |
| 2 | +import asyncio |
3 | 3 | import os
|
| 4 | +from pathlib import Path |
4 | 5 | import shutil
|
5 | 6 | import subprocess
|
6 | 7 | import sys
|
|
20 | 21 | os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "python"
|
21 | 22 |
|
22 | 23 |
|
23 |
| -def clear_directory(path: str): |
24 |
| - for file_or_directory in glob.glob(os.path.join(path, "*")): |
25 |
| - if os.path.isdir(file_or_directory): |
| 24 | +def clear_directory(dir_path: Path): |
| 25 | + for file_or_directory in dir_path.glob("*"): |
| 26 | + if file_or_directory.is_dir(): |
26 | 27 | shutil.rmtree(file_or_directory)
|
27 | 28 | else:
|
28 |
| - os.remove(file_or_directory) |
| 29 | + file_or_directory.unlink() |
29 | 30 |
|
30 | 31 |
|
31 |
| -def generate(whitelist: Set[str]): |
32 |
| - path_whitelist = {os.path.realpath(e) for e in whitelist if os.path.exists(e)} |
33 |
| - name_whitelist = {e for e in whitelist if not os.path.exists(e)} |
| 32 | +async def generate(whitelist: Set[str], verbose: bool): |
| 33 | + test_case_names = set(get_directories(inputs_path)) - {"__pycache__"} |
34 | 34 |
|
35 |
| - test_case_names = set(get_directories(inputs_path)) |
36 |
| - |
37 |
| - failed_test_cases = [] |
| 35 | + path_whitelist = set() |
| 36 | + name_whitelist = set() |
| 37 | + for item in whitelist: |
| 38 | + if item in test_case_names: |
| 39 | + name_whitelist.add(item) |
| 40 | + continue |
| 41 | + path_whitelist.add(item) |
38 | 42 |
|
| 43 | + generation_tasks = [] |
39 | 44 | for test_case_name in sorted(test_case_names):
|
40 |
| - test_case_input_path = os.path.realpath( |
41 |
| - os.path.join(inputs_path, test_case_name) |
42 |
| - ) |
43 |
| - |
| 45 | + test_case_input_path = inputs_path.joinpath(test_case_name).resolve() |
44 | 46 | if (
|
45 | 47 | whitelist
|
46 |
| - and test_case_input_path not in path_whitelist |
| 48 | + and str(test_case_input_path) not in path_whitelist |
47 | 49 | and test_case_name not in name_whitelist
|
48 | 50 | ):
|
49 | 51 | continue
|
| 52 | + generation_tasks.append( |
| 53 | + generate_test_case_output(test_case_input_path, test_case_name, verbose) |
| 54 | + ) |
50 | 55 |
|
51 |
| - print(f"Generating output for {test_case_name}") |
52 |
| - try: |
53 |
| - generate_test_case_output(test_case_name, test_case_input_path) |
54 |
| - except subprocess.CalledProcessError as e: |
| 56 | + failed_test_cases = [] |
| 57 | + # Wait for all subprocs and match any failures to names to report |
| 58 | + for test_case_name, result in zip( |
| 59 | + sorted(test_case_names), await asyncio.gather(*generation_tasks) |
| 60 | + ): |
| 61 | + if result != 0: |
55 | 62 | failed_test_cases.append(test_case_name)
|
56 | 63 |
|
57 | 64 | if failed_test_cases:
|
58 |
| - sys.stderr.write("\nFailed to generate the following test cases:\n") |
| 65 | + sys.stderr.write( |
| 66 | + "\n\033[31;1;4mFailed to generate the following test cases:\033[0m\n" |
| 67 | + ) |
59 | 68 | for failed_test_case in failed_test_cases:
|
60 | 69 | sys.stderr.write(f"- {failed_test_case}\n")
|
61 | 70 |
|
62 | 71 |
|
63 |
| -def generate_test_case_output(test_case_name, test_case_input_path=None): |
64 |
| - if not test_case_input_path: |
65 |
| - test_case_input_path = os.path.realpath( |
66 |
| - os.path.join(inputs_path, test_case_name) |
67 |
| - ) |
| 72 | +async def generate_test_case_output( |
| 73 | + test_case_input_path: Path, test_case_name: str, verbose: bool |
| 74 | +) -> int: |
| 75 | + """ |
| 76 | + Returns the max of the subprocess return values |
| 77 | + """ |
68 | 78 |
|
69 |
| - test_case_output_path_reference = os.path.join( |
70 |
| - output_path_reference, test_case_name |
71 |
| - ) |
72 |
| - test_case_output_path_betterproto = os.path.join( |
73 |
| - output_path_betterproto, test_case_name |
74 |
| - ) |
| 79 | + test_case_output_path_reference = output_path_reference.joinpath(test_case_name) |
| 80 | + test_case_output_path_betterproto = output_path_betterproto.joinpath(test_case_name) |
75 | 81 |
|
76 | 82 | os.makedirs(test_case_output_path_reference, exist_ok=True)
|
77 | 83 | os.makedirs(test_case_output_path_betterproto, exist_ok=True)
|
78 | 84 |
|
79 | 85 | clear_directory(test_case_output_path_reference)
|
80 | 86 | clear_directory(test_case_output_path_betterproto)
|
81 | 87 |
|
82 |
| - protoc_reference(test_case_input_path, test_case_output_path_reference) |
83 |
| - protoc_plugin(test_case_input_path, test_case_output_path_betterproto) |
| 88 | + ( |
| 89 | + (ref_out, ref_err, ref_code), |
| 90 | + (plg_out, plg_err, plg_code), |
| 91 | + ) = await asyncio.gather( |
| 92 | + protoc_reference(test_case_input_path, test_case_output_path_reference), |
| 93 | + protoc_plugin(test_case_input_path, test_case_output_path_betterproto), |
| 94 | + ) |
| 95 | + |
| 96 | + message = f"Generated output for {test_case_name!r}" |
| 97 | + if verbose: |
| 98 | + print(f"\033[31;1;4m{message}\033[0m") |
| 99 | + if ref_out: |
| 100 | + sys.stdout.buffer.write(ref_out) |
| 101 | + if ref_err: |
| 102 | + sys.stderr.buffer.write(ref_err) |
| 103 | + if plg_out: |
| 104 | + sys.stdout.buffer.write(plg_out) |
| 105 | + if plg_err: |
| 106 | + sys.stderr.buffer.write(plg_err) |
| 107 | + sys.stdout.buffer.flush() |
| 108 | + sys.stderr.buffer.flush() |
| 109 | + else: |
| 110 | + print(message) |
| 111 | + |
| 112 | + return max(ref_code, plg_code) |
84 | 113 |
|
85 | 114 |
|
86 | 115 | HELP = "\n".join(
|
87 |
| - [ |
88 |
| - "Usage: python generate.py", |
89 |
| - " python generate.py [DIRECTORIES or NAMES]", |
| 116 | + ( |
| 117 | + "Usage: python generate.py [-h] [-v] [DIRECTORIES or NAMES]", |
90 | 118 | "Generate python classes for standard tests.",
|
91 | 119 | "",
|
92 | 120 | "DIRECTORIES One or more relative or absolute directories of test-cases to generate classes for.",
|
93 | 121 | " python generate.py inputs/bool inputs/double inputs/enum",
|
94 | 122 | "",
|
95 | 123 | "NAMES One or more test-case names to generate classes for.",
|
96 | 124 | " python generate.py bool double enums",
|
97 |
| - ] |
| 125 | + ) |
98 | 126 | )
|
99 | 127 |
|
100 | 128 |
|
101 | 129 | def main():
|
102 | 130 | if set(sys.argv).intersection({"-h", "--help"}):
|
103 | 131 | print(HELP)
|
104 | 132 | return
|
105 |
| - whitelist = set(sys.argv[1:]) |
106 |
| - |
107 |
| - generate(whitelist) |
| 133 | + if sys.argv[1:2] == ["-v"]: |
| 134 | + verbose = True |
| 135 | + whitelist = set(sys.argv[2:]) |
| 136 | + else: |
| 137 | + verbose = False |
| 138 | + whitelist = set(sys.argv[1:]) |
| 139 | + asyncio.get_event_loop().run_until_complete(generate(whitelist, verbose)) |
108 | 140 |
|
109 | 141 |
|
110 | 142 | if __name__ == "__main__":
|
|
0 commit comments