@@ -22,6 +22,7 @@ package main
22
22
23
23
import (
24
24
"bufio"
25
+ "errors"
25
26
"flag"
26
27
"fmt"
27
28
"io/ioutil"
@@ -40,17 +41,26 @@ type (
40
41
41
42
// command line config params
42
43
config struct {
43
- rootDir string
44
- verifyOnly bool
44
+ rootDir string
45
+ verifyOnly bool
46
+ temporalAddMode bool
47
+ temporalModifyMode bool
48
+ filePaths string
45
49
}
46
50
)
47
51
48
52
// licenseFileName is the name of the license file
49
53
const licenseFileName = "LICENSE"
50
54
51
55
// unique prefix that identifies a license header
52
- const licenseHeaderPrefixOld = "// Copyright (c)"
56
+ const licenseHeaderPrefixOld = "Copyright (c)"
53
57
const licenseHeaderPrefix = "// The MIT License (MIT)"
58
+ const cadenceCopyright = "// Copyright (c) 2017-2020 Uber Technologies Inc."
59
+ const cadenceModificationHeader = "// Modifications Copyright (c) 2020 Uber Technologies Inc."
60
+ const temporalCopyright = "// Copyright (c) 2020 Temporal Technologies, Inc."
61
+ const temporalPartialCopyright = "// Portions of the Software are attributed to Copyright (c) 2020 Temporal Technologies Inc."
62
+
63
+ const firstLinesToCheck = 10
54
64
55
65
var (
56
66
// directories to be excluded
@@ -69,15 +79,38 @@ func main() {
69
79
flag .StringVar (& cfg .rootDir , "rootDir" , "." , "project root directory" )
70
80
flag .BoolVar (& cfg .verifyOnly , "verifyOnly" , false ,
71
81
"don't automatically add headers, just verify all files" )
82
+ flag .BoolVar (& cfg .temporalAddMode , "temporalAddMode" , false , "add copyright for new file copied from temporal" )
83
+ flag .BoolVar (& cfg .temporalModifyMode , "temporalModifyMode" , false , "add copyright for existing file which has parts copied from temporal" )
84
+ flag .StringVar (& cfg .filePaths , "filePaths" , "" , "comma separated list of files to run temporal license on" )
72
85
flag .Parse ()
73
86
87
+ if err := verifyCfg (cfg ); err != nil {
88
+ fmt .Println (err )
89
+ os .Exit (- 1 )
90
+ }
91
+
74
92
task := newAddLicenseHeaderTask (& cfg )
75
93
if err := task .run (); err != nil {
76
94
fmt .Println (err )
77
95
os .Exit (- 1 )
78
96
}
79
97
}
80
98
99
+ func verifyCfg (cfg config ) error {
100
+ if cfg .verifyOnly {
101
+ if cfg .temporalModifyMode || cfg .temporalAddMode {
102
+ return errors .New ("invalid config, can only specify one of temporalAddMode, temporalModifyMode or verifyOnly" )
103
+ }
104
+ }
105
+ if cfg .temporalAddMode && cfg .temporalModifyMode {
106
+ return errors .New ("invalid config, can only specify temporalAddMode or temporalModifyMode" )
107
+ }
108
+ if (cfg .temporalModifyMode || cfg .temporalAddMode ) && len (cfg .filePaths ) == 0 {
109
+ return errors .New ("invalid config, when running in temporalAddMode or temporalModifyMode must provide filePaths" )
110
+ }
111
+ return nil
112
+ }
113
+
81
114
func newAddLicenseHeaderTask (cfg * config ) * addLicenseHeaderTask {
82
115
return & addLicenseHeaderTask {
83
116
config : cfg ,
@@ -89,12 +122,28 @@ func (task *addLicenseHeaderTask) run() error {
89
122
if err != nil {
90
123
return fmt .Errorf ("error reading license file, errr=%v" , err .Error ())
91
124
}
92
-
93
125
task .license , err = commentOutLines (string (data ))
94
126
if err != nil {
95
127
return fmt .Errorf ("copyright header failed to comment out lines, err=%v" , err .Error ())
96
128
}
97
-
129
+ if task .config .temporalAddMode {
130
+ task .license = fmt .Sprintf ("%v\n \n %v\n \n %v" , cadenceModificationHeader , temporalCopyright , task .license )
131
+ } else if task .config .temporalModifyMode {
132
+ task .license = fmt .Sprintf ("%v\n \n %v\n \n %v" , cadenceCopyright , temporalPartialCopyright , task .license )
133
+ }
134
+ if task .config .temporalModifyMode || task .config .temporalAddMode {
135
+ filePaths , fileInfos , err := getFilePaths (task .config .filePaths )
136
+ if err != nil {
137
+ return err
138
+ }
139
+ for i := 0 ; i < len (filePaths ); i ++ {
140
+ if err := task .handleFile (filePaths [i ], fileInfos [i ], nil ); err != nil {
141
+ return err
142
+ }
143
+ }
144
+ return nil
145
+ }
146
+ task .license = fmt .Sprintf ("%v\n \n %v\n \n %v" , licenseHeaderPrefix , cadenceCopyright , task .license )
98
147
err = filepath .Walk (task .config .rootDir , task .handleFile )
99
148
if err != nil {
100
149
return fmt .Errorf ("copyright header check failed, err=%v" , err .Error ())
@@ -120,7 +169,7 @@ func (task *addLicenseHeaderTask) handleFile(path string, fileInfo os.FileInfo,
120
169
return nil
121
170
}
122
171
123
- if ! strings .HasSuffix (fileInfo .Name (), ".go" ) {
172
+ if ! strings .HasSuffix (fileInfo .Name (), ".go" ) && ! strings . HasSuffix ( fileInfo . Name (), ".proto" ) {
124
173
return nil
125
174
}
126
175
@@ -131,19 +180,20 @@ func (task *addLicenseHeaderTask) handleFile(path string, fileInfo os.FileInfo,
131
180
return err
132
181
}
133
182
134
- scanner := bufio .NewScanner (f )
135
- readLineSucc := scanner .Scan ()
136
- if ! readLineSucc {
137
- return fmt .Errorf ("fail to read first line of file %v" , path )
183
+ ok , err := hasCopyright (f )
184
+ if err != nil {
185
+ return err
138
186
}
139
- firstLine := strings . TrimSpace ( scanner . Text ())
140
- if err := scanner . Err (); err != nil {
187
+
188
+ if err := f . Close (); err != nil {
141
189
return err
142
190
}
143
- f .Close ()
144
191
145
- if strings .Contains (firstLine , licenseHeaderPrefixOld ) || strings .Contains (firstLine , licenseHeaderPrefix ) {
146
- return nil // file already has the copyright header
192
+ if ok {
193
+ if task .config .temporalModifyMode || task .config .temporalAddMode {
194
+ return fmt .Errorf ("when running in temporalModifyMode or temporalAddMode please first remove existing license header: %v" , path )
195
+ }
196
+ return nil
147
197
}
148
198
149
199
// at this point, src file is missing the header
@@ -163,6 +213,27 @@ func (task *addLicenseHeaderTask) handleFile(path string, fileInfo os.FileInfo,
163
213
return ioutil .WriteFile (path , []byte (task .license + string (data )), defaultFilePerms )
164
214
}
165
215
216
+ func hasCopyright (f * os.File ) (bool , error ) {
217
+ scanner := bufio .NewScanner (f )
218
+ lineSuccess := scanner .Scan ()
219
+ if ! lineSuccess {
220
+ return false , fmt .Errorf ("fail to read first line of file %v" , f .Name ())
221
+ }
222
+ i := 0
223
+ for i < firstLinesToCheck && lineSuccess {
224
+ i ++
225
+ line := strings .TrimSpace (scanner .Text ())
226
+ if err := scanner .Err (); err != nil {
227
+ return false , err
228
+ }
229
+ if lineHasCopyright (line ) {
230
+ return true , nil
231
+ }
232
+ lineSuccess = scanner .Scan ()
233
+ }
234
+ return false , nil
235
+ }
236
+
166
237
func isFileAutogenerated (path string ) bool {
167
238
return strings .HasPrefix (path , ".gen" )
168
239
}
@@ -189,3 +260,21 @@ func commentOutLines(str string) (string, error) {
189
260
}
190
261
return strings .Join (lines , "" ), nil
191
262
}
263
+
264
+ func lineHasCopyright (line string ) bool {
265
+ return strings .Contains (line , licenseHeaderPrefixOld ) ||
266
+ strings .Contains (line , licenseHeaderPrefix )
267
+ }
268
+
269
+ func getFilePaths (filePaths string ) ([]string , []os.FileInfo , error ) {
270
+ paths := strings .Split (filePaths , "," )
271
+ var fileInfos []os.FileInfo
272
+ for _ , p := range paths {
273
+ fileInfo , err := os .Stat (p )
274
+ if err != nil {
275
+ return nil , nil , err
276
+ }
277
+ fileInfos = append (fileInfos , fileInfo )
278
+ }
279
+ return paths , fileInfos , nil
280
+ }
0 commit comments