diff --git a/deps.bzl b/deps.bzl index 7e48b6ec..c1790a15 100644 --- a/deps.bzl +++ b/deps.bzl @@ -675,6 +675,12 @@ def go_dependencies(): sum = "h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=", version = "v0.0.4", ) + go_repository( + name = "com_github_google_addlicense", + importpath = "github.com/google/addlicense", + sum = "h1:jpVf9qPbU8rz5MxKo7d+RMcNHkqxi4YJi/laauX4aAE=", + version = "v1.1.1", + ) go_repository( name = "com_github_google_btree", diff --git a/go.mod b/go.mod index b2cf4653..bd5eb2b3 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/bazelbuild/bazel-watcher v0.23.7 github.com/dexidp/dex v0.0.0-20230804184036-a9d1fd31c329 github.com/gogo/status v1.1.1 + github.com/google/addlicense v1.1.1 github.com/googleapis/api-linter v1.56.1 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 diff --git a/go.sum b/go.sum index 68e8a7a6..16535316 100644 --- a/go.sum +++ b/go.sum @@ -130,6 +130,7 @@ github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCS github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= @@ -307,6 +308,8 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/addlicense v1.1.1 h1:jpVf9qPbU8rz5MxKo7d+RMcNHkqxi4YJi/laauX4aAE= +github.com/google/addlicense v1.1.1/go.mod h1:Sm/DHu7Jk+T5miFHHehdIjbi4M5+dJDRS3Cq0rncIxA= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= diff --git a/vendor.go b/vendor.go index a6e77ebe..a10af003 100644 --- a/vendor.go +++ b/vendor.go @@ -26,4 +26,6 @@ import ( _ "github.com/temporalio/temporalite/cmd/temporalite" // dex _ "github.com/dexidp/dex/cmd/dex" + // addlicense + _ "github.com/google/addlicense" ) diff --git a/vendor/github.com/google/addlicense/.gitignore b/vendor/github.com/google/addlicense/.gitignore new file mode 100644 index 00000000..cde01232 --- /dev/null +++ b/vendor/github.com/google/addlicense/.gitignore @@ -0,0 +1,2 @@ + +dist/ diff --git a/vendor/github.com/google/addlicense/.golangci.yaml b/vendor/github.com/google/addlicense/.golangci.yaml new file mode 100644 index 00000000..1526bd38 --- /dev/null +++ b/vendor/github.com/google/addlicense/.golangci.yaml @@ -0,0 +1,12 @@ +linters: + enable: + - dogsled + - dupl + - gofmt + - goimports + - misspell + - nakedret + - stylecheck + - unconvert + - unparam + - whitespace diff --git a/vendor/github.com/google/addlicense/.goreleaser.yaml b/vendor/github.com/google/addlicense/.goreleaser.yaml new file mode 100644 index 00000000..b06b10e4 --- /dev/null +++ b/vendor/github.com/google/addlicense/.goreleaser.yaml @@ -0,0 +1,34 @@ +before: + hooks: + - go mod tidy +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + goarch: + - amd64 + - arm64 +archives: + - format_overrides: + - goos: windows + format: zip + replacements: + darwin: macOS + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + files: + - LICENSE +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ incpatch .Tag }}-next" +changelog: + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/vendor/github.com/google/addlicense/BUILD b/vendor/github.com/google/addlicense/BUILD new file mode 100644 index 00000000..da6cd783 --- /dev/null +++ b/vendor/github.com/google/addlicense/BUILD @@ -0,0 +1,22 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "addlicense_lib", + srcs = [ + "main.go", + "tmpl.go", + ], + importmap = "go.resf.org/peridot/vendor/github.com/google/addlicense", + importpath = "github.com/google/addlicense", + visibility = ["//visibility:private"], + deps = [ + "//vendor/github.com/bmatcuk/doublestar/v4:doublestar", + "//vendor/golang.org/x/sync/errgroup", + ], +) + +go_binary( + name = "addlicense", + embed = [":addlicense_lib"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/google/addlicense/CONTRIBUTING.md b/vendor/github.com/google/addlicense/CONTRIBUTING.md new file mode 100644 index 00000000..21e4c711 --- /dev/null +++ b/vendor/github.com/google/addlicense/CONTRIBUTING.md @@ -0,0 +1,25 @@ +Want to contribute? Great! First, read this page (including the small print at the end). + +### Before you contribute +Before we can use your code, you must sign the +[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) +(CLA), which you can do online. The CLA is necessary mainly because you own the +copyright to your changes, even after your contribution becomes part of our +codebase, so we need your permission to use and distribute your code. We also +need to be sure of various other things—for instance that you'll tell us if you +know that your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Code reviews +All submissions, including submissions by project members, require review. We +use Github pull requests for this purpose. + +### The small print +Contributions made by corporations are covered by a different agreement than +the one above, the +[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). diff --git a/vendor/github.com/google/addlicense/Dockerfile b/vendor/github.com/google/addlicense/Dockerfile new file mode 100644 index 00000000..39ef3298 --- /dev/null +++ b/vendor/github.com/google/addlicense/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:1.16 AS build + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +# copy source and build +COPY . . +RUN CGO_ENABLED=0 GOOS=linux go build . + + +# make a bare minimal image +FROM scratch + +# source to be scanned should be mounted to /src +WORKDIR /src +COPY --from=build /app/addlicense /app/addlicense + +ENTRYPOINT ["/app/addlicense"] diff --git a/vendor/github.com/google/addlicense/LICENSE b/vendor/github.com/google/addlicense/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/vendor/github.com/google/addlicense/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/google/addlicense/README.md b/vendor/github.com/google/addlicense/README.md new file mode 100644 index 00000000..008f2b23 --- /dev/null +++ b/vendor/github.com/google/addlicense/README.md @@ -0,0 +1,71 @@ +# addlicense + +The program ensures source code files have copyright license headers +by scanning directory patterns recursively. + +It modifies all source files in place and avoids adding a license header +to any file that already has one. + +addlicense requires go 1.16 or later. + +## install + + go install github.com/google/addlicense@latest + +## usage + + addlicense [flags] pattern [pattern ...] + + -c copyright holder (default "Google LLC") + -check check only mode: verify presence of license headers and exit with non-zero code if missing + -f license file + -ignore file patterns to ignore, for example: -ignore **/*.go -ignore vendor/** + -l license type: apache, bsd, mit, mpl (default "apache") + -s Include SPDX identifier in license header. Set -s=only to only include SPDX identifier. + -v verbose mode: print the name of the files that are modified + -y copyright year(s) (default "2022") + +The pattern argument can be provided multiple times, and may also refer +to single files. Directories are processed recursively. + +For example, to run addlicense across everything in the current directory and +all subdirectories: + + addlicense . + +The `-ignore` flag can use any pattern [supported by +doublestar](https://github.com/bmatcuk/doublestar#patterns). + +## Running in a Docker Container + +The simplest way to get the addlicense docker image is to pull from GitHub +Container Registry: + +```bash +docker pull ghcr.io/google/addlicense:latest +``` + +Alternately, you can build it from source yourself: + +```bash +docker build -t ghcr.io/google/addlicense . +``` + +Once you have the image, you can test that it works by running: + +```bash +docker run -it ghcr.io/google/addlicense -h +``` + +Finally, to run it, mount the directory you want to scan to `/src` and pass the +appropriate addlicense flags: + +```bash +docker run -it -v ${PWD}:/src ghcr.io/google/addlicense -c "Google LLC" *.go +``` + +## license + +Apache 2.0 + +This is not an official Google product. diff --git a/vendor/github.com/google/addlicense/main.go b/vendor/github.com/google/addlicense/main.go new file mode 100644 index 00000000..f80a74fa --- /dev/null +++ b/vendor/github.com/google/addlicense/main.go @@ -0,0 +1,378 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This program ensures source code files have copyright license headers. +// See usage with "addlicense -h". +package main + +import ( + "bytes" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "regexp" + "strings" + "text/template" + "time" + + doublestar "github.com/bmatcuk/doublestar/v4" + "golang.org/x/sync/errgroup" +) + +const helpText = `Usage: addlicense [flags] pattern [pattern ...] + +The program ensures source code files have copyright license headers +by scanning directory patterns recursively. + +It modifies all source files in place and avoids adding a license header +to any file that already has one. + +The pattern argument can be provided multiple times, and may also refer +to single files. + +Flags: + +` + +var ( + skipExtensionFlags stringSlice + ignorePatterns stringSlice + spdx spdxFlag + + holder = flag.String("c", "Google LLC", "copyright holder") + license = flag.String("l", "apache", "license type: apache, bsd, mit, mpl") + licensef = flag.String("f", "", "license file") + year = flag.String("y", fmt.Sprint(time.Now().Year()), "copyright year(s)") + verbose = flag.Bool("v", false, "verbose mode: print the name of the files that are modified or were skipped") + checkonly = flag.Bool("check", false, "check only mode: verify presence of license headers and exit with non-zero code if missing") +) + +func init() { + flag.Usage = func() { + fmt.Fprint(os.Stderr, helpText) + flag.PrintDefaults() + } + flag.Var(&skipExtensionFlags, "skip", "[deprecated: see -ignore] file extensions to skip, for example: -skip rb -skip go") + flag.Var(&ignorePatterns, "ignore", "file patterns to ignore, for example: -ignore **/*.go -ignore vendor/**") + flag.Var(&spdx, "s", "Include SPDX identifier in license header. Set -s=only to only include SPDX identifier.") +} + +// stringSlice stores the results of a repeated command line flag as a string slice. +type stringSlice []string + +func (i *stringSlice) String() string { + return fmt.Sprint(*i) +} + +func (i *stringSlice) Set(value string) error { + *i = append(*i, value) + return nil +} + +// spdxFlag defines the line flag behavior for specifying SPDX support. +type spdxFlag string + +const ( + spdxOff spdxFlag = "" + spdxOn spdxFlag = "true" // value set by flag package on bool flag + spdxOnly spdxFlag = "only" +) + +// IsBoolFlag causes a bare '-s' flag to be set as the string 'true'. This +// allows the use of the bare '-s' or setting a string '-s=only'. +func (i *spdxFlag) IsBoolFlag() bool { return true } +func (i *spdxFlag) String() string { return string(*i) } + +func (i *spdxFlag) Set(value string) error { + v := spdxFlag(value) + if v != spdxOn && v != spdxOnly { + return fmt.Errorf("error: flag 's' expects '%v' or '%v'", spdxOn, spdxOnly) + } + *i = v + return nil +} + +func main() { + flag.Parse() + if flag.NArg() == 0 { + flag.Usage() + os.Exit(1) + } + + // convert -skip flags to -ignore equivalents + for _, s := range skipExtensionFlags { + ignorePatterns = append(ignorePatterns, fmt.Sprintf("**/*.%s", s)) + } + // verify that all ignorePatterns are valid + for _, p := range ignorePatterns { + if !doublestar.ValidatePattern(p) { + log.Fatalf("-ignore pattern %q is not valid", p) + } + } + + // map legacy license values + if t, ok := legacyLicenseTypes[*license]; ok { + *license = t + } + + data := licenseData{ + Year: *year, + Holder: *holder, + SPDXID: *license, + } + + tpl, err := fetchTemplate(*license, *licensef, spdx) + if err != nil { + log.Fatal(err) + } + t, err := template.New("").Parse(tpl) + if err != nil { + log.Fatal(err) + } + + // process at most 1000 files in parallel + ch := make(chan *file, 1000) + done := make(chan struct{}) + go func() { + var wg errgroup.Group + for f := range ch { + f := f // https://golang.org/doc/faq#closures_and_goroutines + wg.Go(func() error { + if *checkonly { + // Check if file extension is known + lic, err := licenseHeader(f.path, t, data) + if err != nil { + log.Printf("%s: %v", f.path, err) + return err + } + if lic == nil { // Unknown fileExtension + return nil + } + // Check if file has a license + hasLicense, err := fileHasLicense(f.path) + if err != nil { + log.Printf("%s: %v", f.path, err) + return err + } + if !hasLicense { + fmt.Printf("%s\n", f.path) + return errors.New("missing license header") + } + } else { + modified, err := addLicense(f.path, f.mode, t, data) + if err != nil { + log.Printf("%s: %v", f.path, err) + return err + } + if *verbose && modified { + log.Printf("%s modified", f.path) + } + } + return nil + }) + } + err := wg.Wait() + close(done) + if err != nil { + os.Exit(1) + } + }() + + for _, d := range flag.Args() { + if err := walk(ch, d); err != nil { + log.Fatal(err) + } + } + close(ch) + <-done +} + +type file struct { + path string + mode os.FileMode +} + +func walk(ch chan<- *file, start string) error { + return filepath.Walk(start, func(path string, fi os.FileInfo, err error) error { + if err != nil { + log.Printf("%s error: %v", path, err) + return nil + } + if fi.IsDir() { + return nil + } + if fileMatches(path, ignorePatterns) { + if *verbose { + log.Printf("skipping: %s", path) + } + return nil + } + ch <- &file{path, fi.Mode()} + return nil + }) +} + +// fileMatches determines if path matches one of the provided file patterns. +// Patterns are assumed to be valid. +func fileMatches(path string, patterns []string) bool { + for _, p := range patterns { + // ignore error, since we assume patterns are valid + if match, _ := doublestar.Match(p, path); match { + return true + } + } + return false +} + +// addLicense add a license to the file if missing. +// +// It returns true if the file was updated. +func addLicense(path string, fmode os.FileMode, tmpl *template.Template, data licenseData) (bool, error) { + var lic []byte + var err error + lic, err = licenseHeader(path, tmpl, data) + if err != nil || lic == nil { + return false, err + } + + b, err := ioutil.ReadFile(path) + if err != nil { + return false, err + } + if hasLicense(b) || isGenerated(b) { + return false, err + } + + line := hashBang(b) + if len(line) > 0 { + b = b[len(line):] + if line[len(line)-1] != '\n' { + line = append(line, '\n') + } + lic = append(line, lic...) + } + b = append(lic, b...) + return true, ioutil.WriteFile(path, b, fmode) +} + +// fileHasLicense reports whether the file at path contains a license header. +func fileHasLicense(path string) (bool, error) { + b, err := ioutil.ReadFile(path) + if err != nil { + return false, err + } + // If generated, we count it as if it has a license. + return hasLicense(b) || isGenerated(b), nil +} + +// licenseHeader populates the provided license template with data, and returns +// it with the proper prefix for the file type specified by path. The file does +// not need to actually exist, only its name is used to determine the prefix. +func licenseHeader(path string, tmpl *template.Template, data licenseData) ([]byte, error) { + var lic []byte + var err error + base := strings.ToLower(filepath.Base(path)) + + switch fileExtension(base) { + case ".c", ".h", ".gv", ".java", ".scala", ".kt", ".kts": + lic, err = executeTemplate(tmpl, data, "/*", " * ", " */") + case ".js", ".mjs", ".cjs", ".jsx", ".tsx", ".css", ".scss", ".sass", ".ts": + lic, err = executeTemplate(tmpl, data, "/**", " * ", " */") + case ".cc", ".cpp", ".cs", ".go", ".hcl", ".hh", ".hpp", ".m", ".mm", ".proto", ".rs", ".swift", ".dart", ".groovy", ".v", ".sv": + lic, err = executeTemplate(tmpl, data, "", "// ", "") + case ".py", ".sh", ".yaml", ".yml", ".dockerfile", "dockerfile", ".rb", "gemfile", ".tcl", ".tf", ".bzl", ".pl", ".pp", "build": + lic, err = executeTemplate(tmpl, data, "", "# ", "") + case ".el", ".lisp": + lic, err = executeTemplate(tmpl, data, "", ";; ", "") + case ".erl": + lic, err = executeTemplate(tmpl, data, "", "% ", "") + case ".hs", ".sql", ".sdl": + lic, err = executeTemplate(tmpl, data, "", "-- ", "") + case ".html", ".xml", ".vue", ".wxi", ".wxl", ".wxs": + lic, err = executeTemplate(tmpl, data, "") + case ".php": + lic, err = executeTemplate(tmpl, data, "", "// ", "") + case ".ml", ".mli", ".mll", ".mly": + lic, err = executeTemplate(tmpl, data, "(**", " ", "*)") + default: + // handle various cmake files + if base == "cmakelists.txt" || strings.HasSuffix(base, ".cmake.in") || strings.HasSuffix(base, ".cmake") { + lic, err = executeTemplate(tmpl, data, "", "# ", "") + } + } + return lic, err +} + +// fileExtension returns the file extension of name, or the full name if there +// is no extension. +func fileExtension(name string) string { + if v := filepath.Ext(name); v != "" { + return v + } + return name +} + +var head = []string{ + "#!", // shell script + "