Skip to content

Commit

Permalink
Implement basic dryrun output
Browse files Browse the repository at this point in the history
  • Loading branch information
evanpurkhiser committed Aug 6, 2019
1 parent 6e9fa34 commit ebda609
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 39 deletions.
31 changes: 21 additions & 10 deletions cmd/dots/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/spf13/cobra"

"go.evanpurkhiser.com/dots/installer"
"go.evanpurkhiser.com/dots/output"
"go.evanpurkhiser.com/dots/resolver"
)

Expand All @@ -12,25 +13,35 @@ var installCmd = cobra.Command{
Short: "Install and compile dotfiles from sources",
RunE: func(cmd *cobra.Command, args []string) error {
forceReInstall, _ := cmd.Flags().GetBool("reinstall")
verbose, _ := cmd.Flags().GetBool("verbose")
dryRun, _ := cmd.Flags().GetBool("dry-run")
info, _ := cmd.Flags().GetBool("info")

dotfiles := resolver.ResolveDotfiles(*sourceConfig, *sourceLockfile).Filter(args)
prepared := installer.PrepareDotfiles(dotfiles, *sourceConfig)

if dryRun {
// TODO: Do logging output
return nil
}

config := installer.InstallConfig{
installConfig := installer.InstallConfig{
SourceConfig: sourceConfig,
SourceLockfile: sourceLockfile,
ForceReinstall: forceReInstall,
}

installed := installer.InstallDotfiles(prepared, config)
installer.RunInstallScripts(prepared, config)
installer.FinalizeInstall(installed, config)
installLogger := output.New(output.Config{
SourceConfig: *sourceConfig,
InstallConfig: installConfig,
PreparedInstall: prepared,
IsVerbose: verbose,
IsInfo: info || verbose || dryRun,
})

if dryRun {
installLogger.DryrunInstall()
return nil
}

installed := installer.InstallDotfiles(prepared, installConfig)
installer.RunInstallScripts(prepared, installConfig)
installer.FinalizeInstall(installed, installConfig)

// TODO Needs some error handling clenaup

Expand All @@ -44,7 +55,7 @@ func init() {
flags.SortFlags = false

flags.BoolP("reinstall", "r", false, "forces execution of all installation scripts")
flags.BoolP("dry-run", "n", false, "do not mutate any dotfiles, implies info")
flags.BoolP("info", "i", false, "prints install operation details")
flags.BoolP("verbose", "v", false, "prints debug data, implies info")
flags.BoolP("dry-run", "n", false, "do not mutate any dotfiles, implies info")
}
29 changes: 0 additions & 29 deletions output/fmt.go

This file was deleted.

149 changes: 149 additions & 0 deletions output/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package output

import (
"fmt"
"strings"

"github.com/fatih/color"
"go.evanpurkhiser.com/dots/config"
"go.evanpurkhiser.com/dots/installer"
)

// Config is a object used to configure the output logger.
type Config struct {
SourceConfig config.SourceConfig
InstallConfig installer.InstallConfig
PreparedInstall installer.PreparedInstall
IsVerbose bool
IsInfo bool
}

// New creates a output logger given a configuration.
func New(config Config) *Output {
logger := &Output{
Config: config,
}

// Get the max length of the groups
maxDotfileLength := 0
for _, d := range config.PreparedInstall.Dotfiles {
if logger.shouldLogDotfile(d) && len(d.Path) > maxDotfileLength {
maxDotfileLength = len(d.Path)
}
}
logger.maxDotfileLength = maxDotfileLength

return logger
}

// Output represents a service object used to output logging information about
// dotfile installation operations.
type Output struct {
Config
maxDotfileLength int
}

// shouldLogDotfile indicates if the dotfile should be logged given the current
// Output configuration.
func (l *Output) shouldLogDotfile(dotfile *installer.PreparedDotfile) bool {
return dotfile.PrepareError != nil ||
dotfile.IsChanged() ||
l.InstallConfig.ForceReinstall
}

// DryrunInstall outputs the logging of a dryrun of the prepared dotfiles
func (l *Output) DryrunInstall() {
l.InstallInfo()
fmt.Println()

for _, dotfile := range l.PreparedInstall.Dotfiles {
l.DotfileInfo(dotfile)
}

fmt.Println()
}

// InstallInfo outputs details about the pending installation. Output is only
// performed when verbosity is enabled.
func (l *Output) InstallInfo() {
if !l.IsVerbose {
return
}

fmt.Printf(
"%s %s added %s removed %s modified %s error\n",
color.HiBlackString("legend:"),
color.HiGreenString("◼️"),
color.HiYellowString("◼️"),
color.HiBlueString("◼️"),
color.HiRedString("◼️"),
)

fmt.Printf("%s %s\n", color.HiBlackString("source:"), l.SourceConfig.SourcePath)
fmt.Printf("%s %s\n", color.HiBlackString("target:"), l.SourceConfig.InstallPath)
}

// DotfileInfo outputs information about a single prepared dotfile. Will not
// output anything without IsInfo. When IsVerbose is enabled additional
// information about the prepared dotfile will be included.
func (l *Output) DotfileInfo(dotfile *installer.PreparedDotfile) {
if !l.IsInfo {
return
}

if !l.shouldLogDotfile(dotfile) {
return
}

indicatorColor := color.New()
indicator := "◼️"

switch {
case dotfile.PrepareError != nil:
indicatorColor.Add(color.FgRed)
case dotfile.IsNew:
indicatorColor.Add(color.FgHiGreen)
case dotfile.Removed:
indicatorColor.Add(color.FgHiYellow)
case dotfile.IsChanged():
indicatorColor.Add(color.FgBlue)
default:
indicatorColor.Add(color.FgHiBlack)
indicator = "-"
}

fmt.Printf(" %s ", indicatorColor.Sprint(indicator))

group := ""
if len(dotfile.Sources) == 1 {
group = dotfile.Sources[0].Group
} else {
groups := make([]string, 0, len(dotfile.Sources))

for _, source := range dotfile.Sources {
groups = append(groups, source.Group)
}

group = strings.Join(groups, " ")
}

group = fmt.Sprintf(
"%s %s %s",
color.HiBlackString("["),
color.HiWhiteString(group),
color.HiBlackString("]"),
)

output := fmt.Sprintf("%%-%ds %%s\n", l.maxDotfileLength+1)
fmt.Printf(output, dotfile.Path, group)

if dotfile.PrepareError != nil {
fmt.Printf(" %s", color.RedString(dotfile.PrepareError.Error()))
}

if !l.IsVerbose {
return
}

// TODO: Implement all verbosity outputs here
}

0 comments on commit ebda609

Please sign in to comment.