deps

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 19, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

internal/deps/builder.go

internal/deps/dockerfile.go

internal/deps/install.go

internal/deps/registry.go

Package deps provides dependency management for moat containers.

internal/deps/script.go

Index

Constants

This section is empty.

Variables

View Source
var MoatInitScript string

Functions

func AllSpecs

func AllSpecs() map[string]DepSpec

AllSpecs returns a copy of the registry map.

func GenerateInstallScript

func GenerateInstallScript(deps []Dependency) (string, error)

GenerateInstallScript creates a bash install script for the given dependencies. The script is designed for Apple containers where Docker's layer caching is not available. Commands are idempotent and safe to re-run.

func ImageTag

func ImageTag(deps []Dependency, opts *ImageSpec) string

ImageTag generates a deterministic image tag for a set of dependencies.

func List

func List() []string

List returns all available dependency names sorted alphabetically.

func SetVersionCache

func SetVersionCache(c *versions.Cache)

SetVersionCache allows tests to inject a custom cache.

func Validate

func Validate(deps []Dependency) error

Validate checks that all dependency requirements are satisfied and versions are valid.

Types

type DepSpec

type DepSpec struct {
	Description string      `yaml:"description,omitempty"`
	Type        InstallType `yaml:"type"`
	Default     string      `yaml:"default,omitempty"`
	Versions    []string    `yaml:"versions,omitempty"`
	Requires    []string    `yaml:"requires,omitempty"`

	// For github-binary type
	Repo  string `yaml:"repo,omitempty"`
	Asset string `yaml:"asset,omitempty"` // Supports {version}, {arch}, {target} placeholders
	Bin   string `yaml:"bin,omitempty"`   // Supports {version}, {arch}, {target} placeholders

	// Targets maps Go architecture names to project-specific target strings.
	// Used for {target} placeholder substitution in Asset/Bin fields.
	// Example: {"amd64": "x86_64-unknown-linux-musl", "arm64": "aarch64-unknown-linux-gnu"}
	// If empty and {arch} is used, standard arch name mapping is applied.
	Targets map[string]string `yaml:"targets,omitempty"`

	// TagPrefix is the prefix used for release tags. Defaults to "v" if empty.
	// Set to "none" for repos that don't use a prefix (e.g., ripgrep uses "14.1.1" not "v14.1.1").
	// Set to a custom value for repos with non-standard prefixes (e.g., "bun-v" for bun).
	TagPrefix string `yaml:"tag-prefix,omitempty"`

	// Command is the name of the installed command if different from the dependency name.
	// For example, ripgrep installs as "rg", not "ripgrep".
	Command string `yaml:"command,omitempty"`

	// Legacy ARM64 support (deprecated, use Targets instead)
	AssetARM64 string `yaml:"asset-arm64,omitempty"`
	BinARM64   string `yaml:"bin-arm64,omitempty"`

	// For apt type
	Package string `yaml:"package,omitempty"`

	// For go-install type
	GoPackage string `yaml:"go-package,omitempty"`

	// For service type
	Service *ServiceDef `yaml:"service,omitempty"`

	// Env specifies environment variables to set after installing this dependency.
	// These are emitted as Dockerfile ENV instructions, making them available
	// to all subsequent build steps and at runtime.
	//
	// Note: currently only honored for github-binary type dependencies.
	Env map[string]string `yaml:"env,omitempty"`

	// UserInstall indicates the dependency should be installed as the container
	// user (moatuser) instead of root. This is needed for tools whose installers
	// write to $HOME (e.g., claude-code's native installer).
	UserInstall bool `yaml:"user-install,omitempty"`
}

DepSpec defines a dependency in the registry.

func GetSpec

func GetSpec(name string) (DepSpec, bool)

GetSpec returns the DepSpec for a dependency name, or ok=false if not found.

type Dependency

type Dependency struct {
	Name            string      // e.g., "node", "eslint"
	Version         string      // e.g., "20" or "" for default
	OriginalVersion string      // Pre-resolution version (e.g., "3.11" before resolving to "3.11.15")
	Type            InstallType // Set for dynamic deps (npm:, pip:, etc.)
	Package         string      // For dynamic deps: the package name/path
	DockerMode      DockerMode  // For docker deps: "host" or "dind"
}

Dependency represents a parsed dependency from moat.yaml.

func FilterInstallable

