#!/usr/bin/env bash # kaleidoscope-builder - Kaleidoscope helper tool # Copyright (C) 2017-2018 Keyboard.io, Inc. # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, version 3. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . set -e ###### ###### Build and output configuration ###### identify_os() { ## Platform-specific overrides # Shamelessly stolen from git's Makefile uname_S=$(uname -s 2>/dev/null || echo not) uname_O=$(uname -o 2>/dev/null || echo not) } adjust_for_virtual_build() { if [ "${uname_S}" = "FreeBSD" ]; then : "${COMPILER_PATH:=/usr/local/bin/}" else : "${COMPILER_PATH:=/usr/bin/}" fi COMPILER_PREFIX="" } adjust_for_cygwin() { # The Windows arduino-builder.exe doesn't understand being told to exec against Cygwin symlinks CCACHE_NOT_SUPPORTED=1 # It's important that all of these be underneath /cygdrive/c so they can be converted to Windows paths that the # Windows Arduino binaries can understand. : "${TMPDIR:=/cygdrive/c/Users/${USER}/AppData/Local/Temp}" # We need to prevent Windows executables from being passed parameters that are absolute paths, since they won't # be interpretable when of the form /cygdrive/c/foo. To work around this, we set the common path root variables # to use relative paths instead of absolute paths, since those have mostly platform-agnostic behavior. # # Note that this trick requires that all of these paths exist on the same drive letter as the current directory, # since otherwise even the relative paths would include Cygwin-specific components. So... if [[ $(realpath --relative-base=/cygdrive/c .) == /* ]]; then echo "kaleidoscope-builder's Cygwin support is currently limited to running from within /cygdrive/c" exit 1 fi TMPDIR="$(realpath --relative-to=./ ${TMPDIR})" } absolute_filename() { echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")" } read_conf_files() { for conf_file in \ "${HOME}/.kaleidoscope-builder.conf" \ "$(pwd)/.kaleidoscope-builder.conf" \ "$(pwd)/kaleidoscope-builder.conf"; do if [ -e "${conf_file}" ]; then # shellcheck disable=SC1090 . "${conf_file}" fi done } configure_arduino_cli_env() { SYSTEM_ARDUINO_CLI="$(command -v arduino-cli || true)" if [ -z "${SYSTEM_ARDUINO_CLI}" ]; then : "${ARDUINO_CLI:=${KALEIDOSCOPE_BIN_DIR}/arduino-cli}" else : "${ARDUINO_CLI:=${SYSTEM_ARDUINO_CLI}}" fi : "${ARDUINO_CONTENT:=${KALEIDOSCOPE_DIR}/.arduino}" : "${ARDUINO_DIRECTORIES_DATA:=${ARDUINO_CONTENT}/data}" : "${ARDUINO_DIRECTORIES_DOWNLOADS:=${ARDUINO_CONTENT}/downloads}" : "${ARDUINO_DIRECTORIES_USER:=${ARDUINO_CONTENT}/user}" : "${ARDUINO_CLI_CONFIG:=${ARDUINO_DIRECTORIES_DATA}/arduino-cli.yaml}" : "${ARDUINO_BOARDS_MANAGER_KALEIDOSCOPE:=https://raw.githubusercontent.com/keyboardio/boardsmanager/master/package_keyboardio_index.json}" } install_arduino_cli() { # todo cd to kaleidoscope dir curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh } configure_arduino_cli() { if [ -z "${ARDUINO_CLI}" ]; then install_arduino_cli fi if [ -z "${ARDUINO_CLI_CONFIG}" ]; then install_arduino_cli_config fi } install_arduino_cli_config() { run_arduino_cli config init } install_arduino_core_kaleidoscope() { install_arduino_core_avr install_arduino_core "keyboardio:avr" } install_arduino_core_avr() { install_arduino_core "arduino:avr" } install_arduino_core() { run_arduino_cli core install "$1" } run_arduino_cli() { ARDUINO_DIRECTORIES_USER=${ARDUINO_DIRECTORIES_USER} \ ARDUINO_DIRECTORIES_DATA=${ARDUINO_DIRECTORIES_DATA} \ ARDUINO_DIRECTORIES_DOWNLOADS=${ARDUINO_DIRECTORIES_DOWNLOADS} \ ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS=${ARDUINO_BOARDS_MANAGER_KALEIDOSCOPE} \ "${ARDUINO_CLI}" "$@" } build_version() { : "${LIB_PROPERTIES_PATH:="../.."}" GIT_VERSION="$( cd "${SKETCH_DIR}" if [ -d .git ]; then echo -n '-g' && git describe --abbrev=4 --dirty --always; fi )" LIB_VERSION="$( cd "${SKETCH_DIR}" (grep version= "${LIB_PROPERTIES_PATH}/library.properties" 2>/dev/null || echo version=0.0.0) | cut -d= -f2 )${GIT_VERSION}" } build_paths() { # We need that echo because we\re piping to cksum # shellcheck disable=SC2005 SKETCH_IDENTIFIER="$(echo "${SKETCH_FILE_PATH}" | cksum | cut -d ' ' -f 1)-${SKETCH_FILE_NAME}" : "${KALEIDOSCOPE_TEMP_PATH:=${TMPDIR:-/tmp}/kaleidoscope-${USER}}" : "${KALEIDOSCOPE_BUILD_PATH:=${KALEIDOSCOPE_TEMP_PATH}/sketch}" : "${KALEIDOSCOPE_OUTPUT_PATH:=${KALEIDOSCOPE_TEMP_PATH}/sketch}" : "${SKETCH_OUTPUT_DIR:=${SKETCH_IDENTIFIER}/output}" : "${SKETCH_BUILD_DIR:=${SKETCH_IDENTIFIER}/build}" : "${BUILD_PATH:=${KALEIDOSCOPE_BUILD_PATH}/${SKETCH_BUILD_DIR}}" : "${OUTPUT_PATH:=${KALEIDOSCOPE_OUTPUT_PATH}/${SKETCH_OUTPUT_DIR}}" : "${CCACHE_WRAPPER_PATH:=${KALEIDOSCOPE_TEMP_PATH}/ccache/bin}" : "${CORE_CACHE_PATH:=${KALEIDOSCOPE_TEMP_PATH}/arduino-cores}" mkdir -p "$CORE_CACHE_PATH" mkdir -p "$BUILD_PATH" } build_filenames() { : "${OUTPUT_FILE_PREFIX:=${SKETCH_BASE_NAME}-${LIB_VERSION}}" : "${HEX_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.hex}" : "${HEX_FILE_WITH_BOOTLOADER_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}-with-bootloader.hex}" : "${ELF_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.elf}" : "${LIB_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.a}" } enable_ccache() { if [ -z "${CCACHE_NOT_SUPPORTED}" ] && [ "$(command -v ccache)" ]; then if ! [ -d "$CCACHE_WRAPPER_PATH" ]; then mkdir -p "$CCACHE_WRAPPER_PATH" if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}" ]; then ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}" fi if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}" ]; then ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}" fi if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm" ]; then ln -s "${AVR_NM}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm" fi if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy" ]; then ln -s "${AVR_OBJCOPY}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy" fi if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar" ]; then ln -s "${AVR_AR}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar" fi if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size" ]; then ln -s "${AVR_SIZE}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size" fi fi export CCACHE_PATH=${COMPILER_PATH}/ CCACHE_ENABLED=1 fi } firmware_size() { if [ "${ARCH}" = "virtual" ]; then echo "[Size not computed for virtual build]" return fi : "${MAX_PROG_SIZE:=$(get_arduino_pref 'upload.maximum_size')}" ## This is a terrible hack, please don't hurt me. - algernon set +e raw_output=$("$@" 2>/dev/null) rc=$? set -e if [ $rc -eq 0 ]; then output="$(echo "${raw_output}" | grep "\\(Program\\|Data\\):" | sed -e 's,^, - ,' && echo)" PROGSIZE="$(echo "${output}" | grep "Program:" | cut -d: -f2 | awk '{print $1}')" PERCENT="$(echo "${PROGSIZE}" "${MAX_PROG_SIZE}" | awk "{ printf \"%02.01f\", \$1 / \$2 * 100 }")" # we want the sed there, doing with shell builtins would be worse. # shellcheck disable=SC2001 disable=SC1117 echo "${output}" | sed -e "s/\(Program:.*\)(\([0-9\.]*%\) Full)/\1(${PERCENT}% Full)/" else echo "Unable to determine image size." fi } find_sketch() { SKETCH_DIR="${SKETCH:-$(absolute_filename "$(pwd)")}" SKETCH_BASE_NAME=$(basename "${SKETCH_DIR}") SKETCH_FILE_NAME="${SKETCH_BASE_NAME}.ino" # Arduino sketches are usually a file inside directory Foo named Foo.ino, so try that as a fallback for dir in \ "${SKETCH_DIR}" \ "src/" \ "."; do if [ -f "${dir}/${SKETCH_FILE_NAME}" ]; then SKETCH_DIR="${dir}" SKETCH_FILE_PATH=$(absolute_filename "${dir}/${SKETCH_FILE_NAME}") return fi done echo "I couldn't find your sketch (.ino file)" >&2 exit 1 } find_device_vid_pid() { : "${VID:=$(get_arduino_pref 'build.vid')}" : "${SKETCH_PID:=$(get_arduino_pref 'build.pid')}" : "${BOOTLOADER_PID:=$(get_arduino_pref 'bootloader.pid')}" : "${BOOTLOADER_VID:=$(get_arduino_pref 'bootloader.vid')}" } prompt_before_flashing() { flashing_instructions=$(get_arduino_pref 'build.flashing_instructions') if [ "x${flashing_instructions}x" = "xx" ]; then flashing_instructions="If your keyboard needs you to do something to put it in flashing mode, do that now." fi printf '%b\n\n' "${flashing_instructions}" echo "" echo "When you're ready to proceed, press 'Enter'." # We do not want to permit line continuations here. We just want a newline. # shellcheck disable=SC2162 read } flash() { compile "$@" # Check to see if we can see a keyboard bootloader port. # If we -can-, then we should skip over the "reset to bootloader" thing find_bootloader_ports if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then prompt_before_flashing # This is defined in the (optional) user config. # shellcheck disable=SC2154 ${preFlash_HOOKS} fi find_device_port run_arduino_cli upload \ --fqbn "${FQBN}" \ --port "${DEVICE_PORT}" \ --verbose # This is defined in the (optional) user config. # shellcheck disable=SC2154 ${postFlash_HOOKS} } flash_from_bootloader() { compile "$@" prompt_before_flashing find_bootloader_ports run_arduino_cli upload \ --fqbn "${FQBN}" \ --port "${DEVICE_PORT_BOOTLOADER}" \ --verbose return 0 } hex_with_bootloader() { compile : "${BOOTLOADER_PATH:=$(get_arduino_pref 'runtime.platform.path')/bootloaders/$(get_arduino_pref 'bootloader.file')}" awk '/^:00000001FF/ == 0' "${HEX_FILE_PATH}" >"${HEX_FILE_WITH_BOOTLOADER_PATH}" echo "Using ${BOOTLOADER_PATH}" cat "${BOOTLOADER_PATH}" >>"${HEX_FILE_WITH_BOOTLOADER_PATH}" ln -sf -- "${OUTPUT_FILE_PREFIX}-with-bootloader.hex" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest-with-bootloader.hex" cat <<-EOF Combined firmware and bootloader are now at ${HEX_FILE_WITH_BOOTLOADER_PATH} Make sure you have the bootloader version you expect. And TEST THIS ON REAL HARDWARE BEFORE YOU GIVE IT TO ANYONE EOF } build() { compile "$@" size "$@" } prepare_ccache() { find_sketch build_paths enable_ccache } compile() { find_sketch set_executable_paths build_version build_paths build_filenames # If the hex file is older than the sketch file, or the hex file does not exist # then rebuild. This is not as correct as letting make check our dependencies # But it's less broken for most user use cases # TODO(anyone): Make this suck less if [ "${HEX_FILE_PATH}" -ot "${SKETCH_FILE_PATH}" ]; then do_compile "$@" else echo "${HEX_FILE_PATH} did not need to be rebuilt" fi } set_executable_paths() { ###### ###### Executable paths ###### # Allow the compiler path to be empty for virtual builds # should use compiler.path instead of appending bin, but we don't have substitution het : "${COMPILER_PATH=$(get_arduino_pref 'runtime.tools.avr-gcc.path')/bin}" COMPILER_SUFFIX="" C_COMPILER_BASENAME=$(basename "${CC:-gcc}") CXX_COMPILER_BASENAME=$(basename "${CXX:-g++}") AR_BASENAME=$(basename "${AR:-ar}") # Allow the compiler prefix to be empty for virtual builds COMPILER_PREFIX="${COMPILER_PREFIX-avr-}" : "${AVR_SIZE:=${COMPILER_PATH}/${COMPILER_PREFIX}size}" : "${AVR_OBJDUMP:=${COMPILER_PATH}/${COMPILER_PREFIX}objdump}" : "${AVR_OBJCOPY:=${COMPILER_PATH}/${COMPILER_PREFIX}objcopy}" : "${AVR_NM:=${COMPILER_PATH}/${COMPILER_PREFIX}nm}" : "${AVR_AR:=${COMPILER_PATH}/${COMPILER_PREFIX}ar}" } do_compile() { prepare_ccache install -d "${OUTPUT_PATH}" echo "Building ${SKETCH_FILE_PATH}" # This is defined in the (optional) user config. # shellcheck disable=SC2154 ${compile_HOOKS} SAVED_BOARD="${BOARD}" SAVED_FQBN="${FQBN}" if [ -e "${SKETCH_DIR}/.kaleidoscope-builder.conf" ]; then # shellcheck disable=SC1090 BOARD="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${BOARD}")" # shellcheck disable=SC1090 FQBN="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${FQBN}")" if [ -n "${BOARD}" ]; then : "${ARCH:=avr}" FQBN="keyboardio:${ARCH}:${BOARD}" fi fi do_compile_with_cli if [ -z "${LIBONLY}" ]; then cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.hex" "${HEX_FILE_PATH}" cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.elf" "${ELF_FILE_PATH}" ln -sf "${OUTPUT_FILE_PREFIX}.hex" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.hex" ln -sf "${OUTPUT_FILE_PREFIX}.elf" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.elf" else cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.a" "${LIB_FILE_PATH}" ln -sf "${OUTPUT_FILE_PREFIX}.a" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.a" fi if [ "${ARDUINO_VERBOSE}" == "--verbose" ]; then echo "Build artifacts can be found in ${BUILD_PATH}" fi BOARD="${SAVED_BOARD}" FQBN="${SAVED_FQBN}" } get_arduino_pref() { pref=$1 # Strip the preference name. And then strip leading and trailing quotations MESSAGE=$(dump_arduino_prefs | grep --max-count=1 "${pref}=" | sed -e s/^.*"${pref}"=// -e 's/^"//' -e 's/"$//') echo "$MESSAGE" } dump_arduino_prefs() { if [ "x${_ARDUINO_PREFS}x" == "xx" ]; then _ARDUINO_PREFS=$(run_arduino_cli --fqbn "${FQBN}" compile --show-properties "${SKETCH_FILE_PATH}") fi echo "$_ARDUINO_PREFS" } do_compile_with_cli() { #-build-cache "${CORE_CACHE_PATH}" \ if [ $CCACHE_ENABLED ]; then COMPILER_PATH_PROP="${CCACHE_WRAPPER_PATH}/" else COMPILER_PATH_PROP="${COMPILER_PATH}" fi _CMD_CXX="${CXX:-${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}${COMPILER_SUFFIX}}" _CMD_CC="${CC:-${COMPILER_PREFIX}${C_COMPILER_BASENAME}${COMPILER_SUFFIX}}" _CMD_AR="${AR:-${COMPILER_PREFIX}${AR_BASENAME}${COMPILER_SUFFIX}}" run_arduino_cli compile \ --fqbn "${FQBN}" \ --libraries "${KALEIDOSCOPE_DIR}/.." \ --build-path "${BUILD_PATH}" \ --output-dir "${OUTPUT_PATH}" \ --build-properties "compiler.path=${COMPILER_PATH_PROP}" \ --build-properties "compiler.c.cmd=${_CMD_CC}" \ --build-properties "compiler.cpp.cmd=${_CMD_CXX}" \ --build-properties "compiler.ar.cmd=${_CMD_AR}" \ --build-properties "compiler.c.elf.cmd=${_CMD_CXX}" \ --build-properties "compiler.cpp.extra_flags=${LOCAL_CFLAGS}" \ --warnings all \ "${SKETCH_FILE_PATH}" } find_all_sketches() { for sketch_name in ./*.ino \ $([ -d examples ] && find examples -name '*.ino') \ src/*.ino; do if [ -d "$(dirname "${sketch_name}")" ] || [ -f "${sketch_name}" ]; then p="$(basename "${sketch_name}" .ino)" if [ "${p}" != '*' ]; then case "${sketch_name}" in examples/*/${p}/${p}.ino) echo "${sketch_name}" | sed -e "s,examples/,," | sed -e "s,/${p}\\.ino,," ;; *) echo "${p}" ;; esac fi fi done | sort } build_all() { plugins="$(find_all_sketches)" for sketch in ${plugins}; do export SKETCH="${sketch}" $0 "${sketch}" build done } size() { compile : "${AVR_SIZE_FLAGS:=-C --mcu=$(get_arduino_pref 'build.mcu')}" echo "- Size: ${ELF_FILE_PATH}" # shellcheck disable=SC2086 firmware_size "${AVR_SIZE}" ${AVR_SIZE_FLAGS} "${ELF_FILE_PATH}" echo } size_map() { compile "${AVR_NM}" --size-sort -C -r -l -t decimal "${ELF_FILE_PATH}" } disassemble() { compile "${AVR_OBJDUMP}" -C -d "${ELF_FILE_PATH}" } decompile() { disassemble } clean() { find_sketch build_paths if [ -d "$OUTPUT_PATH" ]; then rm -rf -- "${OUTPUT_PATH}" fi } find_bootloader_ports() { if [ -n "${DEVICE_PORT_BOOTLOADER}" ]; then echo "DEVICE_PORT_BOOTLOADER=\"${DEVICE_PORT_BOOTLOADER}\" predefined." return fi find_device_vid_pid : "${BOOTLOADER_VID:=${VID}}" if [ "${uname_S}" = "Darwin" ]; then DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-macos" DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID})" elif [ "${uname_O}" = "Cygwin" ]; then DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-windows.ps1" DEVICE_PORT_BOOTLOADER="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID} -Format COM)" elif [ "${uname_S}" = "FreeBSD" ]; then DEVICE_PORT_PROBER="${KALEIDOSCPE_BIN_DIR}/find-device-port-freebsd" DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER})" else DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-linux-udev" DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID})" fi } find_device_port() { if [ -n "${DEVICE_PORT}" ]; then echo "DEVICE_PORT=\"${DEVICE_PORT}\" predefined." return fi find_device_vid_pid if [ "${uname_S}" = "Darwin" ]; then DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-macos" DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID})" elif [ "${uname_O}" = "Cygwin" ]; then DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-windows.ps1" DEVICE_PORT="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID} -Format Cygwin)" DEVICE_COM_PORT="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID} -Format COM)" elif [ "${uname_S}" = "FreeBSD" ]; then DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-freebsd" DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER})" else DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-linux-udev" DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID})" fi } usage() { cat <<-EOF Usage: $0 SKETCH commands... Runs all of the commands in the context of the Sketch. Available commands: help This help screen. compile Compiles the sketch. size Reports the size of the compiled sketch. build Runs compile and report-size. clean Cleans up the output directory. size-map Displays the size map for the sketch. disassemble Decompile the sketch. reset-device Reset the device. flash Flashes the firmware using avrdude. EOF } help() { usage } if [ $# -lt 1 ]; then usage exit 1 fi # Temporary migration for old makefiles # I'm not thrilled about how we default to system Arduino dirs. if [ -n "${BOARD_HARDWARE_PATH}" ]; then ARDUINO_DIRECTORIES_USER="${BOARD_HARDWARE_PATH}/../" fi : "${KALEIDOSCOPE_DIR:=$( cd "$(dirname "$0")"/.. pwd )}" # shellcheck disable=SC2034 : "${KALEIDOSCOPE_BIN_DIR:=${KALEIDOSCOPE_DIR}/bin/}" identify_os read_conf_files configure_arduino_cli_env # shellcheck disable=SC1090 if [ -n "${VERBOSE}" ] && [[ "${VERBOSE}" -gt 0 ]]; then ARDUINO_VERBOSE="--verbose" else ARDUINO_VERBOSE="--quiet" fi : "${BOARD:=model01}" if [[ -z "${ARCH}" && -n "${FQBN}" ]]; then ARCH=$(echo "${FQBN}" | sed -n -e 's/^[^:]\+:\([^:]\+\).*/\1/p') fi : "${ARCH:=avr}" : "${FQBN:=keyboardio:${ARCH}:${BOARD}}" if [ "${ARCH}" = "virtual" ]; then adjust_for_virtual_build fi if [ "${uname_O}" = "Cygwin" ]; then adjust_for_cygwin fi ## Parse the command-line ## - anything that has a =, is an env var ## - from the remaining stuff, the first one is the Library/Sketch ## - everything else are commands ## ## - if there is only one argument, that's a command cmds="" ## Export vars for i in $(seq 1 $#); do v="$1" shift case "${v}" in *=*) # Exporting an expansion is *precisely* what we want here. # shellcheck disable=SC2086,SC2163 export ${v} ;; *) cmds="${cmds} ${v}" ;; esac done # Word splitting is desired here. # shellcheck disable=SC2086 set -- ${cmds} if [ $# -eq 1 ]; then cmd="$(echo "$1" | tr '-' '_')" ${cmd} exit $? fi SKETCH="$1" shift cmds="" # shellcheck disable=2034 for i in $(seq 1 $#); do cmds="${cmds} $(echo "$1" | tr '-' '_')" shift done for cmd in ${cmds}; do ${cmd} done