// SPDX-License-Identifier: Unlicense package main import ( "bufio" "errors" "fmt" "io/fs" "os" "path/filepath" "regexp" "strings" ) var goSpdxHeader = `// SPDX-License-Identifier: Unlicense` var tmplSpdxHeader = `{{/* SPDX-License-Identifier: Unlicense */` type MissingSPDXError struct { Name string } func (m MissingSPDXError) Error() string { return fmt.Sprintf("missing or incorrect SPDX header: %s", m.Name) } func checkFileSPDX(header string, name string) error { f, err := os.Open(name) if err != nil { return err } defer f.Close() r := bufio.NewReader(f) pattern := `(?m:^` + regexp.QuoteMeta(header) + `)` matched, err := regexp.MatchReader(pattern, r) if err != nil { return err } if !matched { return MissingSPDXError{Name: name} } return nil } func walkSPDX(header string, extension string) error { var errs []error filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error { if path != "." && strings.HasPrefix(path, ".") { if d.IsDir() { return filepath.SkipDir } return nil } if err != nil { errs = append(errs, err) return nil } if filepath.Ext(path) != extension { return nil } errs = append(errs, checkFileSPDX(header, path)) return nil }) return errors.Join(errs...) } func checkSPDX() error { err := errors.Join( walkSPDX(goSpdxHeader, ".go"), walkSPDX(tmplSpdxHeader, ".tmpl"), ) if err != nil { return fmt.Errorf("Check SPDX Headers:\n%w", err) } return nil } func run() error { return checkSPDX() } func main() { err := run() if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }