🚀 智能安装器 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) *SmartInstallerNewSmartInstaller 会对空缺字段做合理补全:
| 字段 | 为空时补全为 |
|---|---|
Config.InstallPath | 整个 Config 回退到 SmartConfig() |
MaxRetries <= 0 | 3 |
RetryDelay <= 0 | 5 * time.Second |
Context == nil | context.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() InstallOptionsNewSmartInstaller
创建智能安装器,补全空缺字段。
go
func NewSmartInstaller(options InstallOptions) *SmartInstallerInstallWithProgress
执行带进度报告的智能安装。
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_available | true/false |
php_version | PHP 版本(可用时) |
composer_available | true/false |
composer_path | Composer 路径(可用时) |
composer_version | Composer 版本(可用时) |
distro_id / distro_name / distro_version / package_manager | Linux 发行版信息(仅 Linux) |
brew_available | true/false |
curl_available | true/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_installed(EnsureComposerInstalled发现已装)。 - Stages 耗时:
InstallResult.Stages记录checking_php与verifying两阶段的time.Duration,可用于性能分析。其他阶段未单独计时。 - PHP 安装回调:
OnPHPInstalled在 PHP 自动安装成功、通过HasPHP验证后立即触发,适合用来记录日志或通知用户「PHP 已就绪,开始装 Composer」。 - SkipVerification:设为
true跳过阶段 3,InstallResult.ComposerPath与Version将为空——只在确信安装一定成功且不需要版本信息时使用。 - 与 Composer 集成:
pkg/composer的EnsureInstalledWithProgress(callback)与QuickSetupWithProgress内部即调用本包的EnsureComposerInstalled/SmartInstaller,把安装进度透传给上层。