package appconfig import ( "strings" "github.com/chenasraf/sofmani/machine" "github.com/chenasraf/sofmani/platform" "github.com/chenasraf/sofmani/utils" "github.com/samber/lo" ) // SkipSummary controls whether an installer is excluded from the summary. // It can be a boolean (applies to both install and update) or a map with // "install" and "update" keys for granular control. type SkipSummary struct { Install bool Update bool } // UnmarshalYAML implements custom YAML unmarshaling for SkipSummary. func (s *SkipSummary) UnmarshalYAML(unmarshal func(any) error) error { // Try boolean first var boolVal bool if err := unmarshal(&boolVal); err == nil { s.Install = boolVal s.Update = boolVal return nil } // Try map var mapVal map[string]bool if err := unmarshal(&mapVal); err == nil { if v, ok := mapVal["install"]; ok { s.Install = v } if v, ok := mapVal["update"]; ok { s.Update = v } return nil } return nil } // InstallerData represents the configuration for a single installer. type InstallerData struct { // Category is a special field for visual organization. When set, this entry only displays // a bordered header and does not perform any installation. Category *string `json:"category" yaml:"category"` // Desc is an optional description shown below the category name in the bordered header. Desc *string `json:"desc" yaml:"desc"` // Enabled determines if the installer is enabled. Can be a boolean string ("true", "false") or a condition. Enabled *string `json:"enabled" yaml:"enabled"` // Name is the name of the installer. Name *string `json:"name" yaml:"name"` // Type is the type of the installer. Type InstallerType `json:"type" yaml:"type"` // Tags is a space-separated list of tags for the installer. Tags *string `json:"tags" yaml:"tags"` // Env is a map of environment variables to set for the installer. Env *map[string]string `json:"env" yaml:"env"` // PlatformEnv is a map of platform-specific environment variables to set for the installer. PlatformEnv *platform.PlatformMap[map[string]string] `json:"platform_env" yaml:"platform_env"` // Platforms is a list of platforms where this installer should run. Platforms *platform.Platforms `json:"platforms" yaml:"platforms"` // Machines is a list of machine IDs where this installer should run. Machines *machine.Machines `json:"machines" yaml:"machines"` // Steps is a list of sub-installers for group installers. Steps *[]InstallerData `json:"steps" yaml:"steps"` // Opts is a map of options specific to the installer type. Opts *map[string]any `json:"opts" yaml:"opts"` // BinName is the name of the binary to check for existence. BinName *string `json:"bin_name" yaml:"bin_name"` // CheckHasUpdate is a command to check if an update is available. CheckHasUpdate *string `json:"check_has_update" yaml:"check_has_update"` // CheckInstalled is a command to check if the software is installed. CheckInstalled *string `json:"check_installed" yaml:"check_installed"` // PostInstall is a command to run after installation. PostInstall *string `json:"post_install" yaml:"post_install"` // PreInstall is a command to run before installation. PreInstall *string `json:"pre_install" yaml:"pre_install"` // PostUpdate is a command to run after updating. PostUpdate *string `json:"post_update" yaml:"post_update"` // PreUpdate is a command to run before updating. PreUpdate *string `json:"pre_update" yaml:"pre_update"` // EnvShell is a platform-specific shell to use for running commands. EnvShell *platform.PlatformMap[string] `json:"env_shell" yaml:"env_shell"` // SkipSummary controls whether this installer is excluded from the summary. SkipSummary *SkipSummary `json:"skip_summary" yaml:"skip_summary"` // Verbose enables verbose output for the installer's native commands. Verbose *bool `json:"verbose" yaml:"verbose"` // Frequency is a prettified duration (e.g. "1d", "1w", "3m") that limits how often // the installer runs. After a successful install/update, the next run will be skipped // until the frequency period has elapsed. Frequency *string `json:"frequency" yaml:"frequency"` } // InstallerType represents the type of an installer. type InstallerType string // Constants for the different installer types. const ( InstallerTypeGroup InstallerType = "group" // InstallerTypeGroup represents a group of installers. InstallerTypeShell InstallerType = "shell" // InstallerTypeShell represents a shell command installer. InstallerTypeDocker InstallerType = "docker" // InstallerTypeDocker represents a Docker image installer. InstallerTypeBrew InstallerType = "brew" // InstallerTypeBrew represents a Homebrew package installer. InstallerTypeApt InstallerType = "apt" // InstallerTypeApt represents an APT package installer. InstallerTypeApk InstallerType = "apk" // InstallerTypeApk represents an APK package installer. InstallerTypeGit InstallerType = "git" // InstallerTypeGit represents a Git repository installer. InstallerTypeGitHubRelease InstallerType = "github-release" // InstallerTypeGitHubRelease represents a GitHub release installer. InstallerTypeRsync InstallerType = "rsync" // InstallerTypeRsync represents an rsync installer. InstallerTypeNpm InstallerType = "npm" // InstallerTypeNpm represents an npm package installer. InstallerTypePnpm InstallerType = "pnpm" // InstallerTypePnpm represents a pnpm package installer. InstallerTypeYarn InstallerType = "yarn" // InstallerTypeYarn represents a yarn package installer. InstallerTypePipx InstallerType = "pipx" // InstallerTypePipx represents a pipx package installer. InstallerTypeManifest InstallerType = "manifest" // InstallerTypeManifest represents a manifest file installer. InstallerTypePacman InstallerType = "pacman" // InstallerTypePacman represents a pacman package installer. InstallerTypeYay InstallerType = "yay" // InstallerTypeYay represents a yay (AUR helper) package installer. InstallerTypeCargo InstallerType = "cargo" // InstallerTypeCargo represents a Rust cargo package installer. ) // Environ returns the combined environment variables for the installer as a slice of strings. func (i *InstallerData) Environ() []string { return utils.EnvMapAsSlice(utils.CombineEnvMaps(i.Env, i.PlatformEnv.Resolve())) } // GetTagsList returns the list of tags for the installer. func (i *InstallerData) GetTagsList() []string { return lo.Map(strings.Split(*i.Tags, " "), func(tag string, i int) string { return strings.TrimSpace(tag) }) } // IsCategory returns true if this entry is a category header (not an actual installer). func (i *InstallerData) IsCategory() bool { return i.Category != nil && len(*i.Category) > 0 }