diff --git a/appconfig/appconfig.go b/appconfig/appconfig.go index 8cb9ce0..299ceae 100644 --- a/appconfig/appconfig.go +++ b/appconfig/appconfig.go @@ -41,6 +41,7 @@ const ( InstallerTypeBrew InstallerType = "brew" InstallerTypeApt InstallerType = "apt" InstallerTypeGit InstallerType = "git" + InstallerTypeRsync InstallerType = "rsync" ) type Platforms struct { diff --git a/installer/brew_installer.go b/installer/brew_installer.go index 6a426fc..4948093 100644 --- a/installer/brew_installer.go +++ b/installer/brew_installer.go @@ -1,9 +1,6 @@ package installer import ( - "encoding/json" - "slices" - "github.com/chenasraf/sofmani/appconfig" "github.com/chenasraf/sofmani/utils" ) @@ -36,24 +33,11 @@ func (i *BrewInstaller) CheckNeedsUpdate() (error, bool) { if i.GetInfo().CheckHasUpdate != nil { return utils.RunCmdGetSuccess("sh", "-c", *i.GetInfo().CheckHasUpdate) } - out, err := utils.RunCmdGetOutput("brew", "outdated", "--json", *i.Info.Name) + err, success := utils.RunCmdGetSuccess("brew", "outdated", "--json", *i.Info.Name) if err != nil { return err, false } - jsonOut := make(map[string]interface{}) - err = json.Unmarshal(out, &jsonOut) - if err != nil { - return err, false - } - var formulae []interface{} = jsonOut["formulae"].([]interface{}) - strFormulae := make([]string, len(formulae)) - for i, v := range formulae { - strFormulae[i] = v.(string) - } - if slices.Contains(strFormulae, *i.Info.Name) { - return nil, true - } - return nil, false + return nil, !success } // CheckIsInstalled implements IInstaller. diff --git a/installer/installer.go b/installer/installer.go index 8e90002..c6859ad 100644 --- a/installer/installer.go +++ b/installer/installer.go @@ -26,6 +26,8 @@ func GetInstaller(config *appconfig.AppConfig, installer *appconfig.Installer) ( return nil, NewBrewInstaller(config, installer) case appconfig.InstallerTypeShell: return nil, NewShellInstaller(config, installer) + case appconfig.InstallerTypeRsync: + return nil, NewRsyncInstaller(config, installer) } return nil, nil } @@ -95,7 +97,7 @@ func RunInstaller(config *appconfig.AppConfig, installer IInstaller) error { if installed { logger.Debug("%s is already installed", name) if config.CheckUpdates { - logger.Debug("Checking if %s needs an update", name) + logger.Info("Checking if %s needs an update", name) err, needsUpdate := installer.CheckNeedsUpdate() if err != nil { return err @@ -119,6 +121,7 @@ func RunInstaller(config *appconfig.AppConfig, installer IInstaller) error { } } } + return nil } else { return nil } diff --git a/installer/rsync_installer.go b/installer/rsync_installer.go new file mode 100644 index 0000000..596ab1f --- /dev/null +++ b/installer/rsync_installer.go @@ -0,0 +1,100 @@ +package installer + +import ( + "strings" + + "github.com/chenasraf/sofmani/appconfig" + "github.com/chenasraf/sofmani/logger" + "github.com/chenasraf/sofmani/utils" +) + +type RsyncInstaller struct { + Config *appconfig.AppConfig + Info *appconfig.Installer +} + +type RsyncOpts struct { + Source *string + Destination *string + Flags *string +} + +// Install implements IInstaller. +func (i *RsyncInstaller) Install() error { + defaultFlags := "-tr" + if i.Config.Debug { + defaultFlags += "v" + } + flags := []string{defaultFlags} + if i.GetOpts().Flags != nil { + for _, flag := range strings.Split(*i.GetOpts().Flags, " ") { + flags = append(flags, flag) + } + } + + src := utils.GetRealPath(*i.GetOpts().Source) + dest := utils.GetRealPath(*i.GetOpts().Destination) + + flags = append(flags, src) + flags = append(flags, dest) + + logger.Debug("rsync %s to %s", src, dest) + return utils.RunCmdPassThrough("rsync", flags...) +} + +// Update implements IInstaller. +func (i *RsyncInstaller) Update() error { + return i.Install() +} + +// CheckNeedsUpdate implements IInstaller. +func (i *RsyncInstaller) CheckNeedsUpdate() (error, bool) { + if i.GetInfo().CheckHasUpdate != nil { + return utils.RunCmdGetSuccess("sh", "-c", *i.GetInfo().CheckHasUpdate) + } + return nil, true +} + +// CheckIsInstalled implements IInstaller. +func (i *RsyncInstaller) CheckIsInstalled() (error, bool) { + return utils.RunCmdGetSuccess("which", i.GetBinName()) +} + +// GetInfo implements IInstaller. +func (i *RsyncInstaller) GetInfo() *appconfig.Installer { + return i.Info +} + +func (i *RsyncInstaller) GetOpts() *RsyncOpts { + opts := &RsyncOpts{} + info := i.Info + if info.Opts != nil { + if src, ok := (*info.Opts)["source"].(string); ok { + opts.Source = &src + } + if dest, ok := (*info.Opts)["destination"].(string); ok { + opts.Destination = &dest + } + if flags, ok := (*info.Opts)["flags"].(string); ok { + opts.Flags = &flags + } + } + return opts +} + +func (i *RsyncInstaller) GetBinName() string { + info := i.GetInfo() + if info.BinName != nil && len(*info.BinName) > 0 { + return *info.BinName + } + return *info.Name +} + +func NewRsyncInstaller(cfg *appconfig.AppConfig, installer *appconfig.Installer) *RsyncInstaller { + i := &RsyncInstaller{ + Config: cfg, + Info: installer, + } + + return i +} diff --git a/installer/shell_installer.go b/installer/shell_installer.go index 96ef1c5..805f5a4 100644 --- a/installer/shell_installer.go +++ b/installer/shell_installer.go @@ -20,7 +20,7 @@ type ShellOpts struct { // Install implements IInstaller. func (i *ShellInstaller) Install() error { tmpdir := os.TempDir() - tmpfile := fmt.Sprintf("%s/%s", tmpdir, "install.sh") + tmpfile := fmt.Sprintf("%s%s", tmpdir, "install.sh") commandStr := fmt.Sprintf("#!/bin/bash\n%s\n", *i.GetOpts().Command) err := os.WriteFile(tmpfile, []byte(commandStr), 0755) if err != nil { diff --git a/sofmani.yml b/sofmani.yml index e2f1d7f..2c18277 100644 --- a/sofmani.yml +++ b/sofmani.yml @@ -1,4 +1,5 @@ debug: true +check_updates: true defaults: type: brew: @@ -6,10 +7,27 @@ defaults: only: ['macos'] install: + - name: nvim + type: rsync + opts: + source: ~/.dotfiles/.config/nvim/ + destination: ~/.config/nvim/ + flags: --delete --exclude .git --exclude .DS_Store + - name: lazygit + type: rsync + opts: + source: ~/.dotfiles/.config/lazygit.yml + destination: ~/Library/ApplicationSupport/lazygit/config.yml + - name: config + type: rsync + opts: + source: ~/.dotfiles/.config + destination: ~/.config + flags: --exclude lazygit.yml --exclude nvim --exclude .git --exclude .DS_Store - name: treelike type: brew opts: - tap: chenasraf/tap/treelike + tap: chenasraf/tap - name: lazygit type: group steps: diff --git a/utils/os.go b/utils/os.go new file mode 100644 index 0000000..934f141 --- /dev/null +++ b/utils/os.go @@ -0,0 +1,26 @@ +package utils + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +func GetRealPath(path string) string { + if strings.HasPrefix(path, fmt.Sprintf("~%s", string(filepath.Separator))) { + homedir, err := os.UserHomeDir() + if err != nil { + return path + } + isDir := false + if strings.HasSuffix(path, string(filepath.Separator)) { + isDir = true + } + path = filepath.Join(homedir, path[2:]) + if isDir { + path += string(filepath.Separator) + } + } + return path +}