From aa326ea91b9899dd0b490530f86861626e44e15c Mon Sep 17 00:00:00 2001 From: Wu Sheng Date: Wed, 11 Nov 2026 09:52:27 +0800 Subject: [PATCH] Fix the quick install scripts, and test them on Linux, macOS and Windows install.sh and install.bat read the latest version from data/releases.yml on the website, which the website no longer has, so both stopped at "Can't get the latest version". - Both take the version from the latest GitHub release, whose URL redirects to .../releases/tag/; no API rate limit and no JSON to parse, in bash or cmd. - Both download from downloads.apache.org, falling back to archive.apache.org, which has every release but picks up a new one later. Downloads go to a temporary directory that is removed afterwards. - install.sh installs the binary for the machine's architecture (amd64, arm64, 386) instead of always amd64, also under Rosetta 2, accepts sha512sum or shasum, and uses sudo only when /usr/local/bin is not writable. - install.bat picks windows-386 on 32-bit Windows, checks the sha512 with Get-FileHash instead of parsing CertUtil output, and adds the install directory to the system PATH once. setx wrote the merged user and system PATH into the system PATH, cut it at 1024 characters, and added the directory again on every run. - A new Install Scripts workflow runs install.sh on ubuntu x64, ubuntu arm64 and macOS, and install.bat on Windows, twice each, when the scripts change and every Monday, since an outside change broke them last time. --- .github/workflows/install-scripts.yaml | 93 +++++++++++++++++++ CHANGES.md | 6 ++ scripts/install.bat | 121 +++++++++++++++---------- scripts/install.sh | 118 ++++++++++++++---------- 4 files changed, 246 insertions(+), 92 deletions(-) create mode 100644 .github/workflows/install-scripts.yaml diff --git a/.github/workflows/install-scripts.yaml b/.github/workflows/install-scripts.yaml new file mode 100644 index 00000000..598f9dfe --- /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 3ce9cabb..c72531b6 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 57974805..fea755ad 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 83508f34..381b9b76 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."