#!/usr/bin/env bash # # Usage: # # build_all_examples [-b|--branch=] - Branch to fetch from Configurations repo (import-2.1.x) # [-B|--base] - Base path of configurations, overriding -b # [-c|--continue] - Continue the paused build # [-p|--purge] - Purge the status file and start over # [-s|--skip] - Continue the paused build, skipping one # [-r|--resume=] - Start at some config in the filesystem order # [-l|--limit=#] - Limit the number of builds in this run # [-d|--debug] - Print extra debug output (after) # [-n|--nobuild] - Don't actually build anything # [-f|--nofail] - Don't stop on a failed build # [-e|--export=N] - Set CONFIG_EXPORT and export into each config folder # [-a|--archive] - Copy the binary to the export location # [-o|--output] - Redirect export / archiving to another location # (By default export to origin config folders) # [-h|--help] - Print usage and exit # HERE=`dirname $0` . "$HERE/mfutil" GITREPO=https://github.com/MarlinFirmware/Configurations.git STAT_FILE=./.pio/.buildall usage() { echo "Usage: build_all_examples [-b|--branch=] - Branch to fetch from Configurations repo (import-2.1.x) [-B|--base] - Base path of configurations, overriding -b [-c|--continue] - Continue the paused build [-p|--purge] - Purge the status file and start over [-s|--skip] - Continue the paused build, skipping one [-r|--resume=] - Start at some config in the filesystem order [-e|--export=N] - Set CONFIG_EXPORT and export to the export location [-a|--archive] - Copy the binary to the export location [-o|--output] - Redirect export / archiving to another location (By default export to origin config folders) [-d|--debug] - Print extra debug output (after) [-l|--limit=#] - Limit the number of builds in this run [-n|--nobuild] - Don't actually build anything [-f|--nofail] - Don't stop on a failed build [-h|--help] - Print usage and exit " } # Assume the most recent configs BRANCH=import-2.1.x unset FIRST_CONF EXIT_USAGE= LIMIT=1000 while getopts 'aB:b:ce:fdhl:no:pr:sv-:' OFLAG; do case "${OFLAG}" in a) ARCHIVE=1 ; bugout "Archiving" ;; B) OPATH=${OPTARG%/} ; bugout "Base: $OPATH" ;; b) BRANCH=$OPTARG ; bugout "Branch: $BRANCH" ;; f) NOFAIL=1 ; bugout "Continue on Fail" ;; r) ISRES=1 ; FIRST_CONF=$OPTARG ; bugout "Resume: $FIRST_CONF" ;; c) CONTINUE=1 ; bugout "Continue" ;; s) CONTSKIP=1 ; bugout "Continue, skipping" ;; e) CEXPORT=$OPTARG ; bugout "Export $CEXPORT" ;; o) OUTBASE="${OPTARG%/}" ; bugout "Archive to $OUTBASE" ;; h) EXIT_USAGE=1 ; break ;; l) LIMIT=$OPTARG ; bugout "Limit to $LIMIT build(s)" ;; d|v) DEBUG=1 ; bugout "Debug ON" ;; n) DRYRUN=1 ; bugout "Dry Run" ;; p) PURGE=1 ; bugout "Purge stat file" ;; -) ONAM="${OPTARG%%=*}" ; OVAL="${OPTARG#*=}" case "$ONAM" in archive) ARCHIVE=1 ; bugout "Archiving" ;; base) OPATH=${OVAL%/} ; bugout "Base: $OPATH" ;; branch) BRANCH=$OVAL ; bugout "Branch: $BRANCH" ;; nofail) NOFAIL=1 ; bugout "Continue on Fail" ;; resume) ISRES=1 ; FIRST_CONF=$OVAL ; bugout "Resume: $FIRST_CONF" ;; continue) CONTINUE=1 ; bugout "Continue" ;; skip) CONTSKIP=1 ; bugout "Continue, skipping" ;; export) CEXPORT=$OVAL ; bugout "Export $EXPORT" ;; output) OUTBASE="${OVAL%/}" ; bugout "Archive to $OUTBASE" ;; limit) LIMIT=$OVAL ; bugout "Limit to $LIMIT build(s)" ;; help) [[ -z "$OVAL" ]] || perror "option can't take value $OVAL" $ONAM ; EXIT_USAGE=1 ;; debug) DEBUG=1 ; bugout "Debug ON" ;; nobuild) DRYRUN=1 ; bugout "Dry Run" ;; purge) PURGE=1 ; bugout "Purge stat file" ;; *) EXIT_USAGE=2 ; echo "$SELF: unrecognized option \`--$ONAM'" ; break ;; esac ;; *) EXIT_USAGE=2 ; break ;; esac done shift $((OPTIND - 1)) # Check for mixed continue, skip, resume arguments. Only one should be used. ((CONTINUE + CONTSKIP + ISRES + PURGE > 1)) && { echo "Don't mix -c, -p, -s, and -r options" ; echo ; EXIT_USAGE=2 ; } # Exit with helpful usage information ((EXIT_USAGE)) && { usage ; let EXIT_USAGE-- ; exit $EXIT_USAGE ; } echo echo "This script downloads all example configs and attempts to build them." echo "On failure the last-built configs are left in your working copy." echo "Restore your configs with 'git checkout -f' or 'git reset --hard HEAD'." echo [[ -n $PURGE ]] && rm -f "$STAT_FILE" [[ -z $FIRST_CONF && -f "$STAT_FILE" ]] && IFS='*' read BRANCH FIRST_CONF <"$STAT_FILE" # If -c is given start from the last attempted build if ((CONTINUE)); then if [[ -z $BRANCH || -z $FIRST_CONF ]]; then echo "Nothing to continue" exit fi elif ((CONTSKIP)); then if [[ -n $BRANCH && -n $FIRST_CONF ]]; then SKIP_CONF=1 else echo "Nothing to skip" exit fi fi # Check if the current repository has unmerged changes if ((SKIP_CONF)); then echo "Skipping $FIRST_CONF" elif [[ -n $FIRST_CONF ]]; then echo "Resuming from $FIRST_CONF" else git diff --quiet || { echo "The working copy is modified. Commit or stash changes before proceeding."; exit ; } fi # Create a temporary folder inside .pio if [[ -n $OPATH ]]; then [[ -d "$OPATH" ]] || { echo "Given base -B $OPATH not found." ; exit ; } else # Make a Configurations temporary folder if needed OPATH=./.pio/build-$BRANCH [[ -d "$OPATH" ]] || mkdir -p "$OPATH" # Download the specified Configurations branch if needed if [[ ! -e "$OPATH/README.md" ]]; then echo "Fetching Configurations from GitHub to $OPATH" git clone --depth=1 --single-branch --branch "$BRANCH" $GITREPO "$OPATH" || { echo "Failed to clone the configuration repository"; exit ; } fi fi # Build echo -e "=====================\nProceed with builds...\n=====================" shopt -s nullglob shopt -s globstar IFS=' ' CONF_TREE=$( ls -d "$OPATH"/config/examples/**/ | grep -vE ".+\.(\w+)$" ) for CONF in $CONF_TREE ; do # Get a config's directory name DIR=${CONF#$OPATH/config/examples/} # If looking for a config, skip others [[ $FIRST_CONF ]] && [[ $FIRST_CONF != $DIR && "$FIRST_CONF/" != $DIR ]] && continue # Once found, stop looking unset FIRST_CONF # If skipping, don't build the found one [[ $SKIP_CONF ]] && { unset SKIP_CONF ; continue ; } # At least one config file is required here compgen -G "${CONF}Configuration*.h" > /dev/null || continue # Command arguments for 'build_example' CARGS=("-b" "$OPATH" "-c" "$DIR") # Exporting? Add -e argument ((CEXPORT)) && CARGS+=("-e" "$CEXPORT") # Continue on fail? Add -f argument ((NOFAIL)) && CARGS+=("-f") # Archive the build? Add -a argument ((ARCHIVE)) && CARGS+=("-a") # Redirecting the export/archive output? Add -o argument [[ -n $OUTBASE ]] && CARGS+=("-o" "$OUTBASE") # Build or print build command for --nobuild if ((DRYRUN)); then echo -e "\033[0;32m[DRYRUN] build_example ${CARGS[@]}\033[0m" else # Remember where we are in case of failure echo "${BRANCH}*${DIR}" >"$STAT_FILE" ((DEBUG)) && echo "\"$HERE/build_example\" ${CARGS[@]}" # Invoke build_example "$HERE"/build_example "${CARGS[@]}" || { echo "Failed to build $DIR" ; exit ; } fi ((--LIMIT)) || { echo "Limit reached" ; PAUSE=1 ; break ; } echo ; echo done # Delete the build state if not paused early [[ $PAUSE ]] || rm "$STAT_FILE"