Document: github release for RAGFlow Go CLI (#16036)

### What problem does this PR solve?

As title

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
- [x] Documentation Update
This commit is contained in:
Haruko386
2026-06-16 14:53:00 +08:00
committed by GitHub
parent fad82fd1c0
commit 911bb20209
4 changed files with 690 additions and 4 deletions

View File

@@ -0,0 +1,99 @@
# RAGFlow CLI Installation Scripts
RAGFlow publishes static Go CLI binaries as GitHub Release assets for:
- Linux: `amd64`, `arm64`
- macOS: `amd64`, `arm64`
- Windows: `amd64`, `arm64`
The release workflow builds the binaries with `CGO_ENABLED=0`, uploads `SHA256SUMS`, and uploads `install.sh` and `install.ps1`.
## Linux And macOS
Use the hosted script:
```sh
curl -sSfL https://your-domain/install.sh | sh
```
Install a specific version:
```sh
curl -sSfL https://your-domain/install.sh | VERSION=v1.0.0 sh
```
Install to a user-writable directory:
```sh
curl -sSfL https://your-domain/install.sh | INSTALL_DIR="$HOME/.local/bin" sh
```
The Unix installer:
- detects `linux` or `darwin`
- detects `amd64` or `arm64`
- downloads `ragflow_cli-{VERSION}-{OS}-{ARCH}`
- verifies the file with the release `SHA256SUMS`
- installs to `/usr/local/bin` by default
## Windows PowerShell
Use the hosted script:
```powershell
iwr https://your-domain/install.ps1 -OutFile install.ps1
powershell -ExecutionPolicy Bypass -File .\install.ps1
```
Install a specific version:
```powershell
.\install.ps1 -Version "v1.0.0"
```
Install to a custom directory:
```powershell
.\install.ps1 -InstallDir "$env:USERPROFILE\bin"
```
The Windows installer:
- detects `windows/amd64` or `windows/arm64`
- downloads `ragflow_cli-{VERSION}-windows-{ARCH}.exe`
- verifies the file with the release `SHA256SUMS`
- installs to `$env:LOCALAPPDATA\Programs\RAGFlow` by default
- adds the install directory to the user `PATH`
## Release Asset Names
The install scripts expect these names:
```text
ragflow_cli-v1.0.0-linux-amd64
ragflow_cli-v1.0.0-linux-arm64
ragflow_cli-v1.0.0-darwin-amd64
ragflow_cli-v1.0.0-darwin-arm64
ragflow_cli-v1.0.0-windows-amd64.exe
ragflow_cli-v1.0.0-windows-arm64.exe
SHA256SUMS
install.sh
install.ps1
```
## Hosting Options
Use a static domain for the public one-line command:
```text
https://your-domain/install.sh
https://your-domain/install.ps1
```
The same scripts can also be used directly from a GitHub Release asset, for example:
```text
https://github.com/infiniflow/ragflow/releases/download/v1.0.0/install.sh
https://github.com/infiniflow/ragflow/releases/download/v1.0.0/install.ps1
```
By default, both scripts install the latest stable GitHub Release. Set `VERSION` on Unix or `-Version` on Windows to pin a specific release.

232
tools/scripts/install.ps1 Normal file
View File

@@ -0,0 +1,232 @@
#
# Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
#
# Licensed 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.
#
param(
[string]$Version = "latest",
[string]$InstallDir = "$env:LOCALAPPDATA\Programs\RAGFlow",
[string]$GitHubRepo = "infiniflow/ragflow",
[string]$CliName = "ragflow_cli"
)
$ErrorActionPreference = "Stop"
function Write-Info {
param([string]$Message)
Write-Host "[INFO] $Message" -ForegroundColor Green
}
function Write-Warn {
param([string]$Message)
Write-Host "[WARN] $Message" -ForegroundColor Yellow
}
function Write-ErrorMessage {
param([string]$Message)
Write-Host "[ERROR] $Message" -ForegroundColor Red
}
function Get-Platform {
$os = "windows"
$arch = "amd64"
if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64" -or $env:PROCESSOR_ARCHITEW6432 -eq "ARM64") {
$arch = "arm64"
}
elseif ([Environment]::Is64BitOperatingSystem) {
$arch = "amd64"
}
else {
Write-ErrorMessage "Unsupported Windows architecture: 386"
exit 1
}
Write-Info "Detected platform: ${os}/${arch}"
return @{
OS = $os
Arch = $arch
}
}
function Get-ReleaseVersion {
param(
[string]$RequestedVersion,
[string]$Repository
)
if ($RequestedVersion -ne "latest") {
Write-Info "Using specified version: $RequestedVersion"
return $RequestedVersion
}
Write-Info "Fetching latest release information"
$releaseUrl = "https://api.github.com/repos/${Repository}/releases/latest"
$release = Invoke-RestMethod -Uri $releaseUrl -TimeoutSec 20
$latestVersion = $release.tag_name
if ([string]::IsNullOrWhiteSpace($latestVersion)) {
Write-ErrorMessage "Could not determine latest version"
exit 1
}
Write-Info "Latest version: $latestVersion"
return $latestVersion
}
function Get-DownloadInfo {
param(
[string]$ResolvedVersion,
[string]$OS,
[string]$Arch,
[string]$Repository,
[string]$BinaryName
)
$fileName = "${BinaryName}-${ResolvedVersion}-${OS}-${Arch}.exe"
$baseUrl = "https://github.com/${Repository}/releases/download/${ResolvedVersion}"
return @{
FileName = $fileName
BinaryUrl = "${baseUrl}/${fileName}"
ChecksumUrl = "${baseUrl}/SHA256SUMS"
}
}
function Download-File {
param(
[string]$Url,
[string]$OutputPath
)
Write-Info "Downloading $Url"
$ProgressPreference = "SilentlyContinue"
Invoke-WebRequest -Uri $Url -OutFile $OutputPath -TimeoutSec 120
}
function Test-Checksum {
param(
[string]$BinaryPath,
[string]$ChecksumPath,
[string]$FileName
)
$checksumLine = Get-Content $ChecksumPath | Where-Object {
$parts = $_ -split "\s+"
$parts.Count -ge 2 -and $parts[1] -eq $FileName
} | Select-Object -First 1
if ([string]::IsNullOrWhiteSpace($checksumLine)) {
Write-ErrorMessage "No checksum found for $FileName in SHA256SUMS"
exit 1
}
$expected = ($checksumLine -split "\s+")[0].ToLowerInvariant()
$actual = (Get-FileHash -Algorithm SHA256 -Path $BinaryPath).Hash.ToLowerInvariant()
if ($actual -ne $expected) {
Write-ErrorMessage "Checksum verification failed for $FileName"
Write-ErrorMessage "Expected: $expected"
Write-ErrorMessage "Actual: $actual"
exit 1
}
Write-Info "Checksum verified"
}
function Install-CLI {
param(
[string]$TempFile,
[string]$TargetDir,
[string]$BinaryName
)
if (-not (Test-Path $TargetDir)) {
Write-Info "Creating directory: $TargetDir"
New-Item -ItemType Directory -Path $TargetDir -Force | Out-Null
}
$targetFile = Join-Path $TargetDir "${BinaryName}.exe"
Write-Info "Installing CLI to $targetFile"
Stop-Process -Name $BinaryName -Force -ErrorAction SilentlyContinue
Copy-Item -Path $TempFile -Destination $targetFile -Force
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
$pathParts = @()
if (-not [string]::IsNullOrWhiteSpace($userPath)) {
$pathParts = $userPath -split ";"
}
if ($pathParts -notcontains $TargetDir) {
Write-Info "Adding $TargetDir to user PATH"
$newPath = if ([string]::IsNullOrWhiteSpace($userPath)) { $TargetDir } else { "$userPath;$TargetDir" }
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
Write-Warn "Restart your terminal for PATH changes to take effect"
}
Write-Info "CLI installed successfully at $targetFile"
return $targetFile
}
function Test-Installation {
param([string]$CliPath)
if (-not (Test-Path $CliPath)) {
Write-Warn "CLI not found at expected location: $CliPath"
return
}
try {
& $CliPath --version
if ($LASTEXITCODE -eq 0) {
Write-Info "Installation verified successfully"
return
}
}
catch {
Write-Warn "Could not execute version check: $_"
}
Write-Warn "Could not verify CLI execution, but the binary was installed"
}
function Main {
$platform = Get-Platform
$resolvedVersion = Get-ReleaseVersion -RequestedVersion $Version -Repository $GitHubRepo
$downloadInfo = Get-DownloadInfo -ResolvedVersion $resolvedVersion -OS $platform.OS -Arch $platform.Arch -Repository $GitHubRepo -BinaryName $CliName
Write-Info "Download URL: $($downloadInfo.BinaryUrl)"
$tempBinary = [System.IO.Path]::GetTempFileName()
$tempSums = [System.IO.Path]::GetTempFileName()
try {
Download-File -Url $downloadInfo.BinaryUrl -OutputPath $tempBinary
Download-File -Url $downloadInfo.ChecksumUrl -OutputPath $tempSums
Test-Checksum -BinaryPath $tempBinary -ChecksumPath $tempSums -FileName $downloadInfo.FileName
$cliPath = Install-CLI -TempFile $tempBinary -TargetDir $InstallDir -BinaryName $CliName
Test-Installation -CliPath $cliPath
Write-Info "Installation complete"
}
finally {
Remove-Item $tempBinary -Force -ErrorAction SilentlyContinue
Remove-Item $tempSums -Force -ErrorAction SilentlyContinue
}
}
Main

