diff --git a/CHANGELOG.md b/CHANGELOG.md index 332c175..940597d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased] +### Added + +- **`latest-remote` keyword:** Install the newest available remote PHP version directly from package manager repos with `phpvm install latest-remote`. +- **`latest-available` alias:** Alias for `latest-remote`. + ## [v1.11.0](https://github.com/Thavarshan/phpvm/compare/v1.10.0...v1.11.0) - 2026-04-13 ### Added diff --git a/README.md b/README.md index b196eba..bed90d5 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ PHP 8.1.13 - Seamlessly switch between installed PHP versions. - **Run commands with a specific PHP version** without globally switching (`phpvm exec`, `phpvm run`). - **List available remote PHP versions** from your system package manager (`phpvm ls-remote`). +- **Install the latest available remote PHP version** with `phpvm install latest-remote`. - **Resolve version descriptors and aliases** to installed version numbers (`phpvm resolve`). - Auto-switch PHP versions based on project `.phpvmrc` (configurable depth via `PHPVM_PHPVMRC_MAX_DEPTH`). - Automatic directory-based switching via built-in cd hook (`PROMPT_COMMAND` for bash, `chpwd` for zsh). @@ -120,6 +121,7 @@ If the installation was successful, it should output the path to `phpvm`. | `phpvm auto` | Auto-switch based on `.phpvmrc` file | | `phpvm list` or `phpvm ls` | List all installed PHP versions | | `phpvm ls-remote [pattern]` | List available remote PHP versions | +| `phpvm install latest-remote` | Install the latest remote PHP version available | | `phpvm resolve ` | Resolve a version descriptor to an installed version | | `phpvm alias [name] [ver]` | Create, update, or list version aliases | | `phpvm unalias ` | Remove version alias | diff --git a/phpvm.sh b/phpvm.sh index 6799fb3..8fcdb57 100755 --- a/phpvm.sh +++ b/phpvm.sh @@ -11,7 +11,7 @@ # shellcheck disable=SC2155 # Allow declare and assign on same line for better readability -PHPVM_VERSION="1.11.0" +PHPVM_VERSION="1.12.0" # Test mode flag PHPVM_TEST_MODE="${PHPVM_TEST_MODE:-false}" @@ -1016,6 +1016,17 @@ phpvm_resolve_version() { fi fi + if [ "$input" = "latest-remote" ] || [ "$input" = "latest-available" ]; then + if resolved=$(phpvm_get_latest_remote_version); then + printf '%s\n' "$resolved" + return 0 + else + phpvm_err "No remote PHP versions found." + phpvm_warn "List available versions with: phpvm ls-remote" + return "$PHPVM_EXIT_NOT_FOUND" + fi + fi + # SECURITY: Only check alias file if input passes alias name validation # This prevents path traversal attacks like "../../../etc/passwd" if phpvm_validate_alias_name "$input" && [ -f "$PHPVM_DIR/alias/$input" ]; then @@ -1092,6 +1103,95 @@ phpvm_get_latest_installed_version() { return 1 } +# Get available remote PHP versions from package manager repositories +phpvm_get_remote_versions() { + local pattern="$1" + local remote_versions="" + + if phpvm_is_test_mode; then + remote_versions="7.4 +8.0 +8.1 +8.2 +8.3 +8.4" + else + case "$PKG_MANAGER" in + brew) + remote_versions=$( + brew formulae 2> /dev/null | command grep -E '^php(@[0-9]+\.[0-9]+)?$' | while IFS= read -r formula; do + if [ "$formula" = "php" ]; then + printf '%s\n' "$(brew_php_major_minor 2> /dev/null || printf '%s' 'latest')" + else + printf '%s\n' "${formula#php@}" + fi + done | command sort -t. -k1,1n -k2,2n + ) + ;; + apt) + remote_versions=$( + apt-cache search '^php[0-9]' 2> /dev/null | + command grep -oE 'php[0-9]+\.[0-9]+-cli' | + command sed 's/php//;s/-cli//' | + command sort -t. -k1,1n -k2,2n -u + ) + ;; + dnf) + remote_versions=$( + dnf module list php 2> /dev/null | + command grep -oE '[0-9]+\.[0-9]+' | + command sort -t. -k1,1n -k2,2n -u + ) + ;; + yum) + remote_versions=$( + yum list available 'php*-cli' 2> /dev/null | + command grep -oE 'php[0-9]+-php-cli' | + command sed 's/php//;s/-php-cli//' | + command sed 's/\([0-9]\)\([0-9]\)/\1.\2/' | + command sort -t. -k1,1n -k2,2n -u + ) + ;; + pacman) + remote_versions=$( + pacman -Ss '^php' 2> /dev/null | + command grep -oE 'php[0-9]*\s+[0-9]+\.[0-9]+' | + command grep -oE '[0-9]+\.[0-9]+' | + command sort -t. -k1,1n -k2,2n -u + ) + ;; + *) + return 1 + ;; + esac + fi + + if [ -n "$pattern" ] && [ -n "$remote_versions" ]; then + remote_versions=$(printf '%s\n' "$remote_versions" | command grep -F "$pattern" || true) + fi + + printf '%s\n' "$remote_versions" +} + +# Get latest available remote PHP version +phpvm_get_latest_remote_version() { + local remote_versions + local latest + + remote_versions=$(phpvm_get_remote_versions) || return 1 + if [ -z "$remote_versions" ]; then + return 1 + fi + + latest=$(printf '%s\n' "$remote_versions" | phpvm_latest_from_list) + if [ -n "$latest" ]; then + printf '%s\n' "$latest" + return 0 + fi + + return 1 +} + # Check if Remi repository is available/enabled for RHEL/Fedora systems check_remi_repository() { # Check if Remi repository is installed @@ -2530,6 +2630,8 @@ Usage: Version Arguments: X.Y or X.Y.Z Specific PHP version (e.g., 8.1 or 8.1.15) latest Latest installed version (not latest available) + latest-remote Latest remote version available via package manager + latest-available Alias for 'latest-remote' stable Alias for 'latest' (latest installed) system System default PHP Any user-defined alias (e.g., 'default', 'prod') @@ -2879,89 +2981,10 @@ phpvm_ls_remote() { local pattern="${1:-}" local remote_versions="" - # In test mode, return a hardcoded list for testing - if phpvm_is_test_mode; then - remote_versions="7.4 -8.0 -8.1 -8.2 -8.3 -8.4" - if [ -n "$pattern" ]; then - remote_versions=$(printf '%s\n' "$remote_versions" | command grep -F "$pattern") - fi - if [ -z "$remote_versions" ]; then - phpvm_warn "No PHP versions found matching '$pattern'." - return "$PHPVM_EXIT_NOT_FOUND" - fi - phpvm_echo "Available remote PHP versions:" - printf '%s\n' "$remote_versions" | while IFS= read -r v; do - printf ' %s\n' "$v" - done - return "$PHPVM_EXIT_SUCCESS" - fi - - phpvm_echo "Querying available PHP versions from $PKG_MANAGER..." - - case "$PKG_MANAGER" in - brew) - # List all php formulae from Homebrew - remote_versions=$( - brew formulae 2> /dev/null | command grep -E '^php(@[0-9]+\.[0-9]+)?$' | while IFS= read -r formula; do - if [ "$formula" = "php" ]; then - printf '%s\n' "$(brew_php_major_minor 2> /dev/null || printf '%s\n' 'latest')" - else - printf '%s\n' "${formula#php@}" - fi - done | command sort -t. -k1,1n -k2,2n - ) - ;; - apt) - # List PHP versions available from apt repositories - remote_versions=$( - apt-cache search '^php[0-9]' 2> /dev/null | - command grep -oE 'php[0-9]+\.[0-9]+-cli' | - command sed 's/php//;s/-cli//' | - command sort -t. -k1,1n -k2,2n -u - ) - ;; - dnf) - # List PHP module streams available via dnf - remote_versions=$( - dnf module list php 2> /dev/null | - command grep -oE '[0-9]+\.[0-9]+' | - command sort -t. -k1,1n -k2,2n -u - ) - ;; - yum) - # List Remi PHP packages available via yum - remote_versions=$( - yum list available 'php*-cli' 2> /dev/null | - command grep -oE 'php[0-9]+-php-cli' | - command sed 's/php//;s/-php-cli//' | - command sed 's/\([0-9]\)\([0-9]\)/\1.\2/' | - command sort -t. -k1,1n -k2,2n -u - ) - ;; - pacman) - # List PHP packages available via pacman - remote_versions=$( - pacman -Ss '^php' 2> /dev/null | - command grep -oE 'php[0-9]*\s+[0-9]+\.[0-9]+' | - command grep -oE '[0-9]+\.[0-9]+' | - command sort -t. -k1,1n -k2,2n -u - ) - ;; - *) + remote_versions=$(phpvm_get_remote_versions "$pattern") || { phpvm_err "ls-remote is not supported for package manager: $PKG_MANAGER" return "$PHPVM_EXIT_ERROR" - ;; - esac - - # Apply pattern filter if given - if [ -n "$pattern" ] && [ -n "$remote_versions" ]; then - remote_versions=$(printf '%s\n' "$remote_versions" | command grep -F "$pattern") - fi + } if [ -z "$remote_versions" ]; then if [ -n "$pattern" ]; then diff --git a/release-notes-1.12.0.md b/release-notes-1.12.0.md new file mode 100644 index 0000000..ce2f028 --- /dev/null +++ b/release-notes-1.12.0.md @@ -0,0 +1,17 @@ +# v1.12.0 Release Notes + +## Added + +- Add `latest-remote` keyword for `phpvm install`, allowing users to install the newest available PHP version from remote package manager repositories. +- Add `latest-available` alias for `latest-remote`. + +## Details + +- `phpvm install latest-remote` +- `phpvm install latest-available` + +## Notes + +- This feature works with existing package manager support for Homebrew, apt, dnf, yum, and pacman. +- It complements `phpvm ls-remote`, which lists available remote versions. +- In test mode, the remote version list is simulated for coverage. diff --git a/tests/02_features.bats b/tests/02_features.bats index dd4b323..2ec7219 100644 --- a/tests/02_features.bats +++ b/tests/02_features.bats @@ -49,6 +49,24 @@ load test_helper [[ ! "$output" =~ "7.4" ]] } +@test "phpvm install latest-remote installs newest available PHP version" { + run install_php "latest-remote" + [ "$status" -eq 0 ] + [[ "$output" =~ "Installing PHP 8.4" ]] + [[ "$output" =~ "PHP 8.4 installed." ]] + phpvm_test_php_installed "8.4" + [ "$?" -eq 0 ] +} + +@test "phpvm install latest-available also installs newest available remote PHP" { + run install_php "latest-available" + [ "$status" -eq 0 ] + [[ "$output" =~ "Installing PHP 8.4" ]] + [[ "$output" =~ "PHP 8.4 installed." ]] + phpvm_test_php_installed "8.4" + [ "$?" -eq 0 ] +} + # --- resolve command --- @test "phpvm resolve returns installed version" {