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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
- Logging/output: use `dev.jbang.util.Util` helpers (e.g., `infoMsg`, `verboseMsg`).
- Commits: use conventional/semantic format — `feat:`, `fix:`, `build:`, `docs:`, etc. PR titles follow the same convention.
- Startup scripts live in `src/main/scripts/`: `jbang` (bash), `jbang.cmd` (CMD), `jbang.ps1` (PowerShell). The CMD script delegates downloads and JDK installs to `jbang.ps1`. Changes affecting downloads or bootstrap must be applied consistently across all three. Behavior (e.g., retry backoff) must be consistent across tools — watch for tool-specific quirks like `curl --retry-delay 0` meaning exponential backoff while `wget --waitretry=0` meaning no delay.
- Environment variables follow `JBANG_*` naming. New env vars must have defaults in all three scripts, be documented in the reference table in `installation.adoc` ("Startup Script Environment Variables"), and behave identically across platforms.
- Environment variables follow `JBANG_*` naming. New env vars must have defaults in each script that actually uses them (e.g., `jbang.cmd` delegates downloads to `jbang.ps1`, so download-related vars only need defaults in `jbang` and `jbang.ps1`). Document new vars in `installation.adoc` ("Startup Script Environment Variables") and ensure consistent behavior across platforms.
- Documentation is AsciiDoc under `docs/modules/ROOT/pages/` (e.g., `installation.adoc`, `troubleshooting.adoc`).
- Test infrastructure: `BaseTest` includes WireMock for HTTP mocking (records/replays requests). `BaseIT` provides `shell()` helpers for running CLI commands. Use `assumeTrue` for conditionally skipping tests (e.g., `assumeTrue(isCommandAvailable("bash"))` or `assumeTrue(isCommandAvailable("pwsh"))`).
- Script tests should run the real scripts from `src/main/scripts/` — not synthetic copies or extracted functions. Use env var overrides (e.g., `JBANG_DOWNLOAD_URL`) to point real scripts at WireMock.
48 changes: 34 additions & 14 deletions src/main/scripts/jbang
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
# The Java version to install when it's not installed on the system yet
javaVersion=${JBANG_DEFAULT_JAVA_VERSION:-17}

