🚀 cli_basic_usage — Composer CLI 基本用法
本示例演示如何创建 Composer 实例,并通过 Run / RunWithContext 执行基础 Composer 命令,同时设置工作目录与环境变量、触发 Composer 自更新。
🎯 示例定位
cli_basic_usage 是 Composer CLI 本地操作 系列的第一个示例(示例总览第 8 个),是所有 cli_* 系列的起点。它把「拿到一个能跑的 Composer 客户端」这件事拆成最小可运行单元。
- 📚 你将学到:如何用
composer.DefaultOptions()+composer.New()完成客户端初始化,如何用Run执行任意命令、用RunWithContext加超时控制,以及如何通过SetWorkingDir/SetEnv调整执行环境,最后调用SelfUpdate升级 Composer 自身。 - 🔗 对应 SDK 方法:
composer.New、Composer.Run、Composer.RunWithContext、Composer.SetWorkingDir、Composer.SetEnv、Composer.SelfUpdate。 - 💡 与
basic_setup的区别:basic_setup面向 Packagist 远程 API 客户端;本例面向本地 Composer CLI 子进程,二者分属不同子系统,本例是后续cli_package_management、cli_project_management等所有 CLI 示例的前置基础。
💻 完整代码
go
package cli_basic_usage
import (
"context"
"fmt"
"log"
"time"
"github.com/scagogogo/composer-skills/pkg/composer"
)
// Example02RunCommands 演示如何运行基本的Composer命令
func Example02RunCommands() {
// 创建Composer实例
options := composer.DefaultOptions()
c, err := composer.New(options)
if err != nil {
log.Fatalf("无法创建Composer实例: %v", err)
}
// 示例1:使用Run方法执行简单命令
output, err := c.Run("--version")
if err != nil {
log.Fatalf("执行命令失败: %v", err)
}
fmt.Printf("Run方法输出: %s\n", output)
// 输出示例:Run方法输出: Composer version 2.5.7 2023-12-01 11:43:14
// 示例2:使用带超时的上下文执行命令
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
output, err = c.RunWithContext(ctx, "diagnose")
if err != nil {
log.Printf("执行带上下文的命令失败: %v", err)
} else {
fmt.Println("RunWithContext方法执行成功,输出省略...")
}
// 示例3:设置工作目录后执行命令
c.SetWorkingDir("/path/to/your/project")
fmt.Printf("已设置工作目录: %s\n", "/path/to/your/project")
// 示例4:设置环境变量后执行命令
c.SetEnv([]string{"COMPOSER_MEMORY_LIMIT=2G", "COMPOSER_NO_INTERACTION=1"})
fmt.Println("已设置环境变量: COMPOSER_MEMORY_LIMIT=2G, COMPOSER_NO_INTERACTION=1")
// 示例5: 执行更新自身命令
fmt.Println("执行 self-update 命令...")
err = c.SelfUpdate()
if err != nil {
log.Printf("更新Composer失败: %v", err)
} else {
fmt.Println("Composer自更新成功")
}
}🧩 代码讲解
- 🏗️ 初始化客户端:
composer.DefaultOptions()给出一组开箱即用的默认配置,再交给composer.New(options)构造*Composer实例。若本地未检测到 Composer,SDK 会触发自动安装,因此err必须检查。 - ⚡ 最简执行:
c.Run("--version")直接把参数透传给 Composer 子进程,返回合并后的标准输出字符串。这是跑任意「无副作用查询命令」最轻量的入口。 - ⏱️ 带超时的执行:
context.WithTimeout(..., 30*time.Second)派生可取消的 ctx,c.RunWithContext(ctx, "diagnose")在超时或取消时会杀掉子进程,避免diagnose这类耗时命令卡死调用方。defer cancel()释放上下文资源。 - 📁 切换工作目录:
c.SetWorkingDir("/path/to/your/project")让后续所有命令在该 PHP 项目根目录下执行(等价于composer --working-dir),是操作多项目时的关键开关。 - 🌍 注入环境变量:
c.SetEnv([]string{...})设置COMPOSER_MEMORY_LIMIT=2G(放宽内存限制)和COMPOSER_NO_INTERACTION=1(禁用交互式提问),保证命令在 CI / 守护进程中静默、稳定运行。 - 🔄 Composer 自更新:
c.SelfUpdate()封装了composer self-update,把本地 Composer 升级到最新稳定版。它可能因权限或网络失败,故用log.Printf记录而非log.Fatalf中断。 - 🛡️ 错误处理策略:查询型命令(
--version)失败用Fatalf快速暴露;副作用型命令(diagnose、self-update)失败用log.Printf容错继续,体现「初始化致命、运行期可恢复」的分层思路。
▶️ 运行方式
本示例以 Example 函数形式编写,需在示例目录下显式运行对应文件:
bash
cd /home/cc11001100/github/scagogogo/composer-skills/examples/cli_basic_usage
go run 02_run_commands.go⚠️ CLI 示例需要本地安装 PHP 和 Composer;若未安装,SDK 会尝试自动安装。
SelfUpdate会真实升级本地 Composer,建议在测试环境中运行。运行前请把SetWorkingDir的路径替换为你本机真实存在的 PHP 项目目录。
📚 涉及的 SDK 方法
| 方法名 | 所属包 | 作用 | 文档链接 |
|---|---|---|---|
New | pkg/composer | 根据选项构造 *Composer 客户端实例 | /sdk/composer/methods/quick-setup |
Run | pkg/composer | 透传参数执行 Composer 命令,返回输出字符串 | /sdk/composer/methods/run |
RunWithContext | pkg/composer | 同 Run,但接受 context.Context 支持超时/取消 | /sdk/composer/methods/run-with-context |
SetWorkingDir | pkg/composer | 设置后续命令的工作目录 | /sdk/composer/methods/set-working-dir |
SetEnv | pkg/composer | 设置子进程环境变量 | /sdk/composer/environment |
SelfUpdate | pkg/composer | 执行 composer self-update 升级 Composer | /sdk/composer/methods/self-update |
📝 说明:
SetEnv通过批量注入环境变量影响子进程,与单变量级别的SetEnvVariable同属环境配置体系,故链接指向 environment 总览页便于对照。
🚀 进阶
- ⏱️ 统一超时:把
RunWithContext的超时抽成常量,并对不同命令分级(查询 5s、安装 300s),结合run-with-timeout风格的便捷封装避免每次手写context.WithTimeout。 - 📋 结构化输出:
Run返回原始字符串,需要版本号、依赖树等结构化数据时改用GetVersionInfo、ShowDependencyTree等类型化方法,省去正则解析。 - 🧪 可测试性:将
*Composer通过接口注入业务代码,便于在单测里用 stub 替换Run,避免真实拉起子进程。 - 🔁 失败重试:对
SelfUpdate、diagnose等易因网络波动的命令包一层指数退避重试,并在重试耗尽后上报监控。 - 🗂️ 多项目编排:用
SetWorkingDir在多个项目间切换时,配合c.SetEnv注入项目级COMPOSER配置文件路径(COMPOSER=composer.prod.json),实现一套客户端驱动多套部署清单。 - 🔐 权限与隔离:在生产环境运行
SelfUpdate前,先GetVersionInfo比对当前版本与目标版本,必要时锁定到指定版本而非盲目升级到 latest,避免破坏性变更。