2013-08-22 04:43:23 +00:00
|
|
|
// Program envvardoc will verify all referenced environment variables in go
|
|
|
|
// source are properly documented.
|
Rename import paths from camlistore.org to perkeep.org.
Part of the project renaming, issue #981.
After this, users will need to mv their $GOPATH/src/camlistore.org to
$GOPATH/src/perkeep.org. Sorry.
This doesn't yet rename the tools like camlistored, camput, camget,
camtool, etc.
Also, this only moves the lru package to internal. More will move to
internal later.
Also, this doesn't yet remove the "/pkg/" directory. That'll likely
happen later.
This updates some docs, but not all.
devcam test now passes again, even with Go 1.10 (which requires vet
checks are clean too). So a bunch of vet tests are fixed in this CL
too, and a bunch of other broken tests are now fixed (introduced from
the past week of merging the CL backlog).
Change-Id: If580db1691b5b99f8ed6195070789b1f44877dd4
2018-01-01 22:41:41 +00:00
|
|
|
package main // import "perkeep.org/dev/envvardoc"
|
2013-08-22 04:43:23 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"regexp"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"text/tabwriter"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
srcDirs = flag.String("srcDirs", "cmd,dev,pkg,server",
|
|
|
|
"comma separated source directories")
|
|
|
|
doc = flag.String("doc", "doc/environment-vars.txt",
|
|
|
|
"file containing environment variable documentation")
|
|
|
|
all = flag.Bool("all", false, "show all environment vars found")
|
|
|
|
prefixes = flag.String("prefixes", "CAM,DEV,AWS",
|
|
|
|
"comma-separated list of env var prefixes we care about. Empty implies all")
|
|
|
|
|
2013-09-06 04:07:15 +00:00
|
|
|
docVar = regexp.MustCompile(`^(\w+) \(.+?\):$`)
|
2013-08-22 04:43:23 +00:00
|
|
|
literalEnvVar = regexp.MustCompile(`os.Getenv\("(\w+)"\)`)
|
|
|
|
variableEnvVar = regexp.MustCompile(`os.Getenv\((\w+)\)`)
|
|
|
|
)
|
|
|
|
|
|
|
|
type pos struct {
|
|
|
|
line int
|
|
|
|
path string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p pos) String() string {
|
|
|
|
return fmt.Sprintf("%s:%d", p.path, p.line)
|
|
|
|
}
|
|
|
|
|
|
|
|
type varMap map[string][]pos
|
|
|
|
|
|
|
|
func sortedKeys(m varMap) []string {
|
|
|
|
keys := make([]string, 0, len(m))
|
2017-12-11 00:35:57 +00:00
|
|
|
for k := range m {
|
2013-08-22 04:43:23 +00:00
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
sort.Strings(keys)
|
|
|
|
return keys
|
|
|
|
}
|
|
|
|
|
|
|
|
type envCollector struct {
|
|
|
|
literals varMap
|
|
|
|
variables varMap
|
|
|
|
documented map[string]struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func newEncCollector() *envCollector {
|
|
|
|
return &envCollector{
|
|
|
|
literals: varMap{},
|
|
|
|
variables: varMap{},
|
|
|
|
documented: map[string]struct{}{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *envCollector) findEnvVars(path string, r io.Reader) error {
|
|
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
line := 1
|
|
|
|
for scanner.Scan() {
|
|
|
|
l := scanner.Text()
|
|
|
|
m := literalEnvVar.FindStringSubmatch(l)
|
|
|
|
if len(m) == 2 {
|
|
|
|
p := pos{line: line, path: path}
|
|
|
|
ec.literals[m[1]] = append(ec.literals[m[1]], p)
|
|
|
|
}
|
|
|
|
|
|
|
|
m = variableEnvVar.FindStringSubmatch(l)
|
|
|
|
if len(m) == 2 {
|
|
|
|
p := pos{line: line, path: path}
|
|
|
|
ec.variables[m[1]] = append(ec.variables[m[1]], p)
|
|
|
|
}
|
|
|
|
line++
|
|
|
|
}
|
|
|
|
return scanner.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *envCollector) findDocVars(r io.Reader) error {
|
|
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
for scanner.Scan() {
|
|
|
|
l := scanner.Text()
|
|
|
|
m := docVar.FindStringSubmatch(l)
|
|
|
|
if len(m) == 2 {
|
|
|
|
ec.documented[m[1]] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return scanner.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *envCollector) walk(path string, info os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if info.IsDir() || !strings.HasSuffix(path, ".go") {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer r.Close()
|
|
|
|
return ec.findEnvVars(path, r)
|
|
|
|
}
|
|
|
|
|
|
|
|
func printMap(header string, m varMap) {
|
|
|
|
w := new(tabwriter.Writer)
|
|
|
|
w.Init(os.Stdout, 0, 8, 1, ' ', 0)
|
|
|
|
fmt.Fprintln(w, header)
|
|
|
|
for _, k := range sortedKeys(m) {
|
|
|
|
for _, pos := range m[k] {
|
|
|
|
fmt.Fprintf(w, "%s\t%s\n", k, pos)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w.Flush()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *envCollector) printAll() {
|
2013-09-06 04:07:15 +00:00
|
|
|
fmt.Println("All environment variables")
|
2013-08-22 04:43:23 +00:00
|
|
|
printMap("Literal\tLocation", ec.literals)
|
|
|
|
fmt.Println()
|
|
|
|
printMap("Variable\tLocation", ec.variables)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ec *envCollector) printUndocumented(prefixes []string) bool {
|
|
|
|
missing := varMap{}
|
|
|
|
for k, v := range ec.literals {
|
|
|
|
if _, ok := ec.documented[k]; !ok {
|
|
|
|
keep := false
|
|
|
|
for _, p := range prefixes {
|
|
|
|
if strings.HasPrefix(k, p) {
|
|
|
|
keep = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if keep || len(prefixes) == 0 {
|
|
|
|
missing[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-06 04:07:15 +00:00
|
|
|
|
|
|
|
if len(missing) != 0 {
|
|
|
|
printMap("Undocumented\tLocation", missing)
|
|
|
|
} else {
|
|
|
|
fmt.Println("All environment variables are documented")
|
|
|
|
}
|
2013-08-22 04:43:23 +00:00
|
|
|
return len(missing) != 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
flag.Parse()
|
|
|
|
ec := newEncCollector()
|
|
|
|
|
|
|
|
r, err := os.Open(*doc)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
defer r.Close()
|
|
|
|
err = ec.findDocVars(r)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, dn := range strings.Split(*srcDirs, ",") {
|
|
|
|
err := filepath.Walk(dn, ec.walk)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if *all {
|
|
|
|
ec.printAll()
|
|
|
|
} else {
|
|
|
|
if ec.printUndocumented(strings.Split(*prefixes, ",")) {
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|