Skip to content

Add release installation support #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Dec 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/check-formatting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/lint-shell.yml
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
61 changes: 61 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
@@ -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-<DATE>-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.
219 changes: 219 additions & 0 deletions etc/install.sh
Original file line number Diff line number Diff line change
@@ -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 "<title>Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rsora do you know why this approach of scraping the GitHub release page was taken in the Arduino CLI repo instead of using the "latest" link from downloads.arduino.cc (e.g., https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script was borrowed from the Glide repo (https://glide.sh/), we probably used the same approach as the script (that is changed thought from the time we picked it up).

Anyway, I suggest maintaining this approach for the release, as there is no "latest" service deployed for the arduino-lint currently.

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
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ markdown_extensions:
# Navigation
nav:
- Documentation Home: index.md
- installation.md
- Command reference: commands/arduino-lint.md
- CONTRIBUTING.md

Expand Down