|
2 | 2 | import glob
|
3 | 3 | import sys
|
4 | 4 | import subprocess
|
5 |
| -from subprocess import Popen, PIPE |
6 | 5 | import time
|
| 6 | +from multiprocessing import Pool |
7 | 7 |
|
8 | 8 | SUCCEEDED = "\033[32msucceeded\033[0m"
|
9 | 9 | FAILED = "\033[31mfailed\033[0m"
|
10 | 10 | SKIPPED = "\033[35mskipped\033[0m"
|
11 | 11 | WARNING = "\033[33mwarnings\033[0m "
|
12 | 12 |
|
13 |
| -exit_status = 0 |
14 |
| -success_count = 0 |
15 |
| -fail_count = 0 |
16 |
| -skip_count = 0 |
17 |
| - |
18 | 13 | build_format = '| {:25} | {:35} | {:18} | {:6} |'
|
19 | 14 | build_separator = '-' * 88
|
20 | 15 |
|
21 |
| -default_boards = [ 'cluenrf52840', 'cplaynrf52840', 'feather52832', 'feather52840', 'feather52840sense', 'itsybitsy52840' ] |
| 16 | +default_boards = [ |
| 17 | + 'cluenrf52840', |
| 18 | + 'cplaynrf52840', |
| 19 | + 'feather52832', |
| 20 | + 'feather52840', |
| 21 | + 'feather52840sense', |
| 22 | + 'itsybitsy52840' |
| 23 | +] |
22 | 24 | build_boards = []
|
23 | 25 |
|
24 |
| -# build all variants if input not existed |
25 |
| -if len(sys.argv) > 1: |
26 |
| - build_boards.append(sys.argv[1]) |
27 |
| -else: |
28 |
| - build_boards = default_boards |
29 | 26 |
|
30 |
| -all_examples = list(glob.iglob('libraries/**/*.ino', recursive=True)) |
31 |
| -all_examples.sort() |
| 27 | +def build_a_example(arg): |
| 28 | + variant = arg[0] |
| 29 | + sketch = arg[1] |
| 30 | + |
| 31 | + fqbn = "adafruit:nrf52:{}:softdevice={},debug=l0".format(variant, |
| 32 | + 's140v6' if variant != 'feather52832' else 's132v6') |
| 33 | + # succeeded, failed, skipped |
| 34 | + ret = [0, 0, 0] |
| 35 | + |
| 36 | + start_time = time.monotonic() |
| 37 | + |
| 38 | + # Skip if contains: ".board.test.skip" or ".all.test.skip" |
| 39 | + # Skip if not contains: ".board.test.only" for a specific board |
| 40 | + sketchdir = os.path.dirname(sketch) |
| 41 | + if os.path.exists(sketchdir + '/.all.test.skip') or os.path.exists(sketchdir + '/.' + variant + '.test.skip'): |
| 42 | + success = SKIPPED |
| 43 | + ret[2] = 1 |
| 44 | + elif glob.glob(sketchdir + "/.*.test.only") and not os.path.exists(sketchdir + '/.' + variant + '.test.only'): |
| 45 | + success = SKIPPED |
| 46 | + ret[2] = 1 |
| 47 | + else: |
| 48 | + build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, |
| 49 | + stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| 50 | + |
| 51 | + # get stderr into a form where warning/error was output to stderr |
| 52 | + if build_result.returncode != 0: |
| 53 | + ret[1] = 1 |
| 54 | + success = FAILED |
| 55 | + else: |
| 56 | + ret[0] = 1 |
| 57 | + if build_result.stderr: |
| 58 | + success = WARNING |
| 59 | + else: |
| 60 | + success = SUCCEEDED |
| 61 | + |
| 62 | + build_duration = time.monotonic() - start_time |
| 63 | + print(build_format.format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, |
| 64 | + '{:5.2f}s'.format(build_duration))) |
32 | 65 |
|
33 |
| -def build_examples(variant): |
34 |
| - global exit_status, success_count, fail_count, skip_count, build_format, build_separator |
| 66 | + if success != SKIPPED: |
| 67 | + # Build failed |
| 68 | + if build_result.returncode != 0: |
| 69 | + print(build_result.stdout.decode("utf-8")) |
35 | 70 |
|
| 71 | + # Build with warnings |
| 72 | + if build_result.stderr: |
| 73 | + print(f"::group::warning-message") |
| 74 | + print(build_result.stderr.decode("utf-8")) |
| 75 | + print(f"::endgroup::") |
| 76 | + |
| 77 | + return ret |
| 78 | + |
| 79 | + |
| 80 | +def build_all_examples(variant): |
36 | 81 | print('\n')
|
37 | 82 | print(build_separator)
|
38 | 83 | print('| {:^84} |'.format('Board ' + variant))
|
39 | 84 | print(build_separator)
|
40 | 85 | print(build_format.format('Library', 'Example', '\033[39mResult\033[0m', 'Time'))
|
41 | 86 | print(build_separator)
|
42 |
| - |
43 |
| - fqbn = "adafruit:nrf52:{}:softdevice={},debug=l0".format(variant, 's140v6' if variant != 'feather52832' else 's132v6') |
44 |
| - |
45 |
| - for sketch in all_examples: |
46 |
| - # skip TinyUSB library examples for nRF52832 |
47 |
| - if variant == 'feather52832' and "libraries/Adafruit_TinyUSB_Arduino" in sketch: |
48 |
| - continue |
49 |
| - |
50 |
| - start_time = time.monotonic() |
51 |
| - |
52 |
| - # Skip if contains: ".board.test.skip" or ".all.test.skip" |
53 |
| - # Skip if not contains: ".board.test.only" for a specific board |
54 |
| - sketchdir = os.path.dirname(sketch) |
55 |
| - if os.path.exists(sketchdir + '/.all.test.skip') or os.path.exists(sketchdir + '/.' + variant + '.test.skip'): |
56 |
| - success = SKIPPED |
57 |
| - skip_count += 1 |
58 |
| - elif glob.glob(sketchdir+"/.*.test.only") and not os.path.exists(sketchdir + '/.' + variant + '.test.only'): |
59 |
| - success = SKIPPED |
60 |
| - skip_count += 1 |
61 |
| - else: |
62 |
| - build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=PIPE, stderr=PIPE) |
63 | 87 |
|
64 |
| - # get stderr into a form where warning/error was output to stderr |
65 |
| - if build_result.returncode != 0: |
66 |
| - exit_status = build_result.returncode |
67 |
| - success = FAILED |
68 |
| - fail_count += 1 |
69 |
| - else: |
70 |
| - success_count += 1 |
71 |
| - if build_result.stderr: |
72 |
| - success = WARNING |
73 |
| - else: |
74 |
| - success = SUCCEEDED |
75 |
| - |
76 |
| - build_duration = time.monotonic() - start_time |
77 |
| - |
78 |
| - print(build_format.format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, '{:5.2f}s'.format(build_duration))) |
79 |
| - |
80 |
| - if success != SKIPPED: |
81 |
| - # Build failed |
82 |
| - if build_result.returncode != 0: |
83 |
| - print(build_result.stdout.decode("utf-8")) |
84 |
| - |
85 |
| - # Build with warnings |
86 |
| - if build_result.stderr: |
87 |
| - print(build_result.stderr.decode("utf-8")) |
| 88 | + args = [[variant, s] for s in all_examples] |
| 89 | + with Pool() as pool: |
| 90 | + result = pool.map(build_a_example, args) |
| 91 | + # sum all element of same index (column sum) |
| 92 | + return list(map(sum, list(zip(*result)))) |
| 93 | + |
| 94 | + |
| 95 | +if __name__ == "__main__": |
| 96 | + # build all variants if input not existed |
| 97 | + if len(sys.argv) > 1: |
| 98 | + build_boards.append(sys.argv[1]) |
| 99 | + else: |
| 100 | + build_boards = default_boards |
| 101 | + |
| 102 | + # All examples in libraries except TinyUSB which has its own ci to build |
| 103 | + all_examples = list(glob.iglob('libraries/**/*.ino', recursive=True)) |
| 104 | + all_examples = [i for i in all_examples if "Adafruit_TinyUSB_Arduino" not in i] |
| 105 | + all_examples.sort() |
88 | 106 |
|
89 |
| -build_time = time.monotonic() |
| 107 | + build_time = time.monotonic() |
90 | 108 |
|
91 |
| -for board in build_boards: |
92 |
| - build_examples(board) |
| 109 | + # succeeded, failed, skipped |
| 110 | + total_result = [0, 0, 0] |
93 | 111 |
|
94 |
| -print(build_separator) |
95 |
| -build_time = time.monotonic() - build_time |
96 |
| -print("Build Summary: {} {}, {} {}, {} {} and took {:.2f}s".format(success_count, SUCCEEDED, fail_count, FAILED, skip_count, SKIPPED, build_time)) |
97 |
| -print(build_separator) |
| 112 | + for board in build_boards: |
| 113 | + fret = build_all_examples(board) |
| 114 | + if len(fret) == len(total_result): |
| 115 | + total_result = [total_result[i] + fret[i] for i in range(len(fret))] |
| 116 | + |
| 117 | + build_time = time.monotonic() - build_time |
| 118 | + |
| 119 | + print(build_separator) |
| 120 | + print("Build Summary: {} {}, {} {}, {} {} and took {:.2f}s".format(total_result[0], SUCCEEDED, total_result[1], FAILED, total_result[2], SKIPPED, build_time)) |
| 121 | + print(build_separator) |
98 | 122 |
|
99 |
| -sys.exit(exit_status) |
| 123 | + sys.exit(total_result[1]) |
0 commit comments