diff --git a/.github/workflows/install-scripts.yaml b/.github/workflows/install-scripts.yaml new file mode 100644 index 0000000..598f9df --- /dev/null +++ b/.github/workflows/install-scripts.yaml @@ -0,0 +1,93 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +name: Install Scripts + +# The quick install scripts in the README download the latest release from GitHub and the Apache download hosts, so +# they can break without a change here: run them every week as well. +on: + pull_request: + paths: + - scripts/install.sh + - scripts/install.bat + - .github/workflows/install-scripts.yaml + push: + branches: + - master + paths: + - scripts/install.sh + - scripts/install.bat + - .github/workflows/install-scripts.yaml + schedule: + - cron: "0 18 * * 1" # Mondays, TimeZone: UTC 0 + workflow_dispatch: + +concurrency: + group: install-scripts-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + install-sh: + name: install.sh (${{ matrix.os }}) + if: github.repository == 'apache/skywalking-cli' + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest] + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + + # Run it the way the README does. + - name: Install swctl + run: /bin/bash -c "$(cat scripts/install.sh)" + + - name: Install swctl over the installed one + run: /bin/bash -c "$(cat scripts/install.sh)" + + - name: Check swctl + run: | + file "$(command -v swctl)" + swctl --version + + install-bat: + name: install.bat (windows-latest) + if: github.repository == 'apache/skywalking-cli' + runs-on: windows-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + + - name: Install swctl + shell: cmd + run: call scripts\install.bat + + - name: Install swctl over the installed one + shell: cmd + run: call scripts\install.bat + + # Steps keep the PATH the job started with, so read the system PATH the script changed. + - name: Check swctl + shell: pwsh + run: | + & 'C:\Program Files\swctl-cli\swctl.exe' --version + if ($LASTEXITCODE -ne 0) { exit 1 } + $entries = @([Environment]::GetEnvironmentVariable('Path', 'Machine') -split ';' | + Where-Object { $_.TrimEnd('\') -eq 'C:\Program Files\swctl-cli' }) + if ($entries.Count -ne 1) { throw "The system PATH has the install directory $($entries.Count) times, not once." } diff --git a/CHANGES.md b/CHANGES.md index 3ce9cab..c72531b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,12 @@ Release Notes. ### Bug Fixes +* Fix the quick install scripts `scripts/install.sh` and `scripts/install.bat`, which failed since the website dropped + the `data/releases.yml` they read the latest version from. They now take it from the latest GitHub release, install + the binary for the machine's architecture instead of always `amd64`, and `install.bat` no longer rewrites the system + `PATH` with `setx`, which cut it at 1024 characters and added the install directory again on every run. A new + workflow runs both scripts on Linux, macOS and Windows every week. + 0.16.0 ------------------ diff --git a/scripts/install.bat b/scripts/install.bat index 5797480..fea755a 100644 --- a/scripts/install.bat +++ b/scripts/install.bat @@ -13,58 +13,87 @@ @REM See the License for the specific language governing permissions and @REM limitations under the License. -@REM Installation (Note: you need to start cmd or powershell in administrator mode.) +@REM Installs the latest Apache SkyWalking CLI release as "C:\Program Files\swctl-cli\swctl.exe" and adds that directory +@REM to the system PATH. (Note: you need to start cmd or powershell in administrator mode.) @echo off -setlocal ENABLEDELAYEDEXPANSION +setlocal -@REM Get the latest version of swctl. -set FLAG="FALSE" -set VERSION= UNKNOW -curl -LO "https://raw.githubusercontent.com/apache/skywalking-website/master/data/releases.yml" -if EXIST "releases.yml" ( - for /F "tokens=1,2,*" %%i in ('FINDSTR "name version" "./releases.yml"') do ( - if !FLAG! EQU "TRUE" ( - set FLAG="FALSE" - set VERSION=%%k - ) - if "%%k" == "SkyWalking CLI" (set FLAG="TRUE") - ) +set "INSTALL_DIR=C:\Program Files\swctl-cli" + +@REM Get the latest version of swctl: the latest GitHub release redirects to .../releases/tag/. +set "LATEST_URL=none" +for /F "delims=" %%i in ('curl -fsSLI -o NUL -w "%%{url_effective}" https://github.com/apache/skywalking-cli/releases/latest') do set "LATEST_URL=%%i" +set "VERSION=%LATEST_URL:*/tag/=%" +echo %VERSION%| findstr /R /X "[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*" >NUL +if errorlevel 1 ( + echo Can't get the latest version. The install script may be invalid, try other install methods please. + exit /b 1 ) -set VERSION=%VERSION:~1% -@echo The latest version of swctl is %VERSION% +echo The latest version of swctl is %VERSION% + +@REM Pick the binary for this machine: the release has windows-386 and windows-amd64, which Windows on ARM runs too. +set "ARCH=amd64" +if /I "%PROCESSOR_ARCHITECTURE%"=="x86" if not defined PROCESSOR_ARCHITEW6432 set "ARCH=386" -if "%VERSION%" NEQ "UNKNOW" ( +set "PACKAGE=skywalking-cli-%VERSION%-bin" +set "BINARY=%PACKAGE%/bin/swctl-%VERSION%-windows-%ARCH%" +set "WORK_DIR=%TEMP%\swctl-install-%RANDOM%%RANDOM%" +set "PACKAGE_FILE=%WORK_DIR%\%PACKAGE%.tgz" +set "RESULT=1" +mkdir "%WORK_DIR%" || exit /b 1 - @REM Download the binary package. - curl -LO "https://archive.apache.org/dist/skywalking/cli/%VERSION%/skywalking-cli-%VERSION%-bin.tgz" - if EXIST "skywalking-cli-%VERSION%-bin.tgz" ( - tar -zxvf ".\skywalking-cli-%VERSION%-bin.tgz" +@REM Download the binary package and its checksum. downloads.apache.org has the current releases; +@REM archive.apache.org has all of them, but picks up a new one later. +call :download https://downloads.apache.org/skywalking/cli +if errorlevel 1 call :download https://archive.apache.org/dist/skywalking/cli +if errorlevel 1 ( + echo Failed to download %PACKAGE%.tgz + goto :cleanup +) + +@REM Verify the integrity of the downloaded file. +powershell -NoProfile -NonInteractive -Command "$expected = (Get-Content -Raw -LiteralPath ($env:PACKAGE_FILE + '.sha512')).Split()[0]; if ((Get-FileHash -Algorithm SHA512 -LiteralPath $env:PACKAGE_FILE).Hash -ne $expected) { exit 1 }" +if errorlevel 1 ( + echo The downloaded file is incomplete. + goto :cleanup +) +echo The downloaded file is complete. - @REM Verify the integrity of the downloaded file. - curl -LO "https://archive.apache.org/dist/skywalking/cli/%VERSION%/skywalking-cli-%VERSION%-bin.tgz.sha512" - CertUtil -hashfile skywalking-cli-%VERSION%-bin.tgz sha512 | findstr /X "[0-9a-zA-Z]*" > verify.txt - for /F "tokens=*" %%i in ( 'type ".\verify.txt"' ) do ( set VERIFY1="%%i skywalking-cli-%VERSION%-bin.tgz" ) - for /F "tokens=*" %%i in ( 'type ".\skywalking-cli-%VERSION%-bin.tgz.sha512"' ) do ( set VERIFY2="%%i" ) - if "!VERIFY1!" EQU "!VERIFY2!" ( - @echo Through verification, the file is complete. - mkdir "C:\Program Files\swctl-cli" +@REM Extract with a relative path: a GNU tar from Git for Windows reads "C:\..." as a remote host. +pushd "%WORK_DIR%" +tar -xzf "%PACKAGE%.tgz" "%BINARY%" +set "TAR_RESULT=%ERRORLEVEL%" +popd +if not "%TAR_RESULT%"=="0" ( + echo Failed to extract %BINARY% from %PACKAGE%.tgz + goto :cleanup +) - @REM Add swctl to the environment variable PATH. - copy ".\skywalking-cli-%VERSION%-bin\bin\swctl-%VERSION%-windows-amd64" "C:\Program Files\swctl-cli\swctl.exe" - setx "Path" "C:\Program Files\swctl-cli\;%path%" /m +if not exist "%INSTALL_DIR%" mkdir "%INSTALL_DIR%" +copy /Y "%WORK_DIR%\%BINARY:/=\%" "%INSTALL_DIR%\swctl.exe" >NUL +if errorlevel 1 ( + echo Failed to copy swctl.exe to %INSTALL_DIR%, start cmd or powershell in administrator mode please. + goto :cleanup +) - @REM Delete unnecessary files. - del ".\skywalking-cli-%VERSION%-bin.tgz" ".\verify.txt" - del ".\skywalking-cli-%VERSION%-bin.tgz.sha512" ".\releases.yml" - rd /S /Q ".\skywalking-cli-%VERSION%-bin" - - @echo Reopen the terminal and type 'swctl --help' to get more information. - ) else ( - @echo The file is incomplete. - ) - ) else ( - @echo Failed to download skywalking-cli-%VERSION%-bin.tgz - ) -) else ( - @echo Can't get the latest version. The install script may be invalid, try other install methods please. +@REM Add swctl to the system PATH, once. setx would cut a PATH longer than 1024 characters. +powershell -NoProfile -NonInteractive -Command "$path = [Environment]::GetEnvironmentVariable('Path', 'Machine'); if (($path -split ';' | ForEach-Object { $_.TrimEnd('\') }) -notcontains $env:INSTALL_DIR) { [Environment]::SetEnvironmentVariable('Path', $path.TrimEnd(';') + ';' + $env:INSTALL_DIR, 'Machine') }" +if errorlevel 1 ( + echo Failed to add %INSTALL_DIR% to the system PATH. + goto :cleanup ) + +echo Installed swctl %VERSION% (windows-%ARCH%) to %INSTALL_DIR%\swctl.exe. +echo Reopen the terminal and type 'swctl --help' to get more information. +set "RESULT=0" + +:cleanup +rd /S /Q "%WORK_DIR%" 2>NUL +exit /b %RESULT% + +@REM Downloads the package and its checksum from the given host: call :download +:download +echo Downloading %~1/%VERSION%/%PACKAGE%.tgz +curl -fL --progress-bar -o "%PACKAGE_FILE%" "%~1/%VERSION%/%PACKAGE%.tgz" || exit /b 1 +curl -fsSL -o "%PACKAGE_FILE%.sha512" "%~1/%VERSION%/%PACKAGE%.tgz.sha512" || exit /b 1 +exit /b 0 diff --git a/scripts/install.sh b/scripts/install.sh index 83508f3..381b9b7 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -15,12 +15,14 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Installs the latest Apache SkyWalking CLI release as /usr/local/bin/swctl on macOS and Linux. + # Treat unset variables and parameters other than the special parameters ‘@’ or ‘*’ as an error. set -u # Exit the script with a message. abort() { - printf "%s\n" "$@" + printf "%s\n" "$@" >&2 exit 1 } @@ -30,55 +32,79 @@ if [ -z "${BASH_VERSION:-}" ]; then fi # Check OS. -OS="$(uname)" -if [[ "$OS" != "Darwin" && "$OS" != "Linux" ]]; then - abort "The install script is only supported on macOS and Linux." -fi +case "$(uname)" in + Darwin) OS=darwin ;; + Linux) OS=linux ;; + *) abort "The install script is only supported on macOS and Linux." ;; +esac -check_cmd() { - if ! command -v "$@" &> /dev/null - then - abort "You must install "$@" before running the install script." - fi -} +# Pick the binary for this machine: the release has darwin-amd64, darwin-arm64, linux-386, linux-amd64 and linux-arm64. +ARCH="$(uname -m)" +case "$ARCH" in + x86_64 | amd64) ARCH=amd64 ;; + arm64 | aarch64) ARCH=arm64 ;; + i386 | i686) ARCH=386 ;; + *) abort "There is no swctl binary for the $ARCH architecture, try other install methods please." ;; +esac +# A shell running under Rosetta 2 reports x86_64 on Apple silicon; install the native binary there. +if [ "$OS" = darwin ] && [ "$(sysctl -n hw.optional.arm64 2> /dev/null)" = 1 ]; then + ARCH=arm64 +fi # Check if the commands to be used exist. -for cmd in shasum curl tar awk; do - check_cmd $cmd +for cmd in curl tar; do + command -v "$cmd" > /dev/null || abort "You must install $cmd before running the install script." done +if command -v sha512sum > /dev/null; then + verify_sha512() { sha512sum -c "$1"; } +elif command -v shasum > /dev/null; then + verify_sha512() { shasum -a 512 -c "$1"; } +else + abort "You must install sha512sum or shasum before running the install script." +fi -# Convert the string to lower case. -OS=$(echo $OS | awk '{print tolower($0)}') +# Get the latest version of swctl: the latest GitHub release redirects to .../releases/tag/. +LATEST_URL=$(curl -fsSLI -o /dev/null -w '%{url_effective}' https://github.com/apache/skywalking-cli/releases/latest) || LATEST_URL="" +VERSION=${LATEST_URL##*/} +VERSION_PATTERN='^[0-9]+\.[0-9]+\.[0-9]+$' +if ! [[ "$VERSION" =~ $VERSION_PATTERN ]]; then + abort "Can't get the latest version. The install script may be invalid, try other install methods please." +fi +echo "The latest version of swctl is $VERSION" -# Get the latest version of swctl. -VERSION=$(curl "https://raw.githubusercontent.com/apache/skywalking-website/master/data/releases.yml" | grep --after-context=7 "name: SkyWalking CLI" | grep "version" | grep -Eo "[0-9]+.[0-9]+.[0-9]+") -if [ "$VERSION" != "" ]; then - echo "The latest version of swctl is $VERSION" - - # Download the binary package. - curl -sSLO "https://archive.apache.org/dist/skywalking/cli/$VERSION/skywalking-cli-$VERSION-bin.tgz" > /dev/null - if [ -f "skywalking-cli-$VERSION-bin.tgz" ]; then - # Verify the integrity of the downloaded file. - curl -sSLO "https://archive.apache.org/dist/skywalking/cli/$VERSION/skywalking-cli-$VERSION-bin.tgz.sha512" > /dev/null - VERIFY=$(shasum -a512 -c "skywalking-cli-$VERSION-bin.tgz.sha512") - if [ "${VERIFY#* }" = "OK" ]; then - echo "The downloaded file is complete." - tar -zxvf skywalking-cli-$VERSION-bin.tgz - - # Add swctl to the environment variable PATH. - sudo cp skywalking-cli-$VERSION-bin/bin/swctl-$VERSION-$OS-amd64 /usr/local/bin/swctl - - # Delete unnecessary files. - sudo rm -rf "./skywalking-cli-$VERSION-bin.tgz.sha512" "./skywalking-cli-$VERSION-bin.tgz" "./skywalking-cli-$VERSION-bin" - - echo "Type 'swctl --help' to get more information." - else - abort "The downloaded file is incomplete." - fi - else - abort "Failed to download skywalking-cli-$VERSION-bin.tgz" - fi -else - echo $VERSION - abort "Can't get the latest version. The install script may be invalid, try other install methods please." +TMP_DIR=$(mktemp -d) || abort "Failed to create a temporary directory." +trap 'rm -rf "$TMP_DIR"' EXIT + +# Download the binary package and its checksum. downloads.apache.org has the current releases; +# archive.apache.org has all of them, but picks up a new one later. +PACKAGE="skywalking-cli-$VERSION-bin" +DOWNLOADED=false +for HOST in https://downloads.apache.org/skywalking/cli https://archive.apache.org/dist/skywalking/cli; do + echo "Downloading $HOST/$VERSION/$PACKAGE.tgz" + if curl -fL --progress-bar -o "$TMP_DIR/$PACKAGE.tgz" "$HOST/$VERSION/$PACKAGE.tgz" && + curl -fsSL -o "$TMP_DIR/$PACKAGE.tgz.sha512" "$HOST/$VERSION/$PACKAGE.tgz.sha512"; then + DOWNLOADED=true + break + fi +done +[ "$DOWNLOADED" = true ] || abort "Failed to download $PACKAGE.tgz" + +# Verify the integrity of the downloaded file. +(cd "$TMP_DIR" && verify_sha512 "$PACKAGE.tgz.sha512" > /dev/null) || abort "The downloaded file is incomplete." +echo "The downloaded file is complete." + +BINARY="$PACKAGE/bin/swctl-$VERSION-$OS-$ARCH" +tar -xzf "$TMP_DIR/$PACKAGE.tgz" -C "$TMP_DIR" "$BINARY" || abort "Failed to extract $BINARY from $PACKAGE.tgz" + +# Add swctl to the environment variable PATH, using sudo only when /usr/local/bin is not writable. +INSTALL_DIR=/usr/local/bin +SUDO="" +if [ "$(id -u)" != 0 ] && ! { [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; }; then + command -v sudo > /dev/null || abort "Writing to $INSTALL_DIR needs root, run the install script as root please." + SUDO=sudo +fi +if ! { $SUDO mkdir -p "$INSTALL_DIR" && $SUDO install -m 0755 "$TMP_DIR/$BINARY" "$INSTALL_DIR/swctl"; }; then + abort "Failed to install swctl to $INSTALL_DIR" fi + +echo "Installed swctl $VERSION ($OS-$ARCH) to $INSTALL_DIR/swctl. Type 'swctl --help' to get more information."