Compare commits

...

5 Commits

Author SHA1 Message Date
DataHearth f85fc9d39c
fix(pkgs): update command building 2022-07-20 18:03:31 +02:00
DataHearth 8051912b35
feat(packages): add nala package manager 2022-07-20 13:33:04 +02:00
DataHearth 224754870d
fix(pkgs): add pkg manager validation check and parsing cli arguments 2022-07-20 11:35:19 +02:00
DataHearth 0f1019774d
fix(items): fix stdout when no path is available 2022-07-20 11:33:51 +02:00
DataHearth 42d2152f8e chore(template): update brew key 2022-07-17 23:17:37 +02:00
5 changed files with 126 additions and 46 deletions

View File

@ -29,8 +29,10 @@ folders:
linux: "$LOCATION/macos/.config:~/.config"
package-managers:
installation-order: ["homebrew"] # available: brew, pip (pip check also for pip3), cargo, apt, npm, go
homebrew:
# available: brew, pip (pip check also for pip3), cargo, apt, npm, go
installation-order:
- brew
brew:
- bat
- hexyl
- fd

View File

@ -69,9 +69,11 @@ func init() {
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")
loadCmd.Flags().StringSlice("exclude-pkg-managers", []string{}, "package managers to exclude (comma separated)")
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"))
viper.BindPFlag("exclude-pkg-managers", loadCmd.Flags().Lookup("exclude-pkg-managers"))
saveCmd.Flags().Bool("disable-files", false, "files will be ignored")
saveCmd.Flags().Bool("disable-folders", false, "folders will be ignored")

View File

@ -43,4 +43,5 @@ type PkgManagers struct {
Pip []string `mapstructure:"pip" yaml:"pip"`
Npm []string `mapstructure:"npm" yaml:"npm"`
Go []string `mapstructure:"go" yaml:"go"`
Nala []string `mapstructure:"nala" yaml:"nala"`
}

View File

@ -46,18 +46,18 @@ func NewItemsActions(items []configuration.OSLocation, storage string, repositor
//
// If the performed action is "save", it'll also write the `.index` file with all new items.
func (e *Items) Action(action string) {
color.Blue("# %s files and folders\n", action)
fmt.Printf("# %s files and folders\n", action)
newLines := []string{}
for i, l := range e.locations {
var src string
storagePath, systemPath, err := misc.ConfigPaths(l, e.storage)
if err != nil {
PrintError("[%d] failed to resolve item paths \"%v\": %v", i, l, err)
PrintError(" failed to resolve item paths \"%v\": %v", i, l, err)
continue
}
if storagePath == "" && systemPath == "" {
color.Blue("[%d] file doesn't have configuration path for current OS. Skipping...")
fmt.Printf("⛔ Skipping %s\n", src)
continue
}
@ -74,7 +74,7 @@ func (e *Items) Action(action string) {
e.loadItem(storagePath, systemPath, i)
}
color.Green("[%d] %s copied", i, src)
fmt.Printf("✔️ %s\n", src)
}
if action == "save" && !viper.GetBool("disable-index-update") {
@ -94,13 +94,13 @@ func (e *Items) Action(action string) {
// (E.g: /home/user/.config => .config)
func (e *Items) saveItem(src, dst string, index int) string {
if err := os.MkdirAll(path.Dir(dst), 0755); err != nil {
PrintError("[%d] failed to create directory architecture for destination path \"%s\": %v", index, path.Dir(dst), err)
PrintError(" failed to create directory architecture for destination path \"%s\": %v", index, path.Dir(dst), err)
return ""
}
s, err := os.Stat(src)
if err != nil {
PrintError("[%d] failed to check if source path is a folder \"%s\": %v", index, src, err)
PrintError(" failed to check if source path is a folder \"%s\": %v", index, src, err)
return ""
}
@ -109,7 +109,7 @@ func (e *Items) saveItem(src, dst string, index int) string {
s, err := os.Stat(dst)
if err != nil {
if !os.IsNotExist(err) {
PrintError("[%d] failed to check if destination folder \"%s\" exists: %v", index, dst, err)
PrintError(" failed to check if destination folder \"%s\" exists: %v", index, dst, err)
return ""
}
} else {
@ -118,29 +118,29 @@ func (e *Items) saveItem(src, dst string, index int) string {
// remove the destination if it exists. It cleans up the saved location from unused files
if err := os.RemoveAll(dst); err != nil {
PrintError("[%d] failed to truncate destination folder \"%s\": %v", index, dst, err)
PrintError(" failed to truncate destination folder \"%s\": %v", index, dst, err)
}
if err := os.Mkdir(dst, dstPerms); err != nil {
if !os.IsExist(err) {
PrintError("[%d] failed to create destination folder \"%s\": %v", index, dst, err)
PrintError(" failed to create destination folder \"%s\": %v", index, dst, err)
return ""
}
}
if err := misc.CopyFolder(src, dst, true); err != nil {
PrintError("[%d] failed to save folder from \"%s\" to \"%s\": %v", index, src, dst, err)
PrintError(" failed to save folder from \"%s\" to \"%s\": %v", index, src, dst, err)
return ""
}
} else {
if err := misc.CopyFile(src, dst); err != nil {
PrintError("[%d] failed to save file from \"%s\" to \"%s\": %v", index, src, dst, err)
PrintError(" failed to save file from \"%s\" to \"%s\": %v", index, src, dst, err)
return ""
}
}
p, err := misc.AbsolutePath(e.storage)
if err != nil {
PrintError("[%d] failed resolve absolute path from configuration storage: %v", index, err)
PrintError(" failed resolve absolute path from configuration storage: %v", index, err)
return ""
}
@ -153,13 +153,13 @@ func (e *Items) saveItem(src, dst string, index int) string {
// (meaning the item hasn't been saved) and prints the error in STDERR.
func (e *Items) loadItem(src, dst string, index int) {
if err := os.MkdirAll(path.Dir(dst), 0755); err != nil {
PrintError("[%d] failed to create directory architecture for destination path \"%s\": %v", index, path.Dir(dst), err)
PrintError(" failed to create directory architecture for destination path \"%s\": %v", index, path.Dir(dst), err)
return
}
s, err := os.Stat(src)
if err != nil {
PrintError("[%d] failed to check if source path is a folder \"%s\": %v", index, src, err)
PrintError(" failed to check if source path is a folder \"%s\": %v", index, src, err)
return
}
@ -168,7 +168,7 @@ func (e *Items) loadItem(src, dst string, index int) {
s, err := os.Stat(dst)
if err != nil {
if !os.IsNotExist(err) {
PrintError("[%d] failed to check if destination folder \"%s\" exists: %v", index, dst, err)
PrintError(" failed to check if destination folder \"%s\" exists: %v", index, dst, err)
return
}
} else {
@ -177,17 +177,17 @@ func (e *Items) loadItem(src, dst string, index int) {
if err := os.Mkdir(dst, dstPerms); err != nil {
if !os.IsExist(err) {
PrintError("[%d] failed to create destination folder \"%s\": %v", index, dst, err)
PrintError(" failed to create destination folder \"%s\": %v", index, dst, err)
return
}
}
if err := misc.CopyFolder(src, dst, false); err != nil {
PrintError("[%d] failed to load folder from \"%s\" to \"%s\": %v", index, src, dst, err)
PrintError(" failed to load folder from \"%s\" to \"%s\": %v", index, src, dst, err)
return
}
} else {
if err := misc.CopyFile(src, dst); err != nil {
PrintError("[%d] failed to load file from \"%s\" to \"%s\": %v", index, src, dst, err)
PrintError(" failed to load file from \"%s\" to \"%s\": %v", index, src, dst, err)
return
}
}

View File

@ -4,9 +4,10 @@ import (
"fmt"
"os"
"os/exec"
"runtime"
"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"
@ -14,9 +15,20 @@ import (
// InstallPackages install all packages from the configuration file by installation order
func InstallPackages(c configuration.PkgManagers) error {
color.Blue("\n# Installing packages")
pkgManagers := map[string]bool{}
for _, pkgManager := range viper.GetStringSlice("exclude-pkg-managers") {
pkgManagers[pkgManager] = true
}
fmt.Println()
for _, pkgManager := range c.InstallationOrder {
fmt.Printf("# Installing %s packages\n", pkgManager)
if _, ok := pkgManagers[pkgManager]; ok {
fmt.Printf("⛔ Skipping %s packages\n", pkgManager)
fmt.Println()
continue
}
var pkgs []string
switch pkgManager {
case "brew":
@ -31,53 +43,116 @@ func InstallPackages(c configuration.PkgManagers) error {
pkgs = c.Pip
case "go":
pkgs = c.Go
case "nala":
pkgs = c.Nala
default:
PrintError("package manager not supported: %s", pkgManager)
PrintError("package manager not supported: %s\n", pkgManager)
continue
}
if _, err := exec.LookPath(pkgManager); err != nil {
// * pip might not be available on the system but pip3 is
if pkgManager == "pip" {
if _, err := exec.LookPath("pip3"); err != nil {
return fmt.Errorf("%s and pip3 are not available on your system", pkgManager)
PrintError("%s and pip3 are not available on your system\n", pkgManager)
continue
}
pkgManager = "pip3"
} else {
return fmt.Errorf("%s is not available on your system", pkgManager)
PrintError("%s is not available on your system\n", pkgManager)
continue
}
}
// * for some reason, apt binary is available on darwin. Exclude it to avoid errors
if pkgManager == "apt" && runtime.GOOS == "darwin" {
PrintError("%s is not available on your system\n", pkgManager)
continue
}
if len(pkgs) == 0 {
fmt.Printf("%s: nothing to do\n", pkgManager)
return nil
fmt.Printf("✔️ nothing to do\n\n")
continue
}
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
commands := []*exec.Cmd{}
// * package managers requiring sudo permission
if pkgManager == "apt" || pkgManager == "nala" {
commands = append(commands, buildDefaultCommand([]string{"sudo", pkgManager, "install", "-y"}, pkgs, v))
} else if pkgManager == "cargo" {
commands = buildCargoCommand(pkgs, v)
} else {
spinner.Start()
commands = append(commands, buildDefaultCommand([]string{pkgManager, "install"}, pkgs, v))
}
if err := cmd.Run(); err != nil {
spinner.Stop()
PrintError("\n%s command failed: %v", pkgManager, err)
return err
}
for i, cmd := range commands {
spinner := wow.New(os.Stdout, spin.Get(spin.Dots3), " Installing...")
if !v {
spinner.Start()
}
if err := cmd.Run(); err != nil {
if v {
PrintError(err.Error())
} else {
msg := fmt.Sprintf(" %s", cmd.Args)
if i == len(commands)-1 {
msg = fmt.Sprintf("%s\n", msg)
}
spinner.PersistWith(spin.Spinner{Frames: []string{"❌"}}, msg)
}
continue
}
if v {
// todo: find a way to clear spinner when done
spinner.Stop()
if !v {
// msg := fmt.Sprintf(" %s %s", color.GreenString("Success\t"), cmd.Args)
msg := fmt.Sprintf(" %s", cmd.Args)
if i == len(commands)-1 {
msg = fmt.Sprintf("%s\n", msg)
}
spinner.PersistWith(spin.Spinner{Frames: []string{"✔️"}}, msg)
}
}
color.Green("\n%s Packages intalled succesfully !", pkgManager)
}
return nil
}
func buildCargoCommand(packages []string, verbose bool) []*exec.Cmd {
commands := []*exec.Cmd{}
cmd := exec.Command("cargo", "install")
for _, pkg := range packages {
if strings.Contains(pkg, " ") {
customCmd := exec.Command("cargo", "install")
customCmd.Args = append(cmd.Args, strings.Split(pkg, " ")...)
if verbose {
customCmd.Stderr = os.Stderr
customCmd.Stdout = os.Stdout
}
commands = append(commands, customCmd)
} else {
cmd.Args = append(cmd.Args, pkg)
}
}
if verbose {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
}
if len(cmd.Args) > 2 {
commands = append(commands, cmd)
}
return commands
}
func buildDefaultCommand(command, packages []string, verbose bool) *exec.Cmd {
cmd := exec.Command(command[0], command[1:]...)
cmd.Args = append(cmd.Args, packages...)
if verbose {
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
}
return cmd
}