Skip to content

🚀 智能安装器 SmartInstaller

在基础安装器之上叠加「进度回调 + 自动重试 + 上下文取消 + 安装后验证 + 系统诊断」——让安装过程可观测、可控制、可自愈。

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

核心类型

InstallProgress

单次进度事件,传给 ProgressCallback

go
type InstallProgress struct {
    Stage     InstallStage `json:"stage"`      // 当前阶段
    Message   string       `json:"message"`    // 进度消息
    Percent   int          `json:"percent"`    // 百分比 0-100
    Error     error        `json:"error,omitempty"` // 错误(如有)
    Timestamp time.Time    `json:"timestamp"`  // 时间戳
}

InstallStage

安装阶段枚举,贯穿整个流程。

go
type InstallStage string

const (
    StageCheckingPHP     InstallStage = "checking_php"
    StageInstallingPHP   InstallStage = "installing_php"
    StageDetectingDistro InstallStage = "detecting_distro"
    StagePackageManager  InstallStage = "package_manager"
    StageDownloading     InstallStage = "downloading"
    StageInstalling      InstallStage = "installing"
    StageVerifying       InstallStage = "verifying"
    StageConfiguring     InstallStage = "configuring"
    StageCompleted       InstallStage = "completed"
    StageFailed          InstallStage = "failed"
)

ProgressCallback

进度回调函数类型,安装各阶段变化时被调用。

go
type ProgressCallback func(progress InstallProgress)

InstallOptions

SmartInstaller 的完整入参。

go
type InstallOptions struct {
    Config            Config           // 安装器配置(为空时回退 SmartConfig)
    MaxRetries        int              // 最大重试次数
    RetryDelay        time.Duration    // 重试间隔
    ProgressCallback  ProgressCallback // 进度回调
    Context           context.Context  // 上下文,用于取消
    SkipVerification  bool             // 是否跳过安装后验证
    OnPHPInstalled    func()           // PHP 安装完成后的回调
}

InstallResult

安装结果,无论成功失败都会返回。

go
type InstallResult struct {
    Success      bool                       `json:"success"`
    ComposerPath string                     `json:"composer_path,omitempty"`
    Version      string                     `json:"version,omitempty"`
    PHPVersion   string                     `json:"php_version,omitempty"`
    Method       string                     `json:"method,omitempty"` // package_manager / homebrew / direct_download / already_installed
    Duration     time.Duration              `json:"duration,omitempty"`
    Error        error                      `json:"error,omitempty"`
    Stages       map[InstallStage]time.Duration `json:"stages,omitempty"` // 各阶段耗时
}

SmartInstaller

智能安装器主体。

go
type SmartInstaller struct {
    options InstallOptions
    mu      sync.Mutex
}

func NewSmartInstaller(options InstallOptions) *SmartInstaller

NewSmartInstaller 会对空缺字段做合理补全:

字段为空时补全为
Config.InstallPath整个 Config 回退到 SmartConfig()
MaxRetries <= 03
RetryDelay <= 05 * time.Second
Context == nilcontext.Background()

安装阶段流程

InstallWithProgress 把安装拆成若干阶段,每个阶段通过 ProgressCallback 上报百分比:

阶段1: checking_php (5%)
  └─ 无 PHP 且 AutoInstallPHP=true → installing_php (10%)
       └─ DetectLinuxDistro + InstallPHP + 再次 HasPHP 验证
       └─ 成功后触发 OnPHPInstalled 回调
  └─ 无 PHP 且 AutoInstallPHP=false → 报错 StageFailed 返回
  └─ 记录 PHPVersion,记录 checking_php 阶段耗时

阶段2: 循环重试安装 Composer(最多 MaxRetries 次)
  每次尝试:
    ├─ detecting_distro (20% + attempt*5%)  检测系统环境
    └─ doInstall(attempt):
         ├─ package_manager (30%)  PreferPackageManager=true 时试包管理器
         ├─ package_manager (40%)  PreferBrewOnMac=true 时试 Homebrew
         ├─ downloading (50%)      下载 Composer 安装程序
         └─ installing (70%)       执行安装
    成功 → 记录 Method,跳出循环
    失败 → StageFailed (0%),等待 RetryDelay 后重试(Context 取消则中止)

阶段3: verifying (90%)  SkipVerification=false 时
  └─ findComposerBinary 找到 composer → 记录 ComposerPath
  └─ CheckComposerVersion → 记录 Version
  └─ 记录 verifying 阶段耗时

