124 lines
4.8 KiB
Python
124 lines
4.8 KiB
Python
import os
|
|
import glob
|
|
import sys
|
|
import subprocess
|
|
import time
|
|
import argparse
|
|
|
|
FQBN_PREFIX='adafruit:samd:adafruit_'
|
|
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description='python wrapper for adafruit arduino CI workflows',
|
|
allow_abbrev=False
|
|
)
|
|
parser.add_argument(
|
|
'--all_warnings', '--Wall',
|
|
action='store_true',
|
|
help='build with all warnings enabled (`--warnings all`)',
|
|
)
|
|
parser.add_argument(
|
|
'--warnings_do_not_cause_job_failure',
|
|
action='store_true',
|
|
help='failed builds will be listed as failed, but not cause job to exit with an error status',
|
|
)
|
|
parser.add_argument(
|
|
'build_boards',
|
|
metavar='board',
|
|
nargs='*',
|
|
help='list of boards to be built -- Note that the fqbn is created by prepending "{}"'.format(FQBN_PREFIX),
|
|
default= [ 'metro_m0', 'metro_m4', 'circuitplayground_m0' ]
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
exit_status = 0
|
|
success_count = 0
|
|
fail_count = 0
|
|
skip_count = 0
|
|
build_format = '| {:22} | {:30} | {:9} '
|
|
build_separator = '-' * 80
|
|
|
|
def errorOutputFilter(line: str):
|
|
if len(line) == 0:
|
|
return False
|
|
if line.isspace(): # Note: empty string does not match here!
|
|
return False
|
|
# TODO: additional items to remove?
|
|
return True
|
|
|
|
def build_examples(variant: str):
|
|
global args, exit_status, success_count, fail_count, skip_count, build_format, build_separator
|
|
|
|
print('\n')
|
|
print(build_separator)
|
|
print('| {:^76} |'.format('Board ' + variant))
|
|
print(build_separator)
|
|
print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time'))
|
|
print(build_separator)
|
|
|
|
fqbn = "{}{}".format(FQBN_PREFIX, variant)
|
|
|
|
for sketch in glob.iglob('libraries/**/*.ino', recursive=True):
|
|
start_time = time.monotonic()
|
|
|
|
# Skip if contains: ".board.test.skip" or ".all.test.skip"
|
|
# Skip if not contains: ".board.test.only" for a specific board
|
|
sketchdir = os.path.dirname(sketch)
|
|
if os.path.exists(sketchdir + '/.all.test.skip') or os.path.exists(sketchdir + '/.' + variant + '.test.skip'):
|
|
success = "\033[33mskipped\033[0m "
|
|
elif glob.glob(sketchdir+"/.*.test.only") and not os.path.exists(sketchdir + '/.build.' + variant):
|
|
success = "\033[33mskipped\033[0m "
|
|
else:
|
|
# TODO - preferably, would have STDERR show up in **both** STDOUT and STDERR.
|
|
# preferably, would use Python logging handler to get both distinct outputs and one merged output
|
|
# for now, split STDERR when building with all warnings enabled, so can detect warning/error output.
|
|
if args.all_warnings:
|
|
build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
else:
|
|
build_result = subprocess.run("arduino-cli compile --warnings default --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
|
|
# get stderr into a form where len(warningLines) indicates a true warning was output to stderr
|
|
warningLines = [];
|
|
if args.all_warnings and build_result.stderr:
|
|
tmpWarningLines = build_result.stderr.decode("utf-8").splitlines()
|
|
warningLines = list(filter(errorOutputFilter, (tmpWarningLines)))
|
|
|
|
if build_result.returncode != 0:
|
|
exit_status = build_result.returncode
|
|
success = "\033[31mfailed\033[0m "
|
|
fail_count += 1
|
|
elif len(warningLines) != 0:
|
|
if not args.warnings_do_not_cause_job_failure:
|
|
exit_status = -1
|
|
success = "\033[31mwarnings\033[0m "
|
|
fail_count += 1
|
|
else:
|
|
success = "\033[32msucceeded\033[0m"
|
|
success_count += 1
|
|
|
|
build_duration = time.monotonic() - start_time
|
|
|
|
print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration))
|
|
|
|
if success != "\033[33mskipped\033[0m ":
|
|
if build_result.returncode != 0:
|
|
print(build_result.stdout.decode("utf-8"))
|
|
if (build_result.stderr):
|
|
print(build_result.stderr.decode("utf-8"))
|
|
if len(warningLines) != 0:
|
|
for line in warningLines:
|
|
print(line)
|
|
else:
|
|
skip_count += 1
|
|
|
|
build_time = time.monotonic()
|
|
|
|
for board in args.build_boards:
|
|
build_examples(board)
|
|
|
|
print(build_separator)
|
|
build_time = time.monotonic() - build_time
|
|
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))
|
|
print(build_separator)
|
|
|
|
sys.exit(exit_status)
|