feat(pkgs): add more package manager

This commit is contained in:
DataHearth 2022-07-10 12:35:01 +02:00
parent f00d7c0288
commit f576eec3c3
5 changed files with 77 additions and 158 deletions

View File

@ -10,7 +10,7 @@ storage:
basic-auth:
username: USERNAME
# * NOTE: if you're having trouble with error "authentication required", you should maybe use a token access
# * In some cases, it's due to 2FA authentication enabled on the git hosting provided
# * In some cases, it's due to 2FA authentication enabled on the git hosting provider
password: TOKEN
# * by default, if ssh dict is set with its keys filled, I'll try to clone with SSH
ssh:
@ -19,7 +19,7 @@ storage:
passphrase: PASSPHRASE
# NOTE: the $LOCATION if refering to the "storage.location" path. It'll be replaced automatically
# The left part of ":" is your repository location and right part when it should be on your system
# The left part of ":" is your repository location and right part where it should be located on your system
files:
- darwin: "$LOCATION/macos/.zshrc:~/.zshrc"
linux: "$LOCATION/linux/.zshrc:~/.zshrc"
@ -29,7 +29,7 @@ folders:
linux: "$LOCATION/macos/.config:~/.config"
package-managers:
installation-order: ["homebrew"]
installation-order: ["homebrew"] # available: brew, pip (pip check also for pip3), cargo, apt, npm, go
homebrew:
- bat
- hexyl
@ -46,5 +46,3 @@ package-managers:
- nmap
- pinentry
- zsh
apt-get: []

View File

