| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // +build ignore |
| |
| // This file generates exceptions.gen.go. |
| // It builds a map from the files in the subdirectory "exception-files". |
| // Run by a "go:generate" comment in licenses.go. |
| |
| package main |
| |
| import ( |
| "bytes" |
| "crypto/sha256" |
| "errors" |
| "fmt" |
| "go/format" |
| "io/ioutil" |
| "log" |
| "path/filepath" |
| "strings" |
| ) |
| |
| const outfile = "exceptions.gen.go" |
| |
| type fileData struct { |
| key [sha256.Size]byte |
| source string |
| types []string |
| } |
| |
| func main() { |
| files, err := filepath.Glob(filepath.Join("exception-files", "*")) |
| if err != nil { |
| log.Fatal(err) |
| } |
| if len(files) == 0 { |
| log.Fatal("no files") |
| } |
| |
| out := new(bytes.Buffer) |
| |
| fmt.Fprint(out, ` |
| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Code generated by gen_data.go; DO NOT EDIT. |
| |
| package licenses |
| |
| import ( |
| "bytes" |
| "crypto/sha256" |
| ) |
| |
| // exceptionFileTypesMap maps SHAs of normalized licenses (see the exceptionKey function) |
| // to a list of types for each license. |
| var exceptionFileTypesMap = map[[sha256.Size]byte][]string{ |
| `) |
| |
| for _, file := range files { |
| base := filepath.Base(file) |
| if base == "README" { |
| continue |
| } |
| // Ignore common editor backup files. |
| if strings.HasSuffix(base, "~") || strings.HasSuffix(base, ".swp") { |
| continue |
| } |
| data, err := readFile(file) |
| if err != nil { |
| log.Fatalf("%s: %v", file, err) |
| } |
| fmt.Fprintf(out, "\n// file %s\n", base) |
| fmt.Fprintf(out, "// from %s\n", data.source) |
| fmt.Fprintf(out, "\t%#v: %#v,\n", data.key, data.types) |
| } |
| fmt.Fprintf(out, "}\n") |
| fmt.Fprintln(out, exceptionKeyText) |
| |
| src, err := format.Source(out.Bytes()) |
| if err != nil { |
| fmt.Println(string(out.Bytes())) |
| log.Fatalf("format.Source: %v", err) |
| } |
| if err := ioutil.WriteFile(outfile, src, 0640); err != nil { |
| log.Fatal(err) |
| } |
| fmt.Printf("wrote %s\n", outfile) |
| } |
| |
| func readFile(file string) (_ *fileData, err error) { |
| data, err := ioutil.ReadFile(file) |
| if err != nil { |
| return nil, err |
| } |
| parts := bytes.SplitN(data, []byte("\n\n"), 2) |
| if len(parts) != 2 { |
| return nil, errors.New("missing blank line separating header") |
| } |
| header, err := parseHeader(parts[0]) |
| if err != nil { |
| return nil, err |
| } |
| source := header["source"] |
| types := header["types"] |
| if source == "" || types == "" { |
| log.Fatal("%s: missing header: source=%q, types=%q", file, source, types) |
| } |
| return &fileData{ |
| key: exceptionKey(parts[1]), |
| source: source, |
| types: strings.Fields(types), |
| }, nil |
| } |
| |
| func parseHeader(h []byte) (map[string]string, error) { |
| m := map[string]string{} |
| lines := strings.Split(string(h), "\n") |
| for _, l := range lines { |
| kv := strings.SplitN(l, ":", 2) |
| if len(kv) != 2 { |
| return nil, fmt.Errorf("malformed header line %q", l) |
| } |
| m[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1]) |
| } |
| return m, nil |
| } |
| |
| // exceptionKey computes the key for the exceptionFileTypesMap. |
| // Keep in sync with exceptionKeyText, below. |
| func exceptionKey(data []byte) [sha256.Size]byte { |
| norm := bytes.Join(bytes.Fields(bytes.ToLower(data)), []byte{' '}) |
| return sha256.Sum256(norm) |
| } |
| |
| const exceptionKeyText = ` |
| // exceptionKey computes the key for the exceptionFileTypesMap. |
| func exceptionKey(data []byte) [sha256.Size]byte { |
| norm := bytes.Join(bytes.Fields(bytes.ToLower(data)), []byte{' '}) |
| return sha256.Sum256(norm) |
| } |
| ` |