github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/util/ui/ui_for_push.go (about)

     1  package ui
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/liamawhite/cli-with-i18n/types"
    11  
    12  	"github.com/fatih/color"
    13  )
    14  
    15  var ErrValueMissmatch = errors.New("values provided were of different types")
    16  
    17  type Change struct {
    18  	Header       string
    19  	CurrentValue interface{}
    20  	NewValue     interface{}
    21  	HiddenValue  bool
    22  }
    23  
    24  // DisplayChangesForPush will display the set of changes via
    25  // DisplayChangeForPush in the order given.
    26  func (ui *UI) DisplayChangesForPush(changeSet []Change) error {
    27  	if len(changeSet) == 0 {
    28  		return nil
    29  	}
    30  
    31  	var columnWidth int
    32  	for _, change := range changeSet {
    33  		if width := wordSize(ui.TranslateText(change.Header)); width > columnWidth {
    34  			columnWidth = width
    35  		}
    36  	}
    37  
    38  	for _, change := range changeSet {
    39  		padding := columnWidth - wordSize(ui.TranslateText(change.Header)) + 3
    40  		err := ui.DisplayChangeForPush(change.Header, padding, change.HiddenValue, change.CurrentValue, change.NewValue)
    41  		if err != nil {
    42  			return err
    43  		}
    44  	}
    45  
    46  	return nil
    47  }
    48  
    49  // DisplayChangeForPush will display the header and old/new value with the
    50  // appropriately red/green minuses and pluses.
    51  func (ui *UI) DisplayChangeForPush(header string, stringTypePadding int, hiddenValue bool, originalValue interface{}, newValue interface{}) error {
    52  	ui.terminalLock.Lock()
    53  	defer ui.terminalLock.Unlock()
    54  
    55  	originalType := reflect.ValueOf(originalValue).Type()
    56  	newType := reflect.ValueOf(newValue).Type()
    57  	if originalType != newType {
    58  		return ErrValueMissmatch
    59  	}
    60  
    61  	offset := strings.Repeat(" ", stringTypePadding)
    62  
    63  	switch oVal := originalValue.(type) {
    64  	case int:
    65  		nVal := newValue.(int)
    66  		ui.displayDiffForInt(offset, header, oVal, nVal)
    67  	case types.NullInt:
    68  		nVal := newValue.(types.NullInt)
    69  		ui.displayDiffForNullInt(offset, header, oVal, nVal)
    70  	case string:
    71  		nVal := newValue.(string)
    72  		ui.displayDiffForString(offset, header, hiddenValue, oVal, nVal)
    73  	case []string:
    74  		nVal := newValue.([]string)
    75  		if len(oVal) == 0 && len(nVal) == 0 {
    76  			return nil
    77  		}
    78  
    79  		ui.displayDiffForStrings(offset, header, oVal, nVal)
    80  	case map[string]string:
    81  		nVal := newValue.(map[string]string)
    82  		if len(oVal) == 0 && len(nVal) == 0 {
    83  			return nil
    84  		}
    85  
    86  		ui.displayDiffForMapStringString(offset, header, oVal, nVal)
    87  	default:
    88  		panic(fmt.Sprintf("diff display does not have case for '%s'", header))
    89  	}
    90  	return nil
    91  }
    92  
    93  func (ui UI) displayDiffForInt(offset string, header string, oldValue int, newValue int) {
    94  	if oldValue != newValue {
    95  		formattedOld := fmt.Sprintf("- %s%s%d", ui.TranslateText(header), offset, oldValue)
    96  		formattedNew := fmt.Sprintf("+ %s%s%d", ui.TranslateText(header), offset, newValue)
    97  
    98  		if oldValue != 0 {
    99  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedOld, color.New(color.FgRed)))
   100  		}
   101  		fmt.Fprintln(ui.Out, ui.modifyColor(formattedNew, color.New(color.FgGreen)))
   102  	} else {
   103  		fmt.Fprintf(ui.Out, "  %s%s%d\n", ui.TranslateText(header), offset, oldValue)
   104  	}
   105  }
   106  
   107  func (ui UI) displayDiffForMapStringString(offset string, header string, oldMap map[string]string, newMap map[string]string) {
   108  	var oldKeys []string
   109  	for key := range oldMap {
   110  		oldKeys = append(oldKeys, key)
   111  	}
   112  
   113  	var newKeys []string
   114  	for key := range newMap {
   115  		newKeys = append(newKeys, key)
   116  	}
   117  
   118  	sortedKeys := sortedUniqueArray(oldKeys, newKeys)
   119  
   120  	fmt.Fprintf(ui.Out, "  %s\n", ui.TranslateText(header))
   121  	for _, key := range sortedKeys {
   122  		newVal, ok := newMap[key]
   123  		if !ok {
   124  			formattedOld := fmt.Sprintf("-   %s", key)
   125  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedOld, color.New(color.FgRed)))
   126  			continue
   127  		}
   128  		oldVal, ok := oldMap[key]
   129  		if !ok {
   130  			formattedNew := fmt.Sprintf("+   %s", key)
   131  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedNew, color.New(color.FgGreen)))
   132  			continue
   133  		}
   134  
   135  		if oldVal == newVal {
   136  			fmt.Fprintf(ui.Out, "    %s\n", key)
   137  		} else {
   138  			formattedOld := fmt.Sprintf("-   %s", key)
   139  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedOld, color.New(color.FgRed)))
   140  			formattedNew := fmt.Sprintf("+   %s", key)
   141  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedNew, color.New(color.FgGreen)))
   142  		}
   143  	}
   144  }
   145  
   146  func (ui UI) displayDiffForNullInt(offset string, header string, oldValue types.NullInt, newValue types.NullInt) {
   147  	if oldValue != newValue {
   148  		formattedOld := fmt.Sprintf("- %s%s%d", ui.TranslateText(header), offset, oldValue.Value)
   149  		formattedNew := fmt.Sprintf("+ %s%s%d", ui.TranslateText(header), offset, newValue.Value)
   150  
   151  		if oldValue.IsSet {
   152  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedOld, color.New(color.FgRed)))
   153  		}
   154  		fmt.Fprintln(ui.Out, ui.modifyColor(formattedNew, color.New(color.FgGreen)))
   155  	} else {
   156  		fmt.Fprintf(ui.Out, "  %s%s%d\n", ui.TranslateText(header), offset, oldValue.Value)
   157  	}
   158  }
   159  
   160  func (ui UI) displayDiffForString(offset string, header string, hiddenValue bool, oVal string, nVal string) {
   161  	if oVal != nVal {
   162  		var formattedOld, formattedNew string
   163  		if hiddenValue {
   164  			formattedOld = fmt.Sprintf("- %s%s%s", ui.TranslateText(header), offset, RedactedValue)
   165  			formattedNew = fmt.Sprintf("+ %s%s%s", ui.TranslateText(header), offset, RedactedValue)
   166  		} else {
   167  			formattedOld = fmt.Sprintf("- %s%s%s", ui.TranslateText(header), offset, oVal)
   168  			formattedNew = fmt.Sprintf("+ %s%s%s", ui.TranslateText(header), offset, nVal)
   169  		}
   170  
   171  		if oVal != "" {
   172  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedOld, color.New(color.FgRed)))
   173  		}
   174  		if nVal != "" {
   175  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedNew, color.New(color.FgGreen)))
   176  		}
   177  	} else {
   178  		if hiddenValue {
   179  			fmt.Fprintf(ui.Out, "  %s%s%s\n", ui.TranslateText(header), offset, RedactedValue)
   180  		} else {
   181  			fmt.Fprintf(ui.Out, "  %s%s%s\n", ui.TranslateText(header), offset, oVal)
   182  		}
   183  	}
   184  }
   185  
   186  func (ui UI) displayDiffForStrings(offset string, header string, oldList []string, newList []string) {
   187  	fmt.Fprintf(ui.Out, "  %s\n", ui.TranslateText(header))
   188  
   189  	fullList := sortedUniqueArray(oldList, newList)
   190  	for _, item := range fullList {
   191  		inOld := existsIn(item, oldList)
   192  		inNew := existsIn(item, newList)
   193  
   194  		if inOld && inNew {
   195  			fmt.Fprintf(ui.Out, "    %s\n", item)
   196  		} else if inOld {
   197  			formattedOld := fmt.Sprintf("-   %s", item)
   198  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedOld, color.New(color.FgRed)))
   199  		} else {
   200  			formattedNew := fmt.Sprintf("+   %s", item)
   201  			fmt.Fprintln(ui.Out, ui.modifyColor(formattedNew, color.New(color.FgGreen)))
   202  		}
   203  	}
   204  }
   205  
   206  func existsIn(str string, ary []string) bool {
   207  	for _, val := range ary {
   208  		if val == str {
   209  			return true
   210  		}
   211  	}
   212  	return false
   213  }
   214  
   215  func sortedUniqueArray(ary1 []string, ary2 []string) []string {
   216  	uniq := append([]string{}, ary1...)
   217  
   218  	for _, str := range ary2 {
   219  		if !existsIn(str, uniq) {
   220  			uniq = append(uniq, str)
   221  		}
   222  	}
   223  
   224  	sort.Strings(uniq)
   225  	return uniq
   226  }