github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/tools/checklicenses/checklicenses.go (about) 1 // Copyright 2017-2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Run with `go run checklicenses.go`. This script has one drawback: 6 // - It does not correct the licenses; it simply outputs a list of files which 7 // do not conform and returns 1 if the list is non-empty. 8 package main 9 10 import ( 11 "encoding/json" 12 "flag" 13 "fmt" 14 "io/ioutil" 15 "log" 16 "os" 17 "os/exec" 18 "regexp" 19 "strings" 20 ) 21 22 var ( 23 absPath = flag.Bool("a", false, "Print absolute paths") 24 configFile = flag.String("c", "", "Configuration file in JSON format") 25 ) 26 27 type rule struct { 28 *regexp.Regexp 29 invert bool 30 } 31 32 func accept(s string) rule { 33 return rule{ 34 regexp.MustCompile("^" + s + "$"), 35 false, 36 } 37 } 38 39 func reject(s string) rule { 40 return rule{ 41 regexp.MustCompile("^" + s + "$"), 42 true, 43 } 44 } 45 46 // Config contains the rules for license checking. 47 type Config struct { 48 // Licenses is a list of acceptable license headers. Each license is 49 // represented by an array of strings, one string per line, without the 50 // trailing \n . 51 Licenses [][]string 52 licensesRegexps []*regexp.Regexp 53 // GoPkg is the Go package name to check for licenses 54 GoPkg string 55 // Accept is a list of file patterns to include in the license checking 56 Accept []string 57 accept []rule 58 // Reject is a list of file patterns to exclude from the license checking 59 Reject []string 60 reject []rule 61 } 62 63 // CompileRegexps compiles the regular expressions coming from the JSON 64 // configuration, and returns an error if an invalid regexp is found. 65 func (c *Config) CompileRegexps() error { 66 for _, licenseRegexps := range c.Licenses { 67 licenseRegexp := strings.Join(licenseRegexps, "\n") 68 re, err := regexp.Compile(licenseRegexp) 69 if err != nil { 70 return err 71 } 72 c.licensesRegexps = append(c.licensesRegexps, re) 73 } 74 75 c.accept = make([]rule, 0, len(c.Accept)) 76 for _, rule := range c.Accept { 77 c.accept = append(c.accept, accept(rule)) 78 } 79 80 c.reject = make([]rule, 0, len(c.Reject)) 81 for _, rule := range c.Reject { 82 c.reject = append(c.reject, reject(rule)) 83 } 84 85 return nil 86 } 87 88 func main() { 89 flag.Parse() 90 91 if *configFile == "" { 92 log.Fatal("Config file name cannot be empty") 93 } 94 buf, err := ioutil.ReadFile(*configFile) 95 if err != nil { 96 log.Fatalf("Failed to read file %s: %v", *configFile, err) 97 } 98 var config Config 99 if err := json.Unmarshal(buf, &config); err != nil { 100 log.Fatalf("Cannot unmarshal JSON from config file %s: %v", *configFile, err) 101 } 102 if err := config.CompileRegexps(); err != nil { 103 log.Fatalf("Failed to compile regexps from JSON config: %v", err) 104 } 105 106 pkgPath := os.ExpandEnv(config.GoPkg) 107 incorrect := []string{} 108 109 // List files added to u-root. 110 out, err := exec.Command("git", "ls-files").Output() 111 if err != nil { 112 log.Fatalln("error running git ls-files:", err) 113 } 114 files := strings.Fields(string(out)) 115 116 rules := append(config.accept, config.reject...) 117 118 // Iterate over files. 119 outer: 120 for _, file := range files { 121 // Test rules. 122 trimmedPath := strings.TrimPrefix(file, pkgPath) 123 for _, r := range rules { 124 if r.MatchString(trimmedPath) == r.invert { 125 continue outer 126 } 127 } 128 129 // Make sure it is not a directory. 130 info, err := os.Stat(file) 131 if err != nil { 132 log.Fatalln("cannot stat", file, err) 133 } 134 if info.IsDir() { 135 continue 136 } 137 138 // Read from the file. 139 r, err := os.Open(file) 140 if err != nil { 141 log.Fatalln("cannot open", file, err) 142 } 143 defer r.Close() 144 contents, err := ioutil.ReadAll(r) 145 if err != nil { 146 log.Fatalln("cannot read", file, err) 147 } 148 var foundone bool 149 for _, l := range config.licensesRegexps { 150 if l.Match(contents) { 151 foundone = true 152 break 153 } 154 } 155 if !foundone { 156 p := trimmedPath 157 if *absPath { 158 p = file 159 } 160 incorrect = append(incorrect, p) 161 } 162 } 163 if err != nil { 164 log.Fatal(err) 165 } 166 167 // Print files with incorrect licenses. 168 if len(incorrect) > 0 { 169 fmt.Println(strings.Join(incorrect, "\n")) 170 os.Exit(1) 171 } 172 }