diff --git a/actions/table.go b/actions/table.go index 0342c832..a0cace6d 100644 --- a/actions/table.go +++ b/actions/table.go @@ -11,6 +11,9 @@ import ( "strings" ) +// define max column width +var fmtmax = 30 + // PrintNoteFields Print mismatching fields in the note comparison result. func PrintNoteFields(writer io.Writer, header string, noteComparisons map[string]map[string]note.FieldComparison, printComparison bool, result *system.JPNotes) { // initialise @@ -29,7 +32,6 @@ func PrintNoteFields(writer io.Writer, header string, noteComparisons map[string noteList := []system.JPNotesLine{} colorScheme := getColorScheme() - // sort output sortkeys := sortNoteComparisonsOutput(noteComparisons) @@ -73,6 +75,7 @@ func PrintNoteFields(writer io.Writer, header string, noteComparisons map[string } noteLine.ActValue = &pAct pExp = strings.Replace(comparison.ExpectedValueJS, "\t", " ", -1) + tableColumns := make(map[string]string) if printComparison { // verify if system.IsFlagSet("show-non-compliant") && (strings.Contains(compliant, "yes") || strings.Contains(compliant, "-")) { @@ -80,11 +83,12 @@ func PrintNoteFields(writer io.Writer, header string, noteComparisons map[string continue } colFormat, colCompliant = colorPrint(format, compliant, colorScheme) - fmt.Fprintf(writer, colFormat, noteField, comparison.ReflectMapKey, pExp, override, pAct, colCompliant) + tableColumns = map[string]string{"type": "verify", "colFormat": colFormat, "note": noteField, "parameter": comparison.ReflectMapKey, "expected": pExp, "override": override, "actual": pAct, "compliant": colCompliant} } else { // simulate - fmt.Fprintf(writer, format, comparison.ReflectMapKey, pAct, pExp, override, comment) + tableColumns = map[string]string{"type": "simulate", "colFormat": format, "parameter": comparison.ReflectMapKey, "actual": pAct, "expected": pExp, "override": override, "comment": comment} } + printTableRow(writer, tableColumns) noteLine = collectMRO(noteLine, compliant, noteID, noteComparisons, comparison, pExp, override, printComparison, comment, footnote, pAct) noteList = append(noteList, noteLine) } @@ -335,6 +339,7 @@ func setWidthOfColums(compare note.FieldComparison, c1, c2, c3, c4 int) (int, in if len(compare.ReflectMapKey) != 0 { if compare.ReflectFieldName == "OverrideParams" && len(compare.ActualValueJS) > c1 { c1 = len(compare.ActualValueJS) + c1, c3, c4 = chkMaxWidthOfColums([]int{c1, c3, c4}) return c1, c2, c3, c4 } if len(compare.ReflectMapKey) > c2 { @@ -347,9 +352,21 @@ func setWidthOfColums(compare note.FieldComparison, c1, c2, c3, c4 int) (int, in c4 = len(compare.ActualValueJS) } } + c1, c3, c4 = chkMaxWidthOfColums([]int{c1, c3, c4}) return c1, c2, c3, c4 } +// chkMaxWidthOfColums limits the width of the columns for verify and simulate +// to a defined value. Content of columns need to be wrapped +func chkMaxWidthOfColums(fmts []int) (int, int, int) { + for w, width := range fmts { + if width > fmtmax { + fmts[w] = fmtmax + } + } + return fmts[0], fmts[1], fmts[2] +} + // getColorScheme reads the color scheme from CLI flag or from saptune // sysconfig file or sets default func getColorScheme() string { @@ -450,3 +467,92 @@ func colorFormating(colCmpl, colNonCmpl, txt, compliant string) string { } return colFormat } + +// printTableRow prints one row of the table +// If needed the lines of the override column, the expected column and the +// actual column will be wrapped after 'fmtmax' characters +// if override exists, expected == override, so compare of width of expected and +// actual column is sufficient +func printTableRow(writer io.Writer, rowElements map[string]string) { + wrappedActual := system.WrapTxt(rowElements["actual"], fmtmax) + wrappedExpected := system.WrapTxt(rowElements["expected"], fmtmax) + wrappedOverride := system.WrapTxt(rowElements["override"], fmtmax) + linesAct := len(wrappedActual) + linesExp := len(wrappedExpected) + linesOver := len(wrappedOverride) + if linesAct == 1 && linesExp == 1 && linesOver == 1 { + if rowElements["type"] == "verify" { + fmt.Fprintf(writer, rowElements["colFormat"], rowElements["note"], rowElements["parameter"], rowElements["expected"], rowElements["override"], rowElements["actual"], rowElements["compliant"]) + } else { + // simulate + fmt.Fprintf(writer, rowElements["colFormat"], rowElements["parameter"], rowElements["actual"], rowElements["expected"], rowElements["override"], rowElements["comment"]) + } + return + } + wrappedElements := map[string][]string{"wrappedActual": wrappedActual, "wrappedExpected": wrappedExpected, "wrappedOverride": wrappedOverride} + printWrappedRow(writer, wrappedElements, rowElements) +} + +// printWrappedRow prints the wrapped columns of one verify output row +// twist - true - compare order ACT, EXP +// twist - false - compare order EXP, ACT +// if override exists, expected == override +func printWrappedRow(writer io.Writer, wrappedElem map[string][]string, rowElements map[string]string) { + var wrappedA, wrappedB, wrappedC []string + firstLine := true + twist := false + + if len(wrappedElem["wrappedActual"]) >= len(wrappedElem["wrappedExpected"]) { + twist = true + } + if twist { + wrappedA = wrappedElem["wrappedActual"] + wrappedB = wrappedElem["wrappedExpected"] + } else { + wrappedA = wrappedElem["wrappedExpected"] + wrappedB = wrappedElem["wrappedActual"] + } + wrappedC = wrappedElem["wrappedOverride"] + noLinesB := len(wrappedB) + noLinesC := len(wrappedC) + colB := "" + colC := "" + + for c, colA := range wrappedA { + // ANGI todo <= + if c < noLinesB { + colB = wrappedB[c] + } else { + colB = "" + } + if c < noLinesC { + colC = wrappedC[c] + } else { + colC = "" + } + printRow(writer, twist, []string{colA, colB, colC}, rowElements) + if firstLine { + firstLine = false + rowElements["note"] = "" + rowElements["parameter"] = "" + rowElements["compliant"] = "" + } + } +} + +// printRow prints now the row of the table +func printRow (writer io.Writer, twist bool, cols []string, rowElements map[string]string) { + if twist { + if rowElements["type"] == "verify" { + fmt.Fprintf(writer, rowElements["colFormat"], rowElements["note"], rowElements["parameter"], cols[1], cols[2], cols[0], rowElements["compliant"]) + } else { + fmt.Fprintf(writer, rowElements["colFormat"], rowElements["parameter"], cols[0], cols[1], cols[2], rowElements["comment"]) + } + } else { + if rowElements["type"] == "verify" { + fmt.Fprintf(writer, rowElements["colFormat"], rowElements["note"], rowElements["parameter"], cols[0], cols[2], cols[1], rowElements["compliant"]) + } else { + fmt.Fprintf(writer, rowElements["colFormat"], rowElements["parameter"], cols[1], cols[0], cols[2], rowElements["comment"]) + } + } +} diff --git a/system/system.go b/system/system.go index 4e03a44f..00cfd4fd 100644 --- a/system/system.go +++ b/system/system.go @@ -225,7 +225,16 @@ func SwitchOnOut(stdout *os.File, stderr *os.File) { // A given text string will be wrapped at word borders into // lines of a given width func WrapTxt(text string, width int) (folded []string) { - words := strings.Split(text, " ") + var words []string + fallback := false + + if strings.Contains(text, " ") { + words = strings.Split(text, " ") + } else { + // fallback (e.g. net.ipv4.ip_local_reserved_ports) + words = strings.Split(text, ",") + fallback = true + } if len(words) == 0 { return } @@ -241,7 +250,11 @@ func WrapTxt(text string, width int) (folded []string) { } if len(word)+1 > spaceLeft { // fold; start next row - foldedTxt += "\n" + word + if fallback { + foldedTxt += ",\n" + word + } else { + foldedTxt += "\n" + word + } if strings.HasSuffix(word, "\n") { spaceLeft = width noSpace = true @@ -254,6 +267,9 @@ func WrapTxt(text string, width int) (folded []string) { foldedTxt += word spaceLeft -= len(word) noSpace = false + } else if fallback { + foldedTxt += "," + word + spaceLeft -= 1 + len(word) } else { foldedTxt += " " + word spaceLeft -= 1 + len(word)