From 46249857f30dca7588abe6ce3e8e7fe964402327 Mon Sep 17 00:00:00 2001 From: DataHearth Date: Thu, 2 Jun 2022 19:44:51 +0200 Subject: [PATCH] feat(config): add SSH capability with user/pass or key/pass --- cmd/cli.go | 49 ++--- internal/configuration/configuration.go | 67 +++++++ .../definition.go} | 53 +----- internal/configuration/ssh.go | 171 ++++++++++++++++++ internal/{ => git}/git.go | 13 +- internal/index.go | 4 +- internal/items.go | 33 ++-- internal/{ => misc}/tools.go | 30 ++- internal/pkgs.go | 7 +- 9 files changed, 314 insertions(+), 113 deletions(-) create mode 100644 internal/configuration/configuration.go rename internal/{configuration.go => configuration/definition.go} (56%) create mode 100644 internal/configuration/ssh.go rename internal/{ => git}/git.go (89%) rename internal/{ => misc}/tools.go (78%) diff --git a/cmd/cli.go b/cmd/cli.go index 68979f9..e7d1c3c 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -7,6 +7,8 @@ import ( "time" mapper "github.com/datahearth/config-mapper/internal" + "github.com/datahearth/config-mapper/internal/configuration" + "github.com/datahearth/config-mapper/internal/git" "github.com/fatih/color" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -47,30 +49,36 @@ var saveCmd = &cobra.Command{ } func init() { - cobra.OnInitialize(mapper.InitConfig) + cobra.OnInitialize(configuration.InitConfig) rootCmd.AddCommand(initCmd) rootCmd.AddCommand(loadCmd) rootCmd.AddCommand(saveCmd) rootCmd.PersistentFlags().StringP("configuration-file", "c", "", "location of configuration file") + rootCmd.PersistentFlags().String("ssh-user", "", "SSH username to retrieve configuration file") + rootCmd.PersistentFlags().String("ssh-password", "", "SSH password to retrieve configuration file") + rootCmd.PersistentFlags().String("ssh-key", "", "SSH key to retrieve configuration file (if a passphrase is needed, use the \"CONFIG_MAPPER_PASS\" env variable") viper.BindPFlag("configuration-file", rootCmd.PersistentFlags().Lookup("configuration-file")) + viper.BindPFlag("ssh-user", rootCmd.PersistentFlags().Lookup("ssh-user")) + viper.BindPFlag("ssh-password", rootCmd.PersistentFlags().Lookup("ssh-password")) + viper.BindPFlag("ssh-key", rootCmd.PersistentFlags().Lookup("ssh-key")) - loadCmd.PersistentFlags().Bool("disable-files", false, "files will be ignored") - loadCmd.PersistentFlags().Bool("disable-folders", false, "folders will be ignored") - loadCmd.PersistentFlags().Bool("pkgs", false, "packages will be installed") - viper.BindPFlag("load-disable-files", loadCmd.PersistentFlags().Lookup("disable-files")) - viper.BindPFlag("load-disable-folders", loadCmd.PersistentFlags().Lookup("disable-folders")) - viper.BindPFlag("load-enable-pkgs", loadCmd.PersistentFlags().Lookup("pkgs")) + loadCmd.Flags().Bool("disable-files", false, "files will be ignored") + loadCmd.Flags().Bool("disable-folders", false, "folders will be ignored") + loadCmd.Flags().Bool("pkgs", false, "packages will be installed") + viper.BindPFlag("load-disable-files", loadCmd.Flags().Lookup("disable-files")) + viper.BindPFlag("load-disable-folders", loadCmd.Flags().Lookup("disable-folders")) + viper.BindPFlag("load-enable-pkgs", loadCmd.Flags().Lookup("pkgs")) - saveCmd.PersistentFlags().Bool("disable-files", false, "files will be ignored") - saveCmd.PersistentFlags().Bool("disable-folders", false, "folders will be ignored") - saveCmd.PersistentFlags().Bool("pkgs", false, "packages will be saved") + saveCmd.Flags().Bool("disable-files", false, "files will be ignored") + saveCmd.Flags().Bool("disable-folders", false, "folders will be ignored") + saveCmd.Flags().Bool("pkgs", false, "packages will be saved") saveCmd.Flags().BoolP("push", "p", false, "new configurations will be committed and pushed") saveCmd.Flags().StringP("message", "m", strconv.FormatInt(time.Now().Unix(), 10), "combined with --push to set a commit message") saveCmd.Flags().Bool("disable-index", false, "configuration index will not be updated") - viper.BindPFlag("save-disable-files", saveCmd.PersistentFlags().Lookup("disable-files")) - viper.BindPFlag("save-disable-folders", saveCmd.PersistentFlags().Lookup("disable-folders")) - viper.BindPFlag("save-enable-pkgs", saveCmd.PersistentFlags().Lookup("pkgs")) + viper.BindPFlag("save-disable-files", saveCmd.Flags().Lookup("disable-files")) + viper.BindPFlag("save-disable-folders", saveCmd.Flags().Lookup("disable-folders")) + viper.BindPFlag("save-enable-pkgs", saveCmd.Flags().Lookup("pkgs")) viper.BindPFlag("push", saveCmd.Flags().Lookup("push")) viper.BindPFlag("disable-index-update", saveCmd.Flags().Lookup("disable-index")) viper.BindPFlag("message", saveCmd.Flags().Lookup("message")) @@ -84,7 +92,7 @@ func Execute() { } func save(cmd *cobra.Command, args []string) { - var c mapper.Configuration + var c configuration.Configuration if err := viper.Unmarshal(&c); err != nil { mapper.PrintError("failed to decode configuration: %v\n", err) os.Exit(1) @@ -96,7 +104,7 @@ func save(cmd *cobra.Command, args []string) { os.Exit(1) } - r, err := mapper.NewRepository(c.Storage.Git, c.Storage.Path) + r, err := git.NewRepository(c.Storage.Git, c.Storage.Path) if err != nil { mapper.PrintError("failed to open repository at %s: %v\n", c.Storage.Path, err) os.Exit(1) @@ -138,7 +146,7 @@ func save(cmd *cobra.Command, args []string) { } func load(cmd *cobra.Command, args []string) { - var c mapper.Configuration + var c configuration.Configuration if err := viper.Unmarshal(&c); err != nil { mapper.PrintError("failed to decode configuration: %v\n", err) os.Exit(1) @@ -150,7 +158,7 @@ func load(cmd *cobra.Command, args []string) { os.Exit(1) } - r, err := mapper.NewRepository(c.Storage.Git, c.Storage.Path) + r, err := git.NewRepository(c.Storage.Git, c.Storage.Path) if err != nil { mapper.PrintError("failed to open repository at %s: %v\n", c.Storage.Path, err) os.Exit(1) @@ -176,16 +184,15 @@ func load(cmd *cobra.Command, args []string) { } func initCommand(cmd *cobra.Command, args []string) { - var config mapper.Configuration - - if err := viper.Unmarshal(&config); err != nil { + var c configuration.Configuration + if err := viper.Unmarshal(&c); err != nil { mapper.PrintError("failed to decode configuration: %v\n", err) os.Exit(1) } logger.Println("initializing config-mapper folder from configuration...") - if _, err := mapper.NewRepository(config.Storage.Git, config.Storage.Path); err != nil { + if _, err := git.NewRepository(c.Storage.Git, c.Storage.Path); err != nil { mapper.PrintError("failed to initialize folder: %v\n", err) os.Exit(1) } diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go new file mode 100644 index 0000000..f230e0b --- /dev/null +++ b/internal/configuration/configuration.go @@ -0,0 +1,67 @@ +package configuration + +import ( + "fmt" + "log" + "os" + "path" + "strings" + + "github.com/fatih/color" + "github.com/spf13/viper" +) + +var errLogger = log.New(os.Stderr, "", 0) + +func InitConfig() { + h, err := os.UserHomeDir() + if err != nil { + errLogger.Fatalln(err) + } + + if c := viper.GetString("configuration-file"); c != "" { + if strings.Contains(c, "ssh://") { + viper.AddConfigPath(h) + + viper.SetConfigType("yml") + viper.SetConfigName(".config-mapper") + + if err := loadConfigSSH(c); err != nil { + errLogger.Fatalln(err) + } + return + } + + if strings.Contains(c, ".yml") { + viper.AddConfigPath(path.Dir(c)) + } else { + viper.AddConfigPath(c) + } + } + if c := os.Getenv("CONFIG_MAPPER_CFG"); c != "" { + if strings.Contains(c, ".yml") { + viper.AddConfigPath(path.Dir(c)) + } else { + viper.AddConfigPath(c) + } + } + viper.AddConfigPath(h) + + viper.SetConfigType("yml") + viper.SetConfigName(".config-mapper") + + viper.SetDefault("storage.location", fmt.Sprintf("%s/config-mapper", os.TempDir())) + viper.SetDefault("package-managers.installation-order", []string{"apt", "homebrew"}) + + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + color.Error.Write([]byte(color.RedString("no configuration file found: %v\n", err))) + } else { + color.Error.Write([]byte(color.RedString("failed to read config: %v\n", err))) + } + + os.Exit(1) + } + + viper.Set("configuration-file", viper.ConfigFileUsed()) +} diff --git a/internal/configuration.go b/internal/configuration/definition.go similarity index 56% rename from internal/configuration.go rename to internal/configuration/definition.go index bc59d6e..36690d4 100644 --- a/internal/configuration.go +++ b/internal/configuration/definition.go @@ -1,13 +1,4 @@ -package mapper - -import ( - "fmt" - "os" - "path" - "strings" - - "github.com/spf13/viper" -) +package configuration type Configuration struct { Storage Storage `mapstructure:"storage" yaml:"storage"` @@ -49,45 +40,3 @@ type PkgManagers struct { Homebrew []string `mapstructure:"homebrew" yaml:"homebrew"` Aptitude []string `mapstructure:"apt-get" yaml:"apt-get"` } - -func InitConfig() { - h, err := os.UserHomeDir() - if err != nil { - errLogger.Printf("can't get home directory through $HOME variable: %v\n", err) - os.Exit(1) - } - - if c := viper.GetString("configuration-file"); c != "" { - if strings.Contains(c, ".yml") { - viper.AddConfigPath(path.Dir(c)) - } else { - viper.AddConfigPath(c) - } - } - if c := os.Getenv("CONFIG_MAPPER_CFG"); c != "" { - if strings.Contains(c, ".yml") { - viper.AddConfigPath(path.Dir(c)) - } else { - viper.AddConfigPath(c) - } - } - viper.AddConfigPath(h) - - viper.SetConfigType("yml") - viper.SetConfigName(".config-mapper") - - viper.SetDefault("storage.location", fmt.Sprintf("%s/config-mapper", os.TempDir())) - viper.SetDefault("package-managers.installation-order", []string{"apt", "homebrew"}) - - if err := viper.ReadInConfig(); err != nil { - if _, ok := err.(viper.ConfigFileNotFoundError); ok { - PrintError(err.Error()) - } else { - PrintError("failed to read config: %v\n", err) - } - - os.Exit(1) - } - - viper.Set("configuration-file", viper.ConfigFileUsed()) -} diff --git a/internal/configuration/ssh.go b/internal/configuration/ssh.go new file mode 100644 index 0000000..cbefab0 --- /dev/null +++ b/internal/configuration/ssh.go @@ -0,0 +1,171 @@ +package configuration + +import ( + "bytes" + "errors" + "fmt" + "io/ioutil" + "os" + osUser "os/user" + "strings" + + "github.com/fatih/color" + "github.com/spf13/viper" + "golang.org/x/crypto/ssh" + "golang.org/x/crypto/ssh/knownhosts" +) + +func loadConfigSSH(uri string) error { + config, host, path, err := getSSHConfig(uri) + if err != nil { + return err + } + + c, err := ssh.Dial("tcp", host, config) + if err != nil { + return err + } + defer c.Close() + + s, err := c.NewSession() + if err != nil { + return err + } + defer s.Close() + + buff := new(bytes.Buffer) + s.Stdout = buff + if err := s.Run(fmt.Sprintf("cat %s", path)); err != nil { + return err + } + + if err := viper.ReadConfig(buff); err != nil { + return err + } + + return nil +} + +func getSSHConfig(uriFlag string) (*ssh.ClientConfig, string, string, error) { + var err error + var user, passwd, host, configPath, key string + uri := strings.Split(uriFlag, "ssh://")[1] + + if key = viper.GetString("ssh-key"); key != "" { + uri, user, passwd, err = getCredentials(uri) + if err != nil { + return nil, "", "", err + } + + host, configPath, err = getUriContent(uri) + if err != nil { + return nil, "", "", err + } + } else if user = viper.GetString("ssh-user"); user != "" { + host, configPath, err = getUriContent(uri) + if err != nil { + return nil, "", "", err + } + + passwd = viper.GetString("ssh-password") + } else { + uri, user, passwd, err = getCredentials(uri) + if err != nil { + return nil, "", "", err + } + if passwd == "" { + passwd = viper.GetString("ssh-password") + } + + host, configPath, err = getUriContent(uri) + if err != nil { + return nil, "", "", err + } + } + + if user == "" { + color.Yellow("WARNING: no user was found in either the URI and flags. Current user will be used") + + var currentUser *osUser.User + currentUser, err = osUser.Current() + user = currentUser.Username + } + + var auth ssh.AuthMethod + if key != "" { + auth, err = createPubKeyAuth(key) + if err != nil { + return nil, "", "", err + } + } else { + auth = ssh.Password(passwd) + } + + h, err := os.UserHomeDir() + if err != nil { + return nil, "", "", err + } + + hostKeyCallback, err := knownhosts.New(fmt.Sprintf("%s/.ssh/known_hosts", h)) + if err != nil { + return nil, "", "", err + } + + if len(strings.SplitN(host, ":", 1)) == 1 { + host = fmt.Sprintf("%s:22", host) + } + + return &ssh.ClientConfig{ + User: user, + Auth: []ssh.AuthMethod{auth}, + HostKeyCallback: hostKeyCallback, + }, host, configPath, nil +} + +// getCredentials takes an SSH URI and returns (splitted URI, user, passwd, error) +// +// "passwd" can be empty in case of a single credential in URI +func getCredentials(uri string) (string, string, string, error) { + uriContent := strings.SplitN(uri, "@", 2) + if len(uriContent) == 1 { + fmt.Printf("uriContent: %v\n", uriContent) + return "", "", "", errors.New("no credentials in URI") + } + + credentials := strings.SplitN(uriContent[0], ":", 2) + if len(credentials) == 1 { + return uriContent[1], credentials[0], "", nil + } + + return uriContent[1], credentials[0], credentials[1], nil +} + +// getUriContent takes an SSH URI and returns (host, path, error) +func getUriContent(uri string) (string, string, error) { + uriContent := strings.Split(uri, ":") + if len(uriContent) < 2 { + return "", "", errors.New("ssh URI is malformed. It's missing either a host or path. E.g: \"ssh://localhost:/my/config/file.yml\"") + } + + return uriContent[0], uriContent[1], nil +} + +func createPubKeyAuth(key string) (ssh.AuthMethod, error) { + var signer ssh.Signer + privateKey, err := ioutil.ReadFile(key) + if err != nil { + return nil, err + } + + if passphrase := os.Getenv("CONFIG_MAPPER_SSH_PASSPHRASE"); passphrase != "" { + signer, err = ssh.ParsePrivateKeyWithPassphrase(privateKey, []byte(passphrase)) + } else { + signer, err = ssh.ParsePrivateKey(privateKey) + } + + if err != nil { + return nil, err + } + + return ssh.PublicKeys(signer), nil +} diff --git a/internal/git.go b/internal/git/git.go similarity index 89% rename from internal/git.go rename to internal/git/git.go index 93054f0..c8d95e1 100644 --- a/internal/git.go +++ b/internal/git/git.go @@ -1,4 +1,4 @@ -package mapper +package git import ( "errors" @@ -6,6 +6,8 @@ import ( "os/exec" "time" + "github.com/datahearth/config-mapper/internal/configuration" + "github.com/datahearth/config-mapper/internal/misc" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/transport" @@ -14,8 +16,7 @@ import ( ) var ( - ErrDirIsFile = errors.New("path is a file") - ErrInvalidEnv = errors.New("found invalid environment variable in path") + ErrDirIsFile = errors.New("path is a file") ) type RepositoryActions interface { @@ -38,18 +39,18 @@ type author struct { email string } -func NewRepository(config Git, repoPath string) (RepositoryActions, error) { +func NewRepository(config configuration.Git, repoPath string) (RepositoryActions, error) { var auth transport.AuthMethod if config.URL == "" { return nil, errors.New("a repository URI is needed (either using GIT protocol or HTTPS)") } - repoPath, err := absolutePath(repoPath) + repoPath, err := misc.AbsolutePath(repoPath) if err != nil { return nil, err } if config.SSH.Passphrase != "" && config.SSH.PrivateKey != "" { - privateKey, err := absolutePath(config.SSH.PrivateKey) + privateKey, err := misc.AbsolutePath(config.SSH.PrivateKey) if err != nil { return nil, err } diff --git a/internal/index.go b/internal/index.go index 02392ba..818829f 100644 --- a/internal/index.go +++ b/internal/index.go @@ -5,6 +5,8 @@ import ( "io/fs" "os" "strings" + + "github.com/datahearth/config-mapper/internal/misc" ) type Index struct { @@ -24,7 +26,7 @@ type Indexer interface { func NewIndexer(repoPath string) (Indexer, error) { perms := fs.FileMode(0755) - indexPath, err := absolutePath(fmt.Sprintf("%s/.index", repoPath)) + indexPath, err := misc.AbsolutePath(fmt.Sprintf("%s/.index", repoPath)) if err != nil { return nil, err } diff --git a/internal/items.go b/internal/items.go index d9fd66a..a84c840 100644 --- a/internal/items.go +++ b/internal/items.go @@ -7,26 +7,29 @@ import ( "path" "strings" + "github.com/datahearth/config-mapper/internal/configuration" + "github.com/datahearth/config-mapper/internal/git" + "github.com/datahearth/config-mapper/internal/misc" "github.com/fatih/color" "github.com/spf13/viper" ) type Items struct { - locations []OSLocation + locations []configuration.OSLocation storage string - repository RepositoryActions + repository git.RepositoryActions indexer Indexer } type ItemsActions interface { Action(action string) - AddItems(items []OSLocation) + AddItems(items []configuration.OSLocation) CleanUp(removedLines []string) error } -func NewItemsActions(items []OSLocation, storage string, repository RepositoryActions, indexer Indexer) ItemsActions { +func NewItemsActions(items []configuration.OSLocation, storage string, repository git.RepositoryActions, indexer Indexer) ItemsActions { if items == nil { - items = []OSLocation{} + items = []configuration.OSLocation{} } return &Items{ @@ -43,7 +46,7 @@ func (e *Items) Action(action string) { for i, l := range e.locations { var src string - storagePath, systemPath, err := configPaths(l, e.storage) + storagePath, systemPath, err := misc.ConfigPaths(l, e.storage) if err != nil { PrintError("[%d] failed to resolve item paths \"%v\": %v", i, l, err) continue @@ -103,18 +106,18 @@ func (e *Items) saveItem(src, dst string, index int) string { return "" } } - if err := copyFolder(src, dst, true); err != nil { + if err := misc.CopyFolder(src, dst, true); err != nil { PrintError("[%d] failed to save folder from \"%s\" to \"%s\": %v", index, src, dst, err) return "" } } else { - if err := copyFile(src, dst); err != nil { + if err := misc.CopyFile(src, dst); err != nil { PrintError("[%d] failed to save file from \"%s\" to \"%s\": %v", index, src, dst, err) return "" } } - p, err := absolutePath(e.storage) + p, err := misc.AbsolutePath(e.storage) if err != nil { PrintError("[%d] failed resolve absolute path from configuration storage: %v", index, err) return "" @@ -153,25 +156,25 @@ func (e *Items) loadItem(src, dst string, index int) { return } } - if err := copyFolder(src, dst, false); err != nil { + if err := misc.CopyFolder(src, dst, false); err != nil { PrintError("[%d] failed to load folder from \"%s\" to \"%s\": %v", index, src, dst, err) return } } else { - if err := copyFile(src, dst); err != nil { + if err := misc.CopyFile(src, dst); err != nil { PrintError("[%d] failed to load file from \"%s\" to \"%s\": %v", index, src, dst, err) return } } } -func (e *Items) AddItems(items []OSLocation) { +func (e *Items) AddItems(items []configuration.OSLocation) { e.locations = append(e.locations, items...) } func (e *Items) CleanUp(removedLines []string) error { for _, l := range removedLines { - path, err := absolutePath(fmt.Sprintf("%s/%s", e.storage, l)) + path, err := misc.AbsolutePath(fmt.Sprintf("%s/%s", e.storage, l)) if err != nil { return err } @@ -183,3 +186,7 @@ func (e *Items) CleanUp(removedLines []string) error { return nil } + +func PrintError(err string, values ...interface{}) { + color.Error.Write([]byte(color.RedString(err+"\n", values...))) +} diff --git a/internal/tools.go b/internal/misc/tools.go similarity index 78% rename from internal/tools.go rename to internal/misc/tools.go index 67a0e35..d60cb16 100644 --- a/internal/tools.go +++ b/internal/misc/tools.go @@ -1,19 +1,18 @@ -package mapper +package misc import ( "errors" "fmt" "io" - "io/ioutil" "os" "path" "runtime" "strings" - "github.com/fatih/color" + "github.com/datahearth/config-mapper/internal/configuration" ) -func absolutePath(p string) (string, error) { +func AbsolutePath(p string) (string, error) { finalPath := p if strings.Contains(finalPath, "~") { h, err := os.UserHomeDir() @@ -31,7 +30,8 @@ func absolutePath(p string) (string, error) { if strings.Contains(s, "$") { env := os.Getenv(s) if env == "" { - return "", ErrInvalidEnv + return "", errors.New("found invalid environment variable in path") + } pathPart = env } @@ -49,12 +49,12 @@ func getPaths(p string, l string) (string, string, error) { return "", "", errors.New("path incorrectly formatted. It requires \"source:destination\"") } - src, err := absolutePath(strings.Replace(paths[0], "$LOCATION", l, 1)) + src, err := AbsolutePath(strings.Replace(paths[0], "$LOCATION", l, 1)) if err != nil { return "", "", err } - dst, err := absolutePath(paths[1]) + dst, err := AbsolutePath(paths[1]) if err != nil { return "", "", err } @@ -62,7 +62,7 @@ func getPaths(p string, l string) (string, string, error) { return src, dst, nil } -func copyFile(src, dst string) error { +func CopyFile(src, dst string) error { s, err := os.Stat(src) if err != nil { return err @@ -91,7 +91,7 @@ func copyFile(src, dst string) error { return nil } -func configPaths(os OSLocation, location string) (string, string, error) { +func ConfigPaths(os configuration.OSLocation, location string) (string, string, error) { var src, dst string var err error @@ -115,14 +115,14 @@ func configPaths(os OSLocation, location string) (string, string, error) { var ignored map[string]bool -func copyFolder(src, dst string, checkIgnore bool) error { +func CopyFolder(src, dst string, checkIgnore bool) error { items, err := os.ReadDir(src) if err != nil { return err } if checkIgnore { - f, err := ioutil.ReadFile(fmt.Sprintf("%s/.ignore", src)) + f, err := os.ReadFile(fmt.Sprintf("%s/.ignore", src)) if err != nil && !errors.Is(err, io.EOF) { if !errors.Is(err, os.ErrNotExist) { return err @@ -158,21 +158,17 @@ func copyFolder(src, dst string, checkIgnore bool) error { if err := os.MkdirAll(dstItem, info.Mode()); err != nil { return err } - if err := copyFolder(srcItem, dstItem, false); err != nil { + if err := CopyFolder(srcItem, dstItem, false); err != nil { return err } continue } - if err := copyFile(srcItem, dstItem); err != nil { + if err := CopyFile(srcItem, dstItem); err != nil { return err } } return nil } - -func PrintError(err string, values ...interface{}) { - color.Error.Write([]byte(color.RedString(err+"\n", values...))) -} diff --git a/internal/pkgs.go b/internal/pkgs.go index f16a8cb..dd2a108 100644 --- a/internal/pkgs.go +++ b/internal/pkgs.go @@ -8,6 +8,7 @@ import ( "os/exec" "strings" + "github.com/datahearth/config-mapper/internal/configuration" "github.com/fatih/color" "github.com/spf13/viper" "gopkg.in/yaml.v3" @@ -21,7 +22,7 @@ var ( ErrAptNotAvailable = errors.New("aptitude is not available on your system") ) -func LoadPkgs(c PkgManagers) error { +func LoadPkgs(c configuration.PkgManagers) error { color.Blue("# Load folders into saved location") for _, pkg := range c.InstallationOrder { @@ -42,7 +43,7 @@ func LoadPkgs(c PkgManagers) error { return nil } -func SavePkgs(cfg Configuration) error { +func SavePkgs(cfg configuration.Configuration) error { color.Blue("# Save user installed packages") for _, pkg := range cfg.PackageManagers.InstallationOrder { @@ -60,7 +61,7 @@ func SavePkgs(cfg Configuration) error { return nil } -func SaveBrewPkgs(cfg Configuration) error { +func SaveBrewPkgs(cfg configuration.Configuration) error { if _, err := exec.LookPath("brew"); err != nil { return err }