Skip to content

🐧 Distro Detection & PHP

Identify Linux distribution, match package manager, install PHP as needed, install and uninstall Composer by version — all low-level capabilities in the installer package related to "Linux environment" and "PHP runtime" are here.

Package path: github.com/scagogogo/composer-skills/pkg/installer

DistroInfo

Linux distribution information.

go
type DistroInfo struct {
    ID            string // Distro identifier: ubuntu / centos / arch / alpine ...
    Name          string // Human-readable name: Ubuntu / CentOS ...
    Version       string // Version number: 22.04 / 9 ...
    PackageManager string // Package manager: apt / yum / dnf / pacman / apk / zypper / emerge
}

DetectLinuxDistro

Detect current Linux distribution.

go
func DetectLinuxDistro() (*DistroInfo, error)

Returns not running on Linux error on non-Linux systems. Detection falls back in the following priority order:

OrderDetection MethodDescription
1️⃣parseOSRelease()Read /etc/os-release (modern standard), parse ID/NAME/VERSION_ID
2️⃣detectViaLSBRelease()Execute lsb_release -a, parse Distributor ID/Release
3️⃣detectViaKnownFiles()Check distro-specific files (/etc/redhat-release, /etc/debian_version, /etc/arch-release, /etc/alpine-release, /etc/SuSE-release, /etc/gentoo-release)
4️⃣detectViaAvailablePkgManager()Probe which of apt-get/dnf/yum/pacman/apk/zypper/emerge is available, return *-like identifier

Last level fallback returns &DistroInfo{ID: "unknown", Name: "Unknown Linux", PackageManager: "unknown"}, never returns nil.

Distro → Package Manager Mapping

determinePkgManager(distroID) maps distro ID to package manager:

Distro IDPackage Manager
ubuntu/debian/linuxmint/pop/elementary/kubuntu/xubuntu/linuxliteapt
fedoradnf
centos/rhel/redhat/oracle/amzn/almalinux/rockydnf (if available) otherwise yum
arch/manjaro/endeavouros/garudapacman
alpineapk
opensuse/opensuse-leap/opensuse-tumbleweed/sleszypper
gentooemerge
voidxbps
soluseopkg
Otherunknown

InstallComposerViaPackageManager

Install Composer using system-native package manager.

go
func InstallComposerViaPackageManager(distro *DistroInfo, useSudo bool) (bool, error)
ParameterTypeDescription
distro*DistroInfoDistro info, nil or PackageManager=="unknown" returns (false, nil)
useSudoboolWhether to prefix package manager command with sudo

Returns (attempted bool, err error):

  • attempted=true means matched package manager found and command executed (regardless of success or failure).
  • attempted=false means no matching package manager (no error, caller should fallback to other methods).

Commands executed per package manager:

Package ManagerCommand
aptapt-get install -y composer
dnfdnf install -y composer
yumyum install -y composer
pacmanpacman -S --noconfirm composer
apkapk add composer
zypperzypper -n in composer

HasPHP

Check if PHP is available on the system.

go
func HasPHP() bool

First exec.LookPath("php"), on failure checks common paths /usr/bin/php, /usr/local/bin/php, /opt/homebrew/bin/php (macOS Homebrew), returns true if any exists.

GetPHPVersion

Get PHP version string.

go
func GetPHPVersion() (string, error)

Executes php -r "echo PHP_VERSION;", returns trimmed version number. On failure returns failed to get PHP version wrapped error.

InstallPHP

Install PHP and common extensions via system package manager.

go
func InstallPHP(distro *DistroInfo, useSudo bool) error

