This repository has been archived by the owner on Apr 14, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #143 from bpicode/Issue-124-deb-copyright
Write debian copyright file by parsing NOTICE and vendor tree
- Loading branch information
Showing
17 changed files
with
554 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
*.out | ||
coverage-all.html | ||
/fritzctl | ||
/notice2copyright | ||
|
||
# Folders | ||
_obj | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
copyright |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Tools of our trade |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# notice2copyright | ||
|
||
## About | ||
|
||
Parse a `NOTICE` file to generate the [debian copyright file](https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/). | ||
|
||
## Build | ||
|
||
```sh | ||
go build | ||
``` | ||
|
||
## Usage | ||
|
||
```sh | ||
notice2copyright path/to/github.com/user/project "MIT License (Expat)" | ||
``` | ||
|
||
## Assumptions | ||
|
||
* Every dependency is licensed under one license known to this tool. | ||
* The project has a `NOTICE` file in the following format: | ||
```text | ||
... | ||
======================================================================== | ||
Apache License 2.0 (Apache-2.0) | ||
======================================================================== | ||
The following software have components provided under the terms of this license: | ||
- cobra (from https://github.com/spf13/cobra) | ||
======================================================================== | ||
MIT License (Expat) | ||
======================================================================== | ||
The following software have components provided under the terms of this license: | ||
- color (from https://github.com/fatih/color) | ||
... | ||
``` | ||
The file needs to reside at the top-level directory of the project. | ||
* Vendoring. All dependencies need to be in the vendor folder including their `LICENSE` files. | ||
A dependency referenced via `- cobra (from https://github.com/spf13/cobra)` in the `NOTICE` | ||
file has to be present in the vendor folder as `vendor/github.com/spf13/cobra)`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
) | ||
|
||
func assertOrFatal(val bool, f string, v ...interface{}) { | ||
assertTrue(log.Fatalln, val, fmt.Sprintf(f, v...)) | ||
} | ||
|
||
func assertTrue(fat func(v ...interface{}), val bool, f string) { | ||
if !val { | ||
fat(f) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_assertTrue(t *testing.T) { | ||
assert.NotPanics(t, func() { | ||
assertTrue(log.Fatalln, true, "err") | ||
}) | ||
assert.Panics(t, func() { | ||
assertTrue(func(v ...interface{}) { | ||
panic("panic") | ||
}, false, "err") | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
"regexp" | ||
"strings" | ||
) | ||
|
||
var copyrightRegex = regexp.MustCompile(`^>*\s*[Cc]opyright\s(\([Cc]\)|©)*(?P<CLINE>.*)`) | ||
|
||
var copyrightNoAuthorRegex = regexp.MustCompile(`([Cc]opyright notice|[Cc]opyright license to reproduce)`) | ||
|
||
func findCopyrightHolders(projects []project, dir string) []project { | ||
withCpHolders := make([]project, len(projects)) | ||
for i, p := range projects { | ||
withCpHolders[i] = findCopyrightHoldersOf(p, dir) | ||
} | ||
return withCpHolders | ||
} | ||
|
||
func findCopyrightHoldersOf(p project, dir string) project { | ||
srcDir := filepath.Join(dir, p.dir()) | ||
lf, err := openFirst(srcDir, "LICENSE", "LICENSE.md", "LICENSE.txt", "LICENSE.rst") | ||
assertOrFatal(err == nil, "unable to open license file for project '%s' (%s): %v", p.name, p.url, err) | ||
defer lf.Close() | ||
p.copyrightHolders = readCopyrightHolders(lf) | ||
return p | ||
} | ||
|
||
func openFirst(dir string, names ...string) (*os.File, error) { | ||
for _, name := range names { | ||
f, err := os.Open(filepath.Join(dir, name)) | ||
if err == nil { | ||
return f, nil | ||
} | ||
} | ||
return nil, fmt.Errorf("no license file [%s] found in directory '%s'", names, dir) | ||
} | ||
|
||
func readCopyrightHolders(r io.Reader) []string { | ||
var holders []string | ||
s := bufio.NewScanner(r) | ||
for s.Scan() { | ||
line := s.Text() | ||
holders = addCopyRightHolder(line, holders) | ||
} | ||
if len(holders) == 0 { | ||
holders = append(holders, "unknown") | ||
} | ||
return holders | ||
} | ||
|
||
func addCopyRightHolder(text string, holders []string) []string { | ||
if copyrightRegex.MatchString(text) && !copyrightNoAuthorRegex.MatchString(text) { | ||
holders = append(holders, parseCopyrightHolder(text)) | ||
} | ||
return holders | ||
} | ||
|
||
func parseCopyrightHolder(text string) string { | ||
matches := copyrightRegex.FindStringSubmatch(text) | ||
return strings.TrimSpace(matches[len(matches)-1]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func Test_openFirst(t *testing.T) { | ||
_, err := openFirst("/that/should/not/work/ever", "asdfagag.txt", "asasgdsg.md") | ||
assert.Error(t, err) | ||
} | ||
|
||
func Test_parseCopyrightHolder(t *testing.T) { | ||
assert.Equal(t, "2016 bpicode", parseCopyrightHolder("Copyright (c) 2016 bpicode")) | ||
assert.Equal(t, "John Doe <[email protected]>", parseCopyrightHolder("Copyright (c) John Doe <[email protected]>")) | ||
assert.Equal(t, "2009 The Go Authors. All rights reserved.", parseCopyrightHolder("Copyright (c) 2009 The Go Authors. All rights reserved.")) | ||
assert.Equal(t, "2011 John Doe <[email protected]>", parseCopyrightHolder("Copyright © 2011 John Doe <[email protected]>")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"fmt" | ||
"io" | ||
"sort" | ||
"strings" | ||
) | ||
|
||
type copyrightWriter struct { | ||
root project | ||
deps []project | ||
} | ||
|
||
func (c *copyrightWriter) writeTo(w io.Writer) { | ||
c.writeHead(w) | ||
c.writeProject(w, c.root) | ||
c.writeDeps(w) | ||
c.writeLics(w) | ||
} | ||
|
||
func (c *copyrightWriter) writeHead(w io.Writer) { | ||
fmt.Fprintln(w, "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/") | ||
fmt.Fprintf(w, "Upstream-Name: %s\n", c.root.name) | ||
fmt.Fprintf(w, "Source: %s\n", c.root.url) | ||
fmt.Fprintln(w, "") | ||
} | ||
|
||
func (c *copyrightWriter) writeProject(w io.Writer, p project) { | ||
if p.isRoot { | ||
fmt.Fprintln(w, "Files: *") | ||
} else { | ||
fmt.Fprintf(w, "Files: %s/*\n", p.dir()) | ||
} | ||
|
||
fmt.Fprintf(w, "Copyright: %s\n", p.copyrightHolders[0]) | ||
for _, other := range p.copyrightHolders[1:] { | ||
fmt.Fprintf(w, " %s\n", other) | ||
} | ||
fmt.Fprintf(w, "License: %s\n\n", p.license.shortName) | ||
} | ||
|
||
func (c *copyrightWriter) writeDeps(w io.Writer) { | ||
sort.Slice(c.deps, func(i, j int) bool { | ||
return c.deps[i].name < c.deps[j].name | ||
}) | ||
for _, d := range c.deps { | ||
c.writeProject(w, d) | ||
} | ||
} | ||
|
||
func (c *copyrightWriter) writeLics(w io.Writer) { | ||
m := c.licSet() | ||
allLics := c.sortByShortName(m) | ||
for _, l := range allLics { | ||
c.writeLic(w, l) | ||
} | ||
} | ||
|
||
func (c *copyrightWriter) licSet() map[license]interface{} { | ||
m := make(map[license]interface{}) | ||
m[c.root.license] = nil | ||
for _, p := range c.deps { | ||
m[p.license] = nil | ||
} | ||
return m | ||
} | ||
|
||
func (c *copyrightWriter) sortByShortName(m map[license]interface{}) []license { | ||
allLics := make([]license, 0) | ||
for l := range m { | ||
allLics = append(allLics, l) | ||
} | ||
sort.Slice(allLics, func(i, j int) bool { | ||
return allLics[i].shortName < allLics[j].shortName | ||
}) | ||
return allLics | ||
} | ||
|
||
func (c *copyrightWriter) writeLic(w io.Writer, l license) { | ||
fmt.Printf("License: %s\n", l.shortName) | ||
s := bufio.NewScanner(bytes.NewBufferString(l.text)) | ||
for s.Scan() { | ||
line := s.Text() | ||
if strings.TrimSpace(line) == "" { | ||
fmt.Fprintln(w, " .") | ||
} else { | ||
fmt.Fprintf(w, " %s\n", line) | ||
} | ||
} | ||
fmt.Fprintln(w, "") | ||
} |
Oops, something went wrong.