Files
sofmani/installer/apt_installer.go

172 lines
4.8 KiB
Go
Executable File

package installer
import (
"strings"
"github.com/chenasraf/sofmani/appconfig"
"github.com/chenasraf/sofmani/utils"
)
// AptInstaller is an installer for apt and apk packages.
type AptInstaller struct {
InstallerBase
// Config is the application configuration.
Config *appconfig.AppConfig
// Info is the installer data.
Info *appconfig.InstallerData
// PackageManager is the package manager to use (apt or apk).
PackageManager AptPackageManager
}
// AptOpts represents options for the AptInstaller.
type AptOpts struct {
// Flags is a string of additional flags to pass to the apt/apk command.
Flags *string
// InstallFlags is a string of additional flags to pass only during install.
InstallFlags *string
// UpdateFlags is a string of additional flags to pass only during update.
UpdateFlags *string
}
// AptPackageManager represents a package manager type.
type AptPackageManager string
// Constants for supported package managers.
const (
PackageManagerApk AptPackageManager = "apk" // PackageManagerApk represents the apk package manager.
PackageManagerApt AptPackageManager = "apt" // PackageManagerApt represents the apt package manager.
)
// Validate validates the installer configuration.
func (i *AptInstaller) Validate() []ValidationError {
errors := i.BaseValidate()
return errors
}
// Install implements IInstaller.
func (i *AptInstaller) Install() error {
name := *i.Info.Name
opts := i.GetOpts()
err := i.RunCmdPassThrough(string(i.PackageManager), "update")
if err != nil {
return err
}
install := "install"
if i.PackageManager == PackageManagerApk {
install = "add"
}
args := []string{install}
if confirm := i.getConfirmArg(); confirm != "" {
args = append(args, confirm)
}
if opts.InstallFlags != nil {
args = append(args, strings.Fields(*opts.InstallFlags)...)
} else if opts.Flags != nil {
args = append(args, strings.Fields(*opts.Flags)...)
}
args = append(args, name)
return i.RunCmdPassThrough(string(i.PackageManager), args...)
}
// getConfirmArg returns the appropriate confirmation argument for the package manager.
// For apt, it returns "-y". For apk, it returns an empty string.
func (i *AptInstaller) getConfirmArg() string {
confirm := "-y"
if i.PackageManager == PackageManagerApk {
confirm = ""
}
return confirm
}
// Update implements IInstaller.
func (i *AptInstaller) Update() error {
opts := i.GetOpts()
args := []string{"upgrade"}
if confirm := i.getConfirmArg(); confirm != "" {
args = append(args, confirm)
}
if opts.UpdateFlags != nil {
args = append(args, strings.Fields(*opts.UpdateFlags)...)
} else if opts.Flags != nil {
args = append(args, strings.Fields(*opts.Flags)...)
}
args = append(args, *i.Info.Name)
return i.RunCmdPassThrough(string(i.PackageManager), args...)
}
// CheckNeedsUpdate implements IInstaller.
func (i *AptInstaller) CheckNeedsUpdate() (bool, error) {
if i.HasCustomUpdateCheck() {
return i.RunCustomUpdateCheck()
}
err := i.RunCmdPassThrough(string(i.Data.Type), "update")
if err != nil {
return false, err
}
success, err := i.RunCmdGetSuccess(string(i.PackageManager), "--simulate", "upgrade", *i.Info.Name)
if err != nil {
return false, err
}
return !success, nil
}
// CheckIsInstalled implements IInstaller.
func (i *AptInstaller) CheckIsInstalled() (bool, error) {
if i.HasCustomInstallCheck() {
return i.RunCustomInstallCheck()
}
return i.RunCmdGetSuccess(utils.GetShellWhich(), i.GetBinName())
}
// GetData implements IInstaller.
func (i *AptInstaller) GetData() *appconfig.InstallerData {
return i.Info
}
// GetOpts returns the parsed options for the AptInstaller.
func (i *AptInstaller) GetOpts() *AptOpts {
opts := &AptOpts{}
info := i.Info
if info.Opts != nil {
if flags, ok := (*info.Opts)["flags"].(string); ok {
opts.Flags = &flags
}
if installFlags, ok := (*info.Opts)["install_flags"].(string); ok {
opts.InstallFlags = &installFlags
}
if updateFlags, ok := (*info.Opts)["update_flags"].(string); ok {
opts.UpdateFlags = &updateFlags
}
}
return opts
}
// GetBinName returns the binary name for the installer.
// It uses the BinName from the installer data if provided, otherwise it uses the installer name.
func (i *AptInstaller) GetBinName() string {
info := i.GetData()
if info.BinName != nil && len(*info.BinName) > 0 {
return *info.BinName
}
return *info.Name
}
// NewAptInstaller creates a new AptInstaller.
func NewAptInstaller(cfg *appconfig.AppConfig, installer *appconfig.InstallerData) *AptInstaller {
var packageManager AptPackageManager
switch installer.Type {
case appconfig.InstallerTypeApt:
packageManager = PackageManagerApt
case appconfig.InstallerTypeApk:
packageManager = PackageManagerApk
}
i := &AptInstaller{
InstallerBase: InstallerBase{Data: installer},
Config: cfg,
Info: installer,
PackageManager: packageManager,
}
return i
}