Returns cannot install PHP: unknown package manager when distro is nil or `PackageManager=="unknown". Packages installed per package manager:

Package ManagerPackages Installed
aptphp php-cli php-mbstring php-xml php-curl
dnfphp php-cli php-mbstring php-xml php-curl
yumphp php-cli php-mbstring php-xml php-curl
pacmanphp
apkphp81 php81-cli php81-mbstring php81-xml php81-curl
zypperphp7 php7-cli

apk installs php81

Alpine PHP package names carry version numbers (e.g., php81), InstallPHP hardcodes to php81. If Alpine source has a different default version, manual adjustment may be needed.

CheckComposerVersion

Execute composer --version and return output.

go
func CheckComposerVersion(composerPath string) (string, error)

Returns raw --version output (e.g., Composer version 2.7.1 ...), no parsing. On failure returns failed to check composer version wrapped error.

InstallComposerVersion

Install specified Composer version (direct curl fetch phar + generate wrapper script).

go
func InstallComposerVersion(version string, installPath string, useSudo bool) error
ParameterTypeDescription
versionstringVersion alias or specific version number
installPathstringInstallation directory, phar lands at <installPath>/composer.phar
useSudoboolWhether to use sudo for file writing and chmod

version to download URL mapping:

versionDownload URL
1 / 1.xhttps://getcomposer.org/composer-1.phar
2 / 2.x / latest / ""https://getcomposer.org/composer.phar
previewhttps://getcomposer.org/composer-preview.phar
stablehttps://getcomposer.org/composer.phar
Other (e.g., 2.5.1)https://getcomposer.org/download/<version>/composer.phar

Process:

  1. curl -fsSL -o <installPath>/composer.phar <url> download phar.
  2. createComposerWrapper generates executable wrapper: on Windows writes composer.bat (@php "<phar>" %*); on other systems writes composer (#!/bin/sh\nphp "<phar>" "$@") and chmod +x (with sudo chmod if useSudo).

UninstallComposer

Delete Composer executable and composer.phar in same directory.

go
func UninstallComposer(composerPath string, useSudo bool) error

Deletes two files:

  • composerPath itself.
  • composerPath with trailing /composer removed + /composer.phar appended (i.e., phar in same directory).

useSudo=true uses sudo rm -f, otherwise os.Remove. Skips without error if file doesn't exist.

Quick Examples

Detect Distro and Print

go
package main

import (
    "fmt"
    "log"

    "github.com/scagogogo/composer-skills/pkg/installer"
)

func main() {
    info, err := installer.DetectLinuxDistro()
    if err != nil {
        log.Fatalf("Not Linux or detection failed: %v", err)
    }
    fmt.Printf("Distro: %s %s (%s)\nPackage manager: %s\n",
        info.Name, info.Version, info.ID, info.PackageManager)
}

Auto-install PHP When Missing

go
if !installer.HasPHP() {
    distro, _ := installer.DetectLinuxDistro()
    if err := installer.InstallPHP(distro, true); err != nil {
        log.Fatal(err)
    }
}
fmt.Println("PHP version:", must(installer.GetPHPVersion()))

Install Specific Composer Version

go
// Install Composer 2.5.1 to /usr/local/bin, using sudo
err := installer.InstallComposerVersion("2.5.1", "/usr/local/bin", true)
if err != nil {
    log.Fatal(err)
}

Install Composer via Package Manager

go
distro, _ := installer.DetectLinuxDistro()
attempted, err := installer.InstallComposerViaPackageManager(distro, true)
if !attempted {
    log.Println("No available package manager, fallback to direct download")
} else if err != nil {
    log.Printf("Package manager install failed: %v\n", err)
}

Uninstall

go
if err := installer.UninstallComposer("/usr/local/bin/composer", true); err != nil {
    log.Fatal(err)
}

Advanced

  • Why DetectLinuxDistro never returns nil: Worst case returns unknown, letting caller check PackageManager == "unknown" for "unrecognized", avoiding nil dereference. InstallComposerViaPackageManager and InstallPHP both handle this unknown case.
  • PHP version retrieval reliability: GetPHPVersion depends on php in PATH; extreme case where HasPHP() returns true but GetPHPVersion fails (e.g., broken php), caller should handle error.
  • CheckComposerVersion doesn't parse: It returns raw --version output string; for structured version numbers, parse at caller side, or use pkg/composer's GetVersion/GetVersionInfo.
  • InstallComposerVersion's curl dependency: This function uses curl to download, requires curl installed on system. GetSystemInfo checks curl_available for diagnostics.
  • Relationship with SmartInstaller: SmartInstaller.doInstall on Linux first calls InstallComposerViaPackageManager, on failure fallback to installer.Install() (internally includes InstallComposerVersion path), forming "package manager → Homebrew → direct download" three-level fallback.

Released under the MIT License