# Base URL for downloading JBang releases.
# Override for testing or corporate mirrors.
# Example: JBANG_DOWNLOAD_BASEURL=http://localhost:18080
jbangDownloadBaseUrl=${JBANG_DOWNLOAD_BASEURL:-https://github.com/jbangdev/jbang/releases}

# Number of retry attempts for downloads (curl/wget)
downloadRetry=${JBANG_DOWNLOAD_RETRY:-5}
downloadRetryDelay=${JBANG_DOWNLOAD_RETRY_DELAY:-0}
Expand All @@ -25,20 +30,35 @@ script_dir() {
}

download() {
if [ -x "$(command -v curl)" ]; then
curl -sLf --retry "$downloadRetry" --retry-delay "$downloadRetryDelay" -o "$2" "$1"
retval=$?
elif [ -x "$(command -v wget)" ]; then
local attempt=0
local maxAttempts=$((downloadRetry + 1))
while true; do
attempt=$((attempt + 1))
if [ -x "$(command -v curl)" ]; then
curl -sLf -o "$2" "$1"
retval=$?
elif [ -x "$(command -v wget)" ]; then
wget -q -O "$2" "$1"
retval=$?
else
echo "Error: curl or wget not found, please make sure one of them is installed" 1>&2
exit 1
fi
if [ $retval -eq 0 ] || [ $attempt -ge $maxAttempts ]; then
break
fi
if [ "$downloadRetryDelay" -gt 0 ] 2>/dev/null; then
wget -q --tries="$downloadRetry" --waitretry="$downloadRetryDelay" -O "$2" "$1"
sleepSeconds=$downloadRetryDelay
else
wget -q --tries="$downloadRetry" -O "$2" "$1"
# Exponential backoff: 1, 2, 4, 8, ...
sleepSeconds=$((1 << (attempt - 1)))
fi
retval=$?
else
echo "Error: curl or wget not found, please make sure one of them is installed" 1>&2
exit 1
fi
echo "Download $attempt/$maxAttempts failed. Retry in $sleepSeconds second(s)..." 1>&2
if [ $attempt -eq 1 ]; then
echo "(Set JBANG_DOWNLOAD_RETRY=0 to disable retries)" 1>&2
fi
sleep $sleepSeconds
done
}

unpack() {
Expand Down Expand Up @@ -258,15 +278,15 @@ if [[ -z "$binaryPath" ]]; then
fi
if [[ -z "$binaryPath" && -z "$jarPath" ]]; then
if [[ ! -f "$JBDIR/bin/jbang.jar" || ! -f "$JBDIR/bin/jbang" ]]; then
echo "Downloading JBang $JBANG_DOWNLOAD_VERSION..." 1>&2
mkdir -p "$TDIR/urls"
if [ -n "$JBANG_DOWNLOAD_URL" ]; then
jburl="$JBANG_DOWNLOAD_URL";
elif [ -z "$JBANG_DOWNLOAD_VERSION" ]; then
jburl="https://github.com/jbangdev/jbang/releases/latest/download/jbang.tar";
jburl="${jbangDownloadBaseUrl}/latest/download/jbang.tar";
else
jburl="https://github.com/jbangdev/jbang/releases/download/v$JBANG_DOWNLOAD_VERSION/jbang.tar";
jburl="${jbangDownloadBaseUrl}/download/v$JBANG_DOWNLOAD_VERSION/jbang.tar";
fi
echo "Downloading JBang ${JBANG_DOWNLOAD_VERSION:-latest} from $jburl..." 1>&2
download "$jburl" "$TDIR/urls/jbang.tar"
if [ $retval -ne 0 ]; then echo "Error downloading JBang from $jburl" 1>&2; exit $retval; fi
echo "Installing JBang..." 1>&2
Expand Down
17 changes: 13 additions & 4 deletions src/main/scripts/jbang.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ if (-not (Test-Path env:JBANG_DIR)) { $JBDIR="$env:userprofile\.jbang" } else {
if (-not (Test-Path env:JBANG_CACHE_DIR)) { $TDIR="$JBDIR\cache" } else { $TDIR=$env:JBANG_CACHE_DIR }
if (-not (Test-Path env:JBANG_USE_NATIVE)) { $env:JBANG_USE_NATIVE="false" }

# Base URL for downloading JBang releases.
# Override for testing or corporate mirrors.
# Example: $env:JBANG_DOWNLOAD_BASEURL='http://localhost:18080'
if (-not (Test-Path env:JBANG_DOWNLOAD_BASEURL)) { $jbangDownloadBaseUrl='https://github.com/jbangdev/jbang/releases' } else { $jbangDownloadBaseUrl=$env:JBANG_DOWNLOAD_BASEURL }

# Number of retry attempts for downloads
if (-not (Test-Path env:JBANG_DOWNLOAD_RETRY)) { $downloadRetry=5 } else { $downloadRetry=[int]$env:JBANG_DOWNLOAD_RETRY }
if (-not (Test-Path env:JBANG_DOWNLOAD_RETRY_DELAY)) { $downloadRetryDelay=0 } else { $downloadRetryDelay=[int]$env:JBANG_DOWNLOAD_RETRY_DELAY }
Expand All @@ -82,7 +87,10 @@ function Invoke-Download {
# Exponential backoff: 1, 2, 4, 8, ...
$sleepSeconds = [Math]::Pow(2, $attempt - 1)
}
[Console]::Error.WriteLine("Download attempt $attempt/$($downloadRetry + 1) failed, retrying in $sleepSeconds second(s)...")
[Console]::Error.WriteLine("Download $attempt/$($downloadRetry + 1) failed. Retry in $sleepSeconds second(s)...")
if ($attempt -eq 1) {
[Console]::Error.WriteLine("(Set JBANG_DOWNLOAD_RETRY=0 to disable retries)")
}
Start-Sleep -Seconds $sleepSeconds
}
}
Expand Down Expand Up @@ -142,11 +150,12 @@ if (-not $binaryPath -and -not $jarPath) {
if (Test-Path env:JBANG_DOWNLOAD_URL) {
$jburl=$env:JBANG_DOWNLOAD_URL
} elseif (-not (Test-Path env:JBANG_DOWNLOAD_VERSION)) {
$jburl="https://github.com/jbangdev/jbang/releases/latest/download/jbang.zip"
$jburl="$jbangDownloadBaseUrl/latest/download/jbang.zip"
} else {
$jburl="https://github.com/jbangdev/jbang/releases/download/v$env:JBANG_DOWNLOAD_VERSION/jbang.zip";
$jburl="$jbangDownloadBaseUrl/download/v$env:JBANG_DOWNLOAD_VERSION/jbang.zip";
}
[Console]::Error.WriteLine("Downloading JBang $env:JBANG_DOWNLOAD_VERSION...")
$dlVersion = if ($env:JBANG_DOWNLOAD_VERSION) { $env:JBANG_DOWNLOAD_VERSION } else { 'latest' }
[Console]::Error.WriteLine("Downloading JBang $dlVersion from $jburl...")
$ok = Invoke-Download "$jburl" "$TDIR\urls\jbang.zip"
if (-not ($ok)) {
[Console]::Error.WriteLine("Error downloading JBang from $jburl to $TDIR\urls\jbang.zip")
Expand Down
Loading