diff --git a/.github/workflows/check-formatting.yml b/.github/workflows/check-formatting.yml index 92e1de761..b7c3cb06c 100644 --- a/.github/workflows/check-formatting.yml +++ b/.github/workflows/check-formatting.yml @@ -39,6 +39,12 @@ jobs: - name: Check Go code formatting run: task go:check-formatting + - 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/lint-shell.yml b/.github/workflows/lint-shell.yml new file mode 100644 index 000000000..4ed990c40 --- /dev/null +++ b/.github/workflows/lint-shell.yml @@ -0,0 +1,28 @@ +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/actions/setup-taskfile@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Lint shell scripts + run: task shell:lint diff --git a/Taskfile.yml b/Taskfile.yml index 3ac4d6585..84e4a9562 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -203,6 +203,25 @@ tasks: cmds: - npx {{ .PRETTIER }} --write "**/*.md" + shell:lint: + desc: Lint 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 + cmds: + # https://github.com/mvdan/sh#shfmt + - shfmt -d . + + shell:format: + desc: Format shell scripts + cmds: + - shfmt -l -w . + config:check: desc: Lint and check formatting of configuration files cmds: diff --git a/docs/index.md b/docs/index.md index 90d5719a4..314d8bbff 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,6 +5,10 @@ Its focus is on the structure, metadata, and configuration of Arduino projects, [specification](https://arduino.github.io/arduino-cli/latest/library-specification) compliance, Library Manager submission [requirements](https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ), and best practices. +## Installation + +See the [installation instructions](installation.md). + ## Getting started Once installed, you only need to open a terminal at your project folder and run the command: diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 000000000..50de6bb8c --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,61 @@ +## Use the install script + +The script requires `sh`, which is always available on Linux and macOS. `sh` is not available by default on Windows. The +script can be run on Windows by installing [Git for Windows](https://gitforwindows.org/), then running it from Git Bash. + +This script will install the latest version of arduino-lint to `$PWD/bin`: + +``` +curl -fsSL https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/install.sh | sh +``` + +If you want to target a different directory, for example `~/local/bin`, set the `BINDIR` environment variable like this: + +``` +curl -fsSL https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/install.sh | BINDIR=~/local/bin sh +``` + +If you would like to use the `arduino-lint` command from any location, install arduino-lint to a directory already in +your `PATH` or add the arduino-lint installation path to your `PATH` environment variable. + +If you want to download a specific arduino-lint version, for example `0.9.0`, pass the version number as a parameter +like this: + +``` +curl -fsSL https://raw.githubusercontent.com/arduino/arduino-lint/main/etc/install.sh | sh -s 0.9.0 +``` + +### Download + +Pre-built binaries for all the supported platforms are available for download from the links below. + +If you would like to use the `arduino-lint` command from any location, extract the downloaded file to a directory +already in your `PATH` or add the arduino-lint installation path to your `PATH` environment variable. + +#### Latest release + +| Platform | | | +| --------- | -------------------- | -------------------- | +| Linux | [32 bit][linux32] | [64 bit][linux64] | +| Linux ARM | [32 bit][linuxarm32] | [64 bit][linuxarm64] | +| Windows | [32 bit][windows32] | [64 bit][windows64] | +| macOS | | [64 bit][macos] | + +[linux64]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_Linux_64bit.tar.gz +[linux32]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_Linux_32bit.tar.gz +[linuxarm64]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_Linux_ARM64.tar.gz +[linuxarm32]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_Linux_ARMv7.tar.gz +[windows64]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_Windows_64bit.zip +[windows32]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_Windows_32bit.zip +[macos]: https://downloads.arduino.cc/arduino-lint/arduino-lint_latest_macOS_64bit.tar.gz + +#### Previous versions + +These are available from the "Assets" sections on the [releases page](https://github.com/arduino/arduino-lint/releases). + +`https://downloads.arduino.cc/arduino-lint/nightly/nightly--checksums.txt` + +### Build from source + +If you’re familiar with Golang or if you want to contribute to the project, you will probably build arduino-lint locally +with your Go toolchain. See the ["How to contribute"](CONTRIBUTING.md#building-the-source-code) page for instructions. diff --git a/etc/install.sh b/etc/install.sh new file mode 100755 index 000000000..c3bd00f79 --- /dev/null +++ b/etc/install.sh @@ -0,0 +1,219 @@ +#!/bin/sh + +# The original version of this script (https://github.com/Masterminds/glide.sh/blob/master/get) is licensed under the +# MIT license. See https://github.com/Masterminds/glide/blob/master/LICENSE for more details and copyright notice. + +# +# Usage: +# +# To install the latest version of arduino-lint: +# ./install.sh +# +# To pin a specific release of arduino-lint: +# ./install.sh 0.9.0 +# + +PROJECT_OWNER="arduino" +PROJECT_NAME="arduino-lint" + +# BINDIR represents the local bin location, defaults to ./bin. +EFFECTIVE_BINDIR="" +DEFAULT_BINDIR="$PWD/bin" + +fail() { + 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" +} + +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" +} + +initOS() { + 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" +} + +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'" +} + +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'" +} + +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" +} + +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 + DOWNLOAD_URL="https://downloads.arduino.cc/${PROJECT_NAME}/${ARDUINO_LINT_DIST}" + 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" +} + +bye() { + 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" +} + +# Execution + +#Stop execution on any error +trap "bye" EXIT +initDestination +set -e +initArch +initOS +initDownloadTool +downloadFile "$1" +installFile +testVersion diff --git a/mkdocs.yml b/mkdocs.yml index a1784f8e0..8c2cbd726 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -46,6 +46,7 @@ markdown_extensions: # Navigation nav: - Documentation Home: index.md + - installation.md - Command reference: commands/arduino-lint.md - CONTRIBUTING.md