Skip to content

Commit 8ec6d47

Browse files
authored
Merge pull request #11766 from JakubAndrysek/ci/arduino-cli-lib-install
Add function to handle library installation from ci.json
2 parents 098d4f3 + eac284b commit 8ec6d47

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

.github/scripts/sketch_utils.sh

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@ function build_sketch { # build_sketch <ide_path> <user_path> <path-to-ino> [ext
244244
fi
245245
fi
246246

247+
# Install libraries from ci.json if they exist
248+
install_libs -ai "$ide_path" -s "$sketchdir"
249+
install_result=$?
250+
if [ $install_result -ne 0 ]; then
251+
echo "ERROR: Library installation failed for $sketchname" >&2
252+
exit $install_result
253+
fi
254+
247255
ARDUINO_CACHE_DIR="$HOME/.arduino/cache.tmp"
248256
if [ -n "$ARDUINO_BUILD_DIR" ]; then
249257
build_dir="$ARDUINO_BUILD_DIR"
@@ -580,13 +588,168 @@ function build_sketches { # build_sketches <ide_path> <user_path> <target> <path
580588
return 0
581589
}
582590

591+
# Return 0 if the string looks like a git URL we should pass to --git-url
592+
is_git_like_url() {
593+
local u=$1
594+
[[ "$u" =~ ^https?://.+ ]] || [[ "$u" =~ ^git@[^:]+:.+ ]]
595+
}
596+
597+
# If status!=0, print errors/warnings from captured output (fallback to full output)
598+
print_err_warnings() {
599+
local status=$1; shift
600+
local out=$*
601+
if [ "$status" -ne 0 ]; then
602+
printf '%s\n' "$out" | grep -Ei "error|warning|warn" >&2 || printf '%s\n' "$out" >&2
603+
fi
604+
}
605+
606+
function install_libs { # install_libs <ide_path> <sketchdir> [-v]
607+
local ide_path=""
608+
local sketchdir=""
609+
local verbose=false
610+
611+
while [ -n "$1" ]; do
612+
case "$1" in
613+
-ai ) shift; ide_path=$1 ;;
614+
-s ) shift; sketchdir=$1 ;;
615+
-v ) verbose=true ;;
616+
* )
617+
echo "ERROR: Unknown argument: $1" >&2
618+
echo "USAGE: install_libs -ai <ide_path> -s <sketchdir> [-v]" >&2
619+
return 1
620+
;;
621+
esac
622+
shift
623+
done
624+
625+
if [ -z "$ide_path" ]; then
626+
echo "ERROR: IDE path not provided" >&2
627+
echo "USAGE: install_libs -ai <ide_path> -s <sketchdir> [-v]" >&2
628+
return 1
629+
fi
630+
if [ -z "$sketchdir" ]; then
631+
echo "ERROR: Sketch directory not provided" >&2
632+
echo "USAGE: install_libs -ai <ide_path> -s <sketchdir> [-v]" >&2
633+
return 1
634+
fi
635+
if [ ! -f "$ide_path/arduino-cli" ]; then
636+
echo "ERROR: arduino-cli not found at $ide_path/arduino-cli" >&2
637+
return 1
638+
fi
639+
640+
if [ ! -f "$sketchdir/ci.json" ]; then
641+
[ "$verbose" = true ] && echo "No ci.json found in $sketchdir, skipping library installation"
642+
return 0
643+
fi
644+
if ! jq -e . "$sketchdir/ci.json" >/dev/null 2>&1; then
645+
echo "ERROR: $sketchdir/ci.json is not valid JSON" >&2
646+
return 1
647+
fi
648+
649+
local libs_type
650+
libs_type=$(jq -r '.libs | type' "$sketchdir/ci.json" 2>/dev/null)
651+
if [ -z "$libs_type" ] || [ "$libs_type" = "null" ]; then
652+
[ "$verbose" = true ] && echo "No libs field found in ci.json, skipping library installation"
653+
return 0
654+
elif [ "$libs_type" != "array" ]; then
655+
echo "ERROR: libs field in ci.json must be an array, found: $libs_type" >&2
656+
return 1
657+
fi
658+
659+
local libs_count
660+
libs_count=$(jq -r '.libs | length' "$sketchdir/ci.json" 2>/dev/null)
661+
if [ "$libs_count" -eq 0 ]; then
662+
[ "$verbose" = true ] && echo "libs array is empty in ci.json, skipping library installation"
663+
return 0
664+
fi
665+
666+
echo "Installing $libs_count libraries from $sketchdir/ci.json"
667+
668+
local needs_unsafe=false
669+
local original_unsafe_setting=""
670+
local libs
671+
libs=$(jq -r '.libs[]? // empty' "$sketchdir/ci.json")
672+
673+
# Detect any git-like URL (GitHub/GitLab/Bitbucket/self-hosted/ssh)
674+
for lib in $libs; do
675+
if is_git_like_url "$lib"; then
676+
needs_unsafe=true
677+
break
678+
fi
679+
done
680+
681+
if [ "$needs_unsafe" = true ]; then
682+
[ "$verbose" = true ] && echo "Checking current unsafe install setting..."
683+
original_unsafe_setting=$("$ide_path/arduino-cli" config get library.enable_unsafe_install 2>/dev/null || echo "false")
684+
if [ "$original_unsafe_setting" = "false" ]; then
685+
[ "$verbose" = true ] && echo "Enabling unsafe installs for Git URLs..."
686+
"$ide_path/arduino-cli" config set library.enable_unsafe_install true >/dev/null 2>&1 || \
687+
echo "WARNING: Failed to enable unsafe installs, Git URL installs may fail" >&2
688+
else
689+
[ "$verbose" = true ] && echo "Unsafe installs already enabled"
690+
fi
691+
fi
692+
693+
local rc=0 install_status=0 output=""
694+
for lib in $libs; do
695+
[ "$verbose" = true ] && echo "Processing library: $lib"
696+
697+
if is_git_like_url "$lib"; then
698+
[ "$verbose" = true ] && echo "Installing library from git URL: $lib"
699+
if [ "$verbose" = true ]; then
700+
"$ide_path/arduino-cli" lib install --git-url "$lib"
701+
install_status=$?
702+
else
703+
output=$("$ide_path/arduino-cli" lib install --git-url "$lib" 2>&1)
704+
install_status=$?
705+
fi
706+
else
707+
[ "$verbose" = true ] && echo "Installing library by name: $lib"
708+
if [ "$verbose" = true ]; then
709+
"$ide_path/arduino-cli" lib install "$lib"
710+
install_status=$?
711+
else
712+
output=$("$ide_path/arduino-cli" lib install "$lib" 2>&1)
713+
install_status=$?
714+
fi
715+
fi
716+
717+
# Treat "already installed"/"up to date" as success (idempotent)
718+
if [ $install_status -ne 0 ] && echo "$output" | grep -qiE 'already installed|up to date'; then
719+
install_status=0
720+
fi
721+
722+
if [ "$verbose" != true ]; then
723+
print_err_warnings "$install_status" "$output"
724+
fi
725+
726+
if [ $install_status -ne 0 ]; then
727+
echo "ERROR: Failed to install library: $lib" >&2
728+
rc=$install_status
729+
break
730+
else
731+
[ "$verbose" = true ] && echo "Successfully installed library: $lib"
732+
fi
733+
done
734+
735+
if [ "$needs_unsafe" = true ] && [ "$original_unsafe_setting" = "false" ]; then
736+
[ "$verbose" = true ] && echo "Restoring original unsafe install setting..."
737+
"$ide_path/arduino-cli" config set library.enable_unsafe_install false >/dev/null 2>&1 || true
738+
fi
739+
740+
[ $rc -eq 0 ] && echo "Library installation completed"
741+
return $rc
742+
}
743+
744+
583745
USAGE="
584746
USAGE: ${0} [command] [options]
585747
Available commands:
586748
count: Count sketches.
587749
build: Build a sketch.
588750
chunk_build: Build a chunk of sketches.
589751
check_requirements: Check if target meets sketch requirements.
752+
install_libs: Install libraries from ci.json file.
590753
"
591754

