Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create options for human-readable output formats #437

Merged
merged 27 commits into from
Jul 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3e7fe69
Add a -summary option to print a short summary of the linting
acaird May 25, 2020
dbb3332
Added -longsummary option and output
acaird May 25, 2020
eef788b
spelling fix
zakird May 25, 2020
31c7bdc
Remove tablewriter dependency and reimplement the good parts
acaird May 28, 2020
eefe940
spelling fix
zakird May 25, 2020
ec56f06
Merge branch 'summary' of github.com:acaird/zlint into summary
acaird May 28, 2020
b285882
Fixed a missed merge :(
acaird May 28, 2020
fb86585
Merge branch 'master' into summary
cpu May 31, 2020
832bc81
switched longsummary to longSummary; fixed output bug
acaird Jun 2, 2020
b3c3f69
Cleaned up typos, variable names, formatting
acaird Jun 2, 2020
3a60980
Merge branch 'summary' of github.com:acaird/zlint into summary
acaird Jun 3, 2020
aab1521
Merge branch 'master' into summary
cpu Jun 7, 2020
1e6d785
Merge branch 'master' into summary
cpu Jun 11, 2020
4be536f
Merge branch 'master' into summary
cpu Jun 25, 2020
796d10f
parent 99579098a16c10d1d704b8b8149dd8c35329107f
acaird May 25, 2020
83d5bfe
autopull: 2020-05-27T14:34:02Z (#441)
tld-update-bot May 27, 2020
307f3e8
gTLD autopull: 2020-05-28T14:35:00Z (#442)
tld-update-bot May 28, 2020
3aaea14
Moved structure creation out of function into a method for reporting
acaird Jun 28, 2020
e67c57f
Merge branch 'summary' of github.com:acaird/zlint into summary
acaird Jun 28, 2020
0a21f09
Merge branch 'master' into summary
cpu Jul 2, 2020
e12bda4
Moved the formatted output routines out of main
acaird Jul 5, 2020
28441a5
Merge branch 'summary' of github.com:acaird/zlint into summary
acaird Jul 5, 2020
d2079c5
Changed newRT to a pointer receiver
acaird Jul 8, 2020
9798f3f
Changed output options to all them all; newlines for nice output
acaird Jul 11, 2020
c21f46c
Changed output options to allow printing of them all; newlines for ni…
acaird Jul 11, 2020
8a79935
Merge branch 'summary' of github.com:acaird/zlint into summary
acaird Jul 11, 2020
d436af9
Merge branch 'master' into summary
cpu Jul 20, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions v2/cmd/zlint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ import (
"github.com/zmap/zcrypto/x509"
"github.com/zmap/zlint/v2"
"github.com/zmap/zlint/v2/lint"
"github.com/zmap/zlint/v2/formattedoutput"
)

var ( // flags
listLintsJSON bool
listLintSources bool
summary bool
longSummary bool
prettyprint bool
format string
nameFilter string
Expand All @@ -51,14 +54,16 @@ var ( // flags
func init() {
flag.BoolVar(&listLintsJSON, "list-lints-json", false, "Print lints in JSON format, one per line")
flag.BoolVar(&listLintSources, "list-lints-source", false, "Print list of lint sources, one per line")
flag.BoolVar(&summary, "summary", false, "Prints a short human-readable summary report")
flag.BoolVar(&longSummary, "longSummary", false, "Prints a human-readable summary report with details")
flag.StringVar(&format, "format", "pem", "One of {pem, der, base64}")
flag.StringVar(&nameFilter, "nameFilter", "", "Only run lints with a name matching the provided regex. (Can not be used with -includeNames/-excludeNames)")
flag.StringVar(&includeNames, "includeNames", "", "Comma-separated list of lints to include by name")
flag.StringVar(&excludeNames, "excludeNames", "", "Comma-separated list of lints to exclude by name")
flag.StringVar(&includeSources, "includeSources", "", "Comma-separated list of lint sources to include")
flag.StringVar(&excludeSources, "excludeSources", "", "Comma-separated list of lint sources to exclude")

flag.BoolVar(&prettyprint, "pretty", false, "Pretty-print output")
flag.BoolVar(&prettyprint, "pretty", false, "Pretty-print JSON output")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "ZLint version %s\n\n", version)
fmt.Fprintf(os.Stderr, "Usage: %s [flags] file...\n", os.Args[0])
Expand Down Expand Up @@ -156,7 +161,15 @@ func doLint(inputFile *os.File, inform string, registry lint.Registry) {
log.Fatalf("can't format output: %s", err)
}
os.Stdout.Write(out.Bytes())
} else {
fmt.Printf("\n\n")
}
if summary {
formattedoutput.OutputSummary(zlintResult, false)
}
if longSummary {
formattedoutput.OutputSummary(zlintResult, true)
}
if !prettyprint && !summary && !longSummary {
os.Stdout.Write(jsonBytes)
}
os.Stdout.Write([]byte{'\n'})
Expand Down
160 changes: 160 additions & 0 deletions v2/formattedoutput/formattedOutput.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package formattedoutput

import (
"fmt"
"strconv"
"strings"
"unicode/utf8"
"sort"

"github.com/zmap/zlint/v2"
"github.com/zmap/zlint/v2/lint"

)

type resultsTable struct {
resultCount map[lint.LintStatus]int
resultDetails map[lint.LintStatus][]string
lintLevelsAboveThreshold map[int]lint.LintStatus
sortedLevels []int
}

func (r *resultsTable) newRT(threshold lint.LintStatus, results *zlint.ResultSet, longSummary bool) resultsTable {

r.resultCount = make(map[lint.LintStatus]int)
r.resultDetails = make(map[lint.LintStatus][]string)
r.lintLevelsAboveThreshold = make(map[int]lint.LintStatus)

// Make the list of lint levels that matter
for _, i := range lint.StatusLabelToLintStatus {
if i <= threshold {
continue
}
r.lintLevelsAboveThreshold[int(i)] = i
}
// Set all of the levels to 0 events so they are all displayed
// in the -summary table
for _, level := range r.lintLevelsAboveThreshold {
r.resultCount[level] = 0
}
// Count up the number of each event
for lintName, lintResult := range results.Results {
if lintResult.Status > threshold {
r.resultCount[lintResult.Status]++
if longSummary {
r.resultDetails[lintResult.Status] = append(
r.resultDetails[lintResult.Status],
string(lintName),
)
}
}
}
// Sort the levels we have so we can get a nice output
for key := range r.resultCount {
r.sortedLevels = append(r.sortedLevels, int(key))
}
sort.Ints(r.sortedLevels)

return *r
}


func OutputSummary(zlintResult *zlint.ResultSet, longSummary bool) {
// Set the threashold under which (inclusive) events are not
// counted
threshold := lint.Pass

rt := (&resultsTable{}).newRT(threshold, zlintResult, longSummary)

// make and print the requested table type
if longSummary {
// make a table with the internal lint names grouped
// by type
var olsl string
headings := []string{
"Level",
"# occurrences",
" Details ",
}
lines := [][]string{}
lsl := ""
rescount := ""

hlengths := printTableHeadings(headings)
// Construct the table lines, but don't repeat
// LintStatus(level) or the results count. Also, just
// because a level wasn't seen doesn't mean it isn't
// important; display "empty" levels, too
for _, level := range rt.sortedLevels {
foundDetail := false
for _, detail := range rt.resultDetails[lint.LintStatus(level)] {
if fmt.Sprintf("%s", lint.LintStatus(level)) != olsl {
olsl = fmt.Sprintf("%s", lint.LintStatus(level))
lsl = olsl
rescount = strconv.Itoa(rt.resultCount[lint.LintStatus(level)])
} else {
lsl = ""
rescount = ""
}
lines = append(lines, ([]string{lsl, rescount, detail}))
foundDetail = true
}
if !foundDetail {
lines = append(lines, []string{
fmt.Sprintf("%s", lint.LintStatus(level)),
strconv.Itoa(rt.resultCount[lint.LintStatus(level)]),
" - ",
})
}
}
printTableBody(hlengths, lines)
} else {
headings := []string{"Level", "# occurrences"}
hlengths := printTableHeadings(headings)
lines := [][]string{}
for _, level := range rt.sortedLevels {
lines = append(lines, []string{
fmt.Sprintf("%s", lint.LintStatus(level)),
strconv.Itoa(rt.resultCount[lint.LintStatus(level)])})
}
printTableBody(hlengths, lines)
fmt.Printf("\n")
}
}

func printTableHeadings(headings []string) []int {
hlengths := []int{}
for i, h := range headings {
hlengths = append(
hlengths,
utf8.RuneCountInString(h)+1)
fmt.Printf("| %s ", strings.ToUpper(h))
if i == len(headings)-1 {
fmt.Printf("|\n")
for ii, j := range hlengths {
fmt.Printf("+%s", strings.Repeat("-", j+1))
if ii == len(headings)-1 {
fmt.Printf("+\n")
}
}
}
}
return hlengths
}

func printTableBody(hlengths []int, lines [][]string) {
for _, line := range lines {
for i, hlen := range hlengths {
// This makes a format string with the
// right widths, e.g. "%7.7s"
fmtstring := fmt.Sprintf("|%%%[1]d.%[1]ds", hlen)
fmt.Printf(fmtstring, line[i])
if i == len(hlengths)-1 {
fmt.Printf(" |\n")
} else {
fmt.Printf(" ")
}
}
}

}
6 changes: 3 additions & 3 deletions v2/lint/result.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ const (
)

var (
// statusLabelToLintStatus is used to work backwards from
// StatusLabelToLintStatus is used to work backwards from
// a LintStatus.String() to the LintStatus. This is used by
// LintStatus.Unmarshal.
statusLabelToLintStatus = map[string]LintStatus{
StatusLabelToLintStatus = map[string]LintStatus{
Reserved.String(): Reserved,
NA.String(): NA,
NE.String(): NE,
Expand Down Expand Up @@ -73,7 +73,7 @@ func (e LintStatus) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the json.Unmarshaler interface.
func (e *LintStatus) UnmarshalJSON(data []byte) error {
key := strings.ReplaceAll(string(data), `"`, "")
if status, ok := statusLabelToLintStatus[key]; ok {
if status, ok := StatusLabelToLintStatus[key]; ok {
*e = status
} else {
return fmt.Errorf("bad LintStatus JSON value: %s", string(data))
Expand Down