272
tools/scripts/install.sh Executable file
View File

@@ -0,0 +1,272 @@
#!/bin/sh
#
# Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
#
# Licensed 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.
#
set -eu
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
GITHUB_REPO="${GITHUB_REPO:-infiniflow/ragflow}"
CLI_NAME="${CLI_NAME:-ragflow_cli}"
VERSION="${VERSION:-latest}"
RELEASE_API="https://api.github.com/repos/${GITHUB_REPO}/releases/latest"
RELEASE_BASE_URL=""
OS=""
ARCH=""
FILENAME=""
DOWNLOAD_URL=""
CHECKSUM_URL=""
info() {
printf '[INFO] %s\n' "$1" >&2
}
warn() {
printf '[WARN] %s\n' "$1" >&2
}
error() {
printf '[ERROR] %s\n' "$1" >&2
}
need_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
error "$1 is required but not installed"
exit 1
fi
}
run_as_root() {
if "$@" 2>/dev/null; then
return 0
fi
if command -v sudo >/dev/null 2>&1; then
info "Requesting sudo permission for: $*"
sudo "$@"
return $?
fi
error "Permission denied and sudo is not available: $*"
exit 1
}
detect_platform() {
os_name="$(uname -s)"
arch_name="$(uname -m)"
case "$os_name" in
Linux)
OS="linux"
;;
Darwin)
OS="darwin"
;;
*)
error "Unsupported OS for install.sh: $os_name"
error "Use install.ps1 on Windows PowerShell"
exit 1
;;
esac
case "$arch_name" in
x86_64|amd64)
ARCH="amd64"
;;
aarch64|arm64)
ARCH="arm64"
;;
*)
error "Unsupported architecture: $arch_name"
exit 1
;;
esac
info "Detected platform: ${OS}/${ARCH}"
}
resolve_version() {
if [ "$VERSION" != "latest" ]; then
info "Using specified version: $VERSION"
return
fi
info "Fetching latest release information"
response="$(curl -sSfL "$RELEASE_API")"
VERSION="$(printf '%s\n' "$response" | sed -n 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' | head -n 1)"
if [ -z "$VERSION" ]; then
error "Could not determine latest version from GitHub"
exit 1
fi
info "Latest version: $VERSION"
}
build_urls() {
FILENAME="${CLI_NAME}-${VERSION}-${OS}-${ARCH}"
RELEASE_BASE_URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}"
DOWNLOAD_URL="${RELEASE_BASE_URL}/${FILENAME}"
CHECKSUM_URL="${RELEASE_BASE_URL}/SHA256SUMS"
info "Download URL: $DOWNLOAD_URL"
}
download_file() {
url="$1"
output="$2"
if ! curl -sSfL "$url" -o "$output"; then
rm -f "$output"
error "Failed to download $url"
exit 1
fi
}
file_size() {
stat -f%z "$1" 2>/dev/null || stat -c%s "$1" 2>/dev/null || printf '0'
}
sha256_file() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
return
fi
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
return
fi
error "sha256sum or shasum is required to verify the download"
exit 1
}
verify_checksum() {
binary_file="$1"
sums_file="$2"
expected="$(awk -v f="$FILENAME" '$2 == f {print $1}' "$sums_file" | head -n 1)"
if [ -z "$expected" ]; then
error "No checksum found for $FILENAME in SHA256SUMS"
exit 1
fi
actual="$(sha256_file "$binary_file")"
if [ "$actual" != "$expected" ]; then
error "Checksum verification failed for $FILENAME"
error "Expected: $expected"
error "Actual: $actual"
exit 1
fi
info "Checksum verified"
}
download_cli() {
binary_file="$(mktemp)"
sums_file="$(mktemp)"
info "Downloading CLI"
download_file "$DOWNLOAD_URL" "$binary_file"
size="$(file_size "$binary_file")"
if [ "$size" -lt 100000 ]; then
warn "Downloaded file is unusually small (${size} bytes)"
fi
info "Downloading SHA256SUMS"
download_file "$CHECKSUM_URL" "$sums_file"
verify_checksum "$binary_file" "$sums_file"
rm -f "$sums_file"
printf '%s\n' "$binary_file"
}
install_cli() {
source_file="$1"
target_file="${INSTALL_DIR}/${CLI_NAME}"
info "Installing CLI to $target_file"
if [ ! -d "$INSTALL_DIR" ]; then
run_as_root mkdir -p "$INSTALL_DIR"
fi
if [ -w "$INSTALL_DIR" ]; then
mv "$source_file" "$target_file"
chmod 755 "$target_file"
else
run_as_root mv "$source_file" "$target_file"
run_as_root chmod 755 "$target_file"
fi
info "CLI installed successfully at $target_file"
}
verify_installation() {
cli_path="${INSTALL_DIR}/${CLI_NAME}"
if [ ! -x "$cli_path" ]; then
warn "CLI may not be executable: $cli_path"
return
fi
if "$cli_path" --version >/dev/null 2>&1; then
"$cli_path" --version
info "Installation verified successfully"
return
fi
if "$cli_path" -h >/dev/null 2>&1 || "$cli_path" --help >/dev/null 2>&1; then
info "Installation verified successfully"
return
fi
warn "Could not verify CLI execution, but the binary was installed"
}
print_path_notice() {
case ":$PATH:" in
*":$INSTALL_DIR:"*)
;;
*)
warn "$INSTALL_DIR is not in PATH"
warn "Add it with: export PATH=\"$INSTALL_DIR:\$PATH\""
;;
esac
}
main() {
need_cmd curl
need_cmd uname
need_cmd mktemp
need_cmd awk
need_cmd sed
detect_platform
resolve_version
build_urls
temp_file="$(download_cli)"
install_cli "$temp_file"
verify_installation
print_path_notice
info "Installation complete"
}
main "$@"