Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

add template output support #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,27 @@ screenshot is shown below:

![Excel Report](https://user-images.githubusercontent.com/1299/48667086-84893500-ea83-11e8-925c-7929ed441b1b.png)

### Custom Template output

It is possible to provide a template to get a custom report. For the template
the [Go text/template](https://golang.org/pkg/text/template/) is used.

```
$ golicense -in-template report.tmpl -out-template=report.md ./my-program
```

The in-template paramter specifies the template file to use and the out-template
as the filename to write the result.

A simple example of a template content.

```
|Dependency | Version | SPDX| License | Allowed |
|-----------|---------|-----|---------|---------|
{{range . }}| {{.Dependency}} | {{.Version}} | {{.Spdx}} | {{.License}} | {{.Allowed}} |
{{end}}
```

## Limitations

There are a number of limitations to `golicense` currently. These are fixable
Expand Down
27 changes: 27 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ func realMain() int {

var flagLicense bool
var flagOutXLSX string
var flagOutTemplate string
var flagInTemplate string

flags := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
flags.BoolVar(&flagLicense, "license", true,
"look up and verify license. If false, dependencies are\n"+
Expand All @@ -45,6 +48,10 @@ func realMain() int {
flags.BoolVar(&termOut.Verbose, "verbose", false, "additional logging to terminal, requires -plain")
flags.StringVar(&flagOutXLSX, "out-xlsx", "",
"save report in Excel XLSX format to the given path")
flags.StringVar(&flagOutTemplate, "out-template", "",
"save report with in-template in the given path")
flags.StringVar(&flagInTemplate, "in-template", "",
"save report the given template")
flags.Parse(os.Args[1:])
args := flags.Args()
if len(args) == 0 {
Expand All @@ -59,6 +66,13 @@ func realMain() int {
return 1
}

if flagOutTemplate != "" && flagInTemplate =="" {
fmt.Fprintf(os.Stderr, color.RedString(
"❗️ Path to template file for template output expected.\n\n"))
printHelp(flags)
return 1
}

// Determine the exe path and parse the configuration if given.
var cfg config.Config
exePath := args[0]
Expand Down Expand Up @@ -117,6 +131,19 @@ func realMain() int {
})
}

if flagOutTemplate != "" {
if _, err := os.Stat(flagInTemplate); os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, color.RedString(fmt.Sprintf(
"❗️ Error Teamplte file does not exist: %s\n", flagInTemplate)))
return 1
}
out.Outputs = append(out.Outputs, &TemplateOutput {
Path: flagOutTemplate,
Template: flagInTemplate,
Config: &cfg,
})
}

// Setup a context. We don't connect this to an interrupt signal or
// anything since we just exit immediately on interrupt. No cleanup
// necessary.
Expand Down
121 changes: 121 additions & 0 deletions output_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package main

import (
"fmt"
"os"
"sort"
"sync"
"text/template"

"github.com/mitchellh/golicense/config"
"github.com/mitchellh/golicense/license"
"github.com/mitchellh/golicense/module"
)

// TemplateOutput writes the results of license lookups to a tempalte file.
type TemplateOutput struct {
// Path is the path to the file to write. This will be overwritten if
// it exists.
Path string

// The template file to use for rendering.
Template string

// Config is the configuration (if any). This will be used to check
// if a license is allowed or not.
Config *config.Config

modules map[*module.Module]interface{}
lock sync.Mutex
}

// Start implements Output
func (o *TemplateOutput) Start(m *module.Module) {}

// Update implements Output
func (o *TemplateOutput) Update(m *module.Module, t license.StatusType, msg string) {}

// Finish implements Output
func (o *TemplateOutput) Finish(m *module.Module, l *license.License, err error) {
o.lock.Lock()
defer o.lock.Unlock()

if o.modules == nil {
o.modules = make(map[*module.Module]interface{})
}

o.modules[m] = l
if err != nil {
o.modules[m] = err
}
}

type libraryEntry struct {
Dependency string
Version string
Spdx string
License string
Allowed string
}

// Close implements Output
func (o *TemplateOutput) Close() error {
o.lock.Lock()
defer o.lock.Unlock()

keys := make([]string, 0, len(o.modules))
index := map[string]*module.Module{}
for m := range o.modules {
keys = append(keys, m.Path)
index[m.Path] = m
}
sort.Strings(keys)

entries := []*libraryEntry{}

// Go through each module and output it into the spreadsheet
for _, k := range keys {
m := index[k]
entry := libraryEntry{
Dependency: m.Path,
Version: m.Version,
Spdx: "",
License: "",
Allowed: "unknown",
}

raw := o.modules[m]
if raw == nil {
entry.License = "no"
continue
}

if err, ok := raw.(error); ok {
entry.License = fmt.Sprintf("ERROR: %s", err)
continue
}

if lic, ok := raw.(*license.License); ok {
if lic != nil {
entry.Spdx = lic.SPDX
}
entry.License = fmt.Sprintf(lic.String())

if o.Config != nil {
switch o.Config.Allowed(lic) {
case config.StateAllowed:
entry.Allowed = "yes"
case config.StateDenied:
entry.Allowed = "no"
}
}
}
entries = append(entries, &entry)
}

t := template.Must(template.ParseFiles(o.Template))
writer, _ := os.Create(o.Path)
t.Execute(writer, entries)

return nil
}