Compare commits

..

No commits in common. "master" and "dont-warn-learn-library" have entirely different histories.

8 changed files with 258 additions and 429 deletions

View file

@ -1,19 +1,20 @@
name: Github Arduino Library CI name: Github Arduino Library CI
on: [push, pull_request] on: [push]
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: actions/setup-python@v5 - uses: actions/setup-python@v4
with: with:
python-version: '3.x' python-version: '3.x'
- name: pre-install - name: pre-install
run: bash ./actions_install.sh run: bash ./actions_install.sh
- name: test platforms - name: test platforms
run: | run: |
python3 build_platform.py uno leonardo mega2560 zero esp8266 esp32 pico_rp2040 feather_m4_express feather_rp2350 python3 build_platform.py uno leonardo mega2560 zero esp8266 esp32 pico_rp2040 feather_m4_express

2
.gitignore vendored
View file

@ -1,2 +0,0 @@
.DS_Store
.idea

View file

@ -1,93 +1,56 @@
# Arduino CI Scripts # Arduino CI Scripts
This repo contains various scripts and tools related to running continuous integration (CI) checks on Arduino Library Repos. The operations include: This repos contains various scripts and tools related to running
continuous integration (CI) checks on Arduino Library Repos.
* checking formatting using [clang-format](https://clang.llvm.org/docs/ClangFormat.html),
* generating documentation from source comments using [Doxygen](https://www.doxygen.nl/), and
* building each example in the library for selected targets.
There is an associated guide available here: There is an associated guide available here:
https://learn.adafruit.com/the-well-automated-arduino-library/ https://learn.adafruit.com/the-well-automated-arduino-library/
## Adding GitHub Actions to Repo ## Adding GitHub Actions to Repo
To run these continuous integration checks on each push, pull-request or [repository dispatch](https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-dispatch-event) using [GitHub actions](https://github.com/features/actions):
* Create a folder named `.github/worflows` in the root of the repo. * Create a folder named `.github/worflows` in the root of the repo.
* Copy `example_actions.yml` into the above directory and rename it `githubci.yml`. * Copy `example_actions.yml` into the above directory and rename it `githubci.yml`.
* Edit `githubci.yml` and change `PRETTYNAME` to the library repo name. Optionally, delete or comment out steps (using the `#` character), you don't want to include. * Edit `githubci.yml` and change `PRETTYNAME` to the library repo name.
* Here's an example: [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/blob/master/.github/workflows/githubci.yml) * Here's an example: [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/blob/master/.github/workflows/githubci.yml)
* These actions will now run automatically on any pull, push, or dispatch.
## Controlling Test Behavior ## Controlling Test Behavior
The `build_platform.py` script is used to test each `.ino` example in the repo for selected build platforms. The [`ALL_PLATFORMS`](ci-arduino/blob/master/build_platform.py#L54) dictionary contains a listing of all available platforms and selected platform groups. By default, `main_platforms` is used. To select a specific platform or group, replace `main_platforms` in [`githubci.yml`](`example_actions.yml`) with the group or platform name. The `build_platform.py` script is used to test each `.ino` example in the repo for the
selected build platforms. The `ALL_PLATFORMS` dictionary contains a listing of all
available platforms. By default, `main_platforms` is used. Additionally, UF2 files
of the compiled sketches can be generated for supported platforms. The behavior
can be controlled using special hidden filenames. These are just empty files
placed in the root folder:
Additionally, [UF2 files](https://github.com/microsoft/uf2) of the compiled sketches can be generated for supported platforms. * `.YOUR_PLATFORM_HERE.test.skip` - Skip the specified platform. All others are tested.
* `.YOUR_PLATFORM_HERE.test.only` - Test only the specfied platform. All others are skipped.
* `.YOUR_PLATFORM_HERE.generate` - Generate UF2 of sketch for specified platform (if supported).
### Fine tuning test selection Replace `YOUR_PLATFORM_HERE` in the name with exact text from `ALL_PLATFORMS`.
The script behavior can be controlled using special filenames: ### Examples
* `.PLATFORM_ID.test.skip` - Skip the specified platform. All others are tested.
* `.PLATFORM_ID.test.only` - Test the specified platform. All others are skipped.
* `.PLATFORM_ID.generate` - Generate UF2 of sketch for specified platform (if supported).
These are just empty files placed in an example folder. Replace `PLATFORM_ID` in the name with the key from [`ALL_PLATFORMS`](ci-arduino/blob/master/build_platform.py#L54). `metro_m0` from the following line in `build_platform.py`, for example:
```python
"metro_m0" : ["adafruit:samd:adafruit_metro_m0", "0x68ed2b88", None],
```
You can use several `.PLATFORM_ID.test.skip` or `.PLATFORM_ID.test.only` to exclude or include multiple platforms. For example:
* To **skip** testing on ESP8266, add a file named `.esp8266.test.skip` * To **skip** testing on ESP8266, add a file named `.esp8266.test.skip`
* To test **only** the Arduino UNO, add a file named `.uno.test.only` * To test **only** the Arduino UNO, add a file named `.uno.test.only`
* To skip all and test **nothing**, add a file named `.none.test.only` * To skip all and test **nothing**, add a file named `.none.test.only`
* To generate UF2s for PyPortal, add a file named `.pyportal.generate` * To generate UF2s for PyPortal, add a file named `.pyportal.generate`
### Dependencies
Any library dependencies included in the [`library.properties`](https://arduino.github.io/arduino-cli/0.19/library-specification/#libraryproperties-file-format) are automatically installed before the tests are started. To install additional dependencies (e.g., those required for some examples but not the library itself) using [`arduino-cli`](https://arduino.github.io/arduino-cli/0.19/commands/arduino-cli_lib_install/), you could add additional steps to the `githubci.yml` file. For example:
```yaml
- name: Set configuration
run: arduino-cli config set library.enable_unsafe_install true
- name: Install test dependencies
run: arduino-cli lib install --git-url https://github.com/arduino-libraries/Servo --git-url https://github.com/arduino-libraries/Ethernet
```
Note: you'll only need to enable the [`enable_unsafe_install`](https://arduino.github.io/arduino-cli/0.32/configuration/#configuration-keys) option if you want to identify libraries using urls. This isn't necessary when using the library name.
## Formatting Check with Clang ## Formatting Check with Clang
The `run-clang-format.py` script is used to run [clang-format](https://clang.llvm.org/docs/ClangFormat.html) and check file formatting. The `run-clang-format.py` script is used to run ClangFormat and check file formatting.
See [the guide](https://learn.adafruit.com/the-well-automated-arduino-library/formatting-with-clang-format) for details on installing `clang-format` to run formatting locally. See [the guide](https://learn.adafruit.com/the-well-automated-arduino-library/formatting-with-clang-format) for details on installing `clang-format` to run formatting locally.
Even a single extra white space can cause the CI to fail on formatting. Even a single extra white space can cause the CI to fail on formatting.
You can typically just let clang do its thing and edit files in place using: You can typically just let clang do its thing and edit files in place using:
``` ```
clang-format -i File_To_Format.cpp clang-format -i File_To_Format.cpp
``` ```
## Documentation with Doxygen ## Documentation with Doxygen
The `doxy_gen_and_deploy.sh` script uses [Doxygen](https://www.doxygen.nl/) to generate and deploy documentation The `doxy_gen_and_deploy.sh` script uses Doxygen to generate and deploy documentation
for the library. Any issues, like missing documentation, will cause the CI to fail. for the library. Any issues, like missing documentation, will cause the CI to fail.
See the [guide](https://learn.adafruit.com/the-well-automated-arduino-library/doxygen) for details on installing and running Doxygen locally. The guide also has some See the [the guide](https://learn.adafruit.com/the-well-automated-arduino-library/doxygen)
[tips](https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips) on basic usage of Doxygen markup within your code. for details on installing and running doxygen locally. The guide also has some
[tips](https://learn.adafruit.com/the-well-automated-arduino-library/doxygen-tips)
### Preserving Folders in Documentation Branch on basic usage of doxygen markup within your code.
By default, the documentation deployment script cleans the gh-pages branch before adding new documentation. If you need to preserve certain folders (like custom web interfaces), you can set the `PRESERVE_FOLDERS` environment variable in your workflow:
```yaml
- name: doxygen
env:
GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }}
PRETTYNAME : "My Arduino Library"
PRESERVE_FOLDERS: "webserial,assets"
run: bash ci/doxy_gen_and_deploy.sh
```
This will preserve the listed folders (comma-separated) during the documentation generation process.

View file

@ -37,8 +37,7 @@ arduino-cli core update-index > /dev/null
case "$GITHUB_REPOSITORY" in case "$GITHUB_REPOSITORY" in
(*/ci-arduino|*/Adafruit_Learning_System_Guides) ;; (*/ci-arduino|*/Adafruit_Learning_System_Guides) ;;
(*) (*)
repo_topics=$(curl -f --request GET --url "https://api.github.com/repos/$GITHUB_REPOSITORY" || echo '{"topics":[]}') repo_topics=$(curl --request GET --url "https://api.github.com/repos/$GITHUB_REPOSITORY" | jq -r '.topics[]')
repo_topics=$(echo $repo_topics | jq -r '.topics[]' )
if [[ ! $repo_topics =~ "arduino-library" ]]; then if [[ ! $repo_topics =~ "arduino-library" ]]; then
echo "::warning::arduino-library is not found in this repo topics. Please add this tag in repo About" echo "::warning::arduino-library is not found in this repo topics. Please add this tag in repo About"
fi fi

View file

@ -1,179 +0,0 @@
# board: [ platform, uf2_family, manual core URL]
ALL_PLATFORMS={
# classic Arduino AVR
"uno" : ["arduino:avr:uno", None, None],
"leonardo" : ["arduino:avr:leonardo", None, None],
"mega2560" : ["arduino:avr:mega:cpu=atmega2560", None, None],
# Arduino SAMD
"zero" : ["arduino:samd:arduino_zero_native", "0x68ed2b88", None, None],
"cpx" : ["arduino:samd:adafruit_circuitplayground_m0", "0x68ed2b88", None],
# Arduino MBED GIGA
"giga" : ["arduino:mbed_giga:giga", None, None],
# Espressif
"esp8266" : ["esp8266:esp8266:huzzah:eesz=4M3M,xtal=80", None, None],
"esp32" : ["esp32:esp32:featheresp32:FlashFreq=80", None, None],
"itsybitsy_esp32" : ["esp32:esp32:adafruit_itsybitsy_esp32:FlashFreq=80", None, None],
"feather_esp8266" : ["esp8266:esp8266:huzzah:xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=115200", None, None],
"feather_esp32" : ["esp32:esp32:featheresp32:FlashFreq=80", None, None],
"wippersnapper_feather_esp32" : ["esp32:esp32:featheresp32:FlashFreq=80,PartitionScheme=min_spiffs", None, None],
"feather_esp32_v2" : ["esp32:esp32:adafruit_feather_esp32_v2", None, None],
"qtpy_esp32" : ["esp32:esp32:adafruit_qtpy_esp32_pico", None, None],
"sparklemotion_esp32" : ["esp32:esp32:sparklemotion", None, None],
"sparklemotionmini_esp32" : ["esp32:esp32:sparklemotionmini", None, None],
## ESP32-C3/C6
"feather_esp32c6" : ["esp32:esp32:adafruit_feather_esp32c6:FlashMode=qio", None, None],
"wippersnapper_feather_esp32c6" : ["esp32:esp32:adafruit_feather_esp32c6:CDCOnBoot=cdc,CPUFreq=160,FlashFreq=80,FlashMode=qio,PartitionScheme=min_spiffs", None, None],
"wippersnapper_feather_esp32c6_debug" : ["esp32:esp32:adafruit_feather_esp32c6:CDCOnBoot=cdc,DebugLevel=verbose,CPUFreq=160,FlashFreq=80,FlashMode=qio,PartitionScheme=min_spiffs", None, None],
"qtpy_esp32c3" : ["esp32:esp32:adafruit_qtpy_esp32c3:FlashMode=qio", None, None],
"wippersnapper_qtpy_esp32c3" : ["esp32:esp32:adafruit_qtpy_esp32c3:FlashMode=qio,PartitionScheme=min_spiffs", None, None],
## ESP32-S2
"magtag" : ["esp32:esp32:adafruit_magtag29_esp32s2", "0xbfdd4eee", None],
"funhouse" : ["esp32:esp32:adafruit_funhouse_esp32s2", "0xbfdd4eee", None],
"funhouse_noota" : ["esp32:esp32:adafruit_funhouse_esp32s2:PartitionScheme=tinyuf2_noota", "0xbfdd4eee", None],
"metroesp32s2" : ["esp32:esp32:adafruit_metro_esp32s2", "0xbfdd4eee", None],
"qtpy_esp32s2" : ["esp32:esp32:adafruit_qtpy_esp32s2", "0xbfdd4eee", None],
"feather_esp32s2" : ["esp32:esp32:adafruit_feather_esp32s2", "0xbfdd4eee", None],
"feather_esp32s2_debug" : ["esp32:esp32:adafruit_feather_esp32s2:DebugLevel=verbose", "0xbfdd4eee", None],
"feather_esp32s2_tft" : ["esp32:esp32:adafruit_feather_esp32s2_tft", "0xbfdd4eee", None],
"feather_esp32s2_tft_debug" : ["esp32:esp32:adafruit_feather_esp32s2_tft:DebugLevel=verbose", "0xbfdd4eee", None],
"feather_esp32s2_reverse_tft" : ["esp32:esp32:adafruit_feather_esp32s2_reversetft", "0xbfdd4eee", None],
## ESP32-S3
"feather_esp32s3" : ["esp32:esp32:adafruit_feather_esp32s3_nopsram", "0xc47e5767", None],
"feather_esp32s3_debug" : ["esp32:esp32:adafruit_feather_esp32s3_nopsram:DebugLevel=verbose", "0xc47e5767", None],
"feather_esp32s3_4mbflash_2mbpsram" : ["esp32:esp32:adafruit_feather_esp32s3", "0xc47e5767", None],
"feather_esp32s3_4mbflash_2mbpsram_debug" : ["esp32:esp32:adafruit_feather_esp32s3:DebugLevel=verbose", "0xc47e5767", None],
"feather_esp32s3_tft" : ["esp32:esp32:adafruit_feather_esp32s3_tft", "0xc47e5767", None],
"feather_esp32s3_tft_debug" : ["esp32:esp32:adafruit_feather_esp32s3_tft:DebugLevel=verbose", "0xc47e5767", None],
"feather_esp32s3_reverse_tft" : ["esp32:esp32:adafruit_feather_esp32s3_reversetft", "0xc47e5767", None],
"feather_esp32s3_reverse_tft_debug" : ["esp32:esp32:adafruit_feather_esp32s3_reversetft:DebugLevel=verbose", "0xc47e5767", None],
"matrixportal_s3" : ["esp32:esp32:adafruit_matrixportal_esp32s3", "0xc47e5767", None],
"metro_esp32s3" : ["esp32:esp32:adafruit_metro_esp32s3", "0xc47e5767", None],
"pycamera_s3" : ["esp32:esp32:adafruit_camera_esp32s3", "0xc47e5767", None],
"qualia_s3_rgb666" : ["esp32:esp32:adafruit_qualia_s3_rgb666", "0xc47e5767", None],
"qtpy_esp32s3" : ["esp32:esp32:adafruit_qtpy_esp32s3_nopsram", "0xc47e5767", None],
"qtpy_esp32s3_n4r2" : ["esp32:esp32:adafruit_qtpy_esp32s3_n4r2", "0xc47e5767", None],
# ESP32-P4
"esp32p4" : ["esp32:esp32:esp32p4:JTAGAdapter=default,PSRAM=disabled,USBMode=default,CDCOnBoot=cdc,MSCOnBoot=default,DFUOnBoot=default,UploadMode=default,PartitionScheme=default,CPUFreq=360,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none,EraseFlash=none", "0x3d308e94", None],
# Adafruit AVR
"trinket_3v" : ["adafruit:avr:trinket3", None, None],
"trinket_5v" : ["adafruit:avr:trinket5", None, None],
"protrinket_3v" : ["adafruit:avr:protrinket3", None, None],
"protrinket_5v" : ["adafruit:avr:protrinket5", None, None],
"gemma" : ["adafruit:avr:gemma", None, None],
"flora" : ["adafruit:avr:flora8", None, None],
"feather32u4" : ["adafruit:avr:feather32u4", None, None],
"cpc" : ["arduino:avr:circuitplay32u4cat", None, None],
# Adafruit SAMD
"gemma_m0" : ["adafruit:samd:adafruit_gemma_m0", "0x68ed2b88", None],
"trinket_m0" : ["adafruit:samd:adafruit_trinket_m0", "0x68ed2b88", None],
"feather_m0_express" : ["adafruit:samd:adafruit_feather_m0_express", "0x68ed2b88", None],
"feather_m0_express_tinyusb" : ["adafruit:samd:adafruit_feather_m0_express:usbstack=tinyusb", "0x68ed2b88", None],
"feather_m4_express" : ["adafruit:samd:adafruit_feather_m4:speed=120", "0x55114460", None],
"feather_m4_express_tinyusb" : ["adafruit:samd:adafruit_feather_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"feather_m4_can" : ["adafruit:samd:adafruit_feather_m4_can:speed=120", "0x55114460", None],
"feather_m4_can_tinyusb" : ["adafruit:samd:adafruit_feather_m4_can:speed=120,usbstack=tinyusb", "0x55114460", None],
"metro_m0" : ["adafruit:samd:adafruit_metro_m0", "0x68ed2b88", None],
"metro_m0_tinyusb" : ["adafruit:samd:adafruit_metro_m0:usbstack=tinyusb", "0x68ed2b88", None],
"metro_m4" : ["adafruit:samd:adafruit_metro_m4:speed=120", "0x55114460", None],
"metro_m4_tinyusb" : ["adafruit:samd:adafruit_metro_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"metro_m4_airliftlite" : ["adafruit:samd:adafruit_metro_m4_airliftlite:speed=120", "0x55114460", None],
"metro_m4_airliftlite_tinyusb" : ["adafruit:samd:adafruit_metro_m4_airliftlite:speed=120,usbstack=tinyusb", "0x55114460", None],
"pybadge" : ["adafruit:samd:adafruit_pybadge_m4:speed=120", "0x55114460", None],
"pybadge_tinyusb" : ["adafruit:samd:adafruit_pybadge_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"pygamer" : ["adafruit:samd:adafruit_pygamer_m4:speed=120", "0x55114460", None],
"pygamer_tinyusb" : ["adafruit:samd:adafruit_pygamer_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"hallowing_m0" : ["adafruit:samd:adafruit_hallowing", "0x68ed2b88", None],
"hallowing_m4" : ["adafruit:samd:adafruit_hallowing_m4:speed=120", "0x55114460", None],
"hallowing_m4_tinyusb" : ["adafruit:samd:adafruit_hallowing_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"neotrellis_m4" : ["adafruit:samd:adafruit_trellis_m4:speed=120", "0x55114460", None],
"monster_m4sk" : ["adafruit:samd:adafruit_monster_m4sk:speed=120", "0x55114460", None],
"monster_m4sk_tinyusb" : ["adafruit:samd:adafruit_monster_m4sk:speed=120,usbstack=tinyusb", "0x55114460", None],
"pyportal" : ["adafruit:samd:adafruit_pyportal_m4:speed=120", "0x55114460", None],
"pyportal_tinyusb" : ["adafruit:samd:adafruit_pyportal_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"pyportal_titano" : ["adafruit:samd:adafruit_pyportal_m4_titano:speed=120", "0x55114460", None],
"pyportal_titano_tinyusb" : ["adafruit:samd:adafruit_pyportal_m4_titano:speed=120,usbstack=tinyusb", "0x55114460", None],
"cpx_ada" : ["adafruit:samd:adafruit_circuitplayground_m0", "0x68ed2b88", None],
"grand_central" : ["adafruit:samd:adafruit_grandcentral_m4:speed=120", "0x55114460", None],
"grand_central_tinyusb" : ["adafruit:samd:adafruit_grandcentral_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"matrixportal" : ["adafruit:samd:adafruit_matrixportal_m4:speed=120", "0x55114460", None],
"matrixportal_tinyusb" : ["adafruit:samd:adafruit_matrixportal_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"neotrinkey_m0" : ["adafruit:samd:adafruit_neotrinkey_m0", "0x68ed2b88", None],
"rotarytrinkey_m0" : ["adafruit:samd:adafruit_rotarytrinkey_m0", "0x68ed2b88", None],
"neokeytrinkey_m0" : ["adafruit:samd:adafruit_neokeytrinkey_m0", "0x68ed2b88", None],
"slidetrinkey_m0" : ["adafruit:samd:adafruit_slidetrinkey_m0", "0x68ed2b88", None],
"proxlighttrinkey_m0" : ["adafruit:samd:adafruit_proxlighttrinkey_m0", "0x68ed2b88", None],
"trrstrinkey_m0" : ["adafruit:samd:adafruit_trrstrinkey_m0", "0x68ed2b88", None],
"thumbsticktrinkey_m0" : ["adafruit:samd:adafruit_thumbsticktrinkey_m0", "0x68ed2b88", None],
"sht4xtrinkey_m0" : ["adafruit:samd:adafruit_sht4xtrinkey_m0", "0x68ed2b88", None],
"pixeltrinkey_m0" : ["adafruit:samd:adafruit_pixeltrinkey_m0", "0x68ed2b88", None],
"X_m0" : ["adafruit:samd:adafruit_X_m0", "0x68ed2b88", None],
"qtpy_m0" : ["adafruit:samd:adafruit_qtpy_m0", "0x68ed2b88", None],
"qtpy_m0_tinyusb" : ["adafruit:samd:adafruit_qtpy_m0:usbstack=tinyusb", "0x68ed2b88", None],
# Arduino SAMD
"mkrwifi1010" : ["arduino:samd:mkrwifi1010", "0x8054", None],
"nano_33_iot" : ["arduino:samd:nano_33_iot", "0x8057", None],
# Arduino nRF
"microbit" : ["sandeepmistry:nRF5:BBCmicrobit:softdevice=s110", None, None],
# Adafruit nRF
"nrf52832" : ["adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0", None, None],
"nrf52840" : ["adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0", "0xada52840", None],
"cpb" : ["adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0", "0xada52840", None],
"clue" : ["adafruit:nrf52:cluenrf52840:softdevice=s140v6,debug=l0", "0xada52840", None],
"ledglasses_nrf52840" : ["adafruit:nrf52:ledglasses_nrf52840:softdevice=s140v6,debug=l0", "0xada52840", None],
# RP2040 & RP2350 (Philhower)
"pico_rp2040" : ["rp2040:rp2040:rpipico:freq=125,flash=2097152_0", "0xe48bff56", None],
"pico_rp2040_tinyusb" : ["rp2040:rp2040:rpipico:flash=2097152_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"pico_rp2040_tinyusb_host" : ["rp2040:rp2040:rpipico:flash=2097152_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb_host", "0xe48bff56", None],
"pico_rp2350" : ["rp2040:rp2040:rpipico2:freq=125,flash=4194304_0", "0xe48bff56", None],
"pico_rp2350_tinyusb" : ["rp2040:rp2040:rpipico2:flash=4194304_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"pico_rp2350_tinyusb_host" : ["rp2040:rp2040:rpipico2:flash=4194304_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb_host", "0xe48bff56", None],
"picow_rp2040" : ["rp2040:rp2040:rpipicow:flash=2097152_0,freq=125", "0xe48bff56", None],
"picow_rp2040_tinyusb" : ["rp2040:rp2040:rpipicow:flash=2097152_131072,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2040" : ["rp2040:rp2040:adafruit_feather:freq=125,flash=8388608_0", "0xe48bff56", None],
"feather_rp2040_tinyusb" : ["rp2040:rp2040:adafruit_feather:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2040_adalogger" : ["rp2040:rp2040:adafruit_feather_adalogger:freq=125,flash=8388608_0", "0xe48bff56", None],
"feather_rp2040_adalogger_tinyusb" : ["rp2040:rp2040:adafruit_feather_adalogger:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2040_rfm" : ["rp2040:rp2040:adafruit_feather_rfm:freq=125,flash=8388608_0", "0xe48bff56", None],
"feather_rp2040_rfm_tinyusb" : ["rp2040:rp2040:adafruit_feather_rfm:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2040_dvi" : ["rp2040:rp2040:adafruit_feather_dvi:freq=125,flash=8388608_0", "0xe48bff56", None],
"feather_rp2040_dvi_tinyusb" : ["rp2040:rp2040:adafruit_feather_dvi:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2040_usbhost_tinyusb" : ["rp2040:rp2040:adafruit_feather_usb_host:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2350" : ["rp2040:rp2040:adafruit_feather_rp2350_hstx:arch=arm,flash=8388608_0,freq=150,dbgport=Disabled,dbglvl=None,usbstack=picosdk", "0xe48bff56", None],
"feather_rp2350_tinyusb" : ["rp2040:rp2040:adafruit_feather_rp2350_hstx:arch=arm,flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"metro_rp2040" : ["rp2040:rp2040:adafruit_metro:flash=16777216_0,freq=200,dbgport=Disabled,dbglvl=None,usbstack=picosdk", "0xe48bff56", None],
"metro_rp2040_tinyusb" : ["rp2040:rp2040:adafruit_metro:flash=16777216_0,freq=200,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"metro_rp2350" : ["rp2040:rp2040:adafruit_metro_rp2350:arch=arm,flash=16777216_0,freq=150,dbgport=Disabled,dbglvl=None,usbstack=picosdk", "0xe48bff56", None],
"metro_rp2350_tinyusb" : ["rp2040:rp2040:adafruit_metro_rp2350:arch=arm,flash=16777216_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"qt2040_trinkey" : ["rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0,freq=125","0xe48bff56", None],
"qt2040_trinkey_tinyusb" : ["rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"qt_py_rp2040": ["rp2040:rp2040:adafruit_qtpy:freq=125,flash=8388608_0", "0xe48bff56", None],
"qt_py_rp2040_tinyusb": ["rp2040:rp2040:adafruit_qtpy:flash=8388608_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"itsybitsy_rp2040" : ["rp2040:rp2040:adafruit_itsybitsy:freq=125,flash=8388608_524288", "0xe48bff56", None],
"itsybitsy_rp2040_tinyusb" : ["rp2040:rp2040:adafruit_itsybitsy:flash=8388608_524288,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"floppsy_rp2040" : ["rp2040:rp2040:adafruit_floppsy:freq=125,flash=16777216_14680064", "0xe48bff56", None],
"floppsy_rp2040_tinyusb" : ["rp2040:rp2040:adafruit_floppsy:flash=16777216_14680064,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"fruit_jam" : ["rp2040:rp2040:adafruit_fruitjam:arch=arm,flash=16777216_0,freq=150,dbgport=Disabled,dbglvl=None,usbstack=picosdk", "0xe48bff56", None],
"fruit_jam_tinyusb" : ["rp2040:rp2040:adafruit_fruitjam:arch=arm,flash=16777216_0,freq=120,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
# Attiny8xy, 16xy, 32xy (SpenceKonde)
"attiny3217" : ["megaTinyCore:megaavr:atxy7:chip=3217", None, None],
"attiny3216" : ["megaTinyCore:megaavr:atxy6:chip=3216", None, None],
"attiny1617" : ["megaTinyCore:megaavr:atxy7:chip=1617", None, None],
"attiny1616" : ["megaTinyCore:megaavr:atxy6:chip=1616", None, None],
"attiny1607" : ["megaTinyCore:megaavr:atxy7:chip=1607", None, None],
"attiny1606" : ["megaTinyCore:megaavr:atxy6:chip=1606", None, None],
"attiny817" : ["megaTinyCore:megaavr:atxy7:chip=817", None, None],
"attiny816" : ["megaTinyCore:megaavr:atxy6:chip=816", None, None],
"attiny807" : ["megaTinyCore:megaavr:atxy7:chip=807", None, None],
"attiny806" : ["megaTinyCore:megaavr:atxy6:chip=806", None, None],
# CH32v2 (openwch)
"CH32V20x_EVT": ["WCH:ch32v:CH32V20x_EVT", None, None],
# groupings
"main_platforms" : ("uno", "leonardo", "mega2560", "zero", "qtpy_m0",
"esp8266", "esp32", "metro_m4", "trinket_m0"),
"arcada_platforms" : ("pybadge", "pygamer", "hallowing_m4",
"cpb", "cpx_ada"),
"wippersnapper_platforms" : ("metro_m4_airliftlite_tinyusb", "pyportal_tinyusb"),
"rp2040_platforms" : ("pico_rp2040", "feather_rp2040", "feather_rp2350")
}

View file

@ -2,12 +2,10 @@ import sys
import glob import glob
import time import time
import os import os
import re
import shutil import shutil
import subprocess import subprocess
import collections import collections
from contextlib import contextmanager from contextlib import contextmanager
from all_platforms import ALL_PLATFORMS
# optional wall option cause build failed if has warnings # optional wall option cause build failed if has warnings
BUILD_WALL = False BUILD_WALL = False
@ -20,15 +18,6 @@ if "--no_warn" in sys.argv:
BUILD_WARN = False BUILD_WARN = False
sys.argv.remove("--no_warn") sys.argv.remove("--no_warn")
# optional timeout argument to extend build time
# for larger sketches or firmware builds
BUILD_TIMEOUT = False
if "--build_timeout" in sys.argv:
BUILD_TIMEOUT = True
popen_timeout = int(sys.argv[sys.argv.index("--build_timeout") + 1])
sys.argv.pop(sys.argv.index("--build_timeout") + 1)
sys.argv.remove("--build_timeout")
# add user bin to path! # add user bin to path!
BUILD_DIR = '' BUILD_DIR = ''
# add user bin to path! # add user bin to path!
@ -62,20 +51,121 @@ elif "METROX-Examples-and-Project-Sketches" in BUILD_DIR:
CROSS = u'\N{cross mark}' CROSS = u'\N{cross mark}'
CHECK = u'\N{check mark}' CHECK = u'\N{check mark}'
BSP_URLS = ( ALL_PLATFORMS={
"https://adafruit.github.io/arduino-board-index/package_adafruit_index.json," # classic Arduino AVR
"http://arduino.esp8266.com/stable/package_esp8266com_index.json," "uno" : ["arduino:avr:uno", None, None],
#"https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json," # esp32 beta release "leonardo" : ["arduino:avr:leonardo", None, None],
"https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json," "mega2560" : ["arduino:avr:mega:cpu=atmega2560", None, None],
"https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json," # Arduino SAMD
"https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json," "zero" : ["arduino:samd:arduino_zero_native", "0x68ed2b88", None, None],
"https://drazzy.good-enough.cloud/package_drazzy.com_index.json," "cpx" : ["arduino:samd:adafruit_circuitplayground_m0", "0x68ed2b88", None],
"https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json" # Espressif
) "esp8266" : ["esp8266:esp8266:huzzah:eesz=4M3M,xtal=80", None, None],
"esp32" : ["esp32:esp32:featheresp32:FlashFreq=80", None, None],
# global exit code "feather_esp8266" : ["esp8266:esp8266:huzzah:xtal=80,vt=flash,exception=disabled,stacksmash=disabled,ssl=all,mmu=3232,non32xfer=fast,eesz=4M2M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none,baud=115200", None, None],
success = 0 "feather_esp32" : ["esp32:esp32:featheresp32:FlashFreq=80", None, None],
"feather_esp32_v2" : ["esp32:esp32:adafruit_feather_esp32_v2", None, None],
"magtag" : ["esp32:esp32:adafruit_magtag29_esp32s2", "0xbfdd4eee", None],
"funhouse" : ["esp32:esp32:adafruit_funhouse_esp32s2", "0xbfdd4eee", None],
"metroesp32s2" : ["esp32:esp32:adafruit_metro_esp32s2", "0xbfdd4eee", None],
"qtpy_esp32s2" : ["esp32:esp32:adafruit_qtpy_esp32s2", "0xbfdd4eee", None],
"feather_esp32s2" : ["esp32:esp32:adafruit_feather_esp32s2", "0xbfdd4eee", None],
"feather_esp32s2_tft" : ["esp32:esp32:adafruit_feather_esp32s2_tft", "0xbfdd4eee", None],
"feather_esp32s3" : ["esp32:esp32:adafruit_feather_esp32s3_nopsram", "0xc47e5767", None],
"feather_esp32s3_4mbflash_2mbpsram" : ["esp32:esp32:adafruit_feather_esp32s3", "0xc47e5767", "adafruit/master"],
"feather_esp32s3_tft" : ["esp32:esp32:adafruit_feather_esp32s3_tft", "0xc47e5767", None],
"qtpy_esp32s3" : ["esp32:esp32:adafruit_qtpy_esp32s3_nopsram", "0xc47e5767", None],
"qtpy_esp32" : ["esp32:esp32:adafruit_qtpy_esp32_pico", None, None],
"qtpy_esp32c3" : ["esp32:esp32:adafruit_qtpy_esp32c3:FlashMode=qio", None, None],
# Adafruit AVR
"trinket_3v" : ["adafruit:avr:trinket3", None, None],
"trinket_5v" : ["adafruit:avr:trinket5", None, None],
"protrinket_3v" : ["adafruit:avr:protrinket3", None, None],
"protrinket_5v" : ["adafruit:avr:protrinket5", None, None],
"gemma" : ["adafruit:avr:gemma", None, None],
"flora" : ["adafruit:avr:flora8", None, None],
"feather32u4" : ["adafruit:avr:feather32u4", None, None],
"cpc" : ["arduino:avr:circuitplay32u4cat", None, None],
# Adafruit SAMD
"gemma_m0" : ["adafruit:samd:adafruit_gemma_m0", "0x68ed2b88", None],
"trinket_m0" : ["adafruit:samd:adafruit_trinket_m0", "0x68ed2b88", None],
"feather_m0_express" : ["adafruit:samd:adafruit_feather_m0_express", "0x68ed2b88", None],
"feather_m0_express_tinyusb" : ["adafruit:samd:adafruit_feather_m0_express:usbstack=tinyusb", "0x68ed2b88", None],
"feather_m4_express" : ["adafruit:samd:adafruit_feather_m4:speed=120", "0x55114460", None],
"feather_m4_express_tinyusb" : ["adafruit:samd:adafruit_feather_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"feather_m4_can" : ["adafruit:samd:adafruit_feather_m4_can:speed=120", "0x55114460", None],
"feather_m4_can_tinyusb" : ["adafruit:samd:adafruit_feather_m4_can:speed=120,usbstack=tinyusb", "0x55114460", None],
"metro_m0" : ["adafruit:samd:adafruit_metro_m0", "0x68ed2b88", None],
"metro_m0_tinyusb" : ["adafruit:samd:adafruit_metro_m0:usbstack=tinyusb", "0x68ed2b88", None],
"metro_m4" : ["adafruit:samd:adafruit_metro_m4:speed=120", "0x55114460", None],
"metro_m4_tinyusb" : ["adafruit:samd:adafruit_metro_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"metro_m4_airliftlite" : ["adafruit:samd:adafruit_metro_m4_airliftlite:speed=120", "0x55114460", None],
"metro_m4_airliftlite_tinyusb" : ["adafruit:samd:adafruit_metro_m4_airliftlite:speed=120,usbstack=tinyusb", "0x55114460", None],
"pybadge" : ["adafruit:samd:adafruit_pybadge_m4:speed=120", "0x55114460", None],
"pybadge_tinyusb" : ["adafruit:samd:adafruit_pybadge_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"pygamer" : ["adafruit:samd:adafruit_pygamer_m4:speed=120", "0x55114460", None],
"pygamer_tinyusb" : ["adafruit:samd:adafruit_pygamer_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"hallowing_m0" : ["adafruit:samd:adafruit_hallowing", "0x68ed2b88", None],
"hallowing_m4" : ["adafruit:samd:adafruit_hallowing_m4:speed=120", "0x55114460", None],
"hallowing_m4_tinyusb" : ["adafruit:samd:adafruit_hallowing_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"neotrellis_m4" : ["adafruit:samd:adafruit_trellis_m4:speed=120", "0x55114460", None],
"monster_m4sk" : ["adafruit:samd:adafruit_monster_m4sk:speed=120", "0x55114460", None],
"monster_m4sk_tinyusb" : ["adafruit:samd:adafruit_monster_m4sk:speed=120,usbstack=tinyusb", "0x55114460", None],
"pyportal" : ["adafruit:samd:adafruit_pyportal_m4:speed=120", "0x55114460", None],
"pyportal_tinyusb" : ["adafruit:samd:adafruit_pyportal_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"pyportal_titano" : ["adafruit:samd:adafruit_pyportal_m4_titano:speed=120", "0x55114460", None],
"pyportal_titano_tinyusb" : ["adafruit:samd:adafruit_pyportal_m4_titano:speed=120,usbstack=tinyusb", "0x55114460", None],
"cpx_ada" : ["adafruit:samd:adafruit_circuitplayground_m0", "0x68ed2b88", None],
"grand_central" : ["adafruit:samd:adafruit_grandcentral_m4:speed=120", "0x55114460", None],
"grand_central_tinyusb" : ["adafruit:samd:adafruit_grandcentral_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"matrixportal" : ["adafruit:samd:adafruit_matrixportal_m4:speed=120", "0x55114460", None],
"matrixportal_tinyusb" : ["adafruit:samd:adafruit_matrixportal_m4:speed=120,usbstack=tinyusb", "0x55114460", None],
"neotrinkey_m0" : ["adafruit:samd:adafruit_neotrinkey_m0", "0x68ed2b88", None],
"rotarytrinkey_m0" : ["adafruit:samd:adafruit_rotarytrinkey_m0", "0x68ed2b88", None],
"neokeytrinkey_m0" : ["adafruit:samd:adafruit_neokeytrinkey_m0", "0x68ed2b88", None],
"slidetrinkey_m0" : ["adafruit:samd:adafruit_slidetrinkey_m0", "0x68ed2b88", None],
"proxlighttrinkey_m0" : ["adafruit:samd:adafruit_proxlighttrinkey_m0", "0x68ed2b88", None],
"qtpy_m0" : ["adafruit:samd:adafruit_qtpy_m0", "0x68ed2b88", None],
"qtpy_m0_tinyusb" : ["adafruit:samd:adafruit_qtpy_m0:usbstack=tinyusb", "0x68ed2b88", None],
# Arduino SAMD
"mkrwifi1010" : ["arduino:samd:mkrwifi1010", "0x8054", None],
"nano_33_iot" : ["arduino:samd:nano_33_iot", "0x8057", None],
# Arduino nRF
"microbit" : ["sandeepmistry:nRF5:BBCmicrobit:softdevice=s110", None, None],
# Adafruit nRF
"nrf52832" : ["adafruit:nrf52:feather52832:softdevice=s132v6,debug=l0", None, None],
"nrf52840" : ["adafruit:nrf52:feather52840:softdevice=s140v6,debug=l0", "0xada52840", None],
"cpb" : ["adafruit:nrf52:cplaynrf52840:softdevice=s140v6,debug=l0", "0xada52840", None],
"clue" : ["adafruit:nrf52:cluenrf52840:softdevice=s140v6,debug=l0", "0xada52840", None],
"ledglasses_nrf52840" : ["adafruit:nrf52:ledglasses_nrf52840:softdevice=s140v6,debug=l0", "0xada52840", None],
# RP2040 (Philhower)
"pico_rp2040" : ["rp2040:rp2040:rpipico:freq=125,flash=2097152_0", "0xe48bff56", None],
"pico_rp2040_tinyusb" : ["rp2040:rp2040:rpipico:flash=2097152_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"feather_rp2040" : ["rp2040:rp2040:adafruit_feather:freq=125,flash=8388608_0", "0xe48bff56", None],
"feather_rp2040_tinyusb" : ["rp2040:rp2040:adafruit_feather:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
"qt2040_trinkey" : ["rp2040:rp2040:adafruit_trinkeyrp2040qt:freq=125,flash=8388608_0", "0xe48bff56", None],
"qt2040_trinkey_tinyusb" : ["rp2040:rp2040:adafruit_trinkeyrp2040qt:flash=8388608_0,freq=125,dbgport=Disabled,dbglvl=None,usbstack=tinyusb", "0xe48bff56", None],
# Attiny8xy, 16xy, 32xy (SpenceKonde)
"attiny3217" : ["megaTinyCore:megaavr:atxy7:chip=3217", None, None],
"attiny3216" : ["megaTinyCore:megaavr:atxy6:chip=3216", None, None],
"attiny1617" : ["megaTinyCore:megaavr:atxy7:chip=1617", None, None],
"attiny1616" : ["megaTinyCore:megaavr:atxy6:chip=1616", None, None],
"attiny1607" : ["megaTinyCore:megaavr:atxy7:chip=1607", None, None],
"attiny1606" : ["megaTinyCore:megaavr:atxy6:chip=1606", None, None],
"attiny817" : ["megaTinyCore:megaavr:atxy7:chip=817", None, None],
"attiny816" : ["megaTinyCore:megaavr:atxy6:chip=816", None, None],
"attiny807" : ["megaTinyCore:megaavr:atxy7:chip=807", None, None],
"attiny806" : ["megaTinyCore:megaavr:atxy6:chip=806", None, None],
# groupings
"main_platforms" : ("uno", "leonardo", "mega2560", "zero", "qtpy_m0",
"esp8266", "esp32", "metro_m4", "trinket_m0"),
"arcada_platforms" : ("pybadge", "pygamer", "hallowing_m4",
"cpb", "cpx_ada"),
"wippersnapper_platforms" : ("metro_m4_airliftlite_tinyusb", "pyportal_tinyusb"),
"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: class ColorPrint:
@ -99,7 +189,6 @@ class ColorPrint:
def print_bold(message, end = '\n'): def print_bold(message, end = '\n'):
sys.stdout.write('\x1b[1;37m' + message.strip() + '\x1b[0m' + end) sys.stdout.write('\x1b[1;37m' + message.strip() + '\x1b[0m' + end)
def manually_install_esp32_bsp(repo_info): def manually_install_esp32_bsp(repo_info):
print("Manually installing latest ESP32 BSP...") print("Manually installing latest ESP32 BSP...")
# Assemble git url # Assemble git url
@ -134,18 +223,13 @@ def manually_install_esp32_bsp(repo_info):
print(out) print(out)
print("Installed ESP32 BSP from source!") print("Installed ESP32 BSP from source!")
def install_platform(fqbn, full_platform_name=None): def install_platform(fqbn, full_platform_name=None):
if os.path.exists("/home/runner/.arduino15/package_drazzy.json"):
print("Moving drazzy.json")
shutil.move("/home/runner/.arduino15/package_drazzy.json", "/home/runner/.arduino15/package_drazzy.com_index.json")
print("Installing", fqbn, end=" ") print("Installing", fqbn, end=" ")
if fqbn == "adafruit:avr": # we have a platform dep if fqbn == "adafruit:avr": # we have a platform dep
install_platform("arduino:avr", full_platform_name) install_platform("arduino:avr", full_platform_name)
if full_platform_name[2] is not None: if full_platform_name[2] is not None:
manually_install_esp32_bsp(full_platform_name[2]) # build esp32 bsp from desired source and branch manually_install_esp32_bsp(full_platform_name[2]) # build esp32 bsp from desired source and branch
for retry in range(0, 3): for retry in range(0, 3):
print("arduino-cli core install "+fqbn+" --additional-urls "+BSP_URLS)
if os.system("arduino-cli core install "+fqbn+" --additional-urls "+BSP_URLS+" > /dev/null") == 0: if os.system("arduino-cli core install "+fqbn+" --additional-urls "+BSP_URLS+" > /dev/null") == 0:
break break
print("...retrying...", end=" ") print("...retrying...", end=" ")
@ -158,7 +242,6 @@ def install_platform(fqbn, full_platform_name=None):
# print installed core version # print installed core version
print(os.popen('arduino-cli core list | grep {}'.format(fqbn)).read(), end='') print(os.popen('arduino-cli core list | grep {}'.format(fqbn)).read(), end='')
def run_or_die(cmd, error): def run_or_die(cmd, error):
print(cmd) print(cmd)
attempt = 0 attempt = 0
@ -171,81 +254,65 @@ def run_or_die(cmd, error):
ColorPrint.print_fail(error) ColorPrint.print_fail(error)
exit(-1) exit(-1)
################################ Install Arduino IDE
print()
ColorPrint.print_info('#'*40)
print("INSTALLING ARDUINO BOARDS")
ColorPrint.print_info('#'*40)
def is_library_installed(lib_name): run_or_die("arduino-cli core update-index --additional-urls "+BSP_URLS+
" > /dev/null", "FAILED to update core indices")
print()
################################ Install dependencies
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 dependency "+dep)
except OSError:
print("No library dep or properties found!")
pass # no library properties
# Delete the existing library if we somehow downloaded
# due to dependencies
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/*'))
# link our library folder to the arduino libraries folder
if not IS_LEARNING_SYS:
try: try:
installed_libs = subprocess.check_output(["arduino-cli", "lib", "list"]).decode("utf-8") os.symlink(BUILD_DIR, os.environ['HOME']+'/Arduino/libraries/' + os.path.basename(BUILD_DIR))
return not all(not item for item in [re.match('^'+lib_name+'\\s*\\d+\\.', line) for line in installed_libs.split('\n')]) except FileExistsError:
except subprocess.CalledProcessError as e: pass
print("Error checking installed libraries:", e)
return False
def install_library_deps():
print()
ColorPrint.print_info('#'*40)
print("INSTALLING ARDUINO LIBRARIES")
ColorPrint.print_info('#'*40)
run_or_die("arduino-cli core update-index --additional-urls "+BSP_URLS+
" > /dev/null", "FAILED to update core indices")
print()
# Install dependencies
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()
if not is_library_installed(dep):
print("Installing "+dep)
run_or_die('arduino-cli lib install "'+dep+'" > /dev/null',
"FAILED to install dependency "+dep)
else:
print("Skipping already installed lib: "+dep)
except OSError:
print("No library dep or properties found!")
pass # no library properties
# Delete the existing library if we somehow downloaded
# due to dependencies
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/*'))
# link our library folder to the arduino libraries folder
if not IS_LEARNING_SYS:
try:
os.symlink(BUILD_DIR, os.environ['HOME']+'/Arduino/libraries/' + os.path.basename(BUILD_DIR))
except FileExistsError:
pass
################################ UF2 Utils. ################################ UF2 Utils.
def glob01(pattern): def glob01(pattern):
result = glob.glob(pattern) result = glob.glob(pattern)
if len(result) > 1: if len(result) > 1:
raise RuntimeError(f"Required pattern {pattern} to match at most 1 file, got {result}") raise RuntimeError(f"Required pattern {pattern} to match at most 1 file, got {result}")
return result[0] if result else None return result[0] if result else None
def glob1(pattern): def glob1(pattern):
result = glob.glob(pattern) result = glob.glob(pattern)
if len(result) != 1: if len(result) != 1:
raise RuntimeError(f"Required pattern {pattern} to match exactly 1 file, got {result}") raise RuntimeError(f"Required pattern {pattern} to match exactly 1 file, got {result}")
return result[0] return result[0]
def download_uf2_utils(): def download_uf2_utils():
"""Downloads uf2conv tools if we don't already have them """Downloads uf2conv tools if we don't already have them
""" """
@ -261,12 +328,10 @@ def download_uf2_utils():
return False return False
return True return True
def generate_uf2(example_path):
def generate_uf2(platform, fqbn, example_path):
"""Generates a .uf2 file from a .bin or .hex file. """Generates a .uf2 file from a .bin or .hex file.
:param str platform: The platform name.
:param str fqbn: The fully qualified board name.
:param str example_path: A path to the compiled .bin or .hex file. :param str example_path: A path to the compiled .bin or .hex file.
""" """
if not download_uf2_utils(): if not download_uf2_utils():
return None return None
@ -296,23 +361,34 @@ def generate_uf2(platform, fqbn, example_path):
cmd = ['python3', 'uf2conv.py', input_file, '-c', '-f', family_id, '-b', "0x0000", '-o', output_file] cmd = ['python3', 'uf2conv.py', input_file, '-c', '-f', family_id, '-b', "0x0000", '-o', output_file]
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if BUILD_TIMEOUT: r = proc.wait(timeout=60)
r = proc.wait(timeout=popen_timeout)
else:
r = proc.wait(timeout=60)
out = proc.stdout.read() out = proc.stdout.read()
err = proc.stderr.read() err = proc.stderr.read()
if r == 0: # and not err: # we might get warnings that do not affect the result if r == 0 and not err:
ColorPrint.print_pass(CHECK) ColorPrint.print_pass(CHECK)
ColorPrint.print_info(out.decode("utf-8")) ColorPrint.print_info(out.decode("utf-8"))
else: else:
ColorPrint.print_fail(CROSS) ColorPrint.print_fail(CROSS)
ColorPrint.print_fail("\n\rERRCODE:", str(r)) ColorPrint.print_fail(out.decode("utf-8"))
ColorPrint.print_fail("\n\rOUTPUT: ", out.decode("utf-8")) ColorPrint.print_fail(err.decode("utf-8"))
ColorPrint.print_fail("\n\rERROR: ", err.decode("utf-8"))
return None return None
return output_file return output_file
################################ Test platforms
platforms = []
success = 0
# expand groups:
for arg in sys.argv[1:]:
platform = ALL_PLATFORMS.get(arg, None)
if isinstance(platform, list):
platforms.append(arg)
elif isinstance(platform, tuple):
for p in platform:
platforms.append(p)
else:
print("Unknown platform: ", arg)
exit(-1)
@contextmanager @contextmanager
def group_output(title): def group_output(title):
@ -328,42 +404,25 @@ def group_output(title):
sys.stdout.flush() sys.stdout.flush()
def test_examples_in_folder(platform, folderpath): def test_examples_in_folder(folderpath):
global success global success
fqbn = ALL_PLATFORMS[platform][0]
for example in sorted(os.listdir(folderpath)): for example in sorted(os.listdir(folderpath)):
examplepath = folderpath+"/"+example examplepath = folderpath+"/"+example
if os.path.isdir(examplepath): if os.path.isdir(examplepath):
test_examples_in_folder(platform, examplepath) test_examples_in_folder(examplepath)
continue continue
if not examplepath.endswith(".ino"): if not examplepath.endswith(".ino"):
continue continue
print('\t'+example, end=' ') print('\t'+example, end=' ')
# check if we should SKIP # check if we should SKIP
skipfilename = folderpath+"/."+platform+".test.skip" skipfilename = folderpath+"/."+platform+".test.skip"
onlyfilename = folderpath+"/."+platform+".test.only" onlyfilename = folderpath+"/."+platform+".test.only"
# check if we should GENERATE UF2 # check if we should GENERATE UF2
gen_file_name = folderpath+"/."+platform+".generate" gen_file_name = folderpath+"/."+platform+".generate"
# .skip txt include all skipped platforms, one per line
skip_txt = folderpath+"/.skip.txt"
is_skip = False
if os.path.exists(skipfilename): if os.path.exists(skipfilename):
is_skip = True
if os.path.exists(skip_txt):
with open(skip_txt) as f:
lines = f.readlines()
for line in lines:
if line.strip() == platform:
is_skip = True
break
if is_skip:
ColorPrint.print_warn("skipping") ColorPrint.print_warn("skipping")
continue continue
if glob.glob(folderpath+"/.*.test.only"): if glob.glob(folderpath+"/.*.test.only"):
platformname = glob.glob(folderpath+"/.*.test.only")[0].split('.')[1] platformname = glob.glob(folderpath+"/.*.test.only")[0].split('.')[1]
if platformname != "none" and not platformname in ALL_PLATFORMS: if platformname != "none" and not platformname in ALL_PLATFORMS:
@ -388,10 +447,7 @@ def test_examples_in_folder(platform, folderpath):
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE) stderr=subprocess.PIPE)
try: try:
if BUILD_TIMEOUT: out, err = proc.communicate(timeout=120)
out, err = proc.communicate(timeout=popen_timeout)
else:
out, err = proc.communicate(timeout=120)
r = proc.returncode r = proc.returncode
except: except:
proc.kill() proc.kill()
@ -405,11 +461,11 @@ def test_examples_in_folder(platform, folderpath):
with group_output(f"{example} {fqbn} build output"): with group_output(f"{example} {fqbn} build output"):
ColorPrint.print_fail(err.decode("utf-8")) ColorPrint.print_fail(err.decode("utf-8"))
if os.path.exists(gen_file_name): if os.path.exists(gen_file_name):
if ALL_PLATFORMS[platform][1] is None: if ALL_PLATFORMS[platform][1] == None:
ColorPrint.print_info("Platform does not support UF2 files, skipping...") ColorPrint.print_info("Platform does not support UF2 files, skipping...")
else: else:
ColorPrint.print_info("Generating UF2...") ColorPrint.print_info("Generating UF2...")
filename = generate_uf2(platform, fqbn, folderpath) filename = generate_uf2(folderpath)
if filename is None: if filename is None:
success = 1 # failure success = 1 # failure
if IS_LEARNING_SYS: if IS_LEARNING_SYS:
@ -425,38 +481,53 @@ def test_examples_in_folder(platform, folderpath):
ColorPrint.print_fail(err.decode("utf-8")) ColorPrint.print_fail(err.decode("utf-8"))
success = 1 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=' ', flush=True)
# 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
def main(): cmd = ['arduino-cli', 'compile', '--warnings', 'all', '--fqbn', fqbn, projectpath]
# Test platforms proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
platforms = [] stderr=subprocess.PIPE)
r = proc.wait()
# expand groups: out = proc.stdout.read()
for arg in sys.argv[1:]: err = proc.stderr.read()
platform = ALL_PLATFORMS.get(arg, None) if r == 0:
if isinstance(platform, list): ColorPrint.print_pass(CHECK)
platforms.append(arg) if err:
elif isinstance(platform, tuple): # also print out warning message
for p in platform: ColorPrint.print_fail(err.decode("utf-8"))
platforms.append(p)
else: else:
print("Unknown platform: ", arg) ColorPrint.print_fail(CROSS)
exit(-1) ColorPrint.print_fail(out.decode("utf-8"))
ColorPrint.print_fail(err.decode("utf-8"))
# Install libraries deps success = 1
install_library_deps()
for platform in platforms:
fqbn = ALL_PLATFORMS[platform][0]
print('#'*80)
ColorPrint.print_info("SWITCHING TO "+fqbn)
install_platform(":".join(fqbn.split(':', 2)[0:2]), ALL_PLATFORMS[platform]) # take only first two elements
print('#'*80)
if not IS_LEARNING_SYS:
test_examples_in_folder(platform, BUILD_DIR+"/examples")
else:
test_examples_in_folder(platform, BUILD_DIR)
if __name__ == "__main__": for platform in platforms:
main() fqbn = ALL_PLATFORMS[platform][0]
exit(success) print('#'*80)
ColorPrint.print_info("SWITCHING TO "+fqbn)
install_platform(":".join(fqbn.split(':', 2)[0:2]), ALL_PLATFORMS[platform]) # 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)

View file

@ -18,7 +18,6 @@ __AUTHOR__="Jeroen de Bruijn, modified by ladyada"
# Optional global variables: # Optional global variables:
# - DOXYFILE : The Doxygen configuration file. # - DOXYFILE : The Doxygen configuration file.
# - PRETTYNAME : A string name of the project (for the doxy headers) # - PRETTYNAME : A string name of the project (for the doxy headers)
# - PRESERVE_FOLDERS : Comma-separated list of folders to preserve during cleanup
# #
# For information on how to encrypt variables for Travis CI please go to # For information on how to encrypt variables for Travis CI please go to
# https://docs.travis-ci.com/user/environment-variables/#Encrypted-Variables # https://docs.travis-ci.com/user/environment-variables/#Encrypted-Variables
@ -85,19 +84,6 @@ git config --global push.default simple
git config user.name "Doxygen CI" git config user.name "Doxygen CI"
git config user.email "ci-arduino@invalid" git config user.email "ci-arduino@invalid"
# Check if PRESERVE_FOLDERS is set and back them up
if [ -n "$PRESERVE_FOLDERS" ]; then
echo "Preserving folders: $PRESERVE_FOLDERS"
mkdir -p /tmp/preserved
# Move preserved folders to temp dir
for folder in ${PRESERVE_FOLDERS//,/ }; do
if [ -d "$folder" ]; then
echo "Backing up folder: $folder"
cp -r "$folder" /tmp/preserved/
fi
done
fi
# Remove everything currently in the gh-pages branch. # Remove everything currently in the gh-pages branch.
# GitHub is smart enough to know which files have changed and which files have # GitHub is smart enough to know which files have changed and which files have
# stayed the same and will only update the changed files. So the gh-pages branch # stayed the same and will only update the changed files. So the gh-pages branch
@ -113,16 +99,6 @@ else
rm -r -- !(index.html) || true rm -r -- !(index.html) || true
fi fi
# Restore preserved folders if they were backed up
if [ -n "$PRESERVE_FOLDERS" ]; then
for folder in ${PRESERVE_FOLDERS//,/ }; do
if [ -d "/tmp/preserved/$folder" ]; then
echo "Restoring folder: $folder"
cp -r "/tmp/preserved/$folder" ./
fi
done
fi
# Need to create a .nojekyll file to allow filenames starting with an underscore # Need to create a .nojekyll file to allow filenames starting with an underscore
# to be seen on the gh-pages site. Therefore creating an empty .nojekyll file. # to be seen on the gh-pages site. Therefore creating an empty .nojekyll file.
# Presumably this is only needed when the SHORT_NAMES option in Doxygen is set # Presumably this is only needed when the SHORT_NAMES option in Doxygen is set

View file

@ -7,11 +7,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/setup-python@v4 - uses: actions/setup-python@v1
with: with:
python-version: '3.x' python-version: '3.x'
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- uses: actions/checkout@v3 - uses: actions/checkout@v2
with: with:
repository: adafruit/ci-arduino repository: adafruit/ci-arduino
path: ci path: ci