🛠️ Core Runtime
This page covers the "foundation" of pkg/composer — how to create a Composer instance, how to execute arbitrary subcommands, and how to detect and upgrade composer itself. These methods are defined in composer.go and version.go, and are the underlying dependencies for all other methods (Install, RequirePackage, etc.).
🧱 Core Types
Composer Struct
type Composer struct {
executablePath string // composer executable path
workingDir string // working directory
autoInstall bool // whether to auto-install when not found
installer *installer.Installer
detector *detector.Detector
env []string // environment variables (KEY=VALUE format)
defaultTimeout time.Duration
}Composer is a struct, not an interface; all methods are attached to *Composer. You typically don't construct it directly, but create it via New.
Options Struct
type Options struct {
ExecutablePath string // explicitly specify composer path
WorkingDir string // working directory
AutoInstall bool // whether to auto-install when not found
Installer *installer.Installer
Detector *detector.Detector
Env []string
DefaultTimeout time.Duration
}🛠️ New
Create a new Composer instance. If ExecutablePath is not specified, it first detects composer in the system via detector.Detect(); if not found and AutoInstall=true, it automatically installs and re-detects.
Signature
func New(options Options) (*Composer, error)Parameters
| Parameter | Type | Description |
|---|---|---|
options | Options | Options to customize the Composer instance |
Return Values
| Type | Description |
|---|---|
*Composer | The created Composer instance |
error | Returns ErrComposerNotFound or ErrComposerInstallation on failure |
Example
package main
import (
"log"
"time"
"github.com/scagogogo/composer-skills/pkg/composer"
)
func main() {
options := composer.DefaultOptions()
options.WorkingDir = "/path/to/project"
options.DefaultTimeout = 30 * time.Minute
comp, err := composer.New(options)
if err != nil {
log.Fatalf("Failed to initialize Composer: %v", err)
}
_ = comp
}Advanced
- When
ExecutablePathis explicitly specified,Newvalidates the file exists withos.Stat(skipped in test mode). - To completely skip auto-install, set
AutoInstalltofalse; detection failure then directly returnsErrComposerNotFound. - For a one-step solution (detect + install + create instance), use
composer.QuickSetup(workingDir, true).
⚙️ DefaultOptions
Returns Options with default configuration, the most common construction entry point.
Signature
func DefaultOptions() OptionsReturn Values
| Type | Description |
|---|---|
Options | Default config: WorkingDir="", AutoInstall=true, DefaultTimeout=10*time.Minute |
Example
options := composer.DefaultOptions()
comp, err := composer.New(options)Why not just Options{}
Constructing Options{} directly leaves AutoInstall=false and DefaultTimeout=0 (i.e., no timeout), which is error-prone. Always use DefaultOptions() as a starting point and override as needed.
📁 SetWorkingDir
Set the working directory for composer commands. All subsequent commands will execute in this directory.
Signature
func (c *Composer) SetWorkingDir(dir string)Parameters
| Parameter | Type | Description |
|---|---|---|
dir | string | Working directory path to set |
Example
comp.SetWorkingDir("/path/to/php/project")
// All subsequent comp.Install() / comp.Run(...) execute in that directoryAdvanced
- The corresponding getter is
GetWorkingDir() string. - To execute a single command in another directory, use
InstallWithWorkingDir(workingDir, noDev, optimize)(see Dependencies), which restores the original working directory after execution.
🌐 SetEnv
Set environment variables for executing composer commands, commonly used to configure HTTP proxies, COMPOSER_HOME, or authentication information.
Signature
func (c *Composer) SetEnv(env []string)Parameters
| Parameter | Type | Description |
|---|---|---|
env | []string | Environment variable array, format ["KEY=VALUE", ...] |
Example
comp.SetEnv([]string{
"HTTP_PROXY=http://proxy.example.com:8080",
"HTTPS_PROXY=http://proxy.example.com:8080",
"COMPOSER_HOME=/custom/composer/home",
})Advanced
- The corresponding getter is
GetEnv() []string. SetEnvis a full replacement, not append. To inherit the current process environment, concatenate withos.Environ()before passing.- For finer-grained environment variable operations (like
COMPOSER_PROCESS_TIMEOUT), see the Environment module (SetProcessTimeout,DisableInteraction, etc.).
▶️ Run
Execute any composer subcommand and return the output; this is the core method of the SDK. Uses a 10-minute timeout by default.
Signature
func (c *Composer) Run(args ...string) (string, error)Parameters
| Parameter | Type | Description |
|---|---|---|
args | ...string | Command arguments; first argument is the composer subcommand (e.g., "install", "require") |
Return Values
| Type | Description |
|---|---|
string | Combined command output (stdout+stderr) |
error | On failure, returns error wrapping ErrCommandExecution |
Example
// Execute "composer show"
output, err := comp.Run("show")
if err != nil {
log.Fatalf("Command execution failed: %v", err)
}
fmt.Println(output)
// Execute command with arguments
output, err = comp.Run("require", "symfony/console", "--dev")Advanced
Runinternally callsRunWithTimeout(c.defaultTimeout, args...).- In test mode,
RunWithContextfirst checksmockCommandOutput; if hit, it returns directly without actually executing composer. - Use
RunWithTimeoutfor timeout control,RunWithContextfor cancellation capability.
⏱️ RunWithTimeout
Execute composer command within a specified timeout, suitable for potentially long-running commands.
Signature
func (c *Composer) RunWithTimeout(timeout time.Duration, args ...string) (string, error)Parameters
| Parameter | Type | Description |
|---|---|---|
timeout | time.Duration | Maximum timeout for command execution |
args | ...string | Command arguments |
Return Values
| Type | Description |
|---|---|
string | Combined command output |
error | Error on failure or timeout |
Example
// Execute a potentially long installation command with 30-minute timeout
output, err := comp.RunWithTimeout(30*time.Minute, "install")
if err != nil {
log.Fatalf("Install timed out or failed: %v", err)
}Advanced
- Implementation-wise,
RunWithTimeoutcreates acontext.WithTimeoutand delegates toRunWithContext. - The returned
erroron timeout can be checked witherrors.Is(err, context.DeadlineExceeded).
🧩 RunWithContext
Execute composer command within a specified context.Context, providing maximum control — supports timeout, cancellation, and deadlines.
Signature
func (c *Composer) RunWithContext(ctx context.Context, args ...string) (string, error)Parameters
| Parameter | Type | Description |
|---|---|---|
ctx | context.Context | Context, can be used for cancellation or timeout |
args | ...string | Command arguments |
Return Values
| Type | Description |
|---|---|
string | Combined command output |
error | On failure, returns error wrapping ErrCommandExecution |
Example
// Create a context that can be manually cancelled
ctx, cancel := context.WithCancel(context.Background())
// Cancel based on conditions in another goroutine
go func() {
time.Sleep(5 * time.Second)
cancel()
}()
// Execute command
output, err := comp.RunWithContext(ctx, "update")
if err != nil {
if errors.Is(err, context.Canceled) {
fmt.Println("Command cancelled")
} else {
log.Fatalf("Command execution failed: %v", err)
}
}Advanced
RunWithContextis the underlying implementation ofRunandRunWithTimeout, and also the entry point for mock injection: it first callsgetMockOutput(args...), returning mock output if hit.- The command is constructed via
exec.CommandContext(ctx, c.executablePath, args...); whenctxis cancelled, a termination signal is sent to the subprocess. - Working directory and environment variables are injected here:
cmd.Dir = c.workingDir,cmd.Env = c.env.
🔍 GetExecutablePath
Returns the composer executable path used by the current instance.
Signature
func (c *Composer) GetExecutablePath() stringReturn Values
| Type | Description |
|---|---|
string | Full path to the composer executable; empty string if not set |
Example
execPath := comp.GetExecutablePath()
fmt.Printf("Composer executable in use: %s\n", execPath)✅ IsInstalled
Checks whether the current instance points to a valid composer executable path. Only checks if the path is non-empty; does not actually run composer to verify.
Signature
func (c *Composer) IsInstalled() boolReturn Values
| Type | Description |
|---|---|
bool | Returns true if path is non-empty, otherwise false |
Example
if comp.IsInstalled() {
fmt.Println("Composer is installed")
} else {
fmt.Println("Composer is not installed")
}Note
IsInstalled only checks executablePath != "". To confirm composer actually runs, call GetVersion() or GetVersionInfo() for a more reliable check.
🚀 SelfUpdate
Update composer itself to the latest version, equivalent to composer self-update.
Signature
func (c *Composer) SelfUpdate() errorReturn Values
| Type | Description |
|---|---|
error | On failure, returns error wrapping ErrSelfUpdateFailed |
Example
err := comp.SelfUpdate()
if err != nil {
log.Fatalf("Failed to update Composer: %v", err)
}
fmt.Println("Composer updated to latest version")Advanced
- To get a progress callback during update, use
SelfUpdateWithProgress()(inauto_install.go), which returns(string, error)where the string is the new version number. - Before updating, you can use
GetVersion()to record the old version, then compare after. SelfUpdaterequires write permission to the composer executable, often requiringsudo(see Environment module forEnableSuperuser).
📊 Related Helper Methods
In addition to the core methods above, composer.go provides several query methods:
| Method | Signature | Description |
|---|---|---|
GetWorkingDir | func (c *Composer) GetWorkingDir() string | Get current working directory |
GetEnv | func (c *Composer) GetEnv() []string | Get current environment variables |
And package-level test helper functions (generally not used in production code):
| Function | Signature | Description |
|---|---|---|
SetupMockOutput | func SetupMockOutput(command, output string, err error) | Set mock output for a specific command |
ClearMockOutputs | func ClearMockOutputs() | Clear all mock outputs |
🧭 Next Steps
After mastering the core runtime, learn:
- 📦 Dependencies — The full
Install/Update/DumpAutoloadfamily - 🔍 Packages —
RequirePackage/Remove/Show/Search - 📊 Version —
GetVersion/GetVersionInfostructured version