592755
cmd=$1
@@ -606,6 +769,8 @@ case "$cmd" in
606769
;;
607770
"check_requirements") check_requirements "$@"
608771
;;
772+
"install_libs") install_libs "$@"
773+
;;
609774
*)
610775
echo "ERROR: Unrecognized command"
611776
echo "$USAGE"

docs/en/contributing.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ The ``ci.json`` file is used to specify how the test suite and sketches will han
425425
* ``fqbn``: A dictionary that specifies the FQBNs that will be used to compile the sketch. The key is the target name and the value is a list
426426
of FQBNs. The `default FQBNs <https://github.com/espressif/arduino-esp32/blob/a31a5fca1739993173caba995f7785b8eed6b30e/.github/scripts/sketch_utils.sh#L86-L91>`_
427427
are used if this field is not specified. This overrides the default FQBNs and the ``fqbn_append`` field.
428+
* ``libs``: A list of libraries that are required to run the test suite. The libraries will be installed automatically if they are not already present.
429+
Libraries are installed using the ``arduino-cli lib install`` command, so you can specify libraries by name + version (e.g., ``[email protected]``)
430+
or by URL (e.g., ``https://github.com/arduino-libraries/WiFi101.git``).
431+
More information can be found in the `Arduino CLI documentation <https://arduino.github.io/arduino-cli/1.3/commands/arduino-cli_lib_install/>`_.
428432

429433
The ``wifi`` test suite is a good example of how to use the ``ci.json`` file:
430434

0 commit comments

Comments
 (0)