@ -80,7 +80,7 @@ config-mapper save
All defined files and folders will be copied inside your repository.
If you want to exclude one part of your configuration file (files, folders), you can use these flags to ignore them `--disable-files` `--disable-folders`. Note, package managers are disable by default. You can enable this option using the `--pkgs` flag.
If you want to exclude one part of your configuration file (files, folders), you can use these flags to ignore them `--disable-files` `--disable-folders`.
You can also exclude files and folders from a given directory with a `.gitignore` like file named `.ignore`. Put it in the root directory of an included folder and add relative path to exclude (does not support glob for now). E.g:
@ -106,8 +106,6 @@ foo/bar
egg
```
If `homebrew` is provided in the `installation-order` (default: `["apt", "homebrew"]`), it will override the `homebrew` field with all user installed packages (`brew leaves --installed-on-request`). The same principle will be implemented with `Advanced Package Tool`.
template for your configuration:
```yaml
@ -122,8 +120,9 @@ folders:
linux: "$LOCATION/macos/.config:~/.config"
package-managers:
installation-order: ["homebrew"]
homebrew:
installation-order:
- brew
brew:
- bat
- hexyl
- fd
@ -141,6 +140,10 @@ package-managers:
- zsh
apt-get: []
pip: []
cargo: []
pip: []
go: []
```
### Load your configuration onto the system

View File

@ -54,6 +54,7 @@ func init() {
rootCmd.AddCommand(initCmd)
rootCmd.AddCommand(loadCmd)
rootCmd.AddCommand(saveCmd)
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "STDOUT will be more verbose")
rootCmd.PersistentFlags().StringP("configuration-file", "c", "", "location of configuration file")
rootCmd.PersistentFlags().String("ssh-user", "", "SSH username to retrieve configuration file")
@ -74,13 +75,11 @@ func init() {
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.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"))
@ -123,13 +122,6 @@ func save(cmd *cobra.Command, args []string) {
el.Action("save")
if viper.GetBool("save-enable-pkgs") {
if err := mapper.SavePkgs(c); err != nil {
mapper.PrintError(err.Error())
os.Exit(1)
}
}
if err := el.CleanUp(indexer.RemovedLines()); err != nil {
mapper.PrintError("failed to clean repository: %v\n", err)
os.Exit(1)
@ -178,7 +170,7 @@ func load(cmd *cobra.Command, args []string) {
el.Action("load")
if viper.GetBool("load-enable-pkgs") {
if err := mapper.LoadPkgs(c.PackageManagers); err != nil {
if err := mapper.InstallPackages(c.PackageManagers); err != nil {
mapper.PrintError(err.Error())
os.Exit(1)
}

View File

@ -37,6 +37,10 @@ type Ssh struct {
type PkgManagers struct {
InstallationOrder []string `mapstructure:"installation-order" yaml:"installation-order"`
Homebrew []string `mapstructure:"homebrew" yaml:"homebrew"`
Aptitude []string `mapstructure:"apt-get" yaml:"apt-get"`
Brew []string `mapstructure:"brew" yaml:"brew"`
Apt []string `mapstructure:"apt" yaml:"apt"`
Cargo []string `mapstructure:"cargo" yaml:"cargo"`
Pip []string `mapstructure:"pip" yaml:"pip"`
Npm []string `mapstructure:"npm" yaml:"npm"`
Go []string `mapstructure:"go" yaml:"go"`
}

View File

@ -1,161 +1,83 @@
package mapper
import (
"errors"
"fmt"
"os"
"os/exec"
"strings"
"github.com/datahearth/config-mapper/internal/configuration"
"github.com/fatih/color"
"github.com/gernest/wow"
"github.com/gernest/wow/spin"
"github.com/spf13/viper"
"gopkg.in/yaml.v3"
)
var (
ErrFailedInstallation = errors.New("failed to install some packages. Please, checkout STDERR for more information")
ErrFailedSaving = errors.New("failed to save some packages. Please, checkout STDERR for more information")
ErrBrewNotAvailable = errors.New("homebrew is not available on your system")
ErrAptNotAvailable = errors.New("aptitude is not available on your system")
)
// LoadPkgs triggers related functions with passed order
func LoadPkgs(c configuration.PkgManagers) error {
// InstallPackages install all packages from the configuration file by installation order
func InstallPackages(c configuration.PkgManagers) error {
color.Blue("\n# Installing packages")
for _, pkg := range c.InstallationOrder {
switch pkg {
case "homebrew":
if err := installBrewPkgs(c.Homebrew); err != nil {
PrintError(err.Error())
return ErrFailedInstallation
}
for _, pkgManager := range c.InstallationOrder {
var pkgs []string
switch pkgManager {
case "brew":
pkgs = c.Brew
case "apt":
if err := installAptPkgs(c.Aptitude); err != nil {
PrintError(err.Error())
return ErrFailedInstallation
pkgs = c.Apt
case "cargo":
pkgs = c.Cargo
case "npm":
pkgs = c.Npm
case "pip":
pkgs = c.Pip
case "go":
pkgs = c.Go
default:
PrintError("package manager not supported: %s", pkgManager)
continue
}
if _, err := exec.LookPath(pkgManager); err != nil {
if pkgManager == "pip" {
if _, err := exec.LookPath("pip3"); err != nil {
return fmt.Errorf("%s and pip3 are not available on your system", pkgManager)
}
pkgManager = "pip3"
} else {
return fmt.Errorf("%s is not available on your system", pkgManager)
}
}
}
return nil
}
// SavePkgs triggers related functions with passed order
func SavePkgs(cfg configuration.Configuration) error {
color.Blue("# Saving user installed packages")
for _, pkg := range cfg.PackageManagers.InstallationOrder {
switch pkg {
case "homebrew":
if err := saveBrewPkgs(cfg); err != nil {
PrintError(err.Error())
return ErrFailedSaving
}
case "apt":
fmt.Println("implemented soon!")
if len(pkgs) == 0 {
fmt.Printf("%s: nothing to do\n", pkgManager)
return nil
}
cmd := exec.Command(pkgManager, "install")
cmd.Args = append(cmd.Args, pkgs...)
color.Blue("\n## Installing %s packages", pkgManager)
spinner := wow.New(os.Stdout, spin.Get(spin.Dots3), " Running...")
v := viper.GetBool("verbose")
if v {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
} else {
spinner.Start()
}
if err := cmd.Run(); err != nil {
spinner.Stop()
PrintError("\n%s command failed: %v", pkgManager, err)
return err
}
if v {
// todo: find a way to clear spinner when done
spinner.Stop()
}
color.Green("\n%s Packages intalled succesfully !", pkgManager)
}
return nil
}
// saveBrewPkgs gather user installed packages by running `brew leaves --installed-on-request`.
// It captures the output, parse it and save it into the configuration.
func saveBrewPkgs(cfg configuration.Configuration) error {
if _, err := exec.LookPath("brew"); err != nil {
return err
}
color.Blue("\n## Saving Homebrew packages")
o, err := exec.Command("brew", "leaves", "--installed-on-request").Output()
if err != nil {
return err
}
pkgs := strings.Split(string(o), "\n")
cfg.PackageManagers.Homebrew = append([]string{}, pkgs[:len(pkgs)-1]...)
b, err := yaml.Marshal(cfg)
if err != nil {
return err
}
if err := os.WriteFile(viper.GetString("configuration-file"), b, 0755); err != nil {
return err
}
color.Green("Packages saved succesfully !")
return nil
}
// installBrewPkgs installs homebrew packages by passing them to homebrew's CLI.
// STDERR and STDOUT are captured if verbose flag is passed.
func installBrewPkgs(pkgs []string) error {
if _, err := exec.LookPath("brew"); err != nil {
return ErrBrewNotAvailable
}
if len(pkgs) == 0 {
fmt.Println("homebrew: nothing to do")
return nil
}
cmd := exec.Command("brew", "install")
cmd.Args = append(cmd.Args, pkgs...)
color.Blue("\n## Installing Homebrew packages")
spinner := wow.New(os.Stdout, spin.Get(spin.Dots3), " Running...")
v := viper.GetBool("verbose")
if v {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
} else {
spinner.Start()
}
if err := cmd.Run(); err != nil {
spinner.Stop()
PrintError("brew command failed: %v", err)
return err
}
if v {
// todo: find a way to clear spinner when done
spinner.Stop()
}
color.Green("\nPackages intalled succesfully !")
return nil
}
// installAptPkgs installs all provided "apt" packages by passing them to the Advanced Package Tool's CLI
func installAptPkgs(pkgs []string) error {
if _, err := exec.LookPath("apt"); err != nil {
return ErrAptNotAvailable
}
if len(pkgs) == 0 {
fmt.Println("apt: nothing to do")
return nil
}
cmd := exec.Command("sudo", "apt", "install")
cmd.Args = append(cmd.Args, pkgs...)
color.Blue("\n## Installing apt packages")
if err := cmd.Run(); err != nil {
PrintError("apt command failed: %v", err)
return err
}
color.Green("Packages intalled succesfully !")
return nil
}