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
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ jobs:
fi
rm -f "build/$bin"
done
# Attach the install scripts too, so releases/latest/download/install.sh
# is a stable URL that serves the released version of the script.
cp scripts/install.sh scripts/install.ps1 dist/
ls -la dist

- name: Attach binaries to the release
Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,38 @@ jobs:
env:
DBGP_REQUIRE_ENGINE: '1'
run: go test -race -count=1 -v ./...

# The install scripts, run as users run them, against the latest release.
install:
name: install script (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v7
- name: install.sh
if: runner.os != 'Windows'
run: |
cat scripts/install.sh | sh
dbgp -version
# A chosen release, to a directory of its own.
INSTALL_DIR="$RUNNER_TEMP/dbgp" VERSION=0.1.0 sh scripts/install.sh
test "$("$RUNNER_TEMP/dbgp/dbgp" -version)" = "dbgp 0.1.0"
- name: install.ps1
if: runner.os == 'Windows'
shell: pwsh
run: |
Get-Content -Raw scripts/install.ps1 | Invoke-Expression
$dir = Join-Path $env:ProgramFiles "dbgp"
& (Join-Path $dir "dbgp.exe") -version
if (-not (([Environment]::GetEnvironmentVariable("Path", "Machine") -split ';') -contains $dir)) {
throw "$dir is not on the system PATH"
}
# A chosen release, to a directory of its own.
$env:INSTALL_DIR = Join-Path $env:RUNNER_TEMP "dbgp"
$env:VERSION = "0.1.0"
./scripts/install.ps1
$got = & (Join-Path $env:INSTALL_DIR "dbgp.exe") -version
if ($got -ne "dbgp 0.1.0") { throw "installed $got, want dbgp 0.1.0" }
27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,35 @@ out, next, _ := sess.Output(0) // program output, read incrementally
notes, _ := sess.Notifications(0) // PHP warnings and other notifications
```

## Command-line debugger
## Installation

The `dbgp` command, both the command-line debugger and the MCP server, installs system-wide with a script that downloads the latest [release](https://github.com/php-debugger/dbgp-client/releases) for your OS and architecture.

macOS / Linux (installs to `/usr/local/bin`, using `sudo` if needed):

```sh
curl -fsSL https://github.com/php-debugger/dbgp-client/releases/latest/download/install.sh | sh
```

Windows (PowerShell as administrator; installs to `%ProgramFiles%\dbgp` and adds it to the system PATH):

```powershell
powershell -c "irm https://github.com/php-debugger/dbgp-client/releases/latest/download/install.ps1 | iex"
```

`cmd/dbgp` is an interactive debugger built on the library. Each [release](https://github.com/php-debugger/dbgp-client/releases) has it built for Linux and macOS (amd64 and arm64) and Windows (amd64); or install it with Go:
Set `INSTALL_DIR` to install elsewhere, and `VERSION` (e.g. `0.1.0`) to install a release other than the latest. Run the script again to update; if the background MCP server is running, restart it afterwards with `dbgp mcp stop` and `dbgp mcp start`. Builds are published for Linux and macOS (amd64 and arm64) and Windows (amd64, which also runs on ARM); elsewhere, install with Go:

```sh
go install github.com/php-debugger/dbgp-client/cmd/dbgp@latest
```

`dbgp -version` shows the installed version.

## Command-line debugger

`cmd/dbgp` is an interactive debugger built on the library:

```sh
dbgp -break src/Controller/HomeController.php:25
```

Expand Down
73 changes: 73 additions & 0 deletions scripts/install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<#
.SYNOPSIS
dbgp installer (Windows).

.DESCRIPTION
Downloads the latest dbgp release for Windows, installs it system-wide and
adds it to the system PATH. Run it from PowerShell as administrator.

Usage:
powershell -c "irm https://github.com/php-debugger/dbgp-client/releases/latest/download/install.ps1 | iex"

Environment overrides:
$env:INSTALL_DIR where to place the binary (default: %ProgramFiles%\dbgp)
$env:VERSION the release to install (default: the latest)
#>

$ErrorActionPreference = "Stop"

$Repo = "php-debugger/dbgp-client"
$Bin = "dbgp.exe"
$InstallDir = if ($env:INSTALL_DIR) { $env:INSTALL_DIR } else { Join-Path $env:ProgramFiles "dbgp" }
$IsAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
[Security.Principal.WindowsBuiltInRole]::Administrator)

# The default location and the system PATH need administrator rights.
if (-not $env:INSTALL_DIR -and -not $IsAdmin) {
throw "Installing to $InstallDir needs administrator rights: run PowerShell as administrator, or set `$env:INSTALL_DIR"
}

# Only one Windows build is published (x64); Windows-on-ARM runs it via emulation.
$Asset = "dbgp-windows-amd64.zip"

if ($env:VERSION) {
$Url = "https://github.com/$Repo/releases/download/$($env:VERSION)/$Asset"
Write-Host "Installing dbgp $($env:VERSION) (windows/amd64)"
} else {
# The releases/latest/download URL always resolves to the newest release.
$Url = "https://github.com/$Repo/releases/latest/download/$Asset"
Write-Host "Installing dbgp (latest, windows/amd64)"
}

$tmp = Join-Path $env:TEMP ("dbgp-" + [System.Guid]::NewGuid().ToString())
New-Item -ItemType Directory -Path $tmp | Out-Null
try {
$zip = Join-Path $tmp $Asset
Invoke-WebRequest -UseBasicParsing -Uri $Url -OutFile $zip
Expand-Archive -Path $zip -DestinationPath $tmp -Force

$src = Join-Path $tmp $Bin
if (-not (Test-Path $src)) { throw "archive did not contain $Bin" }

New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
$dest = Join-Path $InstallDir $Bin
try {
Move-Item -Force $src $dest
} catch {
throw "Cannot replace $dest, probably because dbgp is running: stop it (dbgp mcp stop for the background MCP server) and run this again"
}
} finally {
Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue
}

Write-Host ""
Write-Host "Installed $(& $dest -version) to $dest"

# Add the directory to the PATH: the system one when installing system-wide.
$scope = if ($IsAdmin) { "Machine" } else { "User" }
$path = [Environment]::GetEnvironmentVariable("Path", $scope)
if (-not $path) { $path = "" }
if (-not (($path -split ';') -contains $InstallDir)) {
[Environment]::SetEnvironmentVariable("Path", ((@($path.TrimEnd(';'), $InstallDir) | Where-Object { $_ }) -join ';'), $scope)
Write-Host "Added $InstallDir to the $($scope.ToLower()) PATH: open a new terminal to use dbgp."
}
99 changes: 99 additions & 0 deletions scripts/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/bin/sh
# dbgp installer (Linux/macOS). Installs the latest release system-wide.
#
# Usage:
# curl -fsSL https://github.com/php-debugger/dbgp-client/releases/latest/download/install.sh | sh
# wget -qO- https://github.com/php-debugger/dbgp-client/releases/latest/download/install.sh | sh
#
# Environment overrides:
# INSTALL_DIR=/path where to place the binary (default: /usr/local/bin)
# VERSION=0.1.0 the release to install (default: the latest)
#
# sudo is used only when INSTALL_DIR is not writable.
#
# Because the archive is fetched with curl/wget (not a browser), the binary is
# not quarantined, so macOS Gatekeeper does not block it. As a safety net the
# script also clears the quarantine attribute if present.
set -eu

REPO="php-debugger/dbgp-client"
BIN="dbgp"
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
VERSION="${VERSION:-}"

info() { printf '%s\n' "$*"; }
fail() { printf 'error: %s\n' "$*" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }

download() { # download URL FILE
if have curl; then curl -fsSL "$1" -o "$2"
elif have wget; then wget -q "$1" -O "$2"
else fail "need curl or wget to download"; fi
}

# --- detect OS ---
kernel="$(uname -s)"
case "$kernel" in
Linux) OS="linux" ;;
Darwin) OS="macos" ;;
*) fail "unsupported operating system: $kernel (install with: go install github.com/$REPO/cmd/dbgp@latest)" ;;
esac

# --- detect architecture ---
machine="$(uname -m)"
case "$machine" in
x86_64 | amd64) ARCH="amd64" ;;
arm64 | aarch64) ARCH="arm64" ;;
*) fail "unsupported architecture: $machine (install with: go install github.com/$REPO/cmd/dbgp@latest)" ;;
esac

ASSET="dbgp-${OS}-${ARCH}.tar.gz"
if [ -n "$VERSION" ]; then
URL="https://github.com/$REPO/releases/download/$VERSION/$ASSET"
info "Installing $BIN $VERSION ($OS/$ARCH)"
else
# The releases/latest/download URL always resolves to the newest release.
URL="https://github.com/$REPO/releases/latest/download/$ASSET"
info "Installing $BIN (latest, $OS/$ARCH)"
fi

# --- download + extract ---
tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT INT TERM
download "$URL" "$tmp/$ASSET" || fail "failed to download $URL"
tar -xzf "$tmp/$ASSET" -C "$tmp" || fail "failed to extract $ASSET"
[ -f "$tmp/$BIN" ] || fail "archive did not contain $BIN"
chmod +x "$tmp/$BIN"
# Clear any quarantine attribute so macOS Gatekeeper does not block it.
if [ "$OS" = "macos" ]; then
xattr -d com.apple.quarantine "$tmp/$BIN" 2>/dev/null || true
fi

# --- install ---
# sudo only if the directory, or the one it would be created in, is not writable.
target="$INSTALL_DIR"
while [ ! -d "$target" ]; do target="$(dirname "$target")"; done
SUDO=""
if [ ! -w "$target" ]; then
have sudo || fail "cannot write to $INSTALL_DIR: run as root, or set INSTALL_DIR"
info "Installing to $INSTALL_DIR needs administrator rights: using sudo"
SUDO="sudo"
fi
$SUDO mkdir -p "$INSTALL_DIR" || fail "cannot create $INSTALL_DIR"
# mv replaces the file rather than writing into it, so a running dbgp (such
# as the background MCP server) keeps running the old one.
$SUDO mv -f "$tmp/$BIN" "$INSTALL_DIR/$BIN" || fail "cannot write to $INSTALL_DIR"

info ""
info "Installed $("$INSTALL_DIR/$BIN" -version) to $INSTALL_DIR/$BIN"
case ":$PATH:" in
*":$INSTALL_DIR:"*) ;;
*)
info "Add $INSTALL_DIR to your PATH, e.g. in your shell's profile:"
info " export PATH=\"$INSTALL_DIR:\$PATH\""
;;
esac
if "$INSTALL_DIR/$BIN" mcp status >/dev/null 2>&1; then
info "The background MCP server still runs the previous version: restart it with"
info " dbgp mcp stop && dbgp mcp start"
fi
Loading