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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,10 @@ Already-loaded extensions are reported as `already ON` and skipped. On Linux, ex
### Composer

```bash
phpvm composer # installs composer.phar + shim into the active PHP version's bin dir
phpvm composer # installs a single global composer that follows the active PHP version
```

The installer signature is verified against `composer.github.io/installer.sig` (SHA-384) before execution. Composer lives **inside the active PHP version's directory** — switch versions with `phpvm use <other>` then re-run `phpvm composer` for that version.
The installer signature is verified against `composer.github.io/installer.sig` (SHA-384) before execution. Composer is installed **once** — `composer.phar` in `~/.phpvm/` and a shim in `~/.phpvm/bin/` (on PATH) that runs whatever PHP is active. Switch versions with `phpvm use <other>` and the same `composer` keeps working; no need to re-run `phpvm composer`. (Composer 2.x requires PHP ≥ 7.2.5, so an extremely old active version won't run the latest composer.)

### Fix `php.ini` extension_dir

Expand Down Expand Up @@ -239,7 +239,8 @@ phpvm/
│ └── 8.1.29/
├── current -> versions/8.3.0 (junction on Windows, symlink on Linux)
├── cache/ # Linux: cached source tarballs
├── bin/ # Windows: phpvm.cmd + phpvm.ps1 shim
├── composer.phar # global Composer (follows the active version)
├── bin/ # on PATH: composer shim (+ phpvm.cmd / phpvm.ps1 on Windows)
├── phpvm.ps1 # Windows: main script
└── phpvm.sh # Linux: main script (sourced in .bashrc)
```
Expand Down
2 changes: 1 addition & 1 deletion linux/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

set -e

PHPVM_VERSION="1.8.0"
PHPVM_VERSION="1.8.1"
PHPVM_DIR="${PHPVM_DIR:-$HOME/.phpvm}"
PHPVM_REPO="https://raw.githubusercontent.com/devhardiyanto/phpvm/main"

Expand Down
49 changes: 32 additions & 17 deletions linux/phpvm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
# phpvm use 8.3.0
# ==============================================================================

PHPVM_VERSION="1.8.0"
PHPVM_VERSION="1.8.1"
PHPVM_DIR="${PHPVM_DIR:-$HOME/.phpvm}"
PHPVM_VERSIONS="$PHPVM_DIR/versions"
PHPVM_CURRENT="$PHPVM_DIR/current"
PHPVM_BIN="$PHPVM_DIR/bin" # global shims (composer) — always on PATH
PHPVM_CACHE="$PHPVM_DIR/cache"
PHPVM_LOG="$PHPVM_DIR/build.log"
PHPVM_UPDATE_URL="https://raw.githubusercontent.com/devhardiyanto/phpvm/main/version.txt"
Expand Down Expand Up @@ -76,16 +77,27 @@ _phpvm_check_update() {


_phpvm_init() {
mkdir -p "$PHPVM_VERSIONS" "$PHPVM_CACHE"
mkdir -p "$PHPVM_VERSIONS" "$PHPVM_CACHE" "$PHPVM_BIN"
}

# ── PATH management ───────────────────────────────────────────────────────────
# Sets $PHPVM_CURRENT/bin as the first entry in PATH
# Order: $PHPVM_BIN (global shims like composer) before $PHPVM_CURRENT/bin so a
# global composer always wins over any stale per-version shim; both ahead of the
# rest of PATH. `php`, `pecl`, etc. still resolve from the active version's bin.
_phpvm_use_path() {
local bin="$PHPVM_CURRENT/bin"
# Remove any existing phpvm path entries
PATH=$(echo "$PATH" | tr ':' '\n' | grep -v "$PHPVM_DIR" | paste -sd ':')
export PATH="$bin:$PATH"
export PATH="$PHPVM_BIN:$bin:$PATH"
}

# Ensure $PHPVM_BIN is on PATH even when no version is active yet, so the global
# `composer` shim is reachable (and gives a clean error) regardless.
_phpvm_ensure_bin_path() {
case ":$PATH:" in
*":$PHPVM_BIN:"*) ;;
*) export PATH="$PHPVM_BIN:$PATH" ;;
esac
}

# ── Auto-switch (.phpvmrc) ────────────────────────────────────────────────────
Expand Down Expand Up @@ -890,22 +902,22 @@ phpvm_ext() {
}

# ==============================================================================
# COMPOSER (one composer.phar per active PHP version)
# COMPOSER (one global composer that follows the active PHP version)
# ==============================================================================
phpvm_composer() {
local cur
cur=$(_phpvm_current_version)
[[ -z "$cur" ]] && { _err "No active PHP version. Run: phpvm use <version>"; return 1; }

local php_root="$PHPVM_VERSIONS/$cur"
local php_bin="$php_root/bin/php"
local php_bin="$PHPVM_VERSIONS/$cur/bin/php"
[[ ! -x "$php_bin" ]] && { _err "php binary not found: $php_bin"; return 1; }

local phar="$php_root/bin/composer.phar"
local shim="$php_root/bin/composer"
local phar="$PHPVM_DIR/composer.phar"
local shim="$PHPVM_BIN/composer"

if [[ -x "$shim" && -f "$phar" ]]; then
_warn "Composer already installed at $shim"
_dim "It follows your active PHP version automatically."
_dim "Run: composer --version"
return 0
fi
Expand Down Expand Up @@ -946,8 +958,8 @@ phpvm_composer() {
_ok "Hash verified."

_step "Installing Composer ..."
mkdir -p "$php_root/bin"
(cd "$php_root/bin" && "$php_bin" "$tmp" --quiet --filename=composer.phar) || {
mkdir -p "$PHPVM_BIN"
(cd "$PHPVM_DIR" && "$php_bin" "$tmp" --quiet --filename=composer.phar) || {
_err "Composer installer failed."
rm -f "$tmp"
return 1
Expand All @@ -956,21 +968,21 @@ phpvm_composer() {

[[ ! -f "$phar" ]] && { _err "composer.phar not created at $phar"; return 1; }

# POSIX shim — works in bash/zsh/sh.
# POSIX shim — execs the *current* PHP, so composer tracks `phpvm use`
# without reinstalling. Works in bash/zsh/sh.
cat > "$shim" <<EOF
#!/usr/bin/env sh
exec "$php_bin" "$phar" "\$@"
exec "$PHPVM_CURRENT/bin/php" "$phar" "\$@"
EOF
chmod +x "$shim"

_ok "Composer installed!"
_ok "Composer installed (global)!"
_ok " phar : $phar"
_ok " shim : $shim"
echo ""
"$php_bin" "$phar" --version 2>/dev/null | sed 's/^/ /'
echo ""
_dim "Note: composer is installed inside the PHP $cur bin dir."
_dim "After 'phpvm use <other>', re-run 'phpvm composer' for that version."
_dim "Composer follows your active PHP version — no need to re-run after 'phpvm use'."
}

# ==============================================================================
Expand Down Expand Up @@ -1280,9 +1292,12 @@ phpvm() {
# Tests / external sourcing can set PHPVM_NO_INIT=1 to skip the source-time
# side effects below (PATH manipulation + hook registration).
if [[ -z "${PHPVM_NO_INIT:-}" ]]; then
# Auto-activate current version if set (on shell load)
# Auto-activate current version if set (on shell load); otherwise still make
# sure the global shim dir is on PATH.
if [[ -L "$PHPVM_CURRENT" ]]; then
_phpvm_use_path
else
_phpvm_ensure_bin_path
fi

# Register .phpvmrc auto-switch hook if user opted in.
Expand Down
10 changes: 5 additions & 5 deletions tests/linux/commands.bats
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ PHPEOF
[[ "$output" == *"No active PHP version"* ]]
}

@test "composer: no-op when shim + phar already present" {
@test "composer: no-op when global shim + phar already present" {
_fake_php_install 8.3.0
local bin="$PHPVM_VERSIONS/8.3.0/bin"
touch "$bin/composer.phar"
cat > "$bin/composer" <<'EOF'
mkdir -p "$PHPVM_BIN"
touch "$PHPVM_DIR/composer.phar"
cat > "$PHPVM_BIN/composer" <<'EOF'
#!/usr/bin/env sh
EOF
chmod +x "$bin/composer"
chmod +x "$PHPVM_BIN/composer"
run phpvm_composer
[ "$status" -eq 0 ]
[[ "$output" == *"already installed"* ]]
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.8.0
1.8.1
2 changes: 1 addition & 1 deletion windows/install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$PHPVM_VERSION = "1.8.0"
$PHPVM_VERSION = "1.8.1"
$PHPVM_DIR = if ($env:PHPVM_DIR) { $env:PHPVM_DIR } else { "$env:USERPROFILE\.phpvm" }
$PHPVM_BIN = "$PHPVM_DIR\bin"

Expand Down
29 changes: 16 additions & 13 deletions windows/phpvm.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# -- Constants -----------------------------------------------------------------
$PHPVM_VERSION = "1.8.0"
$PHPVM_VERSION = "1.8.1"
$PHPVM_DIR = if ($env:PHPVM_DIR) { $env:PHPVM_DIR } else { "$env:USERPROFILE\.phpvm" }
$VERSIONS_DIR = "$PHPVM_DIR\versions"
$CURRENT_LINK = "$PHPVM_DIR\current"
Expand Down Expand Up @@ -1122,13 +1122,15 @@ function Invoke-Composer {
Write-Warn "openssl enabled. If Composer install fails, restart terminal first then re-run 'phpvm composer'."
}

# One composer per PHP version dir; switch versions -> re-run `phpvm composer`.
$phpRoot = Split-Path $info.Exe -Parent
$composerPhar = "$phpRoot\composer.phar"
$composerBat = "$phpRoot\composer.bat"
# One global composer that follows the active PHP version: the phar lives in
# $PHPVM_DIR and the shim sits in $PHPVM_BIN (already on PATH) and calls
# whatever `php` resolves to.
$composerPhar = "$PHPVM_DIR\composer.phar"
$composerBat = "$PHPVM_BIN\composer.bat"

if (Test-Path $composerBat) {
Write-Warn "Composer already installed at $composerBat"
Write-Dim "It follows your active PHP version automatically."
Write-Dim "Run: composer --version"
return
}
Expand Down Expand Up @@ -1157,8 +1159,9 @@ function Invoke-Composer {
Write-Ok "Hash verified."

Write-Step "Installing Composer ..."
Push-Location $phpRoot
& $info.Exe $installerFile --quiet
if (-not (Test-Path $PHPVM_BIN)) { New-Item -ItemType Directory -Path $PHPVM_BIN -Force | Out-Null }
Push-Location $PHPVM_DIR
& $info.Exe $installerFile --quiet --filename composer.phar
Pop-Location

if (-not (Test-Path $composerPhar)) {
Expand All @@ -1169,20 +1172,20 @@ function Invoke-Composer {

Remove-Item $installerFile -Force

# Shim so `composer` works from CMD + PowerShell without PATH gymnastics.
# Shim in $PHPVM_BIN (on PATH) calls `php` from PATH - i.e. the active
# version - so composer follows `phpvm use` without reinstalling.
$bat = @"
@echo off
php "%~dp0composer.phar" %*
php "$composerPhar" %*
"@
$bat | Set-Content $composerBat -Encoding ASCII
Write-Ok "Composer installed!"
Write-Ok "Composer installed (global)!"
Write-Ok " phar : $composerPhar"
Write-Ok " shim : $composerBat"
Write-Host ""
& $info.Exe "$phpRoot\composer.phar" --version | ForEach-Object { Write-Host " $_" }
& $info.Exe $composerPhar --version | ForEach-Object { Write-Host " $_" }
Write-Host ""
Write-Dim "Note: composer.bat is inside the PHP version folder."
Write-Dim "If you switch PHP version, run 'phpvm composer' again for that version."
Write-Dim "Composer follows your active PHP version - no need to re-run after 'phpvm use'."
}

function Show-Help {
Expand Down