319 lines
13 KiB
Python
319 lines
13 KiB
Python
import sys
|
|
import glob
|
|
import time
|
|
import os
|
|
import subprocess
|
|
import collections
|
|
|
|
# optional wall option cause build failed if has warnings
|
|
BUILD_WALL = False
|
|
if "--wall" in sys.argv:
|
|
BUILD_WALL = True
|
|
sys.argv.remove("--wall")
|
|
|
|
# add user bin to path!
|
|
BUILD_DIR = ''
|
|
# add user bin to path!
|
|
try:
|
|
# If we're on actions
|
|
BUILD_DIR = os.environ["GITHUB_WORKSPACE"]
|
|
except KeyError:
|
|
try:
|
|
# If we're on travis
|
|
BUILD_DIR = os.environ["TRAVIS_BUILD_DIR"]
|
|
except KeyError:
|
|
# If we're running on local machine
|
|
BUILD_DIR = os.path.abspath(".")
|
|
pass
|
|
|
|
os.environ["PATH"] += os.pathsep + BUILD_DIR + "/bin"
|
|
print("build dir:", BUILD_DIR)
|
|
|
|
IS_LEARNING_SYS = False
|
|
if "Adafruit_Learning_System_Guides" in BUILD_DIR:
|
|
print("Found learning system repo")
|
|
IS_LEARNING_SYS = True
|
|
elif "METROX-Examples-and-Project-Sketches" in BUILD_DIR:
|
|
print("Found MetroX Examples Repo")
|
|
IS_LEARNING_SYS = True
|
|
|
|
#os.system('pwd')
|
|
#os.system('ls -lA')
|
|
|
|
CROSS = u'\N{cross mark}'
|
|
CHECK = u'\N{check mark}'
|
|
|
|
ALL_PLATFORMS={
|
|
# classic Arduino AVR
|
|
"uno" : "arduino:avr:uno",
|
|
"leonardo" : "arduino:avr:leonardo",
|
|
"mega2560" : "arduino:avr:mega:cpu=atmega2560",
|
|
# Arduino SAMD
|
|
"zero" : "arduino:samd:arduino_zero_native",
|
|
"cpx" : "arduino:samd:adafruit_circuitplayground_m0",
|
|
# Espressif
|
|
"esp8266" : "esp8266:esp8266:huzzah:eesz=4M3M,xtal=80",
|
|
"esp32" : "esp32:esp32:featheresp32:FlashFreq=80",
|
|
"magtag" : "esp32:esp32:adafruit_magtag29_esp32s2",
|
|
"funhouse" : "esp32:esp32:adafruit_funhouse_esp32s2",
|
|
"metroesp32s2" : "esp32:esp32:adafruit_metro_esp32s2",
|
|
# Adafruit AVR
|
|
"trinket_3v" : "adafruit:avr:trinket3",
|
|
"trinket_5v" : "adafruit:avr:trinket5",
|
|
"protrinket_3v" : "adafruit:avr:protrinket3",
|
|
"protrinket_5v" : "adafruit:avr:protrinket5",
|
|
"gemma" : "adafruit:avr:gemma",
|
|
"flora" : "adafruit:avr:flora8",
|
|
"feather32u4" : "adafruit:avr:feather32u4",
|
|
"cpc" : "arduino:avr:circuitplay32u4cat",
|
|
# Adafruit SAMD
|
|
"gemma_m0" : "adafruit:samd:adafruit_gemma_m0",
|
|
"trinket_m0" : "adafruit:samd:adafruit_trinket_m0",
|
|
"feather_m0_express" : "adafruit:samd:adafruit_feather_m0_express",
|
|
"feather_m4_can" : "adafruit:samd:adafruit_feather_m4_can:speed=120",
|
|
"feather_m4_can_tinyusb" : "adafruit:samd:adafruit_feather_m4_can:speed=120,usbstack=tinyusb",
|
|
"metro_m0" : "adafruit:samd:adafruit_metro_m0",
|
|
"metro_m0_tinyusb" : "adafruit:samd:adafruit_metro_m0:usbstack=tinyusb",
|
|
"metro_m4" : "adafruit:samd:adafruit_metro_m4:speed=120",
|
|
"metro_m4_tinyusb" : "adafruit:samd:adafruit_metro_m4:speed=120,usbstack=tinyusb",
|
|
"metro_m4_airliftlite" : "adafruit:samd:adafruit_metro_m4_airliftlite:speed=120",
|
|
"metro_m4_airliftlite_tinyusb" : "adafruit:samd:adafruit_metro_m4_airliftlite:speed=120,usbstack=tinyusb",
|
|
"pybadge" : "adafruit:samd:adafruit_pybadge_m4:speed=120",
|
|
"pybadge_tinyusb" : "adafruit:samd:adafruit_pybadge_m4:speed=120,usbstack=tinyusb",
|
|
"pygamer" : "adafruit:samd:adafruit_pygamer_m4:speed=120",
|
|
"hallowing_m0" : "adafruit:samd:adafruit_hallowing",
|
|
"hallowing_m4" : "adafruit:samd:adafruit_hallowing_m4:speed=120",
|
|
"hallowing_m4_tinyusb" : "adafruit:samd:adafruit_hallowing_m4:speed=120,usbstack=tinyusb",
|
|
"neotrellis_m4" : "adafruit:samd:adafruit_trellis_m4:speed=120",
|
|
"monster_m4sk" : "adafruit:samd:adafruit_monster_m4sk:speed=120",
|
|
"monster_m4sk_tinyusb" : "adafruit:samd:adafruit_monster_m4sk:speed=120,usbstack=tinyusb",
|
|
"pyportal" : "adafruit:samd:adafruit_pyportal_m4:speed=120",
|
|
"pyportal_tinyusb" : "adafruit:samd:adafruit_pyportal_m4:speed=120,usbstack=tinyusb",
|
|
"pyportal_titano" : "adafruit:samd:adafruit_pyportal_m4_titano:speed=120",
|
|
"pyportal_titano_tinyusb" : "adafruit:samd:adafruit_pyportal_m4_titano:speed=120,usbstack=tinyusb",
|
|
"cpx_ada" : "adafruit:samd:adafruit_circuitplayground_m0",
|
|
"grand_central" : "adafruit:samd:adafruit_grandcentral_m4:speed=120",
|
|
"grand_central_tinyusb" : "adafruit:samd:adafruit_grandcentral_m4:speed=120,usbstack=tinyusb",
|
|
"matrixportal" : "adafruit:samd:adafruit_matrixportal_m4:speed=120",
|
|
"matrixportal_tinyusb" : "adafruit:samd:adafruit_matrixportal_m4:speed=120,usbstack=tinyusb",
|
|
"neotrinkey_m0" : "adafruit:samd:adafruit_neotrinkey_m0",
|
|
"rotarytrinkey_m0" : "adafruit:samd:adafruit_rotarytrinkey_m0",
|
|
"neokeytrinkey_m0" : "adafruit:samd:adafruit_neokeytrinkey_m0",
|
|
"slidetrinkey_m0" : "adafruit:samd:adafruit_slidetrinkey_m0",
|
|
"proxlighttrinkey_m0" : "adafruit:samd:adafruit_proxlighttrinkey_m0",
|
|
# Arduino nRF
|
|
"microbit" : "sandeepmistry:nRF5:BBCmicrobit:softdevice=s130",
|
|
# Adafruit nRF
|
|
"nrf52832" : "adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0",
|
|
"nrf52840" : "adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0",
|
|
"cpb" : "adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0",
|
|
"clue" : "adafruit:nrf52:cluenrf52840:softdevice=s140v6,debug=l0",
|
|
# RP2040 (Philhower)
|
|
"pico_rp2040" : "rp2040:rp2040:rpipico:freq=125,flash=2097152_0",
|
|
"pico_rp2040_tinyusb" : "rp2040:rp2040:rpipico:flash=2097152_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb",
|
|
"feather_rp2040" : "rp2040:rp2040:adafruitfeather:freq=125,flash=8388608_0",
|
|
"feather_rp2040_tinyusb" : "rp2040:rp2040:adafruit_feather:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb",
|
|
"qt2040_trinkey" : "rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0",
|
|
"qt2040_trinkey_tinyusb" : "rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb"
|
|
# Attiny8xy (SpenceKonde)
|
|
"attiny817" : "megaTinyCore:megaavr:atxy7:chip=817",
|
|
"attiny816" : "megaTinyCore:megaavr:atxy6:chip=816",
|
|
"attiny807" : "megaTinyCore:megaavr:atxy7:chip=807",
|
|
"attiny806" : "megaTinyCore:megaavr:atxy6:chip=806",
|
|
# groupings
|
|
"main_platforms" : ("uno", "leonardo", "mega2560", "zero",
|
|
"esp8266", "esp32", "metro_m4", "trinket_m0"),
|
|
"arcada_platforms" : ("pybadge", "pygamer", "hallowing_m4",
|
|
"cpb", "cpx_ada"),
|
|
"rp2040_platforms" : ("pico_rp2040", "feather_rp2040")
|
|
}
|
|
|
|
BSP_URLS = "https://adafruit.github.io/arduino-board-index/package_adafruit_index.json,http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json,https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json,https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json,http://drazzy.com/package_drazzy.com_index.json"
|
|
|
|
class ColorPrint:
|
|
|
|
@staticmethod
|
|
def print_fail(message, end = '\n'):
|
|
sys.stdout.write('\x1b[1;31m' + message.strip() + '\x1b[0m' + end)
|
|
|
|
@staticmethod
|
|
def print_pass(message, end = '\n'):
|
|
sys.stdout.write('\x1b[1;32m' + message.strip() + '\x1b[0m' + end)
|
|
|
|
@staticmethod
|
|
def print_warn(message, end = '\n'):
|
|
sys.stdout.write('\x1b[1;33m' + message.strip() + '\x1b[0m' + end)
|
|
|
|
@staticmethod
|
|
def print_info(message, end = '\n'):
|
|
sys.stdout.write('\x1b[1;34m' + message.strip() + '\x1b[0m' + end)
|
|
|
|
@staticmethod
|
|
def print_bold(message, end = '\n'):
|
|
sys.stdout.write('\x1b[1;37m' + message.strip() + '\x1b[0m' + end)
|
|
|
|
|
|
def install_platform(platform):
|
|
print("Installing", platform, end=" ")
|
|
if platform == "adafruit:avr": # we have a platform dep
|
|
install_platform("arduino:avr")
|
|
if os.system("arduino-cli core install "+platform+" --additional-urls "+BSP_URLS+" > /dev/null") != 0:
|
|
ColorPrint.print_fail("FAILED to install "+platform)
|
|
exit(-1)
|
|
ColorPrint.print_pass(CHECK)
|
|
|
|
def run_or_die(cmd, error):
|
|
print(cmd)
|
|
if os.system(cmd) != 0:
|
|
ColorPrint.print_fail(error)
|
|
exit(-1)
|
|
|
|
################################ Install Arduino IDE
|
|
print()
|
|
ColorPrint.print_info('#'*40)
|
|
print("INSTALLING ARDUINO BOARDS")
|
|
ColorPrint.print_info('#'*40)
|
|
|
|
run_or_die("arduino-cli core update-index --additional-urls "+BSP_URLS+
|
|
" > /dev/null", "FAILED to update core indecies")
|
|
print()
|
|
|
|
# link test library folder to the arduino libraries folder
|
|
if not IS_LEARNING_SYS:
|
|
try:
|
|
os.symlink(BUILD_DIR, os.environ['HOME']+'/Arduino/libraries/Adafruit_Test_Library')
|
|
except FileExistsError:
|
|
pass
|
|
|
|
################################ Install dependancies
|
|
our_name=None
|
|
try:
|
|
if IS_LEARNING_SYS:
|
|
libprop = open(BUILD_DIR+'/library.deps')
|
|
else:
|
|
libprop = open(BUILD_DIR+'/library.properties')
|
|
for line in libprop:
|
|
if line.startswith("name="):
|
|
our_name = line.replace("name=", "").strip()
|
|
if line.startswith("depends="):
|
|
deps = line.replace("depends=", "").split(",")
|
|
for dep in deps:
|
|
dep = dep.strip()
|
|
print("Installing "+dep)
|
|
run_or_die('arduino-cli lib install "'+dep+'" > /dev/null',
|
|
"FAILED to install dependancy "+dep)
|
|
except OSError:
|
|
print("No library dep or properties found!")
|
|
pass # no library properties
|
|
|
|
# Delete the existing library if we somehow downloaded
|
|
# due to dependancies
|
|
if our_name:
|
|
run_or_die("arduino-cli lib uninstall \""+our_name+"\"", "Could not uninstall")
|
|
|
|
print("Libraries installed: ", glob.glob(os.environ['HOME']+'/Arduino/libraries/*'))
|
|
|
|
################################ Test platforms
|
|
platforms = []
|
|
success = 0
|
|
|
|
# expand groups:
|
|
for arg in sys.argv[1:]:
|
|
platform = ALL_PLATFORMS.get(arg, None)
|
|
if isinstance(platform, str):
|
|
platforms.append(arg)
|
|
elif isinstance(platform, collections.abc.Iterable):
|
|
for p in platform:
|
|
platforms.append(p)
|
|
else:
|
|
print("Unknown platform: ", arg)
|
|
exit(-1)
|
|
|
|
def test_examples_in_folder(folderpath):
|
|
global success
|
|
for example in sorted(os.listdir(folderpath)):
|
|
examplepath = folderpath+"/"+example
|
|
if os.path.isdir(examplepath):
|
|
test_examples_in_folder(examplepath)
|
|
continue
|
|
if not examplepath.endswith(".ino"):
|
|
continue
|
|
|
|
print('\t'+example, end=' ')
|
|
# check if we should SKIP
|
|
skipfilename = folderpath+"/."+platform+".test.skip"
|
|
onlyfilename = folderpath+"/."+platform+".test.only"
|
|
if os.path.exists(skipfilename):
|
|
ColorPrint.print_warn("skipping")
|
|
continue
|
|
if glob.glob(folderpath+"/.*.test.only") and not os.path.exists(onlyfilename):
|
|
ColorPrint.print_warn("skipping")
|
|
continue
|
|
|
|
cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, examplepath]
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
r = proc.wait()
|
|
out = proc.stdout.read()
|
|
err = proc.stderr.read()
|
|
if r == 0 and not (err and BUILD_WALL == True):
|
|
ColorPrint.print_pass(CHECK)
|
|
if err:
|
|
# also print out warning message
|
|
ColorPrint.print_fail(err.decode("utf-8"))
|
|
else:
|
|
ColorPrint.print_fail(CROSS)
|
|
ColorPrint.print_fail(out.decode("utf-8"))
|
|
ColorPrint.print_fail(err.decode("utf-8"))
|
|
success = 1
|
|
|
|
def test_examples_in_learningrepo(folderpath):
|
|
global success
|
|
for project in os.listdir(folderpath):
|
|
projectpath = folderpath+"/"+project
|
|
if os.path.isdir(learningrepo):
|
|
test_examples_in_learningrepo(projectpath)
|
|
continue
|
|
if not projectpath.endswith(".ino"):
|
|
continue
|
|
# found an INO!
|
|
print('\t'+projectpath, end=' ')
|
|
# check if we should SKIP
|
|
skipfilename = folderpath+"/."+platform+".test.skip"
|
|
onlyfilename = folderpath+"/."+platform+".test.only"
|
|
if os.path.exists(skipfilename):
|
|
ColorPrint.print_warn("skipping")
|
|
continue
|
|
elif glob.glob(folderpath+"/.*.test.only") and not os.path.exists(onlyfilename):
|
|
ColorPrint.print_warn("skipping")
|
|
continue
|
|
|
|
cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, projectpath]
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE)
|
|
r = proc.wait()
|
|
out = proc.stdout.read()
|
|
err = proc.stderr.read()
|
|
if r == 0:
|
|
ColorPrint.print_pass(CHECK)
|
|
if err:
|
|
# also print out warning message
|
|
ColorPrint.print_fail(err.decode("utf-8"))
|
|
else:
|
|
ColorPrint.print_fail(CROSS)
|
|
ColorPrint.print_fail(out.decode("utf-8"))
|
|
ColorPrint.print_fail(err.decode("utf-8"))
|
|
success = 1
|
|
|
|
|
|
for platform in platforms:
|
|
fqbn = ALL_PLATFORMS[platform]
|
|
print('#'*80)
|
|
ColorPrint.print_info("SWITCHING TO "+fqbn)
|
|
install_platform(":".join(fqbn.split(':', 2)[0:2])) # take only first two elements
|
|
print('#'*80)
|
|
if not IS_LEARNING_SYS:
|
|
test_examples_in_folder(BUILD_DIR+"/examples")
|
|
else:
|
|
test_examples_in_folder(BUILD_DIR)
|
|
exit(success)
|