func FilterInstallable(deps []Dependency) []Dependency

FilterInstallable returns dependencies excluding services.

func FilterServices

func FilterServices(deps []Dependency) []Dependency

FilterServices returns only service-type dependencies.

func Parse

func Parse(s string) (Dependency, error)

Parse parses a dependency string like "node", "node@20", or "npm:eslint". For docker dependencies, supports "docker", "docker:host", or "docker:dind".

func ParseAll

func ParseAll(specs []string) ([]Dependency, error)

ParseAll parses multiple dependency strings and validates them. Meta dependencies are expanded into their constituent dependencies. Dynamic dependencies (npm:, pip:, etc.) are handled directly.

func ResolveVersions

func ResolveVersions(ctx context.Context, deps []Dependency) ([]Dependency, error)

ResolveVersions resolves partial version specifications to full versions for runtime dependencies (go, node, python). This uses a cache to avoid repeated API calls - resolved versions are cached for 24 hours.

For non-runtime dependencies or those without version resolvers, the original version is preserved unchanged.

Example: "go@1.22" might resolve to "go@1.22.12"

func (Dependency) ImplicitRequires

func (d Dependency) ImplicitRequires() []string

ImplicitRequires returns dependencies that are implicitly required. For example, npm:eslint requires node.

func (Dependency) IsDynamic

func (d Dependency) IsDynamic() bool

IsDynamic returns true if this dependency was parsed from a prefixed spec.

type DockerMode

type DockerMode string

DockerMode defines how Docker is provided to the container.

const (
	// DockerModeHost mounts the host Docker socket (fast but full host access).
	DockerModeHost DockerMode = "host"
	// DockerModeDind runs an isolated Docker daemon inside the container (privileged but isolated).
	DockerModeDind DockerMode = "dind"
)

type DockerfileResult

type DockerfileResult struct {
	// Dockerfile is the generated Dockerfile content.
	Dockerfile string

	// ContextFiles maps relative file paths to their contents.
	// These files should be written to the build context directory
	// alongside the Dockerfile (e.g., "moat-init.sh" → script content).
	ContextFiles map[string][]byte
}

DockerfileResult contains the generated Dockerfile and any additional context files that should be placed alongside the Dockerfile in the build context directory.

func GenerateDockerfile

func GenerateDockerfile(deps []Dependency, opts *ImageSpec) (*DockerfileResult, error)

GenerateDockerfile creates a Dockerfile for the given dependencies.

type HooksConfig

type HooksConfig struct {
	PostBuild     string
	PostBuildRoot string
	PreRun        string
}

HooksConfig holds hook commands for Dockerfile generation and image tagging. This mirrors config.HooksConfig to avoid circular imports.

type ImageSpec added in v0.4.0

type ImageSpec struct {
	// NeedsSSH indicates SSH grants are present and the image needs
	// openssh-client, socat, and the moat-init entrypoint for agent forwarding.
	NeedsSSH bool

	// SSHHosts lists the hosts for which SSH access is granted (e.g., "github.com").
	// Known host keys will be added to /etc/ssh/ssh_known_hosts for these hosts.
	// Used only by Dockerfile generation.
	SSHHosts []string

	// InitProviders lists agent provider names (e.g., "claude", "codex", "gemini")
	// that need configuration files staged at container startup. Each entry
	// triggers the moat-init entrypoint and contributes to the image tag hash.
	InitProviders []string

	// NeedsFirewall indicates that iptables is needed for strict network
	// policy enforcement.
	NeedsFirewall bool

	// NeedsGitIdentity indicates the host's git identity should be injected
	// into the container. Used only by Dockerfile generation.
	NeedsGitIdentity bool

	// NeedsInitFiles indicates that providers have init files to write at
	// container startup.
	NeedsInitFiles bool

	// NeedsClipboard indicates the image needs Xvfb and xclip for host
	// clipboard bridging. Adds xvfb and xclip apt packages, and starts
	// Xvfb :99 in the moat-init entrypoint.
	NeedsClipboard bool

	// UseBuildKit enables BuildKit-specific features like cache mounts.
	// Used only by Dockerfile generation. Defaults to false if nil.
	UseBuildKit *bool

	// ClaudeMarketplaces are plugin marketplaces to register during image build.
	// Used only by Dockerfile generation.
	ClaudeMarketplaces []claude.MarketplaceConfig

	// ClaudePlugins are plugins to install during image build.
	// Format: "plugin-name@marketplace-name"
	ClaudePlugins []string

	// Hooks contains user-defined lifecycle hook commands.
	Hooks *HooksConfig
}

