go.uber.org/cadence@v1.2.9/internal/cmd/tools/copyright/licensegen.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package main 22 23 import ( 24 "bufio" 25 "flag" 26 "fmt" 27 "io" 28 "io/ioutil" 29 "os" 30 "path/filepath" 31 "strings" 32 ) 33 34 type ( 35 // task that adds license header to source 36 // files, if they don't already exist 37 addLicenseHeaderTask struct { 38 license string // license header string to add 39 config *config // root directory of the project source 40 } 41 42 // command line config params 43 config struct { 44 rootDir string 45 verifyOnly bool 46 } 47 ) 48 49 // licenseFileName is the name of the license file 50 const licenseFileName = "LICENSE" 51 52 // unique indicator that identifies a license header 53 const licenseHeaderIndicator = "Copyright (c)" 54 55 var ( 56 // directories to be excluded 57 dirExcludeList = []string{"vendor/", "idls/"} 58 // default perms for the newly created files 59 defaultFilePerms = os.FileMode(0644) 60 ) 61 62 // command line utility that adds license header 63 // to the source files. Usage as follows: 64 // 65 // ./cmd/tools/copyright/licensegen.go 66 func main() { 67 68 var cfg config 69 flag.StringVar(&cfg.rootDir, "rootDir", ".", "project root directory") 70 flag.BoolVar(&cfg.verifyOnly, "verifyOnly", false, 71 "don't automatically add headers, just verify all files") 72 flag.Parse() 73 74 task := newAddLicenseHeaderTask(&cfg) 75 if err := task.run(); err != nil { 76 fmt.Println(err) 77 os.Exit(-1) 78 } 79 } 80 81 func newAddLicenseHeaderTask(cfg *config) *addLicenseHeaderTask { 82 return &addLicenseHeaderTask{ 83 config: cfg, 84 } 85 } 86 87 func (task *addLicenseHeaderTask) run() error { 88 data, err := ioutil.ReadFile(task.config.rootDir + "/" + licenseFileName) 89 if err != nil { 90 return fmt.Errorf("error reading license file, errr=%v", err.Error()) 91 } 92 93 task.license = string(data) 94 95 err = filepath.Walk(task.config.rootDir, task.handleFile) 96 if err != nil { 97 return fmt.Errorf("copyright header check failed, err=%v", err.Error()) 98 } 99 return nil 100 } 101 102 func (task *addLicenseHeaderTask) handleFile(path string, fileInfo os.FileInfo, err error) error { 103 104 if err != nil { 105 return err 106 } 107 108 if fileInfo.IsDir() { 109 return nil 110 } 111 112 if !mustProcessPath(path) { 113 return nil 114 } 115 116 if !strings.HasSuffix(fileInfo.Name(), ".go") { 117 return nil 118 } 119 120 f, err := os.Open(path) 121 if err != nil { 122 return err 123 } 124 125 reader := bufio.NewReader(f) 126 firstLine, err := reader.ReadString('\n') 127 f.Close() 128 129 if err != nil && !isEOF(err) { 130 return err 131 } 132 133 if strings.Contains(firstLine, licenseHeaderIndicator) { 134 return nil // file already has the copyright header 135 } 136 137 // at this point, src file is missing the header 138 if task.config.verifyOnly { 139 if !isFileAutogenerated(path) { 140 return fmt.Errorf("%v missing license header", path) 141 } 142 } 143 144 data, err := ioutil.ReadFile(path) 145 if err != nil { 146 return err 147 } 148 149 return ioutil.WriteFile(path, []byte(task.license+string(data)), defaultFilePerms) 150 } 151 152 func isFileAutogenerated(path string) bool { 153 return strings.HasPrefix(path, ".gen") 154 } 155 156 func mustProcessPath(path string) bool { 157 for _, d := range dirExcludeList { 158 if strings.HasPrefix(path, d) { 159 return false 160 } 161 } 162 return true 163 } 164 165 // returns true if the error type is an EOF 166 func isEOF(err error) bool { 167 return err == io.EOF || err == io.ErrUnexpectedEOF 168 }