🚀 cli_advanced — Advanced Features
This example demonstrates the advanced capabilities of the Composer CLI: Satis private repository building, binary command execution, version-constraint operations, environment diagnostics, project archiving, and runtime environment-variable tuning.
🎯 Example Positioning
cli_advanced is the capstone example (the final CLI example) of the Composer CLI Local Operations series. It wraps up the advanced scenarios not covered by earlier examples in one place, touching on the corner-case capabilities you'd only meet in real engineering.
- 📚 What you'll learn: drive Satis private-repo initialization and building with the SDK; invoke in-project binaries; read and write version constraints; run
diagnose/check/statushealth checks; archive projects and individual packages; and tune runtime environment variables like memory, timeout, and vendor/bin directories. - 🔗 Corresponding SDK methods:
InitSatis/CreateSatisConfig/BuildSatis,Exec/ExecPHP/ExecWithList,LockPackageVersion/UpdatePackageVersion/FormatVersionConstraint,Diagnose/Check/Status/GetEnvironmentInfo/GetProjectInfo,Archive/ArchivePackage,SetMemoryLimit/SetProcessTimeoutand other package-level environment functions. - 💡 Differences:
cli_basic_usagefocuses on "getting the first command to run," andcli_package_managementfocuses on "CRUD for packages." This example focuses on five themes: building a private ecosystem (Satis), driving toolchains (Exec), constraints and health checks (Version/Diagnosis), artifact distribution (Archive), and runtime tuning (Environment).
💻 Full Code
📁 Source file:
examples/cli_advanced/01_satis_exec_version_diagnosis.go, split into 6 example functions by topic — comments are terse but the logic is complete.
package cli_advanced
import (
"fmt"
"log"
"github.com/scagogogo/composer-skills/pkg/composer"
)
// Example01Satis demonstrates Satis private-repo initialization, configuration, and building
func Example01Satis() {
c, _ := composer.New(composer.DefaultOptions())
c.InitSatis("my-packages", "https://packages.example.com", "/path/to/satis")
c.CreateSatisConfig("/path/to/satis/satis.json", "my-packages", "https://packages.example.com")
c.AddSatisRepository("/path/to/satis/satis.json", "vcs", "https://github.com/myorg/myrepo")
c.AddSatisRequire("/path/to/satis/satis.json", "myorg/mypackage", "*")
output, _ := c.BuildSatis("/path/to/satis/satis.json", "/path/to/satis/web")
c.EnableSatisArchive("/path/to/satis/satis.json", "zip")
c.UpdateSatisStability("/path/to/satis/satis.json", "stable")
}
// Example02Exec demonstrates executing project binaries and arbitrary commands
func Example02Exec() {
c, _ := composer.New(composer.DefaultOptions())
c.SetWorkingDir("/path/to/project")
c.Exec("phpunit", "--version") // Binary under vendor/bin
c.ExecCommand("php", "-v") // Arbitrary system command
c.ExecPHP("/usr/bin/php8.1", "phpunit", "--version") // Specify a PHP interpreter
binaries, _ := c.ExecWithList() // List executables
c.ExecWithWorkingDir("phpunit", "/path/to/project", "--version")
}
// Example03VersionConstraints demonstrates version-constraint query, locking, and formatting
func Example03VersionConstraints() {
c, _ := composer.New(composer.DefaultOptions())
c.SetWorkingDir("/path/to/project")
c.GetPackageVersions("symfony/console")
c.LockPackageVersion("symfony/console", "v6.0.0")
c.UpdatePackageVersion("symfony/console", "^6.0", composer.CaretVersion)
constraint := composer.FormatVersionConstraint("1.2.3", composer.CaretVersion) // ^1.2.3
constraint = composer.FormatVersionConstraint("1.2.3", composer.TildeVersion) // ~1.2.3
}
// Example04Diagnosis demonstrates diagnostics, checks, and structured info retrieval
func Example04Diagnosis() {
c, _ := composer.New(composer.DefaultOptions())
c.SetWorkingDir("/path/to/project")
c.Diagnose() // composer diagnose — full health check
c.Check() // Platform dependency validation
c.Status() // Working-tree local-change status
envInfo, _ := c.GetEnvironmentInfo() // map[string]string
projectInfo, _ := c.GetProjectInfo() // Struct, includes Name/Description
}
// Example05Archive demonstrates project and single-package archiving
func Example05Archive() {
c, _ := composer.New(composer.DefaultOptions())
c.SetWorkingDir("/path/to/project")
c.Archive("./dist") // Whole-project archive
c.ArchiveWithFormat("./dist", "zip") // Specify format
c.ArchivePackage("symfony/console", "v6.0.0", "./dist") // Archive a specific package version
}
// Example06Environment demonstrates runtime environment tuning (package-level functions)
func Example06Environment() {
composer.SetMemoryLimit("2G") // COMPOSER_MEMORY_LIMIT
composer.SetProcessTimeout(600) // COMPOSER_PROCESS_TIMEOUT (seconds)
composer.SetVendorDir("vendor-custom")
composer.SetBinDir("bin-custom")
path, _ := composer.GetComposerPath()
composer.DisableInteraction() // Disable -n interaction in CI
composer.EnableInteraction()
}🧩 Code Walkthrough
🏗️ Satis Private Repository (Example01Satis)
- 🏠
InitSatiscreates the Satis workspace skeleton, the starting point for building a private Packagist mirror;CreateSatisConfiggenerates thesatis.jsonthat all subsequent configuration builds upon. - 🔗
AddSatisRepository(path, "vcs", url)mounts a Git source, andAddSatisRequire(path, pkg, "*")declares which packages to include; together they determine the mirror's contents. - 🏭
BuildSatis(configPath, webDir)materializes a static web directory;EnableSatisArchive(path, "zip")also produces zips;UpdateSatisStability(path, "stable")is equivalent to settingminimum-stability.
⚙️ Command Execution (Example02Exec)
- 🛠️
Exec("phpunit", ...)is equivalent tocomposer execand auto-discoversvendor/bin;ExecCommand("php", "-v")skips discovery and directly runs a system command. - 🐘
ExecPHP(phpPath, bin, args)drives a binary with an explicit PHP path, convenient for multi-version switching;ExecWithList()returns the executable list, suitable for toolchain self-checks. - 📂
ExecWithWorkingDir(bin, dir, args)temporarily switches directories without mutating instance state — good for one-off calls.
🔢 Version Constraints (Example03VersionConstraints)
- 🔎
GetPackageVersions(pkg)prints available versions, a prerequisite for deciding a constraint strategy;LockPackageVersionpins to an exact version for reproducible builds. - 📐
UpdatePackageVersion(pkg, "^6.0", CaretVersion)uses a semantic-constraint operator to modifyrequire;FormatVersionConstraintis a pure function that turns a bare version into^1.2.3/~1.2.3without touching the filesystem.
🩺 Diagnostics and Health Checks (Example04Diagnosis)
- 🩻
Diagnose()is a full health check (HTTP/Git/cache/permissions),Check()validates platform dependencies, andStatus()shows local changes — all return raw text. - 🧬
GetEnvironmentInfo()returns key-value environment info, andGetProjectInfo()returns a struct (you can readName/Descriptiondirectly), sparing you regex parsing.
📦 Archiving (Example05Archive)
- 🗜️
Archive("./dist")archives the whole project;ArchiveWithFormat("./dist", "zip")explicitly selects zip/tar;ArchivePackage(pkg, ver, dir)archives any package's specified version — useful for stocking an offline mirror.
🌡️ Runtime Environment (Example06Environment)
- 🧠
SetMemoryLimit("2G")avoids OOM on large dependency trees; ⏱️SetProcessTimeout(600)prevents Git fetches from being killed on slow networks. - 📁
SetVendorDir/SetBinDirchange the default install directories and must match theconfigsection of the project'scomposer.json; 🛰️GetComposerPath()lets scripts reuse the same Composer; 🔇DisableInteractioncorresponds to-nand is a must in CI.
▶️ How to Run
This example is organized as exported Example0X functions with no main. You can temporarily create a caller file to run it:
cd /home/cc11001100/github/scagogogo/composer-skills/examples/cli_advanced
cat > _run.go <<'EOF'
package cli_advanced
func main() { Example01Satis() }
EOF
go run 01_satis_exec_version_diagnosis.go _run.go⚠️ Requires PHP and Composer installed locally, otherwise an auto-install is triggered. The example paths (
/path/to/project, etc.) are placeholders — replace them with real paths before running; Satis operations also requiresatis/satisto be installed locally.
📚 SDK Methods Involved
📝 Additionally,
AddSatisRepository,AddSatisRequire,EnableSatisArchive,UpdateSatisStability,GetPackageVersions,ExecCommand,ExecWithWorkingDir,ArchiveWithFormat,SetVendorDir,SetBinDir,GetComposerPath,EnableInteraction, and other methods don't yet have standalone doc pages. You can refer to the implementation patterns of their documented siblings (e.g.create-satis-config,build-satis,exec,archive,set-memory-limit,disable-interaction).
🚀 Going Further
- 🔄 Satis CI pipeline: turn
Example01Satisinto a scheduled job — every night,git fetchthenBuildSatisandEnableSatisArchiveto produce zips, keeping a private mirror that's always up to date. - 🧰 Toolchain self-check: after
ExecWithListlists binaries, runExec(bin, "--version")on each as a CI pre-flight readiness self-check script. - 🩺 Health report: combine
Diagnose+GetEnvironmentInfointo a Markdown report, post it to a PR comment or Slack, making environmental health visible. - 📦 Offline delivery:
Archivethe whole project +ArchivePackagekey dependencies into an offline-deployable artifact package, paired withSetVendorDirto match the target machine's layout. - 🌡️ Tuning matrix: in CI, sweep combinations of
SetMemoryLimit(512M/2G/-1) andSetProcessTimeout(120/600) to find the optimal config for parsing large dependency trees, then freeze it into the project'sconfigsection.