Skip to content

🚀 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/status health 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/SetProcessTimeout and other package-level environment functions.
  • 💡 Differences: cli_basic_usage focuses on "getting the first command to run," and cli_package_management focuses 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.

go
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)

  • 🏠 InitSatis creates the Satis workspace skeleton, the starting point for building a private Packagist mirror; CreateSatisConfig generates the satis.json that all subsequent configuration builds upon.
  • 🔗 AddSatisRepository(path, "vcs", url) mounts a Git source, and AddSatisRequire(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 setting minimum-stability.

⚙️ Command Execution (Example02Exec)

  • 🛠️ Exec("phpunit", ...) is equivalent to composer exec and auto-discovers vendor/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; LockPackageVersion pins to an exact version for reproducible builds.
  • 📐 UpdatePackageVersion(pkg, "^6.0", CaretVersion) uses a semantic-constraint operator to modify require; FormatVersionConstraint is a pure function that turns a bare version into ^1.2.3 / ~1.2.3 without touching the filesystem.

🩺 Diagnostics and Health Checks (Example04Diagnosis)

  • 🩻 Diagnose() is a full health check (HTTP/Git/cache/permissions), Check() validates platform dependencies, and Status() shows local changes — all return raw text.
  • 🧬 GetEnvironmentInfo() returns key-value environment info, and GetProjectInfo() returns a struct (you can read Name/Description directly), 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/SetBinDir change the default install directories and must match the config section of the project's composer.json; 🛰️ GetComposerPath() lets scripts reuse the same Composer; 🔇 DisableInteraction corresponds to -n and 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:

bash
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 require satis/satis to be installed locally.

📚 SDK Methods Involved

Method NamePackageDoc Link
InitSatispkg/composer/sdk/composer/methods/init-satis
CreateSatisConfigpkg/composer/sdk/composer/methods/create-satis-config
BuildSatispkg/composer/sdk/composer/methods/build-satis
Execpkg/composer/sdk/composer/methods/exec
ExecPHPpkg/composer/sdk/composer/methods/exec-php
ExecWithListpkg/composer/sdk/composer/methods/exec-with-list
LockPackageVersionpkg/composer/sdk/composer/methods/lock-package-version
UpdatePackageVersionpkg/composer/sdk/composer/methods/update-package-version
FormatVersionConstraintpkg/composer/sdk/composer/methods/format-version-constraint
Diagnosepkg/composer/sdk/composer/methods/diagnose
Checkpkg/composer/sdk/composer/methods/check
Statuspkg/composer/sdk/composer/methods/status
GetEnvironmentInfopkg/composer/sdk/composer/methods/get-environment-info
GetProjectInfopkg/composer/sdk/composer/methods/get-project-info
Archivepkg/composer/sdk/composer/methods/archive
ArchivePackagepkg/composer/sdk/composer/methods/archive-package
SetMemoryLimitpkg/composer/sdk/composer/methods/set-memory-limit
SetProcessTimeoutpkg/composer/sdk/composer/methods/set-process-timeout
DisableInteractionpkg/composer/sdk/composer/methods/disable-interaction
SetWorkingDirpkg/composer/sdk/composer/methods/set-working-dir
DefaultOptionspkg/composer/sdk/composer/methods/default-options

📝 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 Example01Satis into a scheduled job — every night, git fetch then BuildSatis and EnableSatisArchive to produce zips, keeping a private mirror that's always up to date.
  • 🧰 Toolchain self-check: after ExecWithList lists binaries, run Exec(bin, "--version") on each as a CI pre-flight readiness self-check script.
  • 🩺 Health report: combine Diagnose + GetEnvironmentInfo into a Markdown report, post it to a PR comment or Slack, making environmental health visible.
  • 📦 Offline delivery: Archive the whole project + ArchivePackage key dependencies into an offline-deployable artifact package, paired with SetVendorDir to match the target machine's layout.
  • 🌡️ Tuning matrix: in CI, sweep combinations of SetMemoryLimit (512M/2G/-1) and SetProcessTimeout (120/600) to find the optimal config for parsing large dependency trees, then freeze it into the project's config section.

Released under the MIT License