diff --git a/.editorconfig b/.editorconfig index 111e989c..99945e92 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,16 +1,60 @@ -# http://editorconfig.org - -root = true +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/general/.editorconfig +# See: https://editorconfig.org/ +# The formatting style defined in this file is the official standardized style to be used in all Arduino Tooling +# projects and should not be modified. +# Note: indent style for each file type is defined even when it matches the universal config in order to make it clear +# that this type has an official style. [*] charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space insert_final_newline = true trim_trailing_whitespace = true -[*.go] +[*.{adoc,asc,asciidoc}] +indent_size = 2 +indent_style = space + +[*.{bash,sh}] +indent_size = 2 +indent_style = space + +[*.{c,cc,cp,cpp,cxx,h,hh,hpp,hxx,ii,inl,ino,ixx,pde,tpl,tpp,txx}] +indent_size = 2 +indent_style = space + +[*.{go,mod}] indent_style = tab + +[*.java] +indent_size = 2 +indent_style = space + +[*.{js,jsx,json,jsonc,json5,ts,tsx}] +indent_size = 2 +indent_style = space + +[*.{md,mdx,mkdn,mdown,markdown}] +indent_size = unset +indent_style = space + +[*.proto] +indent_size = 2 +indent_style = space + +[*.py] indent_size = 4 +indent_style = space -[*.{yml,yaml}] +[*.svg] +indent_size = 2 indent_style = space + +[*.{yaml,yml}] indent_size = 2 +indent_style = space + +[.gitmodules] +indent_style = tab diff --git a/.github/workflows/check-formatting.yml b/.github/workflows/check-formatting.yml index 35c1b092..05008504 100644 --- a/.github/workflows/check-formatting.yml +++ b/.github/workflows/check-formatting.yml @@ -34,12 +34,6 @@ jobs: repo-token: ${{ secrets.GITHUB_TOKEN }} version: 3.x - - name: Check shell script formatting - # https://github.com/mvdan/sh - run: | - docker run --volume "$GITHUB_WORKSPACE/libraries/spell-check":/mnt --workdir /mnt mvdan/shfmt:latest -w . - git diff --color --exit-code - - name: Check documentation formatting run: task docs:check-formatting diff --git a/.github/workflows/check-shell-task.yml b/.github/workflows/check-shell-task.yml new file mode 100644 index 00000000..8b8bb0c5 --- /dev/null +++ b/.github/workflows/check-shell-task.yml @@ -0,0 +1,147 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-shell-task.md +name: Check Shell Scripts + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/check-shell-task.ya?ml" + - "Taskfile.ya?ml" + - "**/.editorconfig" + - "**.bash" + - "**.sh" + pull_request: + paths: + - ".github/workflows/check-shell-task.ya?ml" + - "Taskfile.ya?ml" + - "**/.editorconfig" + - "**.bash" + - "**.sh" + schedule: + # Run every Tuesday at 8 AM UTC to catch breakage caused by tool changes. + - cron: "0 8 * * TUE" + workflow_dispatch: + repository_dispatch: + +jobs: + lint: + name: ${{ matrix.configuration.name }} + runs-on: ubuntu-latest + + env: + # See: https://github.com/koalaman/shellcheck/releases/latest + SHELLCHECK_RELEASE_ASSET_SUFFIX: .linux.x86_64.tar.xz + + strategy: + fail-fast: false + + matrix: + configuration: + - name: Generate problem matcher output + # ShellCheck's "gcc" output format is required for annotated diffs, but inferior for humans reading the log. + format: gcc + # The other matrix job is used to set the result, so this job is configured to always pass. + continue-on-error: true + - name: ShellCheck + # ShellCheck's "tty" output format is most suitable for humans reading the log. + format: tty + continue-on-error: false + + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "INSTALL_PATH=${{ runner.temp }}/shellcheck" >> "$GITHUB_ENV" + + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Download latest ShellCheck release binary package + id: download + uses: MrOctopus/download-asset-action@1.0 + with: + repository: koalaman/shellcheck + excludes: prerelease, draft + asset: ${{ env.SHELLCHECK_RELEASE_ASSET_SUFFIX }} + target: ${{ env.INSTALL_PATH }} + + - name: Install ShellCheck + run: | + cd "${{ env.INSTALL_PATH }}" + tar --extract --file="${{ steps.download.outputs.name }}" + EXTRACTION_FOLDER="$(basename "${{ steps.download.outputs.name }}" "${{ env.SHELLCHECK_RELEASE_ASSET_SUFFIX }}")" + # Add installation to PATH: + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#adding-a-system-path + echo "${{ env.INSTALL_PATH }}/$EXTRACTION_FOLDER" >> "$GITHUB_PATH" + + - name: Run ShellCheck + uses: liskin/gh-problem-matcher-wrap@v1 + continue-on-error: ${{ matrix.configuration.continue-on-error }} + with: + linters: gcc + run: task --silent shell:check SHELLCHECK_FORMAT=${{ matrix.configuration.format }} + + formatting: + runs-on: ubuntu-latest + + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "SHFMT_INSTALL_PATH=${{ runner.temp }}/shfmt" >> "$GITHUB_ENV" + + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Download shfmt + id: download + uses: MrOctopus/download-asset-action@1.0 + with: + repository: mvdan/sh + excludes: prerelease, draft + asset: _linux_amd64 + target: ${{ env.SHFMT_INSTALL_PATH }} + + - name: Install shfmt + run: | + # Executable permissions of release assets are lost + chmod +x "${{ env.SHFMT_INSTALL_PATH }}/${{ steps.download.outputs.name }}" + # Standardize binary name + mv "${{ env.SHFMT_INSTALL_PATH }}/${{ steps.download.outputs.name }}" "${{ env.SHFMT_INSTALL_PATH }}/shfmt" + # Add installation to PATH: + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#adding-a-system-path + echo "${{ env.SHFMT_INSTALL_PATH }}" >> "$GITHUB_PATH" + + - name: Format shell scripts + run: task --silent shell:format + + - name: Check formatting + run: git diff --color --exit-code + + executable: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Task + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Check for non-executable scripts + run: task --silent shell:check-mode diff --git a/.github/workflows/lint-shell.yml b/.github/workflows/lint-shell.yml deleted file mode 100644 index 9b21c8d0..00000000 --- a/.github/workflows/lint-shell.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Lint shell scripts - -on: - push: - paths: - - ".github/workflows/lint-shell.yml" - - "**.sh" - pull_request: - paths: - - ".github/workflows/lint-shell.yml" - - "**.sh" - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Install Taskfile - uses: arduino/setup-task@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - version: 3.x - - - name: Lint shell scripts - run: task shell:lint diff --git a/README.md b/README.md index df222601..b2767463 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [![Docs Status](https://github.com/arduino/arduino-lint/workflows/Publish%20documentation/badge.svg)](https://github.com/arduino/arduino-lint/actions?workflow=Publish+documentation) [![Codecov](https://codecov.io/gh/arduino/arduino-lint/branch/main/graph/badge.svg?token=nprqPQMbdh)](https://codecov.io/gh/arduino/arduino-lint) [![Check General Formatting status](https://github.com/arduino/arduino-lint/actions/workflows/check-general-formatting-task.yml/badge.svg)](https://github.com/arduino/arduino-lint/actions/workflows/check-general-formatting-task.yml) +[![Check Shell Scripts status](https://github.com/arduino/arduino-lint/actions/workflows/check-shell-task.yml/badge.svg)](https://github.com/arduino/arduino-lint/actions/workflows/check-shell-task.yml) [![Check Certificates status](https://github.com/arduino/arduino-lint/actions/workflows/check-certificates.yml/badge.svg)](https://github.com/arduino/arduino-lint/actions/workflows/check-certificates.yml) **Arduino Lint** is a command line tool that checks for common problems in [Arduino](https://www.arduino.cc/) projects: diff --git a/Taskfile.yml b/Taskfile.yml index a7da6851..61abb84a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -46,6 +46,7 @@ tasks: - task: config:check - task: general:check-formatting - task: check-spelling + - task: shell:check-mode lint: desc: Lint all files @@ -266,24 +267,73 @@ tasks: cmds: - npx {{ .PRETTIER }} --write "**/*.md" - shell:lint: - desc: Lint shell scripts + # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-shell-task/Taskfile.yml + shell:check: + desc: Check for problems with shell scripts cmds: - # https://github.com/koalaman/shellcheck - | - shopt -s globstar # Needed to check all scripts recursively. - shellcheck ./**/*.sh - - shell:check-formatting: - desc: Format shell scripts + if ! which shellcheck &>/dev/null; then + echo "shellcheck not installed or not in PATH. Please install: https://github.com/koalaman/shellcheck#installing" + exit 1 + fi + - | + # There is something odd about shellcheck that causes the task to always exit on the first fail, despite any + # measures that would prevent this with any other command. So it's necessary to call shellcheck only once with + # the list of script paths as an argument. This could lead to exceeding the maximum command length on Windows if + # the repository contained a large number of scripts, but it's unlikely to happen in reality. + shellcheck \ + --format={{default "tty" .SHELLCHECK_FORMAT}} \ + $( + # The odd method for escaping . in the regex is required for windows compatibility because mvdan.cc/sh gives + # \ characters special treatment on Windows in an attempt to support them as path separators. + find . \ + -path ".git" -prune -or \ + \( \ + -regextype posix-extended \ + -regex '.*[.](bash|sh)' -and \ + -type f \ + \) + ) + + # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-shell-task/Taskfile.yml + shell:format: + desc: Format shell script files cmds: - # https://github.com/mvdan/sh#shfmt - - shfmt -d . + - | + if ! which shfmt &>/dev/null; then + echo "shfmt not installed or not in PATH. Please install: https://github.com/mvdan/sh#shfmt" + exit 1 + fi + - shfmt -w . - shell:format: - desc: Format shell scripts + # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/check-shell-task/Taskfile.yml + shell:check-mode: + desc: Check for non-executable shell scripts cmds: - - shfmt -l -w . + - | + EXIT_STATUS=0 + while read -r nonExecutableScriptPath; do + # The while loop always runs once, even if no file was found + if [[ "$nonExecutableScriptPath" == "" ]]; then + continue + fi + + echo "::error file=${nonExecutableScriptPath}::non-executable script file: $nonExecutableScriptPath"; + EXIT_STATUS=1 + done <<<"$( + # The odd approach to escaping `.` in the regex is required for windows compatibility because mvdan.cc/sh + # gives `\` characters special treatment on Windows in an attempt to support them as path separators. + find . \ + -path ".git" -prune -or \ + \( \ + -regextype posix-extended \ + -regex '.*[.](bash|sh)' -and \ + -type f -and \ + -not -executable \ + -print \ + \) + )" + exit $EXIT_STATUS config:check: desc: Lint and check formatting of configuration files diff --git a/etc/install.sh b/etc/install.sh index 3debdc3b..920ab003 100755 --- a/etc/install.sh +++ b/etc/install.sh @@ -21,198 +21,198 @@ EFFECTIVE_BINDIR="" DEFAULT_BINDIR="$PWD/bin" fail() { - echo "$1" - exit 1 + echo "$1" + exit 1 } initDestination() { - if [ -n "$BINDIR" ]; then - if [ ! -d "$BINDIR" ]; then - # The second instance of $BINDIR is intentionally a literal in this message. - # shellcheck disable=SC2016 - fail "$BINDIR "'($BINDIR)'" folder not found. Please create it before continuing." - fi - EFFECTIVE_BINDIR="$BINDIR" - else - if [ ! -d "$DEFAULT_BINDIR" ]; then - mkdir "$DEFAULT_BINDIR" - fi - EFFECTIVE_BINDIR="$DEFAULT_BINDIR" - fi - echo "Installing in $EFFECTIVE_BINDIR" + if [ -n "$BINDIR" ]; then + if [ ! -d "$BINDIR" ]; then + # The second instance of $BINDIR is intentionally a literal in this message. + # shellcheck disable=SC2016 + fail "$BINDIR "'($BINDIR)'" folder not found. Please create it before continuing." + fi + EFFECTIVE_BINDIR="$BINDIR" + else + if [ ! -d "$DEFAULT_BINDIR" ]; then + mkdir "$DEFAULT_BINDIR" + fi + EFFECTIVE_BINDIR="$DEFAULT_BINDIR" + fi + echo "Installing in $EFFECTIVE_BINDIR" } initArch() { - ARCH=$(uname -m) - case $ARCH in - armv5*) ARCH="armv5" ;; - armv6*) ARCH="ARMv6" ;; - armv7*) ARCH="ARMv7" ;; - aarch64) ARCH="ARM64" ;; - x86) ARCH="32bit" ;; - x86_64) ARCH="64bit" ;; - i686) ARCH="32bit" ;; - i386) ARCH="32bit" ;; - esac - echo "ARCH=$ARCH" + ARCH=$(uname -m) + case $ARCH in + armv5*) ARCH="armv5" ;; + armv6*) ARCH="ARMv6" ;; + armv7*) ARCH="ARMv7" ;; + aarch64) ARCH="ARM64" ;; + x86) ARCH="32bit" ;; + x86_64) ARCH="64bit" ;; + i686) ARCH="32bit" ;; + i386) ARCH="32bit" ;; + esac + echo "ARCH=$ARCH" } initOS() { - OS=$(uname -s) - case "$OS" in - Linux*) OS='Linux' ;; - Darwin*) OS='macOS' ;; - MINGW*) OS='Windows' ;; - MSYS*) OS='Windows' ;; - esac - echo "OS=$OS" + OS=$(uname -s) + case "$OS" in + Linux*) OS='Linux' ;; + Darwin*) OS='macOS' ;; + MINGW*) OS='Windows' ;; + MSYS*) OS='Windows' ;; + esac + echo "OS=$OS" } initDownloadTool() { - if command -v "curl" >/dev/null 2>&1; then - DOWNLOAD_TOOL="curl" - elif command -v "wget" >/dev/null 2>&1; then - DOWNLOAD_TOOL="wget" - else - fail "You need curl or wget as download tool. Please install it first before continuing" - fi - echo "Using $DOWNLOAD_TOOL as download tool" + if command -v "curl" >/dev/null 2>&1; then + DOWNLOAD_TOOL="curl" + elif command -v "wget" >/dev/null 2>&1; then + DOWNLOAD_TOOL="wget" + else + fail "You need curl or wget as download tool. Please install it first before continuing" + fi + echo "Using $DOWNLOAD_TOOL as download tool" } checkLatestVersion() { - # Use the GitHub releases webpage to find the latest version for this project - # so we don't get rate-limited. - CHECKLATESTVERSION_REGEX="[0-9][A-Za-z0-9\.-]*" - CHECKLATESTVERSION_LATEST_URL="https://github.com/${PROJECT_OWNER}/${PROJECT_NAME}/releases/latest" - if [ "$DOWNLOAD_TOOL" = "curl" ]; then - CHECKLATESTVERSION_TAG=$(curl -SsL $CHECKLATESTVERSION_LATEST_URL | grep -o "Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX") - elif [ "$DOWNLOAD_TOOL" = "wget" ]; then - CHECKLATESTVERSION_TAG=$(wget -q -O - $CHECKLATESTVERSION_LATEST_URL | grep -o "<title>Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX") - fi - if [ "x$CHECKLATESTVERSION_TAG" = "x" ]; then - echo "Cannot determine latest tag." - exit 1 - fi - eval "$1='$CHECKLATESTVERSION_TAG'" + # Use the GitHub releases webpage to find the latest version for this project + # so we don't get rate-limited. + CHECKLATESTVERSION_REGEX="[0-9][A-Za-z0-9\.-]*" + CHECKLATESTVERSION_LATEST_URL="https://github.com/${PROJECT_OWNER}/${PROJECT_NAME}/releases/latest" + if [ "$DOWNLOAD_TOOL" = "curl" ]; then + CHECKLATESTVERSION_TAG=$(curl -SsL $CHECKLATESTVERSION_LATEST_URL | grep -o "<title>Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX") + elif [ "$DOWNLOAD_TOOL" = "wget" ]; then + CHECKLATESTVERSION_TAG=$(wget -q -O - $CHECKLATESTVERSION_LATEST_URL | grep -o "<title>Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX") + fi + if [ "x$CHECKLATESTVERSION_TAG" = "x" ]; then + echo "Cannot determine latest tag." + exit 1 + fi + eval "$1='$CHECKLATESTVERSION_TAG'" } get() { - GET_URL="$2" - echo "Getting $GET_URL" - if [ "$DOWNLOAD_TOOL" = "curl" ]; then - GET_HTTP_RESPONSE=$(curl -sL --write-out 'HTTPSTATUS:%{http_code}' "$GET_URL") - GET_HTTP_STATUS_CODE=$(echo "$GET_HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') - GET_BODY=$(echo "$GET_HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') - elif [ "$DOWNLOAD_TOOL" = "wget" ]; then - TMP_FILE=$(mktemp) - GET_BODY=$(wget --server-response --content-on-error -q -O - "$GET_URL" 2>"$TMP_FILE" || true) - GET_HTTP_STATUS_CODE=$(awk '/^ HTTP/{print $2}' "$TMP_FILE") - fi - if [ "$GET_HTTP_STATUS_CODE" != 200 ]; then - echo "Request failed with HTTP status code $GET_HTTP_STATUS_CODE" - fail "Body: $GET_BODY" - fi - eval "$1='$GET_BODY'" + GET_URL="$2" + echo "Getting $GET_URL" + if [ "$DOWNLOAD_TOOL" = "curl" ]; then + GET_HTTP_RESPONSE=$(curl -sL --write-out 'HTTPSTATUS:%{http_code}' "$GET_URL") + GET_HTTP_STATUS_CODE=$(echo "$GET_HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') + GET_BODY=$(echo "$GET_HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') + elif [ "$DOWNLOAD_TOOL" = "wget" ]; then + TMP_FILE=$(mktemp) + GET_BODY=$(wget --server-response --content-on-error -q -O - "$GET_URL" 2>"$TMP_FILE" || true) + GET_HTTP_STATUS_CODE=$(awk '/^ HTTP/{print $2}' "$TMP_FILE") + fi + if [ "$GET_HTTP_STATUS_CODE" != 200 ]; then + echo "Request failed with HTTP status code $GET_HTTP_STATUS_CODE" + fail "Body: $GET_BODY" + fi + eval "$1='$GET_BODY'" } getFile() { - GETFILE_URL="$1" - GETFILE_FILE_PATH="$2" - if [ "$DOWNLOAD_TOOL" = "curl" ]; then - GETFILE_HTTP_STATUS_CODE=$(curl -s -w '%{http_code}' -L "$GETFILE_URL" -o "$GETFILE_FILE_PATH") - elif [ "$DOWNLOAD_TOOL" = "wget" ]; then - wget --server-response --content-on-error -q -O "$GETFILE_FILE_PATH" "$GETFILE_URL" - GETFILE_HTTP_STATUS_CODE=$(awk '/^ HTTP/{print $2}' "$TMP_FILE") - fi - echo "$GETFILE_HTTP_STATUS_CODE" + GETFILE_URL="$1" + GETFILE_FILE_PATH="$2" + if [ "$DOWNLOAD_TOOL" = "curl" ]; then + GETFILE_HTTP_STATUS_CODE=$(curl -s -w '%{http_code}' -L "$GETFILE_URL" -o "$GETFILE_FILE_PATH") + elif [ "$DOWNLOAD_TOOL" = "wget" ]; then + wget --server-response --content-on-error -q -O "$GETFILE_FILE_PATH" "$GETFILE_URL" + GETFILE_HTTP_STATUS_CODE=$(awk '/^ HTTP/{print $2}' "$TMP_FILE") + fi + echo "$GETFILE_HTTP_STATUS_CODE" } downloadFile() { - if [ -z "$1" ]; then - checkLatestVersion TAG - else - TAG=$1 - fi - # arduino-lint_0.4.0-rc1_Linux_64bit.[tar.gz, zip] - if [ "$OS" = "Windows" ]; then - ARDUINO_LINT_DIST="${PROJECT_NAME}_${TAG}_${OS}_${ARCH}.zip" - else - ARDUINO_LINT_DIST="${PROJECT_NAME}_${TAG}_${OS}_${ARCH}.tar.gz" - fi - - # Support specifying nightly build versions (e.g., "nightly-latest") via the script argument. - case "$TAG" in - nightly*) - DOWNLOAD_URL="https://downloads.arduino.cc/${PROJECT_NAME}/nightly/${ARDUINO_LINT_DIST}" - ;; - *) - DOWNLOAD_URL="https://downloads.arduino.cc/${PROJECT_NAME}/${ARDUINO_LINT_DIST}" - ;; - esac - - ARDUINO_LINT_TMP_FILE="/tmp/$ARDUINO_LINT_DIST" - echo "Downloading $DOWNLOAD_URL" - httpStatusCode=$(getFile "$DOWNLOAD_URL" "$ARDUINO_LINT_TMP_FILE") - if [ "$httpStatusCode" -ne 200 ]; then - echo "Did not find a release for your system: $OS $ARCH" - echo "Trying to find a release using the GitHub API." - LATEST_RELEASE_URL="https://api.github.com/repos/${PROJECT_OWNER}/$PROJECT_NAME/releases/tags/$TAG" - echo "LATEST_RELEASE_URL=$LATEST_RELEASE_URL" - get LATEST_RELEASE_JSON "$LATEST_RELEASE_URL" - # || true forces this command to not catch error if grep does not find anything - DOWNLOAD_URL=$(echo "$LATEST_RELEASE_JSON" | grep 'browser_' | cut -d\" -f4 | grep "$ARDUINO_LINT_DIST") || true - if [ -z "$DOWNLOAD_URL" ]; then - echo "Sorry, we dont have a dist for your system: $OS $ARCH" - fail "You can request one here: https://github.com/${PROJECT_OWNER}/$PROJECT_NAME/issues" - else - echo "Downloading $DOWNLOAD_URL" - getFile "$DOWNLOAD_URL" "$ARDUINO_LINT_TMP_FILE" - fi - fi + if [ -z "$1" ]; then + checkLatestVersion TAG + else + TAG=$1 + fi + # arduino-lint_0.4.0-rc1_Linux_64bit.[tar.gz, zip] + if [ "$OS" = "Windows" ]; then + ARDUINO_LINT_DIST="${PROJECT_NAME}_${TAG}_${OS}_${ARCH}.zip" + else + ARDUINO_LINT_DIST="${PROJECT_NAME}_${TAG}_${OS}_${ARCH}.tar.gz" + fi + + # Support specifying nightly build versions (e.g., "nightly-latest") via the script argument. + case "$TAG" in + nightly*) + DOWNLOAD_URL="https://downloads.arduino.cc/${PROJECT_NAME}/nightly/${ARDUINO_LINT_DIST}" + ;; + *) + DOWNLOAD_URL="https://downloads.arduino.cc/${PROJECT_NAME}/${ARDUINO_LINT_DIST}" + ;; + esac + + ARDUINO_LINT_TMP_FILE="/tmp/$ARDUINO_LINT_DIST" + echo "Downloading $DOWNLOAD_URL" + httpStatusCode=$(getFile "$DOWNLOAD_URL" "$ARDUINO_LINT_TMP_FILE") + if [ "$httpStatusCode" -ne 200 ]; then + echo "Did not find a release for your system: $OS $ARCH" + echo "Trying to find a release using the GitHub API." + LATEST_RELEASE_URL="https://api.github.com/repos/${PROJECT_OWNER}/$PROJECT_NAME/releases/tags/$TAG" + echo "LATEST_RELEASE_URL=$LATEST_RELEASE_URL" + get LATEST_RELEASE_JSON "$LATEST_RELEASE_URL" + # || true forces this command to not catch error if grep does not find anything + DOWNLOAD_URL=$(echo "$LATEST_RELEASE_JSON" | grep 'browser_' | cut -d\" -f4 | grep "$ARDUINO_LINT_DIST") || true + if [ -z "$DOWNLOAD_URL" ]; then + echo "Sorry, we dont have a dist for your system: $OS $ARCH" + fail "You can request one here: https://github.com/${PROJECT_OWNER}/$PROJECT_NAME/issues" + else + echo "Downloading $DOWNLOAD_URL" + getFile "$DOWNLOAD_URL" "$ARDUINO_LINT_TMP_FILE" + fi + fi } installFile() { - ARDUINO_LINT_TMP="/tmp/$PROJECT_NAME" - mkdir -p "$ARDUINO_LINT_TMP" - if [ "$OS" = "Windows" ]; then - unzip -d "$ARDUINO_LINT_TMP" "$ARDUINO_LINT_TMP_FILE" - else - tar xf "$ARDUINO_LINT_TMP_FILE" -C "$ARDUINO_LINT_TMP" - fi - ARDUINO_LINT_TMP_BIN="$ARDUINO_LINT_TMP/$PROJECT_NAME" - cp "$ARDUINO_LINT_TMP_BIN" "$EFFECTIVE_BINDIR" - rm -rf "$ARDUINO_LINT_TMP" - rm -f "$ARDUINO_LINT_TMP_FILE" + ARDUINO_LINT_TMP="/tmp/$PROJECT_NAME" + mkdir -p "$ARDUINO_LINT_TMP" + if [ "$OS" = "Windows" ]; then + unzip -d "$ARDUINO_LINT_TMP" "$ARDUINO_LINT_TMP_FILE" + else + tar xf "$ARDUINO_LINT_TMP_FILE" -C "$ARDUINO_LINT_TMP" + fi + ARDUINO_LINT_TMP_BIN="$ARDUINO_LINT_TMP/$PROJECT_NAME" + cp "$ARDUINO_LINT_TMP_BIN" "$EFFECTIVE_BINDIR" + rm -rf "$ARDUINO_LINT_TMP" + rm -f "$ARDUINO_LINT_TMP_FILE" } bye() { - BYE_RESULT=$? - if [ "$BYE_RESULT" != "0" ]; then - echo "Failed to install $PROJECT_NAME" - fi - exit $BYE_RESULT + BYE_RESULT=$? + if [ "$BYE_RESULT" != "0" ]; then + echo "Failed to install $PROJECT_NAME" + fi + exit $BYE_RESULT } testVersion() { - set +e - ARDUINO_LINT="$(which $PROJECT_NAME)" - if [ "$?" = "1" ]; then - # $PATH is intentionally a literal in this message. - # shellcheck disable=SC2016 - echo "$PROJECT_NAME not found. You might want to add \"$EFFECTIVE_BINDIR\" to your "'$PATH' - else - # Convert to resolved, absolute paths before comparison - ARDUINO_LINT_REALPATH="$(cd -- "$(dirname -- "$ARDUINO_LINT")" && pwd -P)" - EFFECTIVE_BINDIR_REALPATH="$(cd -- "$EFFECTIVE_BINDIR" && pwd -P)" - if [ "$ARDUINO_LINT_REALPATH" != "$EFFECTIVE_BINDIR_REALPATH" ]; then - # shellcheck disable=SC2016 - echo "An existing $PROJECT_NAME was found at $ARDUINO_LINT. Please prepend \"$EFFECTIVE_BINDIR\" to your "'$PATH'" or remove the existing one." - fi - fi - - set -e - ARDUINO_LINT_VERSION="$("$EFFECTIVE_BINDIR/$PROJECT_NAME" --version)" - echo "$ARDUINO_LINT_VERSION installed successfully in $EFFECTIVE_BINDIR" + set +e + ARDUINO_LINT="$(which $PROJECT_NAME)" + if [ "$?" = "1" ]; then + # $PATH is intentionally a literal in this message. + # shellcheck disable=SC2016 + echo "$PROJECT_NAME not found. You might want to add \"$EFFECTIVE_BINDIR\" to your "'$PATH' + else + # Convert to resolved, absolute paths before comparison + ARDUINO_LINT_REALPATH="$(cd -- "$(dirname -- "$ARDUINO_LINT")" && pwd -P)" + EFFECTIVE_BINDIR_REALPATH="$(cd -- "$EFFECTIVE_BINDIR" && pwd -P)" + if [ "$ARDUINO_LINT_REALPATH" != "$EFFECTIVE_BINDIR_REALPATH" ]; then + # shellcheck disable=SC2016 + echo "An existing $PROJECT_NAME was found at $ARDUINO_LINT. Please prepend \"$EFFECTIVE_BINDIR\" to your "'$PATH'" or remove the existing one." + fi + fi + + set -e + ARDUINO_LINT_VERSION="$("$EFFECTIVE_BINDIR/$PROJECT_NAME" --version)" + echo "$ARDUINO_LINT_VERSION installed successfully in $EFFECTIVE_BINDIR" } # Execution