ImageSpec captures all options needed for image resolution, tag generation, and Dockerfile generation. A single ImageSpec is constructed once and passed through the entire image pipeline.

func (*ImageSpec) NeedsCustomImage added in v0.4.0

func (s *ImageSpec) NeedsCustomImage(hasDeps bool) bool

NeedsCustomImage reports whether any option requires building a custom image.

type InstallCommands

type InstallCommands struct {
	Commands []string          // Shell commands to run
	EnvVars  map[string]string // Environment variables to set
}

InstallCommands holds the commands needed to install a dependency.

func (InstallCommands) FormatForDockerfile

func (ic InstallCommands) FormatForDockerfile() string

FormatForDockerfile formats install commands as Dockerfile RUN instructions.

func (InstallCommands) FormatForScript

func (ic InstallCommands) FormatForScript() string

FormatForScript formats install commands as shell script lines.

type InstallType

type InstallType string

InstallType defines how a dependency is installed.

const (
	// Registry-based types (defined in registry.yaml)
	TypeRuntime      InstallType = "runtime"
	TypeGithubBinary InstallType = "github-binary"
	TypeApt          InstallType = "apt"
	TypeNpm          InstallType = "npm"
	TypeGoInstall    InstallType = "go-install"
	TypeCustom       InstallType = "custom"
	TypeMeta         InstallType = "meta"
	TypeUvTool       InstallType = "uv-tool" // Tools installed via uv tool install
	TypeDocker       InstallType = "docker"  // Docker access via socket mounting or DinD
	TypeService      InstallType = "service" // Service dependencies (databases, caches)

	// Dynamic types (parsed from prefixes like npm:eslint)
	TypeDynamicNpm   InstallType = "dynamic-npm"   // npm:package
	TypeDynamicPip   InstallType = "dynamic-pip"   // pip:package
	TypeDynamicUv    InstallType = "dynamic-uv"    // uv:package
	TypeDynamicCargo InstallType = "dynamic-cargo" // cargo:package
	TypeDynamicGo    InstallType = "dynamic-go"    // go:package
)

func (InstallType) IsDynamic

func (t InstallType) IsDynamic() bool

IsDynamic returns true if this is a dynamic (prefixed) dependency type.

func (InstallType) String

func (t InstallType) String() string

String returns the string representation of an InstallType.

type ServiceDef

type ServiceDef struct {
	Image        string            `yaml:"image"`
	Ports        map[string]int    `yaml:"ports"`
	EnvPrefix    string            `yaml:"env_prefix"`
	DefaultUser  string            `yaml:"default_user,omitempty"`
	DefaultDB    string            `yaml:"default_db,omitempty"`
	PasswordEnv  string            `yaml:"password_env,omitempty"`
	ExtraEnv     map[string]string `yaml:"extra_env,omitempty"`
	ExtraCmd     []string          `yaml:"extra_cmd,omitempty"`
	DBEnv        string            `yaml:"db_env,omitempty"`
	ReadinessCmd string            `yaml:"readiness_cmd"`
	URLScheme    string            `yaml:"url_scheme"`
	URLFormat    string            `yaml:"url_format"`

	// CachePath is the container-side path to mount for host-side caching.
	// If set, ~/.moat/cache/<service-name>/ is bind-mounted here.
	// This allows data to persist across runs (e.g., downloaded models).
	CachePath string `yaml:"cache_path,omitempty"`

	// ProvisionsKey names the key in user's services.<name> config that contains
	// a list of items to provision (e.g., "models"). Used with ProvisionCmd.
	ProvisionsKey string `yaml:"provisions_key,omitempty"`

	// ProvisionCmd is a command template executed once per provision item.
	// The placeholder {item} is replaced with each item value.
	// Commands run via sh -c inside the service container after readiness.
	ProvisionCmd string `yaml:"provision_cmd,omitempty"`
}

ServiceDef holds metadata for service-type dependencies (databases, caches). Parsed from the `service:` block in registry.yaml entries.

Directories

Path Synopsis
Package versions provides version resolution for runtime dependencies.
Package versions provides version resolution for runtime dependencies.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL