2
2
import glob
3
3
import sys
4
4
import subprocess
5
+ from subprocess import Popen , PIPE
5
6
import time
6
- import argparse
7
-
8
- FQBN_PREFIX = 'adafruit:samd:adafruit_'
9
7
10
-
11
- parser = argparse .ArgumentParser (
12
- description = 'python wrapper for adafruit arduino CI workflows' ,
13
- allow_abbrev = False
14
- )
15
- parser .add_argument (
16
- '--all_warnings' , '--Wall' ,
17
- action = 'store_true' ,
18
- help = 'build with all warnings enabled (`--warnings all`)' ,
19
- )
20
- parser .add_argument (
21
- '--warnings_do_not_cause_job_failure' ,
22
- action = 'store_true' ,
23
- help = 'failed builds will be listed as failed, but not cause job to exit with an error status' ,
24
- )
25
- parser .add_argument (
26
- 'build_boards' ,
27
- metavar = 'board' ,
28
- nargs = '*' ,
29
- help = 'list of boards to be built -- Note that the fqbn is created by prepending "{}"' .format (FQBN_PREFIX ),
30
- default = [ 'metro_m0' , 'metro_m4' , 'circuitplayground_m0' , 'feather_m4_can' ]
31
- )
32
- args = parser .parse_args ()
8
+ SUCCEEDED = "\033 [32msucceeded\033 [0m"
9
+ FAILED = "\033 [31mfailed\033 [0m"
10
+ SKIPPED = "\033 [35mskipped\033 [0m"
11
+ WARNING = "\033 [33mwarnings\033 [0m "
33
12
34
13
exit_status = 0
35
14
success_count = 0
36
15
fail_count = 0
37
16
skip_count = 0
38
- build_format = '| {:22} | {:30} | {:9} '
39
- build_separator = '-' * 80
40
17
41
- def errorOutputFilter (line : str ):
42
- if len (line ) == 0 :
43
- return False
44
- if line .isspace (): # Note: empty string does not match here!
45
- return False
46
- # TODO: additional items to remove?
47
- return True
18
+ build_format = '| {:20} | {:35} | {:18} | {:6} |'
19
+ build_separator = '-' * 83
20
+
21
+ FQBN_PREFIX = 'adafruit:samd:adafruit_'
22
+
23
+ default_boards = [ 'metro_m0' , 'metro_m4' , 'circuitplayground_m0' , 'feather_m4_can' ]
24
+ build_boards = []
25
+
26
+ # build all variants if input not existed
27
+ if len (sys .argv ) > 1 :
28
+ build_boards .append (sys .argv [1 ])
29
+ else :
30
+ build_boards = default_boards
31
+
32
+ all_examples = list (glob .iglob ('libraries/**/*.ino' , recursive = True ))
33
+ all_examples .sort ()
48
34
49
- def build_examples (variant : str ):
50
- global args , exit_status , success_count , fail_count , skip_count , build_format , build_separator
35
+ def build_examples (variant ):
36
+ global exit_status , success_count , fail_count , skip_count , build_format , build_separator
51
37
52
38
print ('\n ' )
53
39
print (build_separator )
54
- print ('| {:^76 } |' .format ('Board ' + variant ))
40
+ print ('| {:^79 } |' .format ('Board ' + variant ))
55
41
print (build_separator )
56
- print (( build_format + '| {:6} |' ) .format ('Library' , 'Example' , 'Result ' , 'Time' ))
42
+ print (build_format .format ('Library' , 'Example' , '\033 [39mResult \033 [0m ' , 'Time' ))
57
43
print (build_separator )
58
44
59
45
fqbn = "{}{}" .format (FQBN_PREFIX , variant )
60
46
61
- for sketch in glob . iglob ( 'libraries/**/*.ino' , recursive = True ) :
47
+ for sketch in all_examples :
62
48
# TODO skip TinyUSB library examples for now
63
49
if "libraries/Adafruit_TinyUSB_Arduino" in sketch :
64
50
continue
@@ -69,60 +55,47 @@ def build_examples(variant: str):
69
55
# Skip if not contains: ".board.test.only" for a specific board
70
56
sketchdir = os .path .dirname (sketch )
71
57
if os .path .exists (sketchdir + '/.all.test.skip' ) or os .path .exists (sketchdir + '/.' + variant + '.test.skip' ):
72
- success = "\033 [33mskipped\033 [0m "
73
- elif glob .glob (sketchdir + "/.*.test.only" ) and not os .path .exists (sketchdir + '/.build.' + variant ):
74
- success = "\033 [33mskipped\033 [0m "
58
+ success = SKIPPED
59
+ skip_count += 1
60
+ elif glob .glob (sketchdir + "/.*.test.only" ) and not os .path .exists (sketchdir + '/.' + variant + '.test.only' ):
61
+ success = SKIPPED
62
+ skip_count += 1
75
63
else :
76
- # TODO - preferably, would have STDERR show up in **both** STDOUT and STDERR.
77
- # preferably, would use Python logging handler to get both distinct outputs and one merged output
78
- # for now, split STDERR when building with all warnings enabled, so can detect warning/error output.
79
- if args .all_warnings :
80
- build_result = subprocess .run ("arduino-cli compile --warnings all --fqbn {} {}" .format (fqbn , sketch ), shell = True , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
81
- else :
82
- build_result = subprocess .run ("arduino-cli compile --warnings default --fqbn {} {}" .format (fqbn , sketch ), shell = True , stdout = subprocess .PIPE , stderr = subprocess .STDOUT )
83
-
84
- # get stderr into a form where len(warningLines) indicates a true warning was output to stderr
85
- warningLines = [];
86
- if args .all_warnings and build_result .stderr :
87
- tmpWarningLines = build_result .stderr .decode ("utf-8" ).splitlines ()
88
- warningLines = list (filter (errorOutputFilter , (tmpWarningLines )))
64
+ build_result = subprocess .run ("arduino-cli compile --warnings all --fqbn {} {}" .format (fqbn , sketch ), shell = True , stdout = PIPE , stderr = PIPE )
89
65
66
+ # get stderr into a form where warning/error was output to stderr
90
67
if build_result .returncode != 0 :
91
68
exit_status = build_result .returncode
92
- success = "\033 [31mfailed\033 [0m "
93
- fail_count += 1
94
- elif len (warningLines ) != 0 :
95
- if not args .warnings_do_not_cause_job_failure :
96
- exit_status = - 1
97
- success = "\033 [31mwarnings\033 [0m "
69
+ success = FAILED
98
70
fail_count += 1
99
71
else :
100
- success = "\033 [32msucceeded\033 [0m"
101
72
success_count += 1
73
+ if build_result .stderr :
74
+ success = WARNING
75
+ else :
76
+ success = SUCCEEDED
102
77
103
78
build_duration = time .monotonic () - start_time
104
79
105
- print (( build_format + '| {:5.2f}s |' ). format (sketch .split (os .path .sep )[1 ], os .path .basename (sketch ), success , build_duration ))
80
+ print (build_format . format (sketch .split (os .path .sep )[1 ], os .path .basename (sketch ), success , '{:5.2f}s' . format ( build_duration ) ))
106
81
107
- if success != "\033 [33mskipped\033 [0m " :
82
+ if success != SKIPPED :
83
+ # Build failed
108
84
if build_result .returncode != 0 :
109
85
print (build_result .stdout .decode ("utf-8" ))
110
- if (build_result .stderr ):
111
- print (build_result .stderr .decode ("utf-8" ))
112
- if len (warningLines ) != 0 :
113
- for line in warningLines :
114
- print (line )
115
- else :
116
- skip_count += 1
86
+
87
+ # Build with warnings
88
+ if build_result .stderr :
89
+ print (build_result .stderr .decode ("utf-8" ))
117
90
118
91
build_time = time .monotonic ()
119
92
120
- for board in args . build_boards :
93
+ for board in build_boards :
121
94
build_examples (board )
122
95
123
96
print (build_separator )
124
97
build_time = time .monotonic () - build_time
125
- print ("Build Summary: {} \033 [32msucceeded \033 [0m , {} \033 [31mfailed \033 [0m , {} \033 [33mskipped \033 [0m and took {:.2f}s" .format (success_count , fail_count , skip_count , build_time ))
98
+ print ("Build Summary: {} {} , {} {} , {} {} and took {:.2f}s" .format (success_count , SUCCEEDED , fail_count , FAILED , skip_count , SKIPPED , build_time ))
126
99
print (build_separator )
127
100
128
101
sys .exit (exit_status )
0 commit comments