完成: completed (100%)
  └─ Success=true,记录总 Duration,返回 InstallResult

阶段百分比的含义

百分比是「进度可视化」的提示值,不是严格的工程进度。重试时百分比会随 attempt 递增(20 + attempt*5),失败重试阶段会回到 0。

方法签名

DefaultInstallOptions

返回默认安装选项(SmartConfig + 3 次重试 + 5s 间隔 + context.Background)。

go
func DefaultInstallOptions() InstallOptions

NewSmartInstaller

创建智能安装器,补全空缺字段。

go
func NewSmartInstaller(options InstallOptions) *SmartInstaller

InstallWithProgress

执行带进度报告的智能安装。

go
func (si *SmartInstaller) InstallWithProgress() (*InstallResult, error)

返回值:*InstallResult 始终非 nil(含 Success/Error/Stages 等诊断信息),error 为发生的错误(成功时为 nil)。InstallResult.Error 与返回的 error 在失败时一致。

EnsureComposerInstalled

便捷方法:已装则直接返回,未装则智能安装。

go
func EnsureComposerInstalled(options *InstallOptions) (*InstallResult, error)
  • 已安装:Method="already_installed",填充 ComposerPath/Version/PHPVersion,不执行任何安装动作。
  • 未安装:options 为 nil 时用 DefaultInstallOptions(),否则用传入的 options,调 NewSmartInstaller(opts).InstallWithProgress()

IsComposerInstalled

检查 Composer 是否已安装,一步拿到路径与版本。

go
func IsComposerInstalled() (bool, string, string)

返回:(是否已安装, 安装路径, 版本号)。未安装时路径与版本为空字符串。

GetSystemInfo

收集系统信息用于诊断安装问题。

go
func GetSystemInfo() map[string]string

返回的 map 包含键:

说明
php_availabletrue/false
php_versionPHP 版本(可用时)
composer_availabletrue/false
composer_pathComposer 路径(可用时)
composer_versionComposer 版本(可用时)
distro_id / distro_name / distro_version / package_managerLinux 发行版信息(仅 Linux)
brew_availabletrue/false
curl_availabletrue/false

快速示例

带进度条的安装

go
package main

import (
    "fmt"
    "log"

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

func main() {
    opts := installer.DefaultInstallOptions()
    opts.ProgressCallback = func(p installer.InstallProgress) {
        fmt.Printf("[%s] %s (%d%%)\n", p.Stage, p.Message, p.Percent)
        if p.Error != nil {
            fmt.Printf("  ⚠️ 错误: %v\n", p.Error)
        }
    }

    si := installer.NewSmartInstaller(opts)
    result, err := si.InstallWithProgress()
    if err != nil {
        log.Fatalf("安装失败: %v", err)
    }
    fmt.Printf("✅ Composer %s 安装成功,路径: %s,耗时: %v\n",
        result.Version, result.ComposerPath, result.Duration)
}

可取消的安装

go
package main

import (
    "context"
    "log"
    "time"

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

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    defer cancel()

    opts := installer.DefaultInstallOptions()
    opts.Context = ctx

    si := installer.NewSmartInstaller(opts)
    result, err := si.InstallWithProgress()
    if err != nil {
        log.Fatalf("安装失败或取消: %v", err)
    }
    _ = result
}

一行确保已安装

go
result, err := installer.EnsureComposerInstalled(nil)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Composer 路径:", result.ComposerPath, "方法:", result.Method)

诊断系统环境

go
info := installer.GetSystemInfo()
for k, v := range info {
    fmt.Printf("%s = %s\n", k, v)
}

进阶

  • Method 字段语义package_manager(Linux 包管理器装)、homebrew(macOS brew 装)、direct_download(直接下载 setup.php)、already_installedEnsureComposerInstalled 发现已装)。
  • Stages 耗时InstallResult.Stages 记录 checking_phpverifying 两阶段的 time.Duration,可用于性能分析。其他阶段未单独计时。
  • PHP 安装回调OnPHPInstalled 在 PHP 自动安装成功、通过 HasPHP 验证后立即触发,适合用来记录日志或通知用户「PHP 已就绪,开始装 Composer」。
  • SkipVerification:设为 true 跳过阶段 3,InstallResult.ComposerPathVersion 将为空——只在确信安装一定成功且不需要版本信息时使用。
  • 与 Composer 集成pkg/composerEnsureInstalledWithProgress(callback)QuickSetupWithProgress 内部即调用本包的 EnsureComposerInstalled / SmartInstaller,把安装进度透传给上层。

基于 MIT 许可证发布