Skip to content
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
48 changes: 48 additions & 0 deletions .github/workflows/test-cli-installer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: test-cli-installer

on:
push:
paths:
- "scripts/install.sh"
- "scripts/install.ps1"
- ".github/workflows/test-cli-installer.yml"
pull_request:
paths:
- "scripts/install.sh"
- "scripts/install.ps1"
- ".github/workflows/test-cli-installer.yml"

permissions:
contents: read

jobs:
unix:
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- name: install the latest Explorer CLI
env:
EXPLORER_INSTALL_DIR: ${{ runner.temp }}/explorer-bin
NO_COLOR: 1
run: ./scripts/install.sh
- name: run the installed CLI
run: $RUNNER_TEMP/explorer-bin/explorer version

windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v7
- name: install the latest Explorer CLI
shell: pwsh
env:
EXPLORER_INSTALL_DIR: ${{ runner.temp }}\explorer-bin
NO_COLOR: 1
run: ./scripts/install.ps1
- name: run the installed CLI
shell: pwsh
run: '& "$env:RUNNER_TEMP\explorer-bin\explorer.exe" version'
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,21 @@ If there is a concrete roadmap it will be posted on our [Discord](http://discord
**Limitations**
* Only single-platform OCI images can be built, so setups containing both `linux/arm64` and `linux/amd64` hosts is not possible as of now.

## License
This project uses two different licenses: AGPLv3 and LGPLv3. Everything found under under the `api/` folder is licensed under LGPLv3 while everything else is covered by AGPLv3, if not stated otherwise.
## Install the CLI

On macOS or Linux:

```sh
curl -fsSL https://raw.githubusercontent.com/spacechunks/explorer/main/scripts/install.sh | sh
```

On Windows PowerShell:

```powershell
irm https://raw.githubusercontent.com/spacechunks/explorer/main/scripts/install.ps1 | iex
```

This installs the latest version of the CLI.

## License
This project uses two different licenses: AGPLv3 and LGPLv3. Everything found under under the `api/` folder is licensed under LGPLv3 while everything else is covered by AGPLv3, if not stated otherwise.
17 changes: 12 additions & 5 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,19 @@ Here, we will cover the basics on how to get started with the Chunk Explorer. Ha

## CLI installation

In order to interact with the Explorer, you need our CLI tool. To install it head over to the [releases page](https://github.com/spacechunks/explorer/releases),
and download the binary that is compatible with your system. The CLI is available for the following operating systems and architectures:
On macOS or Linux:

- Linux (arm64/amd64)
- MacOS (arm64/amd64)
- Windows (arm64/amd64)
```sh
curl -fsSL https://raw.githubusercontent.com/spacechunks/explorer/main/scripts/install.sh | sh
```

On Windows PowerShell:

```powershell
irm https://raw.githubusercontent.com/spacechunks/explorer/main/scripts/install.ps1 | iex
```

The installer downloads the latest version of the CLI.

## Concepts

Expand Down
167 changes: 167 additions & 0 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
& {
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$repositoryUrl = "https://github.com/spacechunks/explorer"
$binaryName = "explorer.exe"
$tempDirectory = $null

function Write-Brand {
Write-Host ""
if ($env:NO_COLOR) {
Write-Host "✦" -NoNewline
} else {
Write-Host "✦" -ForegroundColor Magenta -NoNewline
}
Write-Host " Chunk Explorer"
Write-Host ""
}

function Write-Step([string] $Message) {
Write-Host " " -NoNewline
if ($env:NO_COLOR) {
Write-Host "✓" -NoNewline
} else {
Write-Host "✓" -ForegroundColor Green -NoNewline
}
Write-Host " $Message"
}

function Get-LatestVersion {
$response = Invoke-WebRequest -Uri "$repositoryUrl/releases/latest" -Method Head -UseBasicParsing
if ($response.BaseResponse.PSObject.Properties.Name -contains "ResponseUri") {
$releaseUri = $response.BaseResponse.ResponseUri
} elseif ($response.BaseResponse.PSObject.Properties.Name -contains "RequestMessage") {
$releaseUri = $response.BaseResponse.RequestMessage.RequestUri
} else {
throw "GitHub did not return the latest release URL."
}

return [Uri]::UnescapeDataString($releaseUri.Segments[-1].TrimEnd("/"))
}

try {
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor `
[Net.SecurityProtocolType]::Tls12

$architectureName = if ($env:PROCESSOR_ARCHITEW6432) {
$env:PROCESSOR_ARCHITEW6432
} else {
$env:PROCESSOR_ARCHITECTURE
}

$architecture = switch ($architectureName.ToUpperInvariant()) {
"AMD64" { "amd64" }
"ARM64" { "arm64" }
default { throw "Unsupported architecture: $architectureName" }
}

$version = $env:EXPLORER_VERSION
if ([string]::IsNullOrWhiteSpace($version)) {
$version = Get-LatestVersion
}
if (-not $version.StartsWith("v")) {
$version = "v$version"
}
if ($version -notmatch '^v[A-Za-z0-9._+\-]+$') {
throw "Invalid Explorer CLI version: $version"
}

$installDirectory = $env:EXPLORER_INSTALL_DIR
if ([string]::IsNullOrWhiteSpace($installDirectory)) {
$installDirectory = Join-Path $env:LOCALAPPDATA "Programs\Explorer"
}
$installDirectory = $installDirectory.TrimEnd("\", "/")
if ([string]::IsNullOrWhiteSpace($installDirectory)) {
throw "The installation directory cannot be empty."
}

$archiveName = "explorer_${version}_windows_${architecture}.tar.gz"
$checksumName = "explorer_${version}_sha256sums"
$releaseBinary = "explorer_${version}_windows_${architecture}.exe"
$escapedVersion = [Uri]::EscapeDataString($version)
$releaseUrl = "$repositoryUrl/releases/download/$escapedVersion"

$tempDirectory = Join-Path ([IO.Path]::GetTempPath()) "explorer-install-$([Guid]::NewGuid())"
New-Item -ItemType Directory -Path $tempDirectory | Out-Null
$archivePath = Join-Path $tempDirectory $archiveName
$checksumPath = Join-Path $tempDirectory $checksumName

Write-Brand
Write-Host " Installing $version for Windows $architecture"
Write-Host ""

Invoke-WebRequest -Uri "$releaseUrl/$archiveName" -OutFile $archivePath -UseBasicParsing
Invoke-WebRequest -Uri "$releaseUrl/$checksumName" -OutFile $checksumPath -UseBasicParsing
Write-Step "Downloaded $archiveName"

$escapedArchiveName = [Regex]::Escape($archiveName)
$checksumLine = Get-Content -LiteralPath $checksumPath |
Where-Object { $_ -match "^([a-fA-F0-9]{64})\s+$escapedArchiveName$" } |
Select-Object -First 1
if ($null -eq $checksumLine) {
throw "The checksum manifest does not contain $archiveName."
}

$expectedChecksum = ($checksumLine -split '\s+')[0]
$actualChecksum = (Get-FileHash -LiteralPath $archivePath -Algorithm SHA256).Hash
if ($actualChecksum -ine $expectedChecksum) {
throw "Checksum verification failed for $archiveName."
}
Write-Step "Verified the SHA-256 checksum"

$tar = Get-Command "tar.exe" -ErrorAction SilentlyContinue
if ($null -eq $tar) {
throw "tar.exe is required to extract the Explorer CLI release."
}
& $tar.Source -xzf $archivePath -C $tempDirectory
if ($LASTEXITCODE -ne 0) {
throw "Could not extract $archiveName."
}

$sourceBinary = Join-Path $tempDirectory $releaseBinary
if (-not (Test-Path -LiteralPath $sourceBinary -PathType Leaf)) {
throw "The release archive does not contain $releaseBinary."
}

New-Item -ItemType Directory -Path $installDirectory -Force | Out-Null
$installedBinary = Join-Path $installDirectory $binaryName
Copy-Item -LiteralPath $sourceBinary -Destination $installedBinary -Force
Write-Step "Installed explorer to $installedBinary"

$pathEntries = @($env:Path -split ';' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
if (-not ($pathEntries | Where-Object { $_.TrimEnd("\") -ieq $installDirectory.TrimEnd("\") })) {
$env:Path = "$installDirectory;$env:Path"

$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
$userPathEntries = @($userPath -split ';' | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
if (-not ($userPathEntries | Where-Object { $_.TrimEnd("\") -ieq $installDirectory.TrimEnd("\") })) {
$newUserPath = if ([string]::IsNullOrWhiteSpace($userPath)) {
$installDirectory
} else {
"$installDirectory;$userPath"
}
[Environment]::SetEnvironmentVariable("Path", $newUserPath, "User")
}
}

Write-Host ""
Write-Host "Explorer CLI is ready."
Write-Host "Run " -NoNewline
Write-Host "explorer --help" -NoNewline
Write-Host " to get started."
Write-Host ""
} catch {
if ($env:NO_COLOR) {
Write-Host "`n Error: $($_.Exception.Message)`n" -ErrorAction Continue
} else {
Write-Host "`n Error: " -ForegroundColor Red -NoNewline
Write-Host "$($_.Exception.Message)`n"
}
throw
} finally {
if ($null -ne $tempDirectory -and (Test-Path -LiteralPath $tempDirectory)) {
Remove-Item -LiteralPath $tempDirectory -Recurse -Force
}
}
}
Loading