mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-01 19:42:04 +03:00
CI - build with arduino-cli (#9241)
Sync with GCC14 branch test scripts Remove explicit IDE, HARDWARE & LIBRARIES envirnoment in workflows in favour of script defaults Remove explicit dependency on IDE & HARDWARE path, assume arduino-cli default paths Remove explicit library install for platformio, share library path & downloaded libraries with arduino Bump ConfigFile dependencies, set ArduinoJson to v7 & update blob install script
This commit is contained in:
parent
cd844b99d9
commit
8e2094eb08
5
.github/workflows/build-ide.yml
vendored
5
.github/workflows/build-ide.yml
vendored
@ -52,7 +52,6 @@ jobs:
|
|||||||
- name: Build Sketches
|
- name: Build Sketches
|
||||||
env:
|
env:
|
||||||
ESP8266_ARDUINO_BUILDER: "arduino"
|
ESP8266_ARDUINO_BUILDER: "arduino"
|
||||||
ESP8266_ARDUINO_IDE: "${{ runner.temp }}/arduino_ide"
|
|
||||||
ESP8266_ARDUINO_LWIP: ${{ matrix.lwip }}
|
ESP8266_ARDUINO_LWIP: ${{ matrix.lwip }}
|
||||||
run: |
|
run: |
|
||||||
bash ./tests/build.sh 8 ${{ matrix.chunk }}
|
bash ./tests/build.sh 8 ${{ matrix.chunk }}
|
||||||
@ -75,8 +74,6 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_esp8266com_index.template.json', 'tests/common.sh', 'tests/build.sh') }}
|
key: ${{ runner.os }}-${{ hashFiles('package/package_esp8266com_index.template.json', 'tests/common.sh', 'tests/build.sh') }}
|
||||||
- name: Build Sketch
|
- name: Build Sketch
|
||||||
env:
|
env:
|
||||||
ESP8266_ARDUINO_HARDWARE: "${{ runner.temp }}/hardware"
|
|
||||||
ESP8266_ARDUINO_IDE: "${{ runner.temp }}/arduino_ide"
|
|
||||||
ESP8266_ARDUINO_SKETCHES: "libraries/esp8266/examples/Blink/Blink.ino"
|
ESP8266_ARDUINO_SKETCHES: "libraries/esp8266/examples/Blink/Blink.ino"
|
||||||
run: |
|
run: |
|
||||||
bash ./tests/build.sh
|
bash ./tests/build.sh
|
||||||
@ -100,8 +97,6 @@ jobs:
|
|||||||
key: ${{ runner.os }}-${{ hashFiles('package/package_esp8266com_index.template.json', 'tests/common.sh', 'tests/build.sh') }}
|
key: ${{ runner.os }}-${{ hashFiles('package/package_esp8266com_index.template.json', 'tests/common.sh', 'tests/build.sh') }}
|
||||||
- name: Build Sketch
|
- name: Build Sketch
|
||||||
env:
|
env:
|
||||||
ESP8266_ARDUINO_HARDWARE: "${{ runner.temp }}/hardware"
|
|
||||||
ESP8266_ARDUINO_IDE: "${{ runner.temp }}/arduino_ide"
|
|
||||||
ESP8266_ARDUINO_SKETCHES: "libraries/esp8266/examples/Blink/Blink.ino"
|
ESP8266_ARDUINO_SKETCHES: "libraries/esp8266/examples/Blink/Blink.ino"
|
||||||
run: |
|
run: |
|
||||||
bash ./tests/build.sh
|
bash ./tests/build.sh
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
|
|
||||||
// more and possibly updated information can be found at:
|
// more and possibly updated information can be found at:
|
||||||
// https://arduinojson.org/v6/example/config/
|
// https://arduinojson.org/v7/example/config/
|
||||||
|
|
||||||
bool loadConfig() {
|
bool loadConfig() {
|
||||||
File configFile = LittleFS.open("/config.json", "r");
|
File configFile = LittleFS.open("/config.json", "r");
|
||||||
@ -21,7 +21,7 @@ bool loadConfig() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticJsonDocument<200> doc;
|
JsonDocument doc;
|
||||||
auto error = deserializeJson(doc, configFile);
|
auto error = deserializeJson(doc, configFile);
|
||||||
if (error) {
|
if (error) {
|
||||||
Serial.println("Failed to parse config file");
|
Serial.println("Failed to parse config file");
|
||||||
@ -42,7 +42,7 @@ bool loadConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool saveConfig() {
|
bool saveConfig() {
|
||||||
StaticJsonDocument<200> doc;
|
JsonDocument doc;
|
||||||
doc["serverName"] = "api.example.com";
|
doc["serverName"] = "api.example.com";
|
||||||
doc["accessToken"] = "128du9as8du12eoue8da98h123ueh9h98";
|
doc["accessToken"] = "128du9as8du12eoue8da98h123ueh9h98";
|
||||||
|
|
||||||
|
@ -1,19 +1,40 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# expect to have git available
|
||||||
root=$(git rev-parse --show-toplevel)
|
root=$(git rev-parse --show-toplevel)
|
||||||
|
|
||||||
|
# general configuration related to the builder itself
|
||||||
ESP8266_ARDUINO_BUILD_DIR=${ESP8266_ARDUINO_BUILD_DIR:-$root}
|
ESP8266_ARDUINO_BUILD_DIR=${ESP8266_ARDUINO_BUILD_DIR:-$root}
|
||||||
ESP8266_ARDUINO_BUILDER=${ESP8266_ARDUINO_BUILDER:-arduino}
|
ESP8266_ARDUINO_BUILDER=${ESP8266_ARDUINO_BUILDER:-arduino}
|
||||||
ESP8266_ARDUINO_PRESERVE_CACHE=${ESP8266_ARDUINO_PRESERVE_CACHE:-}
|
ESP8266_ARDUINO_PRESERVE_CACHE=${ESP8266_ARDUINO_PRESERVE_CACHE:-}
|
||||||
|
|
||||||
ESP8266_ARDUINO_IDE=${ESP8266_ARDUINO_IDE:-$HOME/arduino_ide}
|
# sketch build options
|
||||||
ESP8266_ARDUINO_HARDWARE=${ESP8266_ARDUINO_HARDWARE:-$HOME/Arduino/hardware}
|
|
||||||
ESP8266_ARDUINO_LIBRARIES=${ESP8266_ARDUINO_LIBRARIES:-$HOME/Arduino/libraries}
|
|
||||||
|
|
||||||
ESP8266_ARDUINO_DEBUG=${ESP8266_ARDUINO_DEBUG:-nodebug}
|
ESP8266_ARDUINO_DEBUG=${ESP8266_ARDUINO_DEBUG:-nodebug}
|
||||||
ESP8266_ARDUINO_LWIP=${ESP8266_ARDUINO_LWIP:-default}
|
ESP8266_ARDUINO_LWIP=${ESP8266_ARDUINO_LWIP:-default}
|
||||||
ESP8266_ARDUINO_SKETCHES=${ESP8266_ARDUINO_SKETCHES:-}
|
ESP8266_ARDUINO_SKETCHES=${ESP8266_ARDUINO_SKETCHES:-}
|
||||||
|
|
||||||
|
ESP8266_ARDUINO_CLI=${ESP8266_ARDUINO_CLI:-$HOME/.local/bin/arduino-cli}
|
||||||
|
|
||||||
|
# ref. https://arduino.github.io/arduino-cli/1.2/configuration/#default-directories
|
||||||
|
case "${RUNNER_OS:-Linux}" in
|
||||||
|
"Linux")
|
||||||
|
ESP8266_ARDUINO_HARDWARE=${ESP8266_ARDUINO_HARDWARE:-$HOME/Arduino/hardware}
|
||||||
|
ESP8266_ARDUINO_LIBRARIES=${ESP8266_ARDUINO_LIBRARIES:-$HOME/Arduino/libraries}
|
||||||
|
;;
|
||||||
|
"macOS")
|
||||||
|
ESP8266_ARDUINO_HARDWARE=${ESP8266_ARDUINO_HARDWARE:-$HOME/Documents/Arduino/hardware}
|
||||||
|
ESP8266_ARDUINO_LIBRARIES=${ESP8266_ARDUINO_LIBRARIES:-$HOME/Documents/Arduino/libraries}
|
||||||
|
;;
|
||||||
|
"Windows")
|
||||||
|
ESP8266_ARDUINO_HARDWARE=${ESP8266_ARDUINO_HARDWARE:-$HOME/Documents/Arduino/hardware}
|
||||||
|
ESP8266_ARDUINO_LIBRARIES=${ESP8266_ARDUINO_LIBRARIES:-$HOME/Documents/Arduino/libraries}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo 'Unknown ${RUNNER_OS} = "' ${RUNNER_OS} '"'
|
||||||
|
exit 2
|
||||||
|
esac
|
||||||
|
|
||||||
|
source "$root/tests/lib-skip-ino.sh"
|
||||||
source "$root/tests/common.sh"
|
source "$root/tests/common.sh"
|
||||||
|
|
||||||
cmd=${0##*/}
|
cmd=${0##*/}
|
||||||
@ -22,8 +43,7 @@ ENVIRONMENT:
|
|||||||
ESP8266_ARDUINO_SKETCHES - list of .ino files; defaults to **all available examples**
|
ESP8266_ARDUINO_SKETCHES - list of .ino files; defaults to **all available examples**
|
||||||
ESP8266_ARDUINO_BUILDER - arduino or platformio
|
ESP8266_ARDUINO_BUILDER - arduino or platformio
|
||||||
|
|
||||||
For Arduino IDE:
|
For Arduino CLI:
|
||||||
ESP8266_ARDUINO_IDE - path to the IDE (portable)
|
|
||||||
ESP8266_ARDUINO_HARDWARE - path to the hardware directory (usually, containing our repo)
|
ESP8266_ARDUINO_HARDWARE - path to the hardware directory (usually, containing our repo)
|
||||||
ESP8266_ARDUINO_LIBRATIES - path to the libraries directory (external dependencies)
|
ESP8266_ARDUINO_LIBRATIES - path to the libraries directory (external dependencies)
|
||||||
ESP8266_ARDUINO_DEBUG - debug or nodebug
|
ESP8266_ARDUINO_DEBUG - debug or nodebug
|
||||||
@ -31,12 +51,14 @@ ENVIRONMENT:
|
|||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
$cmd <[even | odd]> - build every Nth, when '<N> % 2' is either even or odd
|
$cmd <[even | odd]> - build every Nth, when '<N> % 2' is either even or odd
|
||||||
$cmd <mod> <rem> - build every Nth, when '<N> % <mod>' is equal to 'rem'
|
$cmd <mod> <rem> <[cnt]> - build every Nth, when '<N> % <mod>' is equal to 'rem'
|
||||||
|
optionally, set <cnt> to start with the Nth sketch
|
||||||
$cmd - build every .ino file from ESP8266_ARDUINO_SKETCHES
|
$cmd - build every .ino file from ESP8266_ARDUINO_SKETCHES
|
||||||
"
|
"
|
||||||
|
|
||||||
mod=1
|
mod=1
|
||||||
rem=0
|
rem=0
|
||||||
|
cnt=0
|
||||||
|
|
||||||
if [ "$#" -eq 1 ] ; then
|
if [ "$#" -eq 1 ] ; then
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -60,6 +82,10 @@ if [ "$#" -eq 1 ] ; then
|
|||||||
elif [ "$#" -eq 2 ] ; then
|
elif [ "$#" -eq 2 ] ; then
|
||||||
mod=$1
|
mod=$1
|
||||||
rem=$2
|
rem=$2
|
||||||
|
elif [ "$#" -eq 3 ] ; then
|
||||||
|
mod=$1
|
||||||
|
rem=$2
|
||||||
|
cnt=$3
|
||||||
elif [ "$#" -gt 2 ] ; then
|
elif [ "$#" -gt 2 ] ; then
|
||||||
echo "$usage"
|
echo "$usage"
|
||||||
exit 1
|
exit 1
|
||||||
@ -72,14 +98,17 @@ fi
|
|||||||
case "$ESP8266_ARDUINO_BUILDER" in
|
case "$ESP8266_ARDUINO_BUILDER" in
|
||||||
"arduino")
|
"arduino")
|
||||||
install_arduino "$ESP8266_ARDUINO_DEBUG"
|
install_arduino "$ESP8266_ARDUINO_DEBUG"
|
||||||
build_sketches_with_arduino "$mod" "$rem" "$ESP8266_ARDUINO_LWIP"
|
build_sketches_with_arduino "$ESP8266_ARDUINO_LWIP" "$mod" "$rem" "$cnt"
|
||||||
;;
|
;;
|
||||||
"platformio")
|
"platformio")
|
||||||
install_platformio nodemcuv2
|
install_platformio nodemcuv2
|
||||||
build_sketches_with_platformio "$mod" "$rem"
|
build_sketches_with_platformio "$mod" "$rem" "$cnt"
|
||||||
|
;;
|
||||||
|
"print")
|
||||||
|
print_sketch_info "$mod" "$rem"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown builder! Must be either arduino or platformio"
|
echo "Unknown builder! Must be one of - arduino, platformio or print"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
374
tests/common.sh
374
tests/common.sh
@ -16,6 +16,16 @@ function trap_exit()
|
|||||||
exit $exit_code
|
exit $exit_code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if [ "${CI-}" = "true" ] ; then
|
||||||
|
ci_group="::group::"
|
||||||
|
ci_end_group="::endgroup::"
|
||||||
|
ci_error="::error::"
|
||||||
|
else
|
||||||
|
ci_group="==> "
|
||||||
|
ci_end_group=""
|
||||||
|
ci_error=">>> "
|
||||||
|
fi
|
||||||
|
|
||||||
function step_summary()
|
function step_summary()
|
||||||
{
|
{
|
||||||
local header=$1
|
local header=$1
|
||||||
@ -31,50 +41,6 @@ function step_summary()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# return 0 if this sketch should not be built in CI (for other archs, not needed, etc.)
|
|
||||||
function skip_ino()
|
|
||||||
{
|
|
||||||
case $1 in
|
|
||||||
*"/#attic/"* | \
|
|
||||||
*"/AvrAdcLogger/"* | \
|
|
||||||
*"/examplesV1/"* | \
|
|
||||||
*"/RtcTimestampTest/"* | \
|
|
||||||
*"/SoftwareSpi/"* | \
|
|
||||||
*"/TeensyDmaAdcLogger/"* | \
|
|
||||||
*"/TeensyRtcTimestamp/"* | \
|
|
||||||
*"/TeensySdioDemo/"* | \
|
|
||||||
*"/TeensySdioLogger/"* | \
|
|
||||||
*"/UserChipSelectFunction/"* | \
|
|
||||||
*"/UserSPIDriver/"* | \
|
|
||||||
*"/onewiretest/"* | \
|
|
||||||
*"/debug/"*)
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*"Teensy"*)
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# return reason if this sketch is not the main one or it is explicitly disabled with .test.skip in its directory
|
|
||||||
function skip_sketch()
|
|
||||||
{
|
|
||||||
local sketch=$1
|
|
||||||
local sketchname=$2
|
|
||||||
local sketchdir=$3
|
|
||||||
local sketchdirname=$4
|
|
||||||
|
|
||||||
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
|
||||||
echo "Skipping $sketch (not the main sketch file)"
|
|
||||||
fi
|
|
||||||
if skip_ino "$sketch" || [[ -f "$sketchdir/.test.skip" ]]; then
|
|
||||||
echo "Skipping $sketch"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function print_size_info_header()
|
function print_size_info_header()
|
||||||
{
|
{
|
||||||
@ -107,37 +73,74 @@ END {
|
|||||||
awk -v sketch_name="${elf_name%.*}" "$awk_script" -
|
awk -v sketch_name="${elf_name%.*}" "$awk_script" -
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function print_sketch_info()
|
||||||
|
{
|
||||||
|
local build_mod=$1
|
||||||
|
local build_rem=$2
|
||||||
|
|
||||||
|
local testcnt=0
|
||||||
|
local cnt=0
|
||||||
|
|
||||||
|
for sketch in $ESP8266_ARDUINO_SKETCHES; do
|
||||||
|
testcnt=$(( ($testcnt + 1) % $build_mod ))
|
||||||
|
if [ $testcnt -ne $build_rem ]; then
|
||||||
|
continue # Not ours to do
|
||||||
|
fi
|
||||||
|
|
||||||
|
local skip
|
||||||
|
skip=$(skip_sketch "$sketch")
|
||||||
|
if [ -n "$skip" ]; then
|
||||||
|
continue # Should be skipped / cannot be built
|
||||||
|
fi
|
||||||
|
|
||||||
|
cnt=$(( $cnt + 1 ))
|
||||||
|
printf '%2d\t%s\n' "$cnt" "$sketch"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_fqbn()
|
||||||
|
{
|
||||||
|
local board_name=$1
|
||||||
|
local flash_size=$2
|
||||||
|
local lwip=$3
|
||||||
|
|
||||||
|
echo "esp8266com:esp8266:${board_name}:"\
|
||||||
|
"eesz=${flash_size},"\
|
||||||
|
"ip=${lwip}"
|
||||||
|
}
|
||||||
|
|
||||||
function build_sketches()
|
function build_sketches()
|
||||||
{
|
{
|
||||||
local core_path=$1
|
local core_path=$1
|
||||||
local ide_path=$2
|
local cli_path=$2
|
||||||
local hardware_path=$3
|
local library_path=$3
|
||||||
local library_path=$4
|
local lwip=$4
|
||||||
local build_mod=$5
|
local build_mod=$5
|
||||||
local build_rem=$6
|
local build_rem=$6
|
||||||
local lwip=$7
|
local build_cnt=$7
|
||||||
|
|
||||||
local build_dir="$cache_dir"/build
|
local build_dir="$cache_dir"/build
|
||||||
mkdir -p "$build_dir"
|
mkdir -p "$build_dir"
|
||||||
|
|
||||||
local build_cache="$cache_dir"/cache
|
local build_out="$cache_dir"/out
|
||||||
mkdir -p "$build_cache"
|
mkdir -p "$build_out"
|
||||||
|
|
||||||
|
local fqbn=$(format_fqbn "generic" "4M1M" "$lwip")
|
||||||
|
echo "FQBN: $fqbn"
|
||||||
|
|
||||||
local build_cmd
|
local build_cmd
|
||||||
build_cmd="python3 tools/build.py"\
|
build_cmd+=${cli_path}
|
||||||
" --build_cache $build_cache"\
|
build_cmd+=" compile"\
|
||||||
" --build_path $build_dir"\
|
" --build-path $build_dir"\
|
||||||
" --hardware_path $hardware_path"\
|
" --fqbn $fqbn"\
|
||||||
" --ide_path $ide_path"\
|
" --libraries $library_path"\
|
||||||
" --library_path $library_path"\
|
" --output-dir $build_out"
|
||||||
" --lwIP $lwip"\
|
|
||||||
" --board_name generic --verbose --warnings all"\
|
|
||||||
" --flash_size 4M1M --keep"
|
|
||||||
|
|
||||||
print_size_info_header >"$cache_dir"/size.log
|
print_size_info_header >"$cache_dir"/size.log
|
||||||
|
|
||||||
local mk_clean_core=1
|
local clean_core=1
|
||||||
local testcnt=0
|
local testcnt=0
|
||||||
|
local cnt=0
|
||||||
|
|
||||||
for sketch in $ESP8266_ARDUINO_SKETCHES; do
|
for sketch in $ESP8266_ARDUINO_SKETCHES; do
|
||||||
testcnt=$(( ($testcnt + 1) % $build_mod ))
|
testcnt=$(( ($testcnt + 1) % $build_mod ))
|
||||||
@ -145,44 +148,24 @@ function build_sketches()
|
|||||||
continue # Not ours to do
|
continue # Not ours to do
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# mkbuildoptglobals.py is optimized around the Arduino IDE 1.x
|
local skip
|
||||||
# behaviour. One way the CI differs from the Arduino IDE is in the
|
skip=$(skip_sketch "$sketch")
|
||||||
# handling of core and caching core. With the Arduino IDE, each sketch
|
if [ -n "$skip" ]; then
|
||||||
# has a private copy of core and contributes to a core cache. With the
|
echo "$skip"
|
||||||
# CI, there is one shared copy of core for all sketches. When global
|
continue # Should be skipped / cannot be built
|
||||||
# options are used, the shared copy of core and cache are removed before
|
fi
|
||||||
# and after the build.
|
|
||||||
#
|
cnt=$(( $cnt + 1 ))
|
||||||
|
if [ $build_cnt != 0 ] ; then
|
||||||
|
if [ $build_cnt != $cnt ] ; then
|
||||||
|
continue # Haven't reached the $cnt yet
|
||||||
|
fi
|
||||||
|
build_cnt=0
|
||||||
|
fi
|
||||||
|
|
||||||
# Do we need a clean core build? $build_dir/core/* cannot be shared
|
# Do we need a clean core build? $build_dir/core/* cannot be shared
|
||||||
# between sketches when global options are present.
|
# between sketches when global options are present.
|
||||||
if [ -s ${sketch}.globals.h ]; then
|
clean_core=$(arduino_mkbuildoptglobals_cleanup "$clean_core" "$build_dir" "$sketch")
|
||||||
mk_clean_core=1
|
|
||||||
fi
|
|
||||||
if [ $mk_clean_core -ne 0 ]; then
|
|
||||||
rm -rf "$build_dir"/core/*
|
|
||||||
else
|
|
||||||
# Remove sketch specific files from ./core/ between builds.
|
|
||||||
rm -rf "$build_dir/core/build.opt" "$build_dir"/core/*.ino.globals.h
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -e $cache_dir/core/*.a ]; then
|
|
||||||
# We need to preserve the build.options.json file and replace the last .ino
|
|
||||||
# with this sketch's ino file, or builder will throw everything away.
|
|
||||||
jq '."sketchLocation" = "'$sketch'"' $build_dir/build.options.json \
|
|
||||||
> "$build_dir"/build.options.json.tmp
|
|
||||||
mv "$build_dir"/build.options.json.tmp "$build_dir"/build.options.json
|
|
||||||
if [ $mk_clean_core -ne 0 ]; then
|
|
||||||
# Hack workaround for CI not handling core rebuild for global options
|
|
||||||
rm $cache_dir/core/*.a
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -s ${sketch}.globals.h ]; then
|
|
||||||
# Set to cleanup core at the start of the next build.
|
|
||||||
mk_clean_core=1
|
|
||||||
else
|
|
||||||
mk_clean_core=0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Clear out the last built sketch, map, elf, bin files, but leave the compiled
|
# Clear out the last built sketch, map, elf, bin files, but leave the compiled
|
||||||
# objects in the core and libraries available for use so we don't need to rebuild
|
# objects in the core and libraries available for use so we don't need to rebuild
|
||||||
@ -192,23 +175,7 @@ function build_sketches()
|
|||||||
"$build_dir"/*.map \
|
"$build_dir"/*.map \
|
||||||
"$build_dir"/*.elf
|
"$build_dir"/*.elf
|
||||||
|
|
||||||
local sketchdir
|
echo ${ci_group}Building $cnt $sketch
|
||||||
sketchdir=$(dirname $sketch)
|
|
||||||
|
|
||||||
local sketchdirname
|
|
||||||
sketchdirname=$(basename $sketchdir)
|
|
||||||
|
|
||||||
local sketchname
|
|
||||||
sketchname=$(basename $sketch)
|
|
||||||
|
|
||||||
local skip
|
|
||||||
skip=$(skip_sketch "$sketch" "$sketchname" "$sketchdir" "$sketchdirname")
|
|
||||||
if [ -n "$skip" ]; then
|
|
||||||
echo "$skip"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ::group::Building $sketch
|
|
||||||
echo "$build_cmd $sketch"
|
echo "$build_cmd $sketch"
|
||||||
|
|
||||||
local result
|
local result
|
||||||
@ -216,9 +183,9 @@ function build_sketches()
|
|||||||
&& result=0 || result=1
|
&& result=0 || result=1
|
||||||
|
|
||||||
if [ $result -ne 0 ]; then
|
if [ $result -ne 0 ]; then
|
||||||
echo ::error::Build failed for $sketch
|
echo ${ci_error}Build failed for $cnt $sketch
|
||||||
cat "$cache_dir/build.log"
|
cat "$cache_dir/build.log"
|
||||||
echo ::endgroup::
|
echo $ci_end_group
|
||||||
return $result
|
return $result
|
||||||
else
|
else
|
||||||
grep -s -c warning: "$cache_dir"/build.log \
|
grep -s -c warning: "$cache_dir"/build.log \
|
||||||
@ -228,7 +195,7 @@ function build_sketches()
|
|||||||
print_size_info "$core_path"/tools/xtensa-lx106-elf/bin/xtensa-lx106-elf-size \
|
print_size_info "$core_path"/tools/xtensa-lx106-elf/bin/xtensa-lx106-elf-size \
|
||||||
$build_dir/*.elf >>$cache_dir/size.log
|
$build_dir/*.elf >>$cache_dir/size.log
|
||||||
|
|
||||||
echo ::endgroup::
|
echo $ci_end_group
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,14 +245,15 @@ function install_library()
|
|||||||
{
|
{
|
||||||
local lib_path=$1
|
local lib_path=$1
|
||||||
local name=$2
|
local name=$2
|
||||||
local archive=$3
|
local extract=$3
|
||||||
local hash=$4
|
local archive=$4
|
||||||
local url=$5
|
local hash=$5
|
||||||
|
local url=$6
|
||||||
|
|
||||||
fetch_and_unpack "$archive" "$hash" "$url"
|
fetch_and_unpack "$archive" "$hash" "$url"
|
||||||
mkdir -p "$lib_path"
|
mkdir -p "$lib_path"
|
||||||
rm -rf "$lib_path/$name"
|
rm -rf "$lib_path/$name"
|
||||||
mv "$name" "$lib_path/$name"
|
mv "$extract" "$lib_path/$name"
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_libraries()
|
function install_libraries()
|
||||||
@ -296,49 +264,30 @@ function install_libraries()
|
|||||||
mkdir -p "$core_path"/tools/dist
|
mkdir -p "$core_path"/tools/dist
|
||||||
pushd "$core_path"/tools/dist
|
pushd "$core_path"/tools/dist
|
||||||
|
|
||||||
install_library "$lib_path" \
|
source "$root/tests/dep-libraries.sh"
|
||||||
"ArduinoJson" \
|
|
||||||
"ArduinoJson-v6.11.5.zip" \
|
|
||||||
"8b836c862e69e60c4357a5ed7cbcf1310a3bb1c6bd284fe028faaa3d9d7eed319d10febc8a6a3e06040d1c73aaba5ca487aeffe87ae9388dc4ae1677a64d602c" \
|
|
||||||
"https://github.com/bblanchon/ArduinoJson/releases/download/v6.11.5/ArduinoJson-v6.11.5.zip"
|
|
||||||
|
|
||||||
popd
|
popd
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_ide()
|
function install_arduino_cli()
|
||||||
{
|
{
|
||||||
# TODO replace ide distribution + arduino-builder with arduino-cli
|
local path=$1
|
||||||
local idever='1.8.19'
|
local core_path=$2
|
||||||
local ideurl="https://downloads.arduino.cc/arduino-$idever"
|
|
||||||
|
|
||||||
echo "Arduino IDE ${idever}"
|
local ver='1.2.2'
|
||||||
|
local urlbase="https://github.com/arduino/arduino-cli/releases/download/v${ver}/arduino-cli_${ver}_"
|
||||||
|
|
||||||
local core_path=$1
|
echo "Arduino CLI ${ver}"
|
||||||
local ide_path=$2
|
|
||||||
|
|
||||||
mkdir -p ${core_path}/tools/dist
|
mkdir -p ${core_path}/dist
|
||||||
pushd ${core_path}/tools/dist
|
pushd ${core_path}/dist
|
||||||
|
|
||||||
if [ "${RUNNER_OS-}" = "Windows" ]; then
|
source "$root/tests/dep-arduino-cli.sh"
|
||||||
fetch_and_unpack "arduino-windows.zip" \
|
|
||||||
"c4072d808aea3848bceff5772f9d1e56a0fde02366b5aa523d10975c54eee2ca8def25ee466abbc88995aa323d475065ad8eb30bf35a2aaf07f9473f9168e2da" \
|
mkdir -p $(dirname $path)
|
||||||
"${ideurl}-windows.zip"
|
cp -v arduino-cli $path
|
||||||
mv arduino-$idever arduino-distrib
|
chmod +x $path
|
||||||
elif [ "${RUNNER_OS-}" = "macOS" ]; then
|
|
||||||
fetch_and_unpack "arduino-macos.zip" \
|
|
||||||
"053b0c1e70da9176680264e40fcb9502f45ca5a879aeb8b6f71282b38bfdb87c63ebc6b88e35ea70a73720ad439d828cc8cb110e4c6ab07357126a36ee396325" \
|
|
||||||
"${ideurl}-macosx.zip"
|
|
||||||
# Hack to place arduino-builder in the same spot as sane OSes
|
|
||||||
mv Arduino.app arduino-distrib
|
|
||||||
mv arduino-distrib/Contents/Java/* arduino-distrib/.
|
|
||||||
else
|
|
||||||
fetch_and_unpack "arduino-linux.tar.xz" \
|
|
||||||
"9328abf8778200019ed40d4fc0e6afb03a4cee8baaffbcea7dd3626477e14243f779eaa946c809fb153a542bf2ed60cf11a5f135c91ecccb1243c1387be95328" \
|
|
||||||
"${ideurl}-linux64.tar.xz"
|
|
||||||
mv arduino-$idever arduino-distrib
|
|
||||||
fi
|
|
||||||
|
|
||||||
mv arduino-distrib "$ide_path"
|
|
||||||
popd
|
popd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,19 +334,19 @@ function install_core()
|
|||||||
|
|
||||||
function install_arduino()
|
function install_arduino()
|
||||||
{
|
{
|
||||||
echo ::group::Install arduino
|
echo ${ci_group}Install arduino
|
||||||
local debug=$1
|
local debug=$1
|
||||||
|
|
||||||
test -d "$ESP8266_ARDUINO_IDE" \
|
|
||||||
|| install_ide "$ESP8266_ARDUINO_BUILD_DIR" "$ESP8266_ARDUINO_IDE"
|
|
||||||
|
|
||||||
local hardware_core_path="$ESP8266_ARDUINO_HARDWARE/esp8266com/esp8266"
|
local hardware_core_path="$ESP8266_ARDUINO_HARDWARE/esp8266com/esp8266"
|
||||||
test -d "$hardware_core_path" \
|
test -d "$hardware_core_path" \
|
||||||
|| install_core "$ESP8266_ARDUINO_BUILD_DIR" "$hardware_core_path" "$debug"
|
|| install_core "$ESP8266_ARDUINO_BUILD_DIR" "$hardware_core_path" "$debug"
|
||||||
|
|
||||||
|
command -v "${ESP8266_ARDUINO_CLI}" \
|
||||||
|
|| install_arduino_cli "${ESP8266_ARDUINO_CLI}" "$hardware_core_path"
|
||||||
|
|
||||||
install_libraries "$ESP8266_ARDUINO_BUILD_DIR" "$ESP8266_ARDUINO_LIBRARIES"
|
install_libraries "$ESP8266_ARDUINO_BUILD_DIR" "$ESP8266_ARDUINO_LIBRARIES"
|
||||||
|
|
||||||
echo ::endgroup::
|
echo $ci_end_group
|
||||||
}
|
}
|
||||||
|
|
||||||
function arduino_lwip_menu_option()
|
function arduino_lwip_menu_option()
|
||||||
@ -412,25 +361,71 @@ function arduino_lwip_menu_option()
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# mkbuildoptglobals.py is optimized around the Arduino IDE 1.x
|
||||||
|
# behaviour. One way the CI differs from the Arduino IDE is in the
|
||||||
|
# handling of core and caching core. With the Arduino IDE, each sketch
|
||||||
|
# has a private copy of core and contributes to a core cache. With the
|
||||||
|
# CI, there is one shared copy of core for all sketches. When global
|
||||||
|
# options are used, the shared copy of core and cache are removed before
|
||||||
|
# and after the build.
|
||||||
|
function arduino_mkbuildoptglobals_cleanup()
|
||||||
|
{
|
||||||
|
local clean_core=$1
|
||||||
|
local build_dir=$2
|
||||||
|
local sketch=$3
|
||||||
|
|
||||||
|
if [ -s ${sketch}.globals.h ]; then
|
||||||
|
clean_core=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove sketch specific files from ./core/ between builds.
|
||||||
|
if [ $clean_core -ne 0 ]; then
|
||||||
|
rm -rf "$build_dir"/core/*
|
||||||
|
else
|
||||||
|
rm -rf "$build_dir/core/build.opt" "$build_dir"/core/*.ino.globals.h
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -e ${build_dir}/core/*.a ]; then
|
||||||
|
# We need to preserve the build.options.json file and replace the last .ino
|
||||||
|
# with this sketch's ino file, or builder will throw everything away.
|
||||||
|
jq '."sketchLocation" = "'$sketch'"' $build_dir/build.options.json \
|
||||||
|
> "$build_dir"/build.options.json.tmp
|
||||||
|
mv "$build_dir"/build.options.json.tmp "$build_dir"/build.options.json
|
||||||
|
if [ $clean_core -ne 0 ]; then
|
||||||
|
# Hack workaround for CI not handling core rebuild for global options
|
||||||
|
rm ${build_dir}/core/*.a
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s ${sketch}.globals.h ]; then
|
||||||
|
# Set to cleanup core at the start of the next build.
|
||||||
|
clean_core=1
|
||||||
|
else
|
||||||
|
clean_core=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo $clean_core
|
||||||
|
}
|
||||||
|
|
||||||
function build_sketches_with_arduino()
|
function build_sketches_with_arduino()
|
||||||
{
|
{
|
||||||
local build_mod=$1
|
|
||||||
local build_rem=$2
|
|
||||||
|
|
||||||
local lwip
|
local lwip
|
||||||
lwip=$(arduino_lwip_menu_option $3)
|
lwip=$(arduino_lwip_menu_option $1)
|
||||||
|
|
||||||
|
local build_mod=$2
|
||||||
|
local build_rem=$3
|
||||||
|
local build_cnt=$4
|
||||||
|
|
||||||
build_sketches "$ESP8266_ARDUINO_BUILD_DIR" \
|
build_sketches "$ESP8266_ARDUINO_BUILD_DIR" \
|
||||||
"$ESP8266_ARDUINO_IDE" \
|
"$ESP8266_ARDUINO_CLI" \
|
||||||
"$ESP8266_ARDUINO_HARDWARE" \
|
|
||||||
"$ESP8266_ARDUINO_LIBRARIES" \
|
"$ESP8266_ARDUINO_LIBRARIES" \
|
||||||
"$build_mod" "$build_rem" "$lwip"
|
"$lwip" "$build_mod" "$build_rem" "$build_cnt"
|
||||||
step_summary "Size report" "$cache_dir/size.log"
|
step_summary "Size report" "$cache_dir/size.log"
|
||||||
}
|
}
|
||||||
|
|
||||||
function install_platformio()
|
function install_platformio()
|
||||||
{
|
{
|
||||||
echo ::group::Install PlatformIO
|
echo ${ci_group}Install PlatformIO
|
||||||
|
|
||||||
local board=$1
|
local board=$1
|
||||||
|
|
||||||
@ -438,6 +433,8 @@ function install_platformio()
|
|||||||
python3 get.py -q
|
python3 get.py -q
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
install_libraries "$ESP8266_ARDUINO_BUILD_DIR" "$ESP8266_ARDUINO_LIBRARIES"
|
||||||
|
|
||||||
# we should reference our up-to-date build tools
|
# we should reference our up-to-date build tools
|
||||||
# ref. https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html
|
# ref. https://docs.platformio.org/en/latest/core/userguide/pkg/cmd_install.html
|
||||||
pio pkg install --global --skip-dependencies --platform "https://github.com/platformio/platform-espressif8266.git"
|
pio pkg install --global --skip-dependencies --platform "https://github.com/platformio/platform-espressif8266.git"
|
||||||
@ -445,9 +442,11 @@ function install_platformio()
|
|||||||
local framework_symlink="framework-arduinoespressif8266 @ symlink://${ESP8266_ARDUINO_BUILD_DIR}"
|
local framework_symlink="framework-arduinoespressif8266 @ symlink://${ESP8266_ARDUINO_BUILD_DIR}"
|
||||||
local toolchain_symlink="toolchain-xtensa @ symlink://${ESP8266_ARDUINO_BUILD_DIR}/tools/xtensa-lx106-elf/"
|
local toolchain_symlink="toolchain-xtensa @ symlink://${ESP8266_ARDUINO_BUILD_DIR}/tools/xtensa-lx106-elf/"
|
||||||
|
|
||||||
# pre-generate config; pio-ci with multiple '-O' replace each other instead of appending to the same named list
|
# pre-generate config; pio-ci with multiple '-O' options replace each other instead of appending to the same named list
|
||||||
# (and, it is much nicer to write this instead of a multi-line cmdline with several large strings)
|
|
||||||
cat <<EOF > $cache_dir/platformio.ini
|
cat <<EOF > $cache_dir/platformio.ini
|
||||||
|
[platformio]
|
||||||
|
lib_dir =
|
||||||
|
${ESP8266_ARDUINO_LIBRARIES}
|
||||||
[env:$board]
|
[env:$board]
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
board = $board
|
board = $board
|
||||||
@ -457,17 +456,14 @@ platform_packages =
|
|||||||
${toolchain_symlink}
|
${toolchain_symlink}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Install dependencies:
|
echo $ci_end_group
|
||||||
# - esp8266/examples/ConfigFile
|
|
||||||
pio pkg install --global --library "ArduinoJson@^6.11.0"
|
|
||||||
|
|
||||||
echo ::endgroup::
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_sketches_with_platformio()
|
function build_sketches_with_platformio()
|
||||||
{
|
{
|
||||||
local build_mod=$1
|
local build_mod=$1
|
||||||
local build_rem=$2
|
local build_rem=$2
|
||||||
|
local build_cnt=$3
|
||||||
local testcnt=0
|
local testcnt=0
|
||||||
|
|
||||||
for sketch in $ESP8266_ARDUINO_SKETCHES; do
|
for sketch in $ESP8266_ARDUINO_SKETCHES; do
|
||||||
@ -476,23 +472,25 @@ function build_sketches_with_platformio()
|
|||||||
continue # Not ours to do
|
continue # Not ours to do
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local sketchdir
|
|
||||||
sketchdir=$(dirname $sketch)
|
|
||||||
|
|
||||||
local sketchdirname
|
|
||||||
sketchdirname=$(basename $sketchdir)
|
|
||||||
|
|
||||||
local sketchname
|
|
||||||
sketchname=$(basename $sketch)
|
|
||||||
|
|
||||||
local skip
|
local skip
|
||||||
skip=$(skip_sketch "$sketch" "$sketchname" "$sketchdir" "$sketchdirname")
|
skip=$(skip_sketch "$sketch")
|
||||||
if [ -n "$skip" ]; then
|
if [ -n "$skip" ]; then
|
||||||
echo "$skip"
|
echo "$skip"
|
||||||
continue
|
continue # Should be skipped / cannot be built
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ::group::Building $sketch
|
cnt=$(( $cnt + 1 ))
|
||||||
|
if [ $build_cnt != 0 ] ; then
|
||||||
|
if [ $build_cnt != $cnt ] ; then
|
||||||
|
continue # Haven't reached the $cnt yet
|
||||||
|
fi
|
||||||
|
build_cnt=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ${ci_group}Building $sketch
|
||||||
|
|
||||||
|
local sketchdir
|
||||||
|
sketchdir=$(dirname $sketch)
|
||||||
|
|
||||||
local result
|
local result
|
||||||
time pio ci \
|
time pio ci \
|
||||||
@ -502,13 +500,13 @@ function build_sketches_with_platformio()
|
|||||||
&& result=0 || result=1
|
&& result=0 || result=1
|
||||||
|
|
||||||
if [ $result -ne 0 ]; then
|
if [ $result -ne 0 ]; then
|
||||||
echo ::error::Build failed for $sketch
|
echo ${ci_error}Build failed for $sketch
|
||||||
cat "$cache_dir/build.log"
|
cat "$cache_dir/build.log"
|
||||||
echo ::endgroup::
|
echo $ci_end_group
|
||||||
return $result
|
return $result
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ::endgroup::
|
echo $ci_end_group
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
tests/dep-arduino-cli.sh
Normal file
27
tests/dep-arduino-cli.sh
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
case "${RUNNER_OS-}" in
|
||||||
|
"Linux")
|
||||||
|
fetch_and_unpack "Linux_64bit.tar.gz" \
|
||||||
|
"d421e2b1cbef59c41e46cf06d077214a1d24cb784030462763781c9d3911cc55257fbcc02a7ee6a2ddda5b459101dc83aeda6b3b5198805bfdce856f82774c93" \
|
||||||
|
"${urlbase}Linux_64bit.tar.gz"
|
||||||
|
;;
|
||||||
|
"Windows")
|
||||||
|
fetch_and_unpack "Windows_64bit.zip" \
|
||||||
|
"05b4eb5820fbaf670de00399d40513ecf2de9d0c2c5593a1227be03b2d11ba53e9d14cf6f934110447d6fd15c6a09769606a34fcab32ec3c2dbaa42f4627b072" \
|
||||||
|
"${urlbase}Windows_64bit.zip"
|
||||||
|
;;
|
||||||
|
"macOS")
|
||||||
|
if [ "${RUNNER_ARCH-}" = "ARM64" ] ; then
|
||||||
|
fetch_and_unpack "macOS_ARM64.tar.gz" \
|
||||||
|
"672693418b730d8ebc57cae2c892553e821706bee06312cc77a598e834afcba7d380df4d337138ecc03a4013a349d89b744b2a3b97fafc214b619856d9162827" \
|
||||||
|
"${urlbase}macOS_ARM64.tar.gz"
|
||||||
|
else
|
||||||
|
fetch_and_unpack "macOS_64bit.tar.gz" \
|
||||||
|
"5659f08d787840aa6689fd063477402b4ed572663fea20de496b249d86a440059e3e6f377bd8020fb6b67202c1bdea6f98a4c4e052c31f01b2c9027ebec10b04" \
|
||||||
|
"${urlbase}macOS_64bit.tar.gz"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo 'Unknown ${RUNNER_OS} = "' ${RUNNER_OS} '"'
|
||||||
|
exit 2
|
||||||
|
esac
|
||||||
|
|
6
tests/dep-libraries.sh
Normal file
6
tests/dep-libraries.sh
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
install_library "$lib_path" \
|
||||||
|
"ArduinoJson" \
|
||||||
|
"ArduinoJson-7.4.1" \
|
||||||
|
"ArduinoJson-v7.4.1.zip" \
|
||||||
|
"1bfbc4aa3e4aa3c8e38f660333b6d5129b0443dbd0fd1eb448d14c7f041ffd2df782951ce622c6da50e2a07dcfcd268727b1f0a000211b9a5a92a806b1645bc0" \
|
||||||
|
"https://github.com/bblanchon/ArduinoJson/archive/refs/tags/v7.4.1.zip"
|
53
tests/lib-skip-ino.sh
Normal file
53
tests/lib-skip-ino.sh
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# return 0 if this sketch should not be built in CI (for other archs, not needed, etc.)
|
||||||
|
function skip_ino()
|
||||||
|
{
|
||||||
|
local ino=$1
|
||||||
|
|
||||||
|
case "$ino" in
|
||||||
|
*"/#attic/"* | \
|
||||||
|
*"/AvrAdcLogger/"* | \
|
||||||
|
*"/RtcTimestampTest/"* | \
|
||||||
|
*"/SoftwareSpi/"* | \
|
||||||
|
*"/TeensyDmaAdcLogger/"* | \
|
||||||
|
*"/TeensyRtcTimestamp/"* | \
|
||||||
|
*"/TeensySdioDemo/"* | \
|
||||||
|
*"/TeensySdioLogger/"* | \
|
||||||
|
*"/UnicodeFilenames/"* | \
|
||||||
|
*"/UserChipSelectFunction/"* | \
|
||||||
|
*"/UserSPIDriver/"* | \
|
||||||
|
*"/debug/"* | \
|
||||||
|
*"/examplesV1/"* | \
|
||||||
|
*"/onewiretest/"*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*"Teensy"*)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# return reason if this sketch is not the main one or it is explicitly disabled with .test.skip in its directory
|
||||||
|
function skip_sketch()
|
||||||
|
{
|
||||||
|
local sketch=$1
|
||||||
|
|
||||||
|
local sketchdir
|
||||||
|
sketchdir=$(dirname $sketch)
|
||||||
|
|
||||||
|
local sketchdirname
|
||||||
|
sketchdirname=$(basename $sketchdir)
|
||||||
|
|
||||||
|
local sketchname
|
||||||
|
sketchname=$(basename $sketch)
|
||||||
|
|
||||||
|
if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then
|
||||||
|
echo "Skipping $sketch (not the main sketch file)"
|
||||||
|
fi
|
||||||
|
if skip_ino "$sketch" || [[ -f "$sketchdir/.test.skip" ]]; then
|
||||||
|
echo "Skipping $sketch"
|
||||||
|
fi
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user