Skip to content

🐧 发行版检测与 PHP

识别 Linux 发行版、匹配包管理器、按需安装 PHP、按版本安装与卸载 Composer——installer 包里所有与「Linux 环境」和「PHP 运行时」相关的底层能力都在这里。

包路径:github.com/scagogogo/composer-skills/pkg/installer

DistroInfo

Linux 发行版信息。

go
type DistroInfo struct {
    ID            string // 发行版标识:ubuntu / centos / arch / alpine ...
    Name          string // 人类可读名:Ubuntu / CentOS ...
    Version       string // 版本号:22.04 / 9 ...
    PackageManager string // 包管理器:apt / yum / dnf / pacman / apk / zypper / emerge
}

DetectLinuxDistro

检测当前 Linux 发行版。

go
func DetectLinuxDistro() (*DistroInfo, error)

非 Linux 系统返回 not running on Linux 错误。检测按以下优先级逐级回退:

顺序检测方式说明
1️⃣parseOSRelease()/etc/os-release(现代标准),解析 ID/NAME/VERSION_ID
2️⃣detectViaLSBRelease()执行 lsb_release -a,解析 Distributor ID/Release
3️⃣detectViaKnownFiles()检查发行版专属文件(/etc/redhat-release/etc/debian_version/etc/arch-release/etc/alpine-release/etc/SuSE-release/etc/gentoo-release
4️⃣detectViaAvailablePkgManager()探测 apt-get/dnf/yum/pacman/apk/zypper/emerge 哪个可用,返回 *-like 标识

最后一级回退返回 &DistroInfo{ID: "unknown", Name: "Unknown Linux", PackageManager: "unknown"},不会返回 nil。

发行版 → 包管理器映射

determinePkgManager(distroID) 把发行版 ID 映射到包管理器:

发行版 ID包管理器
ubuntu/debian/linuxmint/pop/elementary/kubuntu/xubuntu/linuxliteapt
fedoradnf
centos/rhel/redhat/oracle/amzn/almalinux/rockydnf(若可用)否则 yum
arch/manjaro/endeavouros/garudapacman
alpineapk
opensuse/opensuse-leap/opensuse-tumbleweed/sleszypper
gentooemerge
voidxbps
soluseopkg
其他unknown

InstallComposerViaPackageManager

用系统原生包管理器安装 Composer。

go
func InstallComposerViaPackageManager(distro *DistroInfo, useSudo bool) (bool, error)
参数类型说明
distro*DistroInfo发行版信息,nilPackageManager=="unknown" 时返回 (false, nil)
useSudobool是否在包管理器命令前加 sudo

返回 (attempted bool, err error)

  • attempted=true 表示找到了匹配的包管理器并执行了命令(无论成功失败)。
  • attempted=false 表示没有匹配的包管理器(不报错,调用方应回退其他方式)。

各包管理器执行的命令:

包管理器命令
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

检查系统是否可用 PHP。

go
func HasPHP() bool

exec.LookPath("php"),失败再检查常见路径 /usr/bin/php/usr/local/bin/php/opt/homebrew/bin/php(macOS Homebrew),任一存在即返回 true

GetPHPVersion

获取 PHP 版本字符串。

go
func GetPHPVersion() (string, error)

执行 php -r "echo PHP_VERSION;",返回去除首尾空白后的版本号。失败返回 failed to get PHP version 包装错误。

InstallPHP

通过系统包管理器安装 PHP 及常用扩展。

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

distro 为 nil 或 PackageManager=="unknown" 时返回 cannot install PHP: unknown package manager。各包管理器安装的包:

包管理器安装的包
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 装 php81

Alpine 的 PHP 包名带版本号(如 php81),InstallPHP 硬编码为 php81。若 Alpine 源里默认是其他版本,可能需要手动调整。

CheckComposerVersion

执行 composer --version 并返回输出。

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

返回的是 --version 的原始输出(如 Composer version 2.7.1 ...),不做解析。失败返回 failed to check composer version 包装错误。

InstallComposerVersion

安装指定版本的 Composer(直接 curl 拉 phar + 生成包装脚本)。

go
func InstallComposerVersion(version string, installPath string, useSudo bool) error
参数类型说明
versionstring版本别名或具体版本号
installPathstring安装目录,phar 落到 <installPath>/composer.phar
useSudobool写文件与 chmod 是否用 sudo

version 到下载 URL 的映射:

version下载 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
其他(如 2.5.1https://getcomposer.org/download/<version>/composer.phar

流程:

  1. curl -fsSL -o <installPath>/composer.phar <url> 下载 phar。
  2. createComposerWrapper 生成可执行包装:Windows 上写 composer.bat@php "<phar>" %*);其他系统写 composer#!/bin/sh\nphp "<phar>" "$@")并 chmod +xuseSudo 时用 sudo chmod)。

UninstallComposer

删除 Composer 可执行文件及同目录下的 composer.phar

go
func UninstallComposer(composerPath string, useSudo bool) error

会删除两个文件:

  • composerPath 本身。
  • composerPath 去掉末尾 /composer 后拼接的 /composer.phar(即同目录下的 phar)。

useSudo=truesudo rm -f,否则 os.Remove。文件不存在时跳过不报错。

快速示例

检测发行版并打印

go
package main

import (
    "fmt"
    "log"

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

func main() {
    info, err := installer.DetectLinuxDistro()
    if err != nil {
        log.Fatalf("非 Linux 或检测失败: %v", err)
    }
    fmt.Printf("发行版: %s %s (%s)\n包管理器: %s\n",
        info.Name, info.Version, info.ID, info.PackageManager)
}

缺 PHP 时自动装

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

安装指定版本 Composer

go
// 装 Composer 2.5.1 到 /usr/local/bin,使用 sudo
err := installer.InstallComposerVersion("2.5.1", "/usr/local/bin", true)
if err != nil {
    log.Fatal(err)
}

通过包管理器装 Composer

go
distro, _ := installer.DetectLinuxDistro()
attempted, err := installer.InstallComposerViaPackageManager(distro, true)
if !attempted {
    log.Println("没有可用的包管理器,回退直接下载")
} else if err != nil {
    log.Printf("包管理器安装失败: %v\n", err)
}

卸载

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

进阶

  • 为什么 DetectLinuxDistro 不返回 nil:最坏情况下返回 unknown,让调用方可以用 PackageManager == "unknown" 判断「无法识别」,避免 nil 解引用。InstallComposerViaPackageManagerInstallPHP 都兼容这种 unknown 情况。
  • PHP 版本获取的可靠性GetPHPVersion 依赖 php 在 PATH 中;HasPHP() 返回 true 但 GetPHPVersion 失败的极端情况(如 php 损坏),调用方应处理错误。
  • CheckComposerVersion 不解析:它返回原始 --version 输出字符串;如需结构化版本号,应在调用方自行解析,或用 pkg/composerGetVersion/GetVersionInfo
  • InstallComposerVersion 的 curl 依赖:此函数用 curl 下载,需要系统装有 curl。GetSystemInfo 会检测 curl_available 用于诊断。
  • 与 SmartInstaller 的关系SmartInstaller.doInstall 在 Linux 上会先调 InstallComposerViaPackageManager,失败再回退 installer.Install()(内部含 InstallComposerVersion 路径),形成「包管理器 → Homebrew → 直接下载」三级回退。

基于 MIT 许可证发布