diff --git a/hack/k-license/Readme.md b/hack/k-license/Readme.md new file mode 100644 index 0000000000..168302af0e --- /dev/null +++ b/hack/k-license/Readme.md @@ -0,0 +1,46 @@ +# k-license + +## Prepends project files with given template. + +* Can be used for adding licence or copyright information on src files of project. +* Skip directory, if template (as provided) already present +* Supports Golang/Python source files, Dockerfile, Makefiles and bash scripts + +## Build + +`go build -o k-license main.go ` + +Example +To Apply header from ./templates folder default +``` +$ k-license --path=temp +Modified temp/Dockerfile file +Modified temp/create-specinfo.py file +Modified temp/install-dependencies.sh file +``` + +## Help + +``` + ./k-license --help +Usage: ./k-lic [--help] [-d dir] [--exclude ] [--templates] [--author] + +Add a copyright/license header to all source files in a Git repository. + +Options: + -author string + Replace Author/ORG name (default "The Kubernetes Authors") + -exclude string + comma-separated list of directories to exclude (default ".git,vendor,node_modules") + -help + Display this help message and exit. + -path string + Absolute Path to directory location (default ".") + -templates string + directory containing license templates (default "./templates") + +Examples: + ./k-lic # Add license headers to all source files in the current directory and its subdirectories, using the default file extensions and templates directory. + ./k-lic --dir /path/to/repo --exclude vendor,node_modules --templates /path/to/templates # Add license headers to all .go, .sh, .py, makefile, docker files in /path/to/repo and its subdirectories, using the license header templates in /path/to/templates. + +``` \ No newline at end of file diff --git a/hack/k-license/k-license.go b/hack/k-license/k-license.go new file mode 100644 index 0000000000..209654d68b --- /dev/null +++ b/hack/k-license/k-license.go @@ -0,0 +1,138 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "time" +) + +var ( + templatesDir = flag.String("templates", "../boilerplate", "directory containing license templates") + excludeDirs = flag.String("exclude", ".git,vendor,node_modules", "comma-separated list of directories to exclude") + path = flag.String("path", ".", "Absolute Path to directory location") + author = flag.String("author", "The Kubernetes Authors", "Replace Author/ORG name") + helpFlag = flag.Bool("help", false, "Display this help message and exit.") +) + +func main() { + flag.Parse() + if *helpFlag { + printHelp(os.Args[0]) + return + } + excludeList := strings.Split(*excludeDirs, ",") + err := filepath.Walk(*path, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() && contains(excludeList, info.Name()) { + return filepath.SkipDir + } + if !info.IsDir() && (isCodeFile(path) || isBuildFile(path)) && !hasLicense(path) { + currentYear := strconv.Itoa(time.Now().Year()) + err := addLicense(path, *templatesDir, currentYear, *author) + if err != nil { + return err + } + fmt.Printf("Modified %s file\n", path) + } + + return nil + }) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func contains(list []string, str string) bool { + for _, item := range list { + if item == str { + return true + } + } + return false +} + +func printHelp(progName string) { + fmt.Fprintf(os.Stderr, "Usage: %s [--help] [-d dir] [--exclude ] [--templates] [--author]\n", progName) + fmt.Fprintln(os.Stderr, "\nAdd a copyright/license header to all source files in a Git repository.\n") + fmt.Fprintln(os.Stderr, "Options:") + flag.PrintDefaults() + fmt.Fprintln(os.Stderr, "\nExamples:") + fmt.Fprintf(os.Stderr, " %s # Add license headers to all source files in the current directory and its subdirectories, using the default file extensions and templates directory.\n", progName) + fmt.Fprintf(os.Stderr, " %s --dir /path/to/repo --exclude vendor,node_modules --templates /path/to/templates # Add license headers to all .go, .sh, .py, makefile, docker files in /path/to/repo and its subdirectories, using the license header templates in /path/to/templates.\n", progName) +} + +func isCodeFile(path string) bool { + ext := strings.ToLower(filepath.Ext(path)) + switch ext { + case ".go", ".c", ".h", ".cpp", ".py", ".ipynb", ".java": + return true + } + return false +} +func isBuildFile(path string) bool { + switch { + case strings.HasSuffix(path, ".sh"): + return true + case strings.HasSuffix(path, "Makefile"): + return true + case strings.HasSuffix(path, "Dockerfile"): + return true + } + return false +} + +func hasLicense(path string) bool { + data, err := ioutil.ReadFile(path) + if err != nil { + return false + } + return strings.Contains(string(data), "Copyright") +} +func getFileType(path string) string { + var tmplFilename string + switch { + case strings.HasSuffix(path, ".sh"): + tmplFilename = "boilerplate.sh.txt" + case strings.HasSuffix(path, "Makefile"): + tmplFilename = "boilerplate.Makefile.txt" + case strings.HasSuffix(path, "Dockerfile"): + tmplFilename = "boilerplate.Dockerfile.txt" + case filepath.Ext(path) == ".py": + tmplFilename = "boilerplate.py.txt" + case filepath.Ext(path) == ".go": + tmplFilename = "boilerplate.go.txt" + default: + tmplFilename = "boilerplate.tf.txt" + } + return tmplFilename +} + +func addLicense(path, templatesDir, year, author string) error { + + tmplData, err := ioutil.ReadFile(filepath.Join(templatesDir, getFileType(path))) + if err != nil { + return err + } + + // Replace placeholders with actual values + tmpl := strings.ReplaceAll(string(tmplData), "", year) + tmpl = strings.ReplaceAll(tmpl, "", author) + + codeData, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + newData := append([]byte(tmpl), []byte("\n\n")...) + newData = append(newData, codeData...) + + return ioutil.WriteFile(path, newData, 0644) +} diff --git a/hack/k-license/k-license_test.go b/hack/k-license/k-license_test.go new file mode 100644 index 0000000000..808ce23b61 --- /dev/null +++ b/hack/k-license/k-license_test.go @@ -0,0 +1,39 @@ +package main + +import ( + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" +) + +func TestAddLicense(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "testdir") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + testfile := filepath.Join(tmpdir, "testfile.go") + err = ioutil.WriteFile(testfile, []byte("package main\n\nfunc main() {\n}\n"), 0644) + if err != nil { + t.Fatal(err) + } + currentYear := strconv.Itoa(time.Now().Year()) + err = addLicense(testfile, "./templates", currentYear, "") + if err != nil { + t.Fatal(err) + } + + data, err := ioutil.ReadFile(testfile) + if err != nil { + t.Fatal(err) + } + + if !strings.Contains(string(data), "Copyright") { + t.Errorf("License not added") + } +}