tweak
This commit is contained in:
@@ -3,25 +3,37 @@
|
||||
set -e
|
||||
|
||||
help() {
|
||||
echo "Usage: $0 [-e <config|compile|clean>] [-c <string>] [-t <string>]" 1>&2
|
||||
echo "Usage: $0 [-e <config|compile|clean>] [-c <string>] [-t <string>] [-j <number>] [-p <string>] [-f]" 1>&2
|
||||
echo 1>&2
|
||||
echo " - e - Parameter for esphome command. Default compile. Common alternative is config." 1>&2
|
||||
echo " - c - Component folder name to test. Default *. E.g. '-c logger'." 1>&2
|
||||
echo " - t - Target name to test. Put '-t list' to display all possibilities. E.g. '-t esp32-s2-idf-51'." 1>&2
|
||||
echo " - j - Number of parallel jobs. Default is number of CPU cores." 1>&2
|
||||
echo " - p - Platform filter. E.g. '-p esp32' to test only ESP32 platforms." 1>&2
|
||||
echo " - f - Fail fast. Exit on first failure." 1>&2
|
||||
echo " - b - Build cache directory. E.g. '-b /tmp/esphome_cache'." 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse parameter:
|
||||
# - `e` - Parameter for `esphome` command. Default `compile`. Common alternative is `config`.
|
||||
# - `c` - Component folder name to test. Default `*`.
|
||||
esphome_command="compile"
|
||||
target_component="*"
|
||||
while getopts e:c:t: flag
|
||||
num_jobs=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
||||
platform_filter=""
|
||||
fail_fast=false
|
||||
build_cache_dir=""
|
||||
|
||||
while getopts e:c:t:j:p:b:fh flag
|
||||
do
|
||||
case $flag in
|
||||
e) esphome_command=${OPTARG};;
|
||||
c) target_component=${OPTARG};;
|
||||
t) requested_target_platform=${OPTARG};;
|
||||
j) num_jobs=${OPTARG};;
|
||||
p) platform_filter=${OPTARG};;
|
||||
f) fail_fast=true;;
|
||||
b) build_cache_dir=${OPTARG};;
|
||||
h) help;;
|
||||
\?) help;;
|
||||
esac
|
||||
done
|
||||
@@ -29,16 +41,66 @@ done
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if ! [ -d "./tests/test_build_components/build" ]; then
|
||||
mkdir ./tests/test_build_components/build
|
||||
mkdir -p ./tests/test_build_components/build
|
||||
fi
|
||||
|
||||
# Export build cache directory if specified
|
||||
if [ -n "$build_cache_dir" ]; then
|
||||
export PLATFORMIO_BUILD_CACHE_DIR="$build_cache_dir"
|
||||
mkdir -p "$build_cache_dir"
|
||||
echo "Using build cache directory: $build_cache_dir"
|
||||
fi
|
||||
|
||||
# Track PIDs for parallel execution
|
||||
pids=()
|
||||
failed_builds=()
|
||||
build_count=0
|
||||
total_builds=0
|
||||
|
||||
# Function to wait for jobs and handle failures
|
||||
wait_for_jobs() {
|
||||
local max_jobs=$1
|
||||
while [ ${#pids[@]} -ge $max_jobs ]; do
|
||||
for i in "${!pids[@]}"; do
|
||||
if ! kill -0 "${pids[$i]}" 2>/dev/null; then
|
||||
wait "${pids[$i]}"
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
failed_builds+=("${build_info[$i]}")
|
||||
if [ "$fail_fast" = true ]; then
|
||||
echo "Build failed, exiting due to fail-fast mode"
|
||||
# Kill remaining jobs
|
||||
for pid in "${pids[@]}"; do
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
unset pids[$i]
|
||||
unset build_info[$i]
|
||||
# Reindex arrays
|
||||
pids=("${pids[@]}")
|
||||
build_info=("${build_info[@]}")
|
||||
break
|
||||
fi
|
||||
done
|
||||
sleep 0.1
|
||||
done
|
||||
}
|
||||
|
||||
start_esphome() {
|
||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||
echo "Skipping $target_platform_with_version"
|
||||
return
|
||||
fi
|
||||
|
||||
# Apply platform filter if specified
|
||||
if [ -n "$platform_filter" ] && [[ ! "$target_platform_with_version" =~ ^$platform_filter ]]; then
|
||||
echo "Skipping $target_platform_with_version (filtered)"
|
||||
return
|
||||
fi
|
||||
|
||||
# create dynamic yaml file in `build` folder.
|
||||
# `./tests/test_build_components/build/[target_component].[test_name].[target_platform_with_version].yaml`
|
||||
component_test_file="./tests/test_build_components/build/$target_component.$test_name.$target_platform_with_version.yaml"
|
||||
|
||||
cp $target_platform_file $component_test_file
|
||||
@@ -49,17 +111,72 @@ start_esphome() {
|
||||
sed -i "s!\$component_test_file!../../.$f!g" $component_test_file
|
||||
fi
|
||||
|
||||
# Start esphome process
|
||||
echo "> [$target_component] [$test_name] [$target_platform_with_version]"
|
||||
set -x
|
||||
# TODO: Validate escape of Command line substitution value
|
||||
python3 -m esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file
|
||||
{ set +x; } 2>/dev/null
|
||||
# Start esphome process in background
|
||||
build_count=$((build_count + 1))
|
||||
echo "> [$build_count/$total_builds] [$target_component] [$test_name] [$target_platform_with_version]"
|
||||
|
||||
(
|
||||
# Add compile process limit for ESPHome internal parallelization
|
||||
export ESPHOME_COMPILE_PROCESS_LIMIT=2
|
||||
python3 -m esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file
|
||||
) &
|
||||
|
||||
local pid=$!
|
||||
pids+=($pid)
|
||||
build_info+=("$target_component/$test_name/$target_platform_with_version")
|
||||
|
||||
# Wait if we've reached the job limit
|
||||
wait_for_jobs $num_jobs
|
||||
}
|
||||
|
||||
# Find all test yaml files.
|
||||
# - `./tests/components/[target_component]/[test_name].[target_platform].yaml`
|
||||
# - `./tests/components/[target_component]/[test_name].all.yaml`
|
||||
# First pass: count total builds
|
||||
echo "Calculating total number of builds..."
|
||||
for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
[ -f "$f" ] || continue
|
||||
IFS='/' read -r -a folder_name <<< "$f"
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[4]}"
|
||||
target_platform="${file_name[1]}"
|
||||
file_name_parts=${#file_name[@]}
|
||||
|
||||
if [ "$target_platform" = "all" ] || [ $file_name_parts = 2 ]; then
|
||||
for target_platform_file in ./tests/test_build_components/build_components_base.*.yaml; do
|
||||
IFS='/' read -r -a folder_name <<< "$target_platform_file"
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[3]}"
|
||||
target_platform="${file_name[1]}"
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
|
||||
if [ -n "$platform_filter" ] && [[ ! "$target_platform_with_version" =~ ^$platform_filter ]]; then
|
||||
continue
|
||||
fi
|
||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||
continue
|
||||
fi
|
||||
total_builds=$((total_builds + 1))
|
||||
done
|
||||
else
|
||||
target_platform_file="./tests/test_build_components/build_components_base.$target_platform.yaml"
|
||||
if [ -f "$target_platform_file" ]; then
|
||||
for target_platform_file in ./tests/test_build_components/build_components_base.$target_platform*.yaml; do
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
|
||||
if [ -n "$platform_filter" ] && [[ ! "$target_platform_with_version" =~ ^$platform_filter ]]; then
|
||||
continue
|
||||
fi
|
||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||
continue
|
||||
fi
|
||||
total_builds=$((total_builds + 1))
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Total builds to execute: $total_builds with $num_jobs parallel jobs"
|
||||
echo
|
||||
|
||||
# Second pass: execute builds
|
||||
for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
[ -f "$f" ] || continue
|
||||
IFS='/' read -r -a folder_name <<< "$f"
|
||||
@@ -77,6 +194,8 @@ for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
IFS='/' read -r -a folder_name <<< "$target_platform_file"
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[3]}"
|
||||
target_platform="${file_name[1]}"
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
|
||||
start_esphome
|
||||
done
|
||||
@@ -85,9 +204,6 @@ for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
# Test has defined a specific target platform.
|
||||
|
||||
# Validate we have a base test yaml for selected platform.
|
||||
# The target_platform is sourced from the following location.
|
||||
# 1. `./tests/test_build_components/build_components_base.[target_platform].yaml`
|
||||
# 2. `./tests/test_build_components/build_components_base.[target_platform]-ard.yaml`
|
||||
target_platform_file="./tests/test_build_components/build_components_base.$target_platform.yaml"
|
||||
if ! [ -f "$target_platform_file" ]; then
|
||||
echo "No base test file [./tests/test_build_components/build_components_base.$target_platform.yaml] for component test [$f] found."
|
||||
@@ -104,3 +220,23 @@ for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# Wait for all remaining jobs
|
||||
wait_for_jobs 1
|
||||
|
||||
echo
|
||||
echo "============================================"
|
||||
echo "Build Summary:"
|
||||
echo "Total builds: $total_builds"
|
||||
echo "Failed builds: ${#failed_builds[@]}"
|
||||
|
||||
if [ ${#failed_builds[@]} -gt 0 ]; then
|
||||
echo
|
||||
echo "Failed builds:"
|
||||
for build in "${failed_builds[@]}"; do
|
||||
echo " - $build"
|
||||
done
|
||||
exit 1
|
||||
else
|
||||
echo "All builds completed successfully!"
|
||||
fi
|
||||
242
script/test_build_components_parallel
Executable file
242
script/test_build_components_parallel
Executable file
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
help() {
|
||||
echo "Usage: $0 [-e <config|compile|clean>] [-c <string>] [-t <string>] [-j <number>] [-p <string>] [-f]" 1>&2
|
||||
echo 1>&2
|
||||
echo " - e - Parameter for esphome command. Default compile. Common alternative is config." 1>&2
|
||||
echo " - c - Component folder name to test. Default *. E.g. '-c logger'." 1>&2
|
||||
echo " - t - Target name to test. Put '-t list' to display all possibilities. E.g. '-t esp32-s2-idf-51'." 1>&2
|
||||
echo " - j - Number of parallel jobs. Default is number of CPU cores." 1>&2
|
||||
echo " - p - Platform filter. E.g. '-p esp32' to test only ESP32 platforms." 1>&2
|
||||
echo " - f - Fail fast. Exit on first failure." 1>&2
|
||||
echo " - b - Build cache directory. E.g. '-b /tmp/esphome_cache'." 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Parse parameter:
|
||||
esphome_command="compile"
|
||||
target_component="*"
|
||||
num_jobs=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
||||
platform_filter=""
|
||||
fail_fast=false
|
||||
build_cache_dir=""
|
||||
|
||||
while getopts e:c:t:j:p:b:fh flag
|
||||
do
|
||||
case $flag in
|
||||
e) esphome_command=${OPTARG};;
|
||||
c) target_component=${OPTARG};;
|
||||
t) requested_target_platform=${OPTARG};;
|
||||
j) num_jobs=${OPTARG};;
|
||||
p) platform_filter=${OPTARG};;
|
||||
f) fail_fast=true;;
|
||||
b) build_cache_dir=${OPTARG};;
|
||||
h) help;;
|
||||
\?) help;;
|
||||
esac
|
||||
done
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
if ! [ -d "./tests/test_build_components/build" ]; then
|
||||
mkdir -p ./tests/test_build_components/build
|
||||
fi
|
||||
|
||||
# Export build cache directory if specified
|
||||
if [ -n "$build_cache_dir" ]; then
|
||||
export PLATFORMIO_BUILD_CACHE_DIR="$build_cache_dir"
|
||||
mkdir -p "$build_cache_dir"
|
||||
echo "Using build cache directory: $build_cache_dir"
|
||||
fi
|
||||
|
||||
# Track PIDs for parallel execution
|
||||
pids=()
|
||||
failed_builds=()
|
||||
build_count=0
|
||||
total_builds=0
|
||||
|
||||
# Function to wait for jobs and handle failures
|
||||
wait_for_jobs() {
|
||||
local max_jobs=$1
|
||||
while [ ${#pids[@]} -ge $max_jobs ]; do
|
||||
for i in "${!pids[@]}"; do
|
||||
if ! kill -0 "${pids[$i]}" 2>/dev/null; then
|
||||
wait "${pids[$i]}"
|
||||
exit_code=$?
|
||||
if [ $exit_code -ne 0 ]; then
|
||||
failed_builds+=("${build_info[$i]}")
|
||||
if [ "$fail_fast" = true ]; then
|
||||
echo "Build failed, exiting due to fail-fast mode"
|
||||
# Kill remaining jobs
|
||||
for pid in "${pids[@]}"; do
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
unset pids[$i]
|
||||
unset build_info[$i]
|
||||
# Reindex arrays
|
||||
pids=("${pids[@]}")
|
||||
build_info=("${build_info[@]}")
|
||||
break
|
||||
fi
|
||||
done
|
||||
sleep 0.1
|
||||
done
|
||||
}
|
||||
|
||||
start_esphome() {
|
||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||
echo "Skipping $target_platform_with_version"
|
||||
return
|
||||
fi
|
||||
|
||||
# Apply platform filter if specified
|
||||
if [ -n "$platform_filter" ] && [[ ! "$target_platform_with_version" =~ ^$platform_filter ]]; then
|
||||
echo "Skipping $target_platform_with_version (filtered)"
|
||||
return
|
||||
fi
|
||||
|
||||
# create dynamic yaml file in `build` folder.
|
||||
component_test_file="./tests/test_build_components/build/$target_component.$test_name.$target_platform_with_version.yaml"
|
||||
|
||||
cp $target_platform_file $component_test_file
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS sed is...different
|
||||
sed -i '' "s!\$component_test_file!../../.$f!g" $component_test_file
|
||||
else
|
||||
sed -i "s!\$component_test_file!../../.$f!g" $component_test_file
|
||||
fi
|
||||
|
||||
# Start esphome process in background
|
||||
build_count=$((build_count + 1))
|
||||
echo "> [$build_count/$total_builds] [$target_component] [$test_name] [$target_platform_with_version]"
|
||||
|
||||
(
|
||||
# Add compile process limit for ESPHome internal parallelization
|
||||
export ESPHOME_COMPILE_PROCESS_LIMIT=2
|
||||
python3 -m esphome -s component_name $target_component -s component_dir ../../components/$target_component -s test_name $test_name -s target_platform $target_platform $esphome_command $component_test_file
|
||||
) &
|
||||
|
||||
local pid=$!
|
||||
pids+=($pid)
|
||||
build_info+=("$target_component/$test_name/$target_platform_with_version")
|
||||
|
||||
# Wait if we've reached the job limit
|
||||
wait_for_jobs $num_jobs
|
||||
}
|
||||
|
||||
# First pass: count total builds
|
||||
echo "Calculating total number of builds..."
|
||||
for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
[ -f "$f" ] || continue
|
||||
IFS='/' read -r -a folder_name <<< "$f"
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[4]}"
|
||||
target_platform="${file_name[1]}"
|
||||
file_name_parts=${#file_name[@]}
|
||||
|
||||
if [ "$target_platform" = "all" ] || [ $file_name_parts = 2 ]; then
|
||||
for target_platform_file in ./tests/test_build_components/build_components_base.*.yaml; do
|
||||
IFS='/' read -r -a folder_name <<< "$target_platform_file"
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[3]}"
|
||||
target_platform="${file_name[1]}"
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
|
||||
if [ -n "$platform_filter" ] && [[ ! "$target_platform_with_version" =~ ^$platform_filter ]]; then
|
||||
continue
|
||||
fi
|
||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||
continue
|
||||
fi
|
||||
total_builds=$((total_builds + 1))
|
||||
done
|
||||
else
|
||||
target_platform_file="./tests/test_build_components/build_components_base.$target_platform.yaml"
|
||||
if [ -f "$target_platform_file" ]; then
|
||||
for target_platform_file in ./tests/test_build_components/build_components_base.$target_platform*.yaml; do
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
|
||||
if [ -n "$platform_filter" ] && [[ ! "$target_platform_with_version" =~ ^$platform_filter ]]; then
|
||||
continue
|
||||
fi
|
||||
if [ -n "$requested_target_platform" ] && [ "$requested_target_platform" != "$target_platform_with_version" ]; then
|
||||
continue
|
||||
fi
|
||||
total_builds=$((total_builds + 1))
|
||||
done
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Total builds to execute: $total_builds with $num_jobs parallel jobs"
|
||||
echo
|
||||
|
||||
# Second pass: execute builds
|
||||
for f in ./tests/components/$target_component/*.*.yaml; do
|
||||
[ -f "$f" ] || continue
|
||||
IFS='/' read -r -a folder_name <<< "$f"
|
||||
target_component="${folder_name[3]}"
|
||||
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[4]}"
|
||||
test_name="${file_name[0]}"
|
||||
target_platform="${file_name[1]}"
|
||||
file_name_parts=${#file_name[@]}
|
||||
|
||||
if [ "$target_platform" = "all" ] || [ $file_name_parts = 2 ]; then
|
||||
# Test has *not* defined a specific target platform. Need to run tests for all possible target platforms.
|
||||
|
||||
for target_platform_file in ./tests/test_build_components/build_components_base.*.yaml; do
|
||||
IFS='/' read -r -a folder_name <<< "$target_platform_file"
|
||||
IFS='.' read -r -a file_name <<< "${folder_name[3]}"
|
||||
target_platform="${file_name[1]}"
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
|
||||
start_esphome
|
||||
done
|
||||
|
||||
else
|
||||
# Test has defined a specific target platform.
|
||||
|
||||
# Validate we have a base test yaml for selected platform.
|
||||
target_platform_file="./tests/test_build_components/build_components_base.$target_platform.yaml"
|
||||
if ! [ -f "$target_platform_file" ]; then
|
||||
echo "No base test file [./tests/test_build_components/build_components_base.$target_platform.yaml] for component test [$f] found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for target_platform_file in ./tests/test_build_components/build_components_base.$target_platform*.yaml; do
|
||||
# trim off "./tests/test_build_components/build_components_base." prefix
|
||||
target_platform_with_version=${target_platform_file:52}
|
||||
# ...now remove suffix starting with "." leaving just the test target hardware and software platform (possibly with version)
|
||||
# For example: "esp32-s3-idf-50"
|
||||
target_platform_with_version=${target_platform_with_version%.*}
|
||||
start_esphome
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# Wait for all remaining jobs
|
||||
wait_for_jobs 1
|
||||
|
||||
echo
|
||||
echo "============================================"
|
||||
echo "Build Summary:"
|
||||
echo "Total builds: $total_builds"
|
||||
echo "Failed builds: ${#failed_builds[@]}"
|
||||
|
||||
if [ ${#failed_builds[@]} -gt 0 ]; then
|
||||
echo
|
||||
echo "Failed builds:"
|
||||
for build in "${failed_builds[@]}"; do
|
||||
echo " - $build"
|
||||
done
|
||||
exit 1
|
||||
else
|
||||
echo "All builds completed successfully!"
|
||||
fi
|
||||
Reference in New Issue
Block a user