mirror of
https://github.com/chenasraf/sofmani.git
synced 2026-05-17 17:28:04 +00:00
feat: add install_flags and update_flags to various installers
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package installer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/chenasraf/sofmani/appconfig"
|
||||
"github.com/chenasraf/sofmani/utils"
|
||||
)
|
||||
@@ -18,7 +20,12 @@ type AptInstaller struct {
|
||||
|
||||
// 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.
|
||||
@@ -39,6 +46,7 @@ func (i *AptInstaller) Validate() []ValidationError {
|
||||
// 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
|
||||
@@ -47,7 +55,17 @@ func (i *AptInstaller) Install() error {
|
||||
if i.PackageManager == PackageManagerApk {
|
||||
install = "add"
|
||||
}
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), install, i.getConfirmArg(), name)
|
||||
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.
|
||||
@@ -62,7 +80,18 @@ func (i *AptInstaller) getConfirmArg() string {
|
||||
|
||||
// Update implements IInstaller.
|
||||
func (i *AptInstaller) Update() error {
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), "upgrade", i.getConfirmArg(), *i.Info.Name)
|
||||
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.
|
||||
@@ -96,7 +125,20 @@ func (i *AptInstaller) GetData() *appconfig.InstallerData {
|
||||
|
||||
// GetOpts returns the parsed options for the AptInstaller.
|
||||
func (i *AptInstaller) GetOpts() *AptOpts {
|
||||
return &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.
|
||||
|
||||
@@ -27,3 +27,88 @@ func TestAptValidation(t *testing.T) {
|
||||
)
|
||||
assertNoValidationErrors(t, aptInstaller.Validate())
|
||||
}
|
||||
|
||||
func TestAptGetOpts(t *testing.T) {
|
||||
logger.InitLogger(false)
|
||||
|
||||
// Test default opts (no options set)
|
||||
defaultData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeApt,
|
||||
}
|
||||
installer := newAptInstaller(defaultData)
|
||||
opts := installer.GetOpts()
|
||||
if opts.Flags != nil {
|
||||
t.Errorf("expected Flags to be nil")
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
t.Errorf("expected InstallFlags to be nil")
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
t.Errorf("expected UpdateFlags to be nil")
|
||||
}
|
||||
|
||||
// Test with flags option
|
||||
flagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeApt,
|
||||
Opts: &map[string]any{
|
||||
"flags": "-y --no-install-recommends",
|
||||
},
|
||||
}
|
||||
installerWithFlags := newAptInstaller(flagsData)
|
||||
optsWithFlags := installerWithFlags.GetOpts()
|
||||
if optsWithFlags.Flags == nil || *optsWithFlags.Flags != "-y --no-install-recommends" {
|
||||
t.Errorf("expected Flags to be '-y --no-install-recommends'")
|
||||
}
|
||||
|
||||
// Test with install_flags option
|
||||
installFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeApt,
|
||||
Opts: &map[string]any{
|
||||
"install_flags": "--no-install-recommends",
|
||||
},
|
||||
}
|
||||
installerWithInstallFlags := newAptInstaller(installFlagsData)
|
||||
optsWithInstallFlags := installerWithInstallFlags.GetOpts()
|
||||
if optsWithInstallFlags.InstallFlags == nil || *optsWithInstallFlags.InstallFlags != "--no-install-recommends" {
|
||||
t.Errorf("expected InstallFlags to be '--no-install-recommends'")
|
||||
}
|
||||
|
||||
// Test with update_flags option
|
||||
updateFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeApt,
|
||||
Opts: &map[string]any{
|
||||
"update_flags": "--only-upgrade",
|
||||
},
|
||||
}
|
||||
installerWithUpdateFlags := newAptInstaller(updateFlagsData)
|
||||
optsWithUpdateFlags := installerWithUpdateFlags.GetOpts()
|
||||
if optsWithUpdateFlags.UpdateFlags == nil || *optsWithUpdateFlags.UpdateFlags != "--only-upgrade" {
|
||||
t.Errorf("expected UpdateFlags to be '--only-upgrade'")
|
||||
}
|
||||
|
||||
// Test with all flags options combined
|
||||
allFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeApt,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--common",
|
||||
"install_flags": "--install-specific",
|
||||
"update_flags": "--update-specific",
|
||||
},
|
||||
}
|
||||
installerWithAllFlags := newAptInstaller(allFlagsData)
|
||||
optsWithAllFlags := installerWithAllFlags.GetOpts()
|
||||
if optsWithAllFlags.Flags == nil || *optsWithAllFlags.Flags != "--common" {
|
||||
t.Errorf("expected Flags to be '--common'")
|
||||
}
|
||||
if optsWithAllFlags.InstallFlags == nil || *optsWithAllFlags.InstallFlags != "--install-specific" {
|
||||
t.Errorf("expected InstallFlags to be '--install-specific'")
|
||||
}
|
||||
if optsWithAllFlags.UpdateFlags == nil || *optsWithAllFlags.UpdateFlags != "--update-specific" {
|
||||
t.Errorf("expected UpdateFlags to be '--update-specific'")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@ type BrewOpts struct {
|
||||
Tap *string
|
||||
// Cask installs the formula as a cask instead of a regular package.
|
||||
Cask *bool
|
||||
// Flags is a string of additional flags to pass to the brew 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
|
||||
}
|
||||
|
||||
// Validate validates the installer configuration.
|
||||
@@ -48,20 +54,32 @@ func (i *BrewInstaller) Validate() []ValidationError {
|
||||
// Install implements IInstaller.
|
||||
func (i *BrewInstaller) Install() error {
|
||||
name := i.GetFullName()
|
||||
opts := i.GetOpts()
|
||||
cmd := "brew install"
|
||||
if i.IsCask() {
|
||||
cmd += " --cask"
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
cmd += " " + *opts.InstallFlags
|
||||
} else if opts.Flags != nil {
|
||||
cmd += " " + *opts.Flags
|
||||
}
|
||||
return i.RunCmdAsFile(fmt.Sprintf("%s %s", cmd, name))
|
||||
}
|
||||
|
||||
// Update implements IInstaller.
|
||||
func (i *BrewInstaller) Update() error {
|
||||
name := i.GetFullName()
|
||||
opts := i.GetOpts()
|
||||
cmd := "brew upgrade"
|
||||
if i.IsCask() {
|
||||
cmd += " --cask"
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
cmd += " " + *opts.UpdateFlags
|
||||
} else if opts.Flags != nil {
|
||||
cmd += " " + *opts.Flags
|
||||
}
|
||||
return i.RunCmdAsFile(fmt.Sprintf("%s %s", cmd, name))
|
||||
}
|
||||
|
||||
@@ -189,6 +207,15 @@ func (i *BrewInstaller) GetOpts() *BrewOpts {
|
||||
if caskVal, ok := (*info.Opts)["cask"].(bool); ok {
|
||||
opts.Cask = &caskVal
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -79,6 +79,105 @@ func simulateBrewCheck(input string, exitCode int) (logs string, updateNeeded bo
|
||||
return logBuf.String(), needsUpdate, nil
|
||||
}
|
||||
|
||||
func TestBrewGetOpts(t *testing.T) {
|
||||
logger.InitLogger(false)
|
||||
|
||||
// Test default opts (no options set)
|
||||
defaultData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeBrew,
|
||||
}
|
||||
installer := newTestBrewInstaller(defaultData)
|
||||
opts := installer.GetOpts()
|
||||
if opts.Tap != nil {
|
||||
t.Errorf("expected Tap to be nil")
|
||||
}
|
||||
if opts.Cask != nil {
|
||||
t.Errorf("expected Cask to be nil")
|
||||
}
|
||||
if opts.Flags != nil {
|
||||
t.Errorf("expected Flags to be nil")
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
t.Errorf("expected InstallFlags to be nil")
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
t.Errorf("expected UpdateFlags to be nil")
|
||||
}
|
||||
|
||||
// Test with flags option
|
||||
flagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeBrew,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--verbose --debug",
|
||||
},
|
||||
}
|
||||
installerWithFlags := newTestBrewInstaller(flagsData)
|
||||
optsWithFlags := installerWithFlags.GetOpts()
|
||||
if optsWithFlags.Flags == nil || *optsWithFlags.Flags != "--verbose --debug" {
|
||||
t.Errorf("expected Flags to be '--verbose --debug'")
|
||||
}
|
||||
|
||||
// Test with install_flags option
|
||||
installFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeBrew,
|
||||
Opts: &map[string]any{
|
||||
"install_flags": "--force",
|
||||
},
|
||||
}
|
||||
installerWithInstallFlags := newTestBrewInstaller(installFlagsData)
|
||||
optsWithInstallFlags := installerWithInstallFlags.GetOpts()
|
||||
if optsWithInstallFlags.InstallFlags == nil || *optsWithInstallFlags.InstallFlags != "--force" {
|
||||
t.Errorf("expected InstallFlags to be '--force'")
|
||||
}
|
||||
|
||||
// Test with update_flags option
|
||||
updateFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeBrew,
|
||||
Opts: &map[string]any{
|
||||
"update_flags": "--dry-run",
|
||||
},
|
||||
}
|
||||
installerWithUpdateFlags := newTestBrewInstaller(updateFlagsData)
|
||||
optsWithUpdateFlags := installerWithUpdateFlags.GetOpts()
|
||||
if optsWithUpdateFlags.UpdateFlags == nil || *optsWithUpdateFlags.UpdateFlags != "--dry-run" {
|
||||
t.Errorf("expected UpdateFlags to be '--dry-run'")
|
||||
}
|
||||
|
||||
// Test with all flags options combined
|
||||
allFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypeBrew,
|
||||
Opts: &map[string]any{
|
||||
"tap": "homebrew/core",
|
||||
"cask": true,
|
||||
"flags": "--common",
|
||||
"install_flags": "--install-specific",
|
||||
"update_flags": "--update-specific",
|
||||
},
|
||||
}
|
||||
installerWithAllFlags := newTestBrewInstaller(allFlagsData)
|
||||
optsWithAllFlags := installerWithAllFlags.GetOpts()
|
||||
if optsWithAllFlags.Tap == nil || *optsWithAllFlags.Tap != "homebrew/core" {
|
||||
t.Errorf("expected Tap to be 'homebrew/core'")
|
||||
}
|
||||
if optsWithAllFlags.Cask == nil || !*optsWithAllFlags.Cask {
|
||||
t.Errorf("expected Cask to be true")
|
||||
}
|
||||
if optsWithAllFlags.Flags == nil || *optsWithAllFlags.Flags != "--common" {
|
||||
t.Errorf("expected Flags to be '--common'")
|
||||
}
|
||||
if optsWithAllFlags.InstallFlags == nil || *optsWithAllFlags.InstallFlags != "--install-specific" {
|
||||
t.Errorf("expected InstallFlags to be '--install-specific'")
|
||||
}
|
||||
if optsWithAllFlags.UpdateFlags == nil || *optsWithAllFlags.UpdateFlags != "--update-specific" {
|
||||
t.Errorf("expected UpdateFlags to be '--update-specific'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBrewNeedsUpdateWithExitCode(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
@@ -25,6 +25,12 @@ type GitOpts struct {
|
||||
Destination *string
|
||||
// Ref is the Git reference (branch, tag, or commit) to checkout.
|
||||
Ref *string
|
||||
// Flags is a string of additional flags to pass to git commands.
|
||||
Flags *string
|
||||
// InstallFlags is a string of additional flags to pass only to git clone.
|
||||
InstallFlags *string
|
||||
// UpdateFlags is a string of additional flags to pass only to git pull.
|
||||
UpdateFlags *string
|
||||
}
|
||||
|
||||
// Validate validates the installer configuration.
|
||||
@@ -43,20 +49,34 @@ func (i *GitInstaller) Validate() []ValidationError {
|
||||
|
||||
// Install implements IInstaller.
|
||||
func (i *GitInstaller) Install() error {
|
||||
args := []string{"clone", i.GetRepositoryUrl(), i.GetInstallDir()}
|
||||
opts := i.GetOpts()
|
||||
args := []string{"clone"}
|
||||
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, i.GetRepositoryUrl(), i.GetInstallDir())
|
||||
err := i.RunCmdPassThrough("git", args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i.GetOpts().Ref != nil {
|
||||
return i.RunCmdPassThrough("git", "-C", i.GetInstallDir(), "checkout", *i.GetOpts().Ref)
|
||||
if opts.Ref != nil {
|
||||
return i.RunCmdPassThrough("git", "-C", i.GetInstallDir(), "checkout", *opts.Ref)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update implements IInstaller.
|
||||
func (i *GitInstaller) Update() error {
|
||||
return i.RunCmdPassThrough("git", "-C", i.GetInstallDir(), "pull")
|
||||
opts := i.GetOpts()
|
||||
args := []string{"-C", i.GetInstallDir(), "pull"}
|
||||
if opts.UpdateFlags != nil {
|
||||
args = append(args, strings.Fields(*opts.UpdateFlags)...)
|
||||
} else if opts.Flags != nil {
|
||||
args = append(args, strings.Fields(*opts.Flags)...)
|
||||
}
|
||||
return i.RunCmdPassThrough("git", args...)
|
||||
}
|
||||
|
||||
// CheckNeedsUpdate implements IInstaller.
|
||||
@@ -103,6 +123,15 @@ func (i *GitInstaller) GetOpts() *GitOpts {
|
||||
if ref, ok := (*info.Opts)["ref"].(string); ok {
|
||||
opts.Ref = &ref
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -50,3 +50,108 @@ func TestGitValidation(t *testing.T) {
|
||||
}
|
||||
assertValidationError(t, newTestGitInstaller(missingDestData).Validate(), "destination")
|
||||
}
|
||||
|
||||
func TestGitGetOpts(t *testing.T) {
|
||||
logger.InitLogger(false)
|
||||
|
||||
// Test default opts (only destination set)
|
||||
defaultData := &appconfig.InstallerData{
|
||||
Name: strPtr("owner/repo"),
|
||||
Type: appconfig.InstallerTypeGit,
|
||||
Opts: &map[string]any{
|
||||
"destination": "/some/path",
|
||||
},
|
||||
}
|
||||
installer := newTestGitInstaller(defaultData)
|
||||
opts := installer.GetOpts()
|
||||
if opts.Destination == nil || *opts.Destination != "/some/path" {
|
||||
t.Errorf("expected Destination to be '/some/path'")
|
||||
}
|
||||
if opts.Ref != nil {
|
||||
t.Errorf("expected Ref to be nil")
|
||||
}
|
||||
if opts.Flags != nil {
|
||||
t.Errorf("expected Flags to be nil")
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
t.Errorf("expected InstallFlags to be nil")
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
t.Errorf("expected UpdateFlags to be nil")
|
||||
}
|
||||
|
||||
// Test with flags option
|
||||
flagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("owner/repo"),
|
||||
Type: appconfig.InstallerTypeGit,
|
||||
Opts: &map[string]any{
|
||||
"destination": "/some/path",
|
||||
"flags": "--depth 1",
|
||||
},
|
||||
}
|
||||
installerWithFlags := newTestGitInstaller(flagsData)
|
||||
optsWithFlags := installerWithFlags.GetOpts()
|
||||
if optsWithFlags.Flags == nil || *optsWithFlags.Flags != "--depth 1" {
|
||||
t.Errorf("expected Flags to be '--depth 1'")
|
||||
}
|
||||
|
||||
// Test with install_flags option (for git clone)
|
||||
installFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("owner/repo"),
|
||||
Type: appconfig.InstallerTypeGit,
|
||||
Opts: &map[string]any{
|
||||
"destination": "/some/path",
|
||||
"install_flags": "--depth 1 --single-branch",
|
||||
},
|
||||
}
|
||||
installerWithInstallFlags := newTestGitInstaller(installFlagsData)
|
||||
optsWithInstallFlags := installerWithInstallFlags.GetOpts()
|
||||
if optsWithInstallFlags.InstallFlags == nil || *optsWithInstallFlags.InstallFlags != "--depth 1 --single-branch" {
|
||||
t.Errorf("expected InstallFlags to be '--depth 1 --single-branch'")
|
||||
}
|
||||
|
||||
// Test with update_flags option (for git pull)
|
||||
updateFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("owner/repo"),
|
||||
Type: appconfig.InstallerTypeGit,
|
||||
Opts: &map[string]any{
|
||||
"destination": "/some/path",
|
||||
"update_flags": "--rebase",
|
||||
},
|
||||
}
|
||||
installerWithUpdateFlags := newTestGitInstaller(updateFlagsData)
|
||||
optsWithUpdateFlags := installerWithUpdateFlags.GetOpts()
|
||||
if optsWithUpdateFlags.UpdateFlags == nil || *optsWithUpdateFlags.UpdateFlags != "--rebase" {
|
||||
t.Errorf("expected UpdateFlags to be '--rebase'")
|
||||
}
|
||||
|
||||
// Test with all options combined
|
||||
allOptsData := &appconfig.InstallerData{
|
||||
Name: strPtr("owner/repo"),
|
||||
Type: appconfig.InstallerTypeGit,
|
||||
Opts: &map[string]any{
|
||||
"destination": "/some/path",
|
||||
"ref": "develop",
|
||||
"flags": "--common",
|
||||
"install_flags": "--depth 1",
|
||||
"update_flags": "--rebase",
|
||||
},
|
||||
}
|
||||
installerWithAllOpts := newTestGitInstaller(allOptsData)
|
||||
optsWithAllOpts := installerWithAllOpts.GetOpts()
|
||||
if optsWithAllOpts.Destination == nil || *optsWithAllOpts.Destination != "/some/path" {
|
||||
t.Errorf("expected Destination to be '/some/path'")
|
||||
}
|
||||
if optsWithAllOpts.Ref == nil || *optsWithAllOpts.Ref != "develop" {
|
||||
t.Errorf("expected Ref to be 'develop'")
|
||||
}
|
||||
if optsWithAllOpts.Flags == nil || *optsWithAllOpts.Flags != "--common" {
|
||||
t.Errorf("expected Flags to be '--common'")
|
||||
}
|
||||
if optsWithAllOpts.InstallFlags == nil || *optsWithAllOpts.InstallFlags != "--depth 1" {
|
||||
t.Errorf("expected InstallFlags to be '--depth 1'")
|
||||
}
|
||||
if optsWithAllOpts.UpdateFlags == nil || *optsWithAllOpts.UpdateFlags != "--rebase" {
|
||||
t.Errorf("expected UpdateFlags to be '--rebase'")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package installer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/chenasraf/sofmani/appconfig"
|
||||
"github.com/chenasraf/sofmani/utils"
|
||||
)
|
||||
@@ -18,7 +20,12 @@ type NpmInstaller struct {
|
||||
|
||||
// NpmOpts represents options for the NpmInstaller.
|
||||
type NpmOpts struct {
|
||||
//
|
||||
// Flags is a string of additional flags to pass to the npm/pnpm/yarn 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
|
||||
}
|
||||
|
||||
// NpmPackageManager represents a Node.js package manager type.
|
||||
@@ -40,12 +47,28 @@ func (i *NpmInstaller) Validate() []ValidationError {
|
||||
|
||||
// Install implements IInstaller.
|
||||
func (i *NpmInstaller) Install() error {
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), "install", "--global", *i.Info.Name)
|
||||
opts := i.GetOpts()
|
||||
args := []string{"install", "--global"}
|
||||
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, *i.Info.Name)
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), args...)
|
||||
}
|
||||
|
||||
// Update implements IInstaller.
|
||||
func (i *NpmInstaller) Update() error {
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), "install", "--global", *i.Info.Name+"@latest")
|
||||
opts := i.GetOpts()
|
||||
args := []string{"install", "--global"}
|
||||
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+"@latest")
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), args...)
|
||||
}
|
||||
|
||||
// CheckNeedsUpdate implements IInstaller.
|
||||
@@ -76,7 +99,18 @@ func (i *NpmInstaller) GetData() *appconfig.InstallerData {
|
||||
// GetOpts returns the parsed options for the NpmInstaller.
|
||||
func (i *NpmInstaller) GetOpts() *NpmOpts {
|
||||
opts := &NpmOpts{}
|
||||
// info := i.Info
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -35,3 +35,88 @@ func TestNpmValidation(t *testing.T) {
|
||||
}
|
||||
assertValidationError(t, newTestNpmInstaller(nilNameData).Validate(), "name")
|
||||
}
|
||||
|
||||
func TestNpmGetOpts(t *testing.T) {
|
||||
logger.InitLogger(false)
|
||||
|
||||
// Test default opts (no options set)
|
||||
defaultData := &appconfig.InstallerData{
|
||||
Name: strPtr("prettier"),
|
||||
Type: appconfig.InstallerTypeNpm,
|
||||
}
|
||||
installer := newTestNpmInstaller(defaultData)
|
||||
opts := installer.GetOpts()
|
||||
if opts.Flags != nil {
|
||||
t.Errorf("expected Flags to be nil")
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
t.Errorf("expected InstallFlags to be nil")
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
t.Errorf("expected UpdateFlags to be nil")
|
||||
}
|
||||
|
||||
// Test with flags option
|
||||
flagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("prettier"),
|
||||
Type: appconfig.InstallerTypeNpm,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--legacy-peer-deps",
|
||||
},
|
||||
}
|
||||
installerWithFlags := newTestNpmInstaller(flagsData)
|
||||
optsWithFlags := installerWithFlags.GetOpts()
|
||||
if optsWithFlags.Flags == nil || *optsWithFlags.Flags != "--legacy-peer-deps" {
|
||||
t.Errorf("expected Flags to be '--legacy-peer-deps'")
|
||||
}
|
||||
|
||||
// Test with install_flags option
|
||||
installFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("prettier"),
|
||||
Type: appconfig.InstallerTypeNpm,
|
||||
Opts: &map[string]any{
|
||||
"install_flags": "--save-exact",
|
||||
},
|
||||
}
|
||||
installerWithInstallFlags := newTestNpmInstaller(installFlagsData)
|
||||
optsWithInstallFlags := installerWithInstallFlags.GetOpts()
|
||||
if optsWithInstallFlags.InstallFlags == nil || *optsWithInstallFlags.InstallFlags != "--save-exact" {
|
||||
t.Errorf("expected InstallFlags to be '--save-exact'")
|
||||
}
|
||||
|
||||
// Test with update_flags option
|
||||
updateFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("prettier"),
|
||||
Type: appconfig.InstallerTypeNpm,
|
||||
Opts: &map[string]any{
|
||||
"update_flags": "--force",
|
||||
},
|
||||
}
|
||||
installerWithUpdateFlags := newTestNpmInstaller(updateFlagsData)
|
||||
optsWithUpdateFlags := installerWithUpdateFlags.GetOpts()
|
||||
if optsWithUpdateFlags.UpdateFlags == nil || *optsWithUpdateFlags.UpdateFlags != "--force" {
|
||||
t.Errorf("expected UpdateFlags to be '--force'")
|
||||
}
|
||||
|
||||
// Test with all flags options combined
|
||||
allFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("prettier"),
|
||||
Type: appconfig.InstallerTypeNpm,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--common",
|
||||
"install_flags": "--install-specific",
|
||||
"update_flags": "--update-specific",
|
||||
},
|
||||
}
|
||||
installerWithAllFlags := newTestNpmInstaller(allFlagsData)
|
||||
optsWithAllFlags := installerWithAllFlags.GetOpts()
|
||||
if optsWithAllFlags.Flags == nil || *optsWithAllFlags.Flags != "--common" {
|
||||
t.Errorf("expected Flags to be '--common'")
|
||||
}
|
||||
if optsWithAllFlags.InstallFlags == nil || *optsWithAllFlags.InstallFlags != "--install-specific" {
|
||||
t.Errorf("expected InstallFlags to be '--install-specific'")
|
||||
}
|
||||
if optsWithAllFlags.UpdateFlags == nil || *optsWithAllFlags.UpdateFlags != "--update-specific" {
|
||||
t.Errorf("expected UpdateFlags to be '--update-specific'")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package installer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/chenasraf/sofmani/appconfig"
|
||||
)
|
||||
|
||||
@@ -19,6 +21,12 @@ type PacmanInstaller struct {
|
||||
type PacmanOpts struct {
|
||||
// Needed skips reinstalling up-to-date packages (--needed flag).
|
||||
Needed *bool
|
||||
// Flags is a string of additional flags to pass to the pacman/yay 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
|
||||
}
|
||||
|
||||
// PacmanPackageManager represents an Arch Linux package manager type.
|
||||
@@ -39,10 +47,16 @@ func (i *PacmanInstaller) Validate() []ValidationError {
|
||||
// Install implements IInstaller.
|
||||
func (i *PacmanInstaller) Install() error {
|
||||
name := *i.Info.Name
|
||||
opts := i.GetOpts()
|
||||
args := []string{"-S", "--noconfirm"}
|
||||
if i.GetOpts().Needed != nil && *i.GetOpts().Needed {
|
||||
if opts.Needed != nil && *opts.Needed {
|
||||
args = append(args, "--needed")
|
||||
}
|
||||
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...)
|
||||
}
|
||||
@@ -50,10 +64,16 @@ func (i *PacmanInstaller) Install() error {
|
||||
// Update implements IInstaller.
|
||||
func (i *PacmanInstaller) Update() error {
|
||||
name := *i.Info.Name
|
||||
opts := i.GetOpts()
|
||||
args := []string{"-S", "--noconfirm"}
|
||||
if i.GetOpts().Needed != nil && *i.GetOpts().Needed {
|
||||
if opts.Needed != nil && *opts.Needed {
|
||||
args = append(args, "--needed")
|
||||
}
|
||||
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, name)
|
||||
return i.RunCmdPassThrough(string(i.PackageManager), args...)
|
||||
}
|
||||
@@ -96,6 +116,15 @@ func (i *PacmanInstaller) GetOpts() *PacmanOpts {
|
||||
if needed, ok := (*info.Opts)["needed"].(bool); ok {
|
||||
opts.Needed = &needed
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -93,6 +93,15 @@ func TestPacmanGetOpts(t *testing.T) {
|
||||
if opts.Needed != nil {
|
||||
t.Errorf("expected Needed to be nil, got %v", *opts.Needed)
|
||||
}
|
||||
if opts.Flags != nil {
|
||||
t.Errorf("expected Flags to be nil")
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
t.Errorf("expected InstallFlags to be nil")
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
t.Errorf("expected UpdateFlags to be nil")
|
||||
}
|
||||
|
||||
// Test with needed option set to true
|
||||
neededData := &appconfig.InstallerData{
|
||||
@@ -121,4 +130,68 @@ func TestPacmanGetOpts(t *testing.T) {
|
||||
if optsNotNeeded.Needed == nil || *optsNotNeeded.Needed {
|
||||
t.Errorf("expected Needed to be false")
|
||||
}
|
||||
|
||||
// Test with flags option
|
||||
flagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypePacman,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--asdeps --overwrite '*'",
|
||||
},
|
||||
}
|
||||
installerWithFlags := newTestPacmanInstaller(flagsData)
|
||||
optsWithFlags := installerWithFlags.GetOpts()
|
||||
if optsWithFlags.Flags == nil || *optsWithFlags.Flags != "--asdeps --overwrite '*'" {
|
||||
t.Errorf("expected Flags to be '--asdeps --overwrite '*''")
|
||||
}
|
||||
|
||||
// Test with install_flags option
|
||||
installFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypePacman,
|
||||
Opts: &map[string]any{
|
||||
"install_flags": "--asdeps",
|
||||
},
|
||||
}
|
||||
installerWithInstallFlags := newTestPacmanInstaller(installFlagsData)
|
||||
optsWithInstallFlags := installerWithInstallFlags.GetOpts()
|
||||
if optsWithInstallFlags.InstallFlags == nil || *optsWithInstallFlags.InstallFlags != "--asdeps" {
|
||||
t.Errorf("expected InstallFlags to be '--asdeps'")
|
||||
}
|
||||
|
||||
// Test with update_flags option
|
||||
updateFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypePacman,
|
||||
Opts: &map[string]any{
|
||||
"update_flags": "--ignore vim",
|
||||
},
|
||||
}
|
||||
installerWithUpdateFlags := newTestPacmanInstaller(updateFlagsData)
|
||||
optsWithUpdateFlags := installerWithUpdateFlags.GetOpts()
|
||||
if optsWithUpdateFlags.UpdateFlags == nil || *optsWithUpdateFlags.UpdateFlags != "--ignore vim" {
|
||||
t.Errorf("expected UpdateFlags to be '--ignore vim'")
|
||||
}
|
||||
|
||||
// Test with all flags options combined
|
||||
allFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("vim"),
|
||||
Type: appconfig.InstallerTypePacman,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--common",
|
||||
"install_flags": "--install-specific",
|
||||
"update_flags": "--update-specific",
|
||||
},
|
||||
}
|
||||
installerWithAllFlags := newTestPacmanInstaller(allFlagsData)
|
||||
optsWithAllFlags := installerWithAllFlags.GetOpts()
|
||||
if optsWithAllFlags.Flags == nil || *optsWithAllFlags.Flags != "--common" {
|
||||
t.Errorf("expected Flags to be '--common'")
|
||||
}
|
||||
if optsWithAllFlags.InstallFlags == nil || *optsWithAllFlags.InstallFlags != "--install-specific" {
|
||||
t.Errorf("expected InstallFlags to be '--install-specific'")
|
||||
}
|
||||
if optsWithAllFlags.UpdateFlags == nil || *optsWithAllFlags.UpdateFlags != "--update-specific" {
|
||||
t.Errorf("expected UpdateFlags to be '--update-specific'")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package installer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/chenasraf/sofmani/appconfig"
|
||||
"github.com/chenasraf/sofmani/utils"
|
||||
)
|
||||
@@ -16,7 +18,12 @@ type PipxInstaller struct {
|
||||
|
||||
// PipxOpts represents options for the PipxInstaller.
|
||||
type PipxOpts struct {
|
||||
//
|
||||
// Flags is a string of additional flags to pass to the pipx 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
|
||||
}
|
||||
|
||||
// Validate validates the installer configuration.
|
||||
@@ -28,12 +35,28 @@ func (i *PipxInstaller) Validate() []ValidationError {
|
||||
// Install implements IInstaller.
|
||||
func (i *PipxInstaller) Install() error {
|
||||
name := *i.Info.Name
|
||||
return i.RunCmdPassThrough("pipx", "install", name)
|
||||
opts := i.GetOpts()
|
||||
args := []string{"install"}
|
||||
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("pipx", args...)
|
||||
}
|
||||
|
||||
// Update implements IInstaller.
|
||||
func (i *PipxInstaller) Update() error {
|
||||
return i.RunCmdPassThrough("pipx", "upgrade", *i.Info.Name)
|
||||
opts := i.GetOpts()
|
||||
args := []string{"upgrade"}
|
||||
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("pipx", args...)
|
||||
}
|
||||
|
||||
// CheckNeedsUpdate implements IInstaller.
|
||||
@@ -63,7 +86,20 @@ func (i *PipxInstaller) GetData() *appconfig.InstallerData {
|
||||
|
||||
// GetOpts returns the parsed options for the PipxInstaller.
|
||||
func (i *PipxInstaller) GetOpts() *PipxOpts {
|
||||
return &PipxOpts{}
|
||||
opts := &PipxOpts{}
|
||||
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.
|
||||
|
||||
@@ -34,3 +34,88 @@ func TestPipxValidation(t *testing.T) {
|
||||
}
|
||||
assertValidationError(t, newTestPipxInstaller(nilNameData).Validate(), "name")
|
||||
}
|
||||
|
||||
func TestPipxGetOpts(t *testing.T) {
|
||||
logger.InitLogger(false)
|
||||
|
||||
// Test default opts (no options set)
|
||||
defaultData := &appconfig.InstallerData{
|
||||
Name: strPtr("black"),
|
||||
Type: appconfig.InstallerTypePipx,
|
||||
}
|
||||
installer := newTestPipxInstaller(defaultData)
|
||||
opts := installer.GetOpts()
|
||||
if opts.Flags != nil {
|
||||
t.Errorf("expected Flags to be nil")
|
||||
}
|
||||
if opts.InstallFlags != nil {
|
||||
t.Errorf("expected InstallFlags to be nil")
|
||||
}
|
||||
if opts.UpdateFlags != nil {
|
||||
t.Errorf("expected UpdateFlags to be nil")
|
||||
}
|
||||
|
||||
// Test with flags option
|
||||
flagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("black"),
|
||||
Type: appconfig.InstallerTypePipx,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--verbose",
|
||||
},
|
||||
}
|
||||
installerWithFlags := newTestPipxInstaller(flagsData)
|
||||
optsWithFlags := installerWithFlags.GetOpts()
|
||||
if optsWithFlags.Flags == nil || *optsWithFlags.Flags != "--verbose" {
|
||||
t.Errorf("expected Flags to be '--verbose'")
|
||||
}
|
||||
|
||||
// Test with install_flags option
|
||||
installFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("black"),
|
||||
Type: appconfig.InstallerTypePipx,
|
||||
Opts: &map[string]any{
|
||||
"install_flags": "--python python3.11",
|
||||
},
|
||||
}
|
||||
installerWithInstallFlags := newTestPipxInstaller(installFlagsData)
|
||||
optsWithInstallFlags := installerWithInstallFlags.GetOpts()
|
||||
if optsWithInstallFlags.InstallFlags == nil || *optsWithInstallFlags.InstallFlags != "--python python3.11" {
|
||||
t.Errorf("expected InstallFlags to be '--python python3.11'")
|
||||
}
|
||||
|
||||
// Test with update_flags option
|
||||
updateFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("black"),
|
||||
Type: appconfig.InstallerTypePipx,
|
||||
Opts: &map[string]any{
|
||||
"update_flags": "--force",
|
||||
},
|
||||
}
|
||||
installerWithUpdateFlags := newTestPipxInstaller(updateFlagsData)
|
||||
optsWithUpdateFlags := installerWithUpdateFlags.GetOpts()
|
||||
if optsWithUpdateFlags.UpdateFlags == nil || *optsWithUpdateFlags.UpdateFlags != "--force" {
|
||||
t.Errorf("expected UpdateFlags to be '--force'")
|
||||
}
|
||||
|
||||
// Test with all flags options combined
|
||||
allFlagsData := &appconfig.InstallerData{
|
||||
Name: strPtr("black"),
|
||||
Type: appconfig.InstallerTypePipx,
|
||||
Opts: &map[string]any{
|
||||
"flags": "--common",
|
||||
"install_flags": "--install-specific",
|
||||
"update_flags": "--update-specific",
|
||||
},
|
||||
}
|
||||
installerWithAllFlags := newTestPipxInstaller(allFlagsData)
|
||||
optsWithAllFlags := installerWithAllFlags.GetOpts()
|
||||
if optsWithAllFlags.Flags == nil || *optsWithAllFlags.Flags != "--common" {
|
||||
t.Errorf("expected Flags to be '--common'")
|
||||
}
|
||||
if optsWithAllFlags.InstallFlags == nil || *optsWithAllFlags.InstallFlags != "--install-specific" {
|
||||
t.Errorf("expected InstallFlags to be '--install-specific'")
|
||||
}
|
||||
if optsWithAllFlags.UpdateFlags == nil || *optsWithAllFlags.UpdateFlags != "--update-specific" {
|
||||
t.Errorf("expected UpdateFlags to be '--update-specific'")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user