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

Markdown report generation #3

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
164 changes: 160 additions & 4 deletions licenses.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ func expandPackages(gopath string, pkgs []string) ([]string, error) {
if err != nil {
output := string(out)
if strings.Contains(output, "cannot find package") ||
strings.Contains(output, "no buildable Go source files") {
strings.Contains(output, "no buildable Go source files") ||
strings.Contains(output, "can't load package") {
return nil, &MissingError{Err: output}
}
return nil, fmt.Errorf("'go %s' failed with:\n%s",
Expand Down Expand Up @@ -243,7 +244,8 @@ func listPackagesAndDeps(gopath string, pkgs []string) ([]string, error) {
if err != nil {
output := string(out)
if strings.Contains(output, "cannot find package") ||
strings.Contains(output, "no buildable Go source files") {
strings.Contains(output, "no buildable Go source files") ||
strings.Contains(output, "can't load package") {
return nil, &MissingError{Err: output}
}
return nil, fmt.Errorf("'go %s' failed with:\n%s",
Expand Down Expand Up @@ -321,7 +323,8 @@ var (
`((?:un)?licen[sc]e)|` +
`((?:un)?licen[sc]e\.(?:md|markdown|txt))|` +
`(copy(?:ing|right)(?:\.[^.]+)?)|` +
`(licen[sc]e\.[^.]+)` +
`(licen[sc]e\.[^.]+)|` +
`(.*(?:un)?licen[sc]e.*)` +
`)$`)
)

Expand All @@ -340,6 +343,8 @@ func scoreLicenseName(name string) float64 {
return 0.8
case m[4] != "":
return 0.7
case m[5] != "":
return 0.6
}
return 0.
}
Expand Down Expand Up @@ -533,6 +538,151 @@ func groupLicenses(licenses []License) ([]License, error) {
return kept, nil
}

type Row struct {
Package, License, Match, Words string
Score float64
}

type Rows []Row

func (r Rows) Len() int {
return len(r)
}

func (r Rows) Less(i, j int) bool {
ii, jj := r[i], r[j]
if license := strings.Compare(ii.License, jj.License); license < 0 {
return true
} else if license == 0 {
if ii.Score < jj.Score {
return true
} else if ii.Score == jj.Score {
if pack := strings.Compare(ii.Package, jj.Package); pack < 0 {
return true
}
}
}
return false
}

func (r Rows) Swap(i, j int) {
r[i], r[j] = r[j], r[i]
}

func generateReport(report string, licenses []License, confidence float64, words bool) error {
table := make(Rows, len(licenses))
for i, l := range licenses {
license, diff := "?", ""
if l.Template != nil {
if l.Score > .99 {
license = fmt.Sprintf("%s", l.Template.Title)
} else if l.Score >= confidence {
license = fmt.Sprintf("%s", l.Template.Title)
for _, word := range l.ExtraWords {
diff += " +" + word
}
for _, word := range l.MissingWords {
diff += " -" + word
}
} else {
license = fmt.Sprintf("? (%s)", l.Template.Title)
}
} else if l.Err != "" {
license = strings.Replace(l.Err, "\n", " ", -1)
}
table[i].Package = l.Package
table[i].License = license
table[i].Match = fmt.Sprintf("%2d%%", int(100*l.Score+.5))
table[i].Words = diff
table[i].Score = l.Score
}
sort.Sort(table)

maxPackage, maxLicense, maxMatch, maxWords := 0, 0, 0, 0
for _, row := range table {
if width := len(row.Package); width > maxPackage {
maxPackage = width
}
if width := len(row.License); width > maxLicense {
maxLicense = width
}
if width := len(row.Match); width > maxMatch {
maxMatch = width
}
if width := len(row.Words); width > maxWords {
maxWords = width
}
}

out, err := os.Create(report)
if err != nil {
return err
}
defer out.Close()

writeHeading := func(name string, width int) int {
out.WriteString(" ")
out.WriteString(name)
padding, rowWidth := width-len(name), width
if padding < 0 {
padding, rowWidth = 0, len(name)
}
for i := 0; i < padding; i++ {
out.WriteString(" ")
}
out.WriteString(" |")

return rowWidth
}
out.WriteString("|")
rowWidthPackage := writeHeading("Package", maxPackage)
rowWidthLicense := writeHeading("License", maxLicense)
rowWidthMatch := writeHeading("Match", maxMatch)
var rowWidthWords int
if words {
rowWidthWords = writeHeading("Words", maxWords)
}
out.WriteString("\n")

writeSep := func(width int) {
out.WriteString(" ")
for i := 0; i < width; i++ {
out.WriteString("-")
}
out.WriteString(" |")
}
out.WriteString("|")
writeSep(rowWidthPackage)
writeSep(rowWidthLicense)
writeSep(rowWidthMatch)
if words {
writeSep(rowWidthWords)
}
out.WriteString("\n")

writeRow := func(data string, width int) {
out.WriteString(" ")
out.WriteString(data)
padding := width - len(data)
for i := 0; i < padding; i++ {
out.WriteString(" ")
}
out.WriteString(" |")
}
for _, row := range table {
out.WriteString("|")
writeRow(row.Package, rowWidthPackage)
writeRow(row.License, rowWidthLicense)
writeRow(row.Match, rowWidthMatch)
if words {
writeRow(row.Words, rowWidthWords)
}
out.WriteString("\n")
}

return nil
}

func printLicenses() error {
flag.Usage = func() {
fmt.Println(`Usage: licenses IMPORTPATH...
Expand All @@ -548,11 +698,12 @@ With -a, all individual packages are displayed instead of grouping them by
license files.
With -w, words in package license file not found in the template license are
displayed. It helps assessing the changes importance.
`)
With -r, a report is generated and saved in the specified file.`)
os.Exit(1)
}
all := flag.Bool("a", false, "display all individual packages")
words := flag.Bool("w", false, "display words not matching license template")
report := flag.String("r", "", "generate a report file")
flag.Parse()
if flag.NArg() < 1 {
return fmt.Errorf("expect at least one package argument")
Expand All @@ -570,6 +721,11 @@ displayed. It helps assessing the changes importance.
return err
}
}

if *report != "" {
return generateReport(*report, licenses, confidence, *words)
}

w := tabwriter.NewWriter(os.Stdout, 1, 4, 2, ' ', 0)
for _, l := range licenses {
license := "?"
Expand Down