From 64de3c12533145c97ce2ffcefaf3c291caaa204c Mon Sep 17 00:00:00 2001 From: Jaime Soriano Pastor Date: Wed, 18 Sep 2019 18:26:57 +0200 Subject: [PATCH] Implement check and add headers in mage (#13215) Add a framework to wrap go tooling in mage, taken from go-txtfile. Using it, reimplement all uses of go-licenser in mage. go-licenser is vendored. --- Makefile | 12 +- NOTICE.txt | 16 ++ dev-tools/mage/check.go | 21 ++ dev-tools/mage/fmt.go | 12 +- dev-tools/mage/gotool/get.go | 31 +++ dev-tools/mage/gotool/go.go | 257 ++++++++++++++++++ dev-tools/mage/gotool/licenser.go | 37 +++ dev-tools/mage/install.go | 49 ++++ dev-tools/mage/target/common/check.go | 5 + dev-tools/mage/target/common/fmt.go | 5 + libbeat/scripts/Makefile | 10 +- magefile.go | 51 +++- .../elastic/go-licenser/CONTRIBUTING.md | 47 ++++ vendor/github.com/elastic/go-licenser/LICENSE | 202 ++++++++++++++ .../github.com/elastic/go-licenser/Makefile | 105 +++++++ vendor/github.com/elastic/go-licenser/NOTICE | 5 + .../github.com/elastic/go-licenser/README.md | 46 ++++ .../elastic/go-licenser/appveyor.yml | 38 +++ .../github.com/elastic/go-licenser/error.go | 39 +++ vendor/github.com/elastic/go-licenser/go.mod | 1 + .../elastic/go-licenser/licensing/doc.go | 20 ++ .../elastic/go-licenser/licensing/license.go | 132 +++++++++ vendor/github.com/elastic/go-licenser/main.go | 236 ++++++++++++++++ vendor/github.com/elastic/go-licenser/path.go | 54 ++++ .../github.com/elastic/go-licenser/version.go | 23 ++ vendor/vendor.json | 16 ++ 26 files changed, 1440 insertions(+), 30 deletions(-) create mode 100644 dev-tools/mage/gotool/get.go create mode 100644 dev-tools/mage/gotool/go.go create mode 100644 dev-tools/mage/gotool/licenser.go create mode 100644 dev-tools/mage/install.go create mode 100644 vendor/github.com/elastic/go-licenser/CONTRIBUTING.md create mode 100644 vendor/github.com/elastic/go-licenser/LICENSE create mode 100644 vendor/github.com/elastic/go-licenser/Makefile create mode 100644 vendor/github.com/elastic/go-licenser/NOTICE create mode 100644 vendor/github.com/elastic/go-licenser/README.md create mode 100644 vendor/github.com/elastic/go-licenser/appveyor.yml create mode 100644 vendor/github.com/elastic/go-licenser/error.go create mode 100644 vendor/github.com/elastic/go-licenser/go.mod create mode 100644 vendor/github.com/elastic/go-licenser/licensing/doc.go create mode 100644 vendor/github.com/elastic/go-licenser/licensing/license.go create mode 100644 vendor/github.com/elastic/go-licenser/main.go create mode 100644 vendor/github.com/elastic/go-licenser/path.go create mode 100644 vendor/github.com/elastic/go-licenser/version.go diff --git a/Makefile b/Makefile index 16f326ab0200..a75c772d7aa6 100644 --- a/Makefile +++ b/Makefile @@ -98,16 +98,12 @@ check: python-env @git diff-index --exit-code HEAD -- .PHONY: check-headers -check-headers: - @go get -u github.com/elastic/go-licenser - @go-licenser -d -exclude x-pack -exclude generator/beat/\{beat\} -exclude generator/metricbeat/\{beat\} - @go-licenser -d -license Elastic x-pack +check-headers: mage + @mage checkLicenseHeaders .PHONY: add-headers -add-headers: - @go get github.com/elastic/go-licenser - @go-licenser -exclude x-pack - @go-licenser -license Elastic x-pack +add-headers: mage + @mage addLicenseHeaders # Corrects spelling errors .PHONY: misspell diff --git a/NOTICE.txt b/NOTICE.txt index 907b79cf3b35..da031af8026c 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -859,6 +859,22 @@ License type (autodetected): Apache-2.0 Apache License 2.0 +-------------------------------------------------------------------- +Dependency: github.com/elastic/go-licenser +Version: 0.2.0 +Revision: 2b2abd4ee9b58025ebd0630d7621cfd7619f58ac +License type (autodetected): Apache-2.0 +./vendor/github.com/elastic/go-licenser/LICENSE: +-------------------------------------------------------------------- +Apache License 2.0 + +-------NOTICE----- +Elastic go-licenser +Copyright 2018 Elasticsearch B.V. + +This product includes software developed at +Elasticsearch, B.V. (https://www.elastic.co/). + -------------------------------------------------------------------- Dependency: github.com/elastic/go-lookslike Version: =v0.3.0 diff --git a/dev-tools/mage/check.go b/dev-tools/mage/check.go index 86f0a28ef617..6c30bd1dafc1 100644 --- a/dev-tools/mage/check.go +++ b/dev-tools/mage/check.go @@ -35,6 +35,7 @@ import ( "github.com/magefile/mage/sh" "github.com/pkg/errors" + "github.com/elastic/beats/dev-tools/mage/gotool" "github.com/elastic/beats/libbeat/processors/dissect" ) @@ -189,6 +190,26 @@ func GoVet() error { return errors.Wrap(err, "failed running go vet, please fix the issues reported") } +// CheckLicenseHeaders checks license headers in .go files. +func CheckLicenseHeaders() error { + fmt.Println(">> fmt - go-licenser: Checking for missing headers") + + mg.Deps(InstallGoLicenser) + + var license string + switch BeatLicense { + case "ASL2", "ASL 2.0": + license = "ASL2" + case "Elastic", "Elastic License": + license = "Elastic" + default: + return errors.Errorf("unknown license type %v", BeatLicense) + } + + licenser := gotool.Licenser + return licenser(licenser.Check(), licenser.License(license)) +} + // CheckDashboardsFormat checks the format of dashboards func CheckDashboardsFormat() error { dashboardSubDir := "/_meta/kibana/" diff --git a/dev-tools/mage/fmt.go b/dev-tools/mage/fmt.go index e2671015fa98..8851f67676ad 100644 --- a/dev-tools/mage/fmt.go +++ b/dev-tools/mage/fmt.go @@ -26,6 +26,8 @@ import ( "github.com/magefile/mage/mg" "github.com/magefile/mage/sh" "github.com/pkg/errors" + + "github.com/elastic/beats/dev-tools/mage/gotool" ) var ( @@ -35,9 +37,6 @@ var ( // GoImportsLocalPrefix is a string prefix matching imports that should be // grouped after third-party packages. GoImportsLocalPrefix = "github.com/elastic" - - // GoLicenserImportPath controls the import path used to install go-licenser. - GoLicenserImportPath = "github.com/elastic/go-licenser" ) // Format adds license headers, formats .go files with goimports, and formats @@ -120,9 +119,7 @@ func AddLicenseHeaders() error { fmt.Println(">> fmt - go-licenser: Adding missing headers") - if err := sh.Run("go", "get", GoLicenserImportPath); err != nil { - return err - } + mg.Deps(InstallGoLicenser) var license string switch BeatLicense { @@ -134,5 +131,6 @@ func AddLicenseHeaders() error { return errors.Errorf("unknown license type %v", BeatLicense) } - return sh.RunV("go-licenser", "-license", license) + licenser := gotool.Licenser + return licenser(licenser.License(license)) } diff --git a/dev-tools/mage/gotool/get.go b/dev-tools/mage/gotool/get.go new file mode 100644 index 000000000000..6a147ca93921 --- /dev/null +++ b/dev-tools/mage/gotool/get.go @@ -0,0 +1,31 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package gotool + +type goGet func(opts ...ArgOpt) error + +// Get runs `go get` and provides optionals for adding command line arguments. +var Get goGet = runGoGet + +func runGoGet(opts ...ArgOpt) error { + args := buildArgs(opts) + return runVGo("get", args) +} + +func (goGet) Update() ArgOpt { return flagBoolIf("-u", true) } +func (goGet) Package(pkg string) ArgOpt { return posArg(pkg) } diff --git a/dev-tools/mage/gotool/go.go b/dev-tools/mage/gotool/go.go new file mode 100644 index 000000000000..def2d5d59acb --- /dev/null +++ b/dev-tools/mage/gotool/go.go @@ -0,0 +1,257 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package gotool + +import ( + "os" + "strings" + + "github.com/magefile/mage/mg" + "github.com/magefile/mage/sh" +) + +// Args holds parameters, environment variables and flag information used to +// pass to the go tool. +type Args struct { + extra map[string]string // extra flags one can pass to the command + env map[string]string + flags map[string][]string + pos []string +} + +// ArgOpt is a functional option adding info to Args once executed. +type ArgOpt func(args *Args) + +type goTest func(opts ...ArgOpt) error + +// Test runs `go test` and provides optionals for adding command line arguments. +var Test goTest = runGoTest + +// ListProjectPackages lists all packages in the current project +func ListProjectPackages() ([]string, error) { + return ListPackages("./...") +} + +// ListPackages calls `go list` for every package spec given. +func ListPackages(pkgs ...string) ([]string, error) { + return getLines(callGo(nil, "list", pkgs...)) +} + +// ListTestFiles lists all go and cgo test files available in a package. +func ListTestFiles(pkg string) ([]string, error) { + const tmpl = `{{ range .TestGoFiles }}{{ printf "%s\n" . }}{{ end }}` + + `{{ range .XTestGoFiles }}{{ printf "%s\n" . }}{{ end }}` + + return getLines(callGo(nil, "list", "-f", tmpl, pkg)) +} + +// HasTests returns true if the given package contains test files. +func HasTests(pkg string) (bool, error) { + files, err := ListTestFiles(pkg) + if err != nil { + return false, err + } + return len(files) > 0, nil +} + +func (goTest) WithCoverage(to string) ArgOpt { + return combine(flagArg("-cover", ""), flagArgIf("-test.coverprofile", to)) +} +func (goTest) Short(b bool) ArgOpt { return flagBoolIf("-test.short", b) } +func (goTest) Use(bin string) ArgOpt { return extraArgIf("use", bin) } +func (goTest) OS(os string) ArgOpt { return envArgIf("GOOS", os) } +func (goTest) ARCH(arch string) ArgOpt { return envArgIf("GOARCH", arch) } +func (goTest) Create() ArgOpt { return flagArg("-c", "") } +func (goTest) Out(path string) ArgOpt { return flagArg("-o", path) } +func (goTest) Package(path string) ArgOpt { return posArg(path) } +func (goTest) Verbose() ArgOpt { return flagArg("-test.v", "") } +func runGoTest(opts ...ArgOpt) error { + args := buildArgs(opts) + if bin := args.Val("use"); bin != "" { + flags := map[string][]string{} + for k, v := range args.flags { + if strings.HasPrefix(k, "-test.") { + flags[k] = v + } + } + + useArgs := &Args{} + *useArgs = *args + useArgs.flags = flags + + _, err := sh.Exec(useArgs.env, os.Stdout, os.Stderr, bin, useArgs.build()...) + return err + } + + return runVGo("test", args) +} + +func getLines(out string, err error) ([]string, error) { + if err != nil { + return nil, err + } + + lines := strings.Split(out, "\n") + res := lines[:0] + for _, line := range lines { + line = strings.TrimSpace(line) + if len(line) > 0 { + res = append(res, line) + } + } + + return res, nil +} + +func callGo(env map[string]string, cmd string, opts ...string) (string, error) { + args := []string{cmd} + args = append(args, opts...) + return sh.OutputWith(env, mg.GoCmd(), args...) +} + +func runVGo(cmd string, args *Args) error { + return execGoWith(func(env map[string]string, cmd string, args ...string) error { + _, err := sh.Exec(env, os.Stdout, os.Stderr, cmd, args...) + return err + }, cmd, args) +} + +func runGo(cmd string, args *Args) error { + return execGoWith(sh.RunWith, cmd, args) +} + +func execGoWith( + fn func(map[string]string, string, ...string) error, + cmd string, args *Args, +) error { + cliArgs := []string{cmd} + cliArgs = append(cliArgs, args.build()...) + return fn(args.env, mg.GoCmd(), cliArgs...) +} + +func posArg(value string) ArgOpt { + return func(a *Args) { a.Add(value) } +} + +func extraArg(k, v string) ArgOpt { + return func(a *Args) { a.Extra(k, v) } +} + +func extraArgIf(k, v string) ArgOpt { + if v == "" { + return nil + } + return extraArg(k, v) +} + +func envArg(k, v string) ArgOpt { + return func(a *Args) { a.Env(k, v) } +} + +func envArgIf(k, v string) ArgOpt { + if v == "" { + return nil + } + return envArg(k, v) +} + +func flagArg(flag, value string) ArgOpt { + return func(a *Args) { a.Flag(flag, value) } +} + +func flagArgIf(flag, value string) ArgOpt { + if value == "" { + return nil + } + return flagArg(flag, value) +} + +func flagBoolIf(flag string, b bool) ArgOpt { + if b { + return flagArg(flag, "") + } + return nil +} + +func combine(opts ...ArgOpt) ArgOpt { + return func(a *Args) { + for _, opt := range opts { + if opt != nil { + opt(a) + } + } + } +} + +func buildArgs(opts []ArgOpt) *Args { + a := &Args{} + combine(opts...)(a) + return a +} + +// Extra sets a special k/v pair to be interpreted by the execution function. +func (a *Args) Extra(k, v string) { + if a.extra == nil { + a.extra = map[string]string{} + } + a.extra[k] = v +} + +// Val returns a special functions value for a given key. +func (a *Args) Val(k string) string { + if a.extra == nil { + return "" + } + return a.extra[k] +} + +// Env sets an environmant variable to be passed to the child process on exec. +func (a *Args) Env(k, v string) { + if a.env == nil { + a.env = map[string]string{} + } + a.env[k] = v +} + +// Flag adds a flag to be passed to the child process on exec. +func (a *Args) Flag(flag, value string) { + if a.flags == nil { + a.flags = map[string][]string{} + } + a.flags[flag] = append(a.flags[flag], value) +} + +// Add adds a positional argument to be passed to the child process on exec. +func (a *Args) Add(p string) { + a.pos = append(a.pos, p) +} + +func (a *Args) build() []string { + args := make([]string, 0, 2*len(a.flags)+len(a.pos)) + for k, values := range a.flags { + for _, v := range values { + args = append(args, k) + if v != "" { + args = append(args, v) + } + } + } + + args = append(args, a.pos...) + return args +} diff --git a/dev-tools/mage/gotool/licenser.go b/dev-tools/mage/gotool/licenser.go new file mode 100644 index 000000000000..1d7c6d5255c7 --- /dev/null +++ b/dev-tools/mage/gotool/licenser.go @@ -0,0 +1,37 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package gotool + +import ( + "github.com/magefile/mage/sh" +) + +type goLicenser func(opts ...ArgOpt) error + +// Licenser runs `go-licenser` and provides optionals for adding command line arguments. +var Licenser goLicenser = runGoLicenser + +func runGoLicenser(opts ...ArgOpt) error { + args := buildArgs(opts).build() + return sh.RunV("go-licenser", args...) +} + +func (goLicenser) Check() ArgOpt { return flagBoolIf("-d", true) } +func (goLicenser) License(license string) ArgOpt { return flagArgIf("-license", license) } +func (goLicenser) Exclude(path string) ArgOpt { return flagArgIf("-exclude", path) } +func (goLicenser) Path(path string) ArgOpt { return posArg(path) } diff --git a/dev-tools/mage/install.go b/dev-tools/mage/install.go new file mode 100644 index 000000000000..9b2c7795c631 --- /dev/null +++ b/dev-tools/mage/install.go @@ -0,0 +1,49 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package mage + +import ( + "path/filepath" + + "github.com/pkg/errors" + + "github.com/elastic/beats/dev-tools/mage/gotool" +) + +var ( + // GoLicenserImportPath controls the import path used to install go-licenser. + GoLicenserImportPath = "github.com/elastic/go-licenser" +) + +// InstallVendored uses go get to install a command from its vendored source +func InstallVendored(importPath string) error { + beatDir, err := ElasticBeatsDir() + if err != nil { + return errors.Wrap(err, "failed to obtain beats repository path") + } + + get := gotool.Get + return get( + get.Package(filepath.Join(beatDir, "vendor", importPath)), + ) +} + +// InstallGoLicenser target installs go-licenser +func InstallGoLicenser() error { + return InstallVendored(GoLicenserImportPath) +} diff --git a/dev-tools/mage/target/common/check.go b/dev-tools/mage/target/common/check.go index 16ad95689497..d5038c99c947 100644 --- a/dev-tools/mage/target/common/check.go +++ b/dev-tools/mage/target/common/check.go @@ -39,3 +39,8 @@ func Check() { deps = append(deps, devtools.Check) mg.SerialDeps(deps...) } + +// CheckLicenseHeaders checks license headers +func CheckLicenseHeaders() { + mg.Deps(devtools.CheckLicenseHeaders) +} diff --git a/dev-tools/mage/target/common/fmt.go b/dev-tools/mage/target/common/fmt.go index 69f45fd4a824..9405d69ca487 100644 --- a/dev-tools/mage/target/common/fmt.go +++ b/dev-tools/mage/target/common/fmt.go @@ -27,3 +27,8 @@ import ( func Fmt() { mg.Deps(devtools.Format) } + +// AddLicenseHeaders adds license headers +func AddLicenseHeaders() { + mg.Deps(devtools.AddLicenseHeaders) +} diff --git a/libbeat/scripts/Makefile b/libbeat/scripts/Makefile index 180d567f0332..8c6969d3bca8 100755 --- a/libbeat/scripts/Makefile +++ b/libbeat/scripts/Makefile @@ -125,17 +125,15 @@ check: check-headers mage ## @build Checks project and source code if everything @mage check .PHONY: $(.OVER)check-headers -$(.OVER)check-headers: +$(.OVER)check-headers: mage ifndef CHECK_HEADERS_DISABLED - @go get -u github.com/elastic/go-licenser - @go-licenser -d -license ${LICENSE} + @mage checkLicenseHeaders endif .PHONY: $(.OVER)add-headers -$(.OVER)add-headers: +$(.OVER)add-headers: mage ifndef CHECK_HEADERS_DISABLED - @go get github.com/elastic/go-licenser - @go-licenser -license ${LICENSE} + @mage addLicenseHeaders endif .PHONY: fmt diff --git a/magefile.go b/magefile.go index e89775b07ba2..25eddd0acef6 100644 --- a/magefile.go +++ b/magefile.go @@ -25,11 +25,11 @@ import ( "path/filepath" "github.com/magefile/mage/mg" - "github.com/magefile/mage/sh" "github.com/pkg/errors" "go.uber.org/multierr" devtools "github.com/elastic/beats/dev-tools/mage" + "github.com/elastic/beats/dev-tools/mage/gotool" ) var ( @@ -87,21 +87,54 @@ func PackageBeatDashboards() error { // Fmt formats code and adds license headers. func Fmt() { mg.Deps(devtools.GoImports, devtools.PythonAutopep8) - mg.Deps(addLicenseHeaders) + mg.Deps(AddLicenseHeaders) } -// addLicenseHeaders adds ASL2 headers to .go files outside of x-pack and +// AddLicenseHeaders adds ASL2 headers to .go files outside of x-pack and // add Elastic headers to .go files in x-pack. -func addLicenseHeaders() error { +func AddLicenseHeaders() error { fmt.Println(">> fmt - go-licenser: Adding missing headers") - if err := sh.Run("go", "get", devtools.GoLicenserImportPath); err != nil { - return err - } + mg.Deps(devtools.InstallGoLicenser) + + licenser := gotool.Licenser + + return multierr.Combine( + licenser( + licenser.License("ASL2"), + licenser.Exclude("x-pack"), + licenser.Exclude("generator/beat/{beat}"), + licenser.Exclude("generator/metricbeat/{beat}"), + ), + licenser( + licenser.License("Elastic"), + licenser.Path("x-pack"), + ), + ) +} + +// CheckLicenseHeaders checks ASL2 headers in .go files outside of x-pack and +// checks Elastic headers in .go files in x-pack. +func CheckLicenseHeaders() error { + fmt.Println(">> fmt - go-licenser: Checking for missing headers") + + mg.Deps(devtools.InstallGoLicenser) + + licenser := gotool.Licenser return multierr.Combine( - sh.RunV("go-licenser", "-license", "ASL2", "-exclude", "x-pack"), - sh.RunV("go-licenser", "-license", "Elastic", "x-pack"), + licenser( + licenser.Check(), + licenser.License("ASL2"), + licenser.Exclude("x-pack"), + licenser.Exclude("generator/beat/{beat}"), + licenser.Exclude("generator/metricbeat/{beat}"), + ), + licenser( + licenser.Check(), + licenser.License("Elastic"), + licenser.Path("x-pack"), + ), ) } diff --git a/vendor/github.com/elastic/go-licenser/CONTRIBUTING.md b/vendor/github.com/elastic/go-licenser/CONTRIBUTING.md new file mode 100644 index 000000000000..0c8d15b6f59e --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributing + +Contributions are very welcome, this includes documentation, tutorials, bug reports, issues, feature requests, feature implementations, pull requests or simply organizing the repository issues. + +*Pull requests that contain changes on the code base **and** related documentation, e.g. for a new feature, shall remain a single, atomic one.* + +## Building From Source + +### Environment Prerequisites + +To install the latest changes directly from source code, you will need to have `go` installed with `$GOPATH` defined. If you need assistance with this please follow [golangbootcamp guide](http://www.golangbootcamp.com/book/get_setup#cha-get_setup). + +### Actual installation commands + +**Make sure you have followed through the environment requisites** + +```sh +go get -u github.com/elastic/go-licenser +``` + +## Reporting Issues + +If you have found an issue or defect in `go-licenser` or the latest documentation, use the GitHub [issue tracker](https://github.com/elastic/go-licenser/issues) to report the problem. Make sure to follow the template provided for you to provide all the useful details possible. + + +### Code Contribution Guidelines + +For the benefit of all, here are some recommendations with regards to your PR: + +* Go ahead and fork the project and make your changes. We encourage pull requests to allow for review and discussion of code changes. +* As a best practice it's best to open an Issue on the repository before submitting a PR. +* When you’re ready to create a pull request, be sure to: + * Sign your commit messages, see [DCO details](https://probot.github.io/apps/dco/) + * Have test cases for the new code. If you have questions about how to do this, please ask in your pull request. + * Run `make format` and `make lint`. + * Ensure that `make unit` succeeds. + + +### Golden Files + +If you're working with a function that relies on testdata or golden files, you might need to update those if your +change is modifying that logic. + +```console +$ make update-golden-files +ok github.com/elastic/go-licenser 0.029s +``` diff --git a/vendor/github.com/elastic/go-licenser/LICENSE b/vendor/github.com/elastic/go-licenser/LICENSE new file mode 100644 index 000000000000..0d4ee7515f06 --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/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 2018 Elasticsearch B.V. + + 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/elastic/go-licenser/Makefile b/vendor/github.com/elastic/go-licenser/Makefile new file mode 100644 index 000000000000..c60e3872397b --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/Makefile @@ -0,0 +1,105 @@ +export VERSION := 0.2.0 +OWNER ?= elastic +REPO ?= go-licenser +TEST_UNIT_FLAGS ?= -timeout 10s -p 4 -race -cover +TEST_UNIT_PACKAGE ?= ./... +GOLINT_PRESENT := $(shell command -v golint 2> /dev/null) +GOIMPORTS_PRESENT := $(shell command -v goimports 2> /dev/null) +GORELEASER_PRESENT := $(shell command -v goreleaser 2> /dev/null) +RELEASED = $(shell git tag -l $(VERSION)) +DEFAULT_LDFLAGS ?= -X main.version=$(VERSION)-dev -X main.commit=$(shell git rev-parse HEAD) + +define HELP +///////////////////////////////////////// +/\t$(REPO) Makefile \t\t/ +///////////////////////////////////////// + +## Build target + +- build: It will build $(REPO) for the current architecture in bin/$(REPO). +- install: It will install $(REPO) in the current system (by default in $(GOPATH)/bin/$(REPO)). + +## Development targets + +- deps: It will install the dependencies required to run developemtn targets. +- unit: Runs the unit tests. +- lint: Runs the linters. +- format: Formats the source files according to gofmt, goimports and go-licenser. +- update-golden-files: Updates the test golden files. + +## Release targets + +- release: Creates and publishes a new release matching the VERSION variable. +- snapshot: Creates a snapshot locally in the dist/ folder. + +endef +export HELP + +.DEFAULT: help +.PHONY: help +help: + @ echo "$$HELP" + +.PHONY: deps +deps: +ifndef GOLINT_PRESENT + @ go get -u golang.org/x/lint/golint +endif +ifndef GOIMPORTS_PRESENT + @ go get -u golang.org/x/tools/cmd/goimports +endif + +.PHONY: release_deps +release_deps: +ifndef GORELEASER_PRESENT + @ echo "-> goreleaser not found in path, please install it following the instructions:" + @ echo "-> https://goreleaser.com/introduction" + @ exit 1 +endif + +.PHONY: update-golden-files +update-golden-files: + $(eval GOLDEN_FILE_PACKAGES := "github.com/$(OWNER)/$(REPO)") + @ go test $(GOLDEN_FILE_PACKAGES) -update + +.PHONY: unit +unit: + @ go test $(TEST_UNIT_FLAGS) $(TEST_UNIT_PACKAGE) + +.PHONY: build +build: deps + @ go build -o bin/$(REPO) -ldflags="$(DEFAULT_LDFLAGS)" + +.PHONY: install +install: deps + @ go install + +.PHONY: lint +lint: build + @ golint -set_exit_status $(shell go list ./...) + @ gofmt -d -e -s . + @ ./bin/go-licenser -d -exclude golden + +.PHONY: format +format: deps build + @ gofmt -e -w -s . + @ goimports -w . + @ ./bin/go-licenser -exclude golden + +.PHONY: release +release: deps release_deps + @ echo "-> Releasing $(REPO) $(VERSION)..." + @ git fetch upstream +ifeq ($(strip $(RELEASED)),) + @ echo "-> Creating and pushing a new tag $(VERSION)..." + @ git tag $(VERSION) + @ git push upstream $(VERSION) + @ goreleaser release --rm-dist +else + @ echo "-> git tag $(VERSION) already present, skipping release..." +endif + +.PHONY: snapshot +snapshot: deps release_deps + @ echo "-> Snapshotting $(REPO) $(VERSION)..." + @ goreleaser release --snapshot --rm-dist diff --git a/vendor/github.com/elastic/go-licenser/NOTICE b/vendor/github.com/elastic/go-licenser/NOTICE new file mode 100644 index 000000000000..4972cec5acdd --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/NOTICE @@ -0,0 +1,5 @@ +Elastic go-licenser +Copyright 2018 Elasticsearch B.V. + +This product includes software developed at +Elasticsearch, B.V. (https://www.elastic.co/). diff --git a/vendor/github.com/elastic/go-licenser/README.md b/vendor/github.com/elastic/go-licenser/README.md new file mode 100644 index 000000000000..435b4b1cc3cb --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/README.md @@ -0,0 +1,46 @@ +# Go Licenser [![Build Status](https://travis-ci.org/elastic/go-licenser.svg?branch=master)](https://travis-ci.org/elastic/go-licenser) + +Small zero dependency license header checker for source files. The aim of this project is to provide a common +binary that can be used to ensure that code source files contain a license header. It's unlikely that this project +is useful outside of Elastic **_at the current stage_**, but the `licensing` package can be used as a building block. + +## Supported Licenses + +* Apache 2.0 +* Elastic + +## Supported languages + +* Go + +## Installing + +``` +go get -u github.com/elastic/go-licenser +``` + +## Usage + +``` +Usage: go-licenser [flags] [path] + + go-licenser walks the specified path recursiely and appends a license Header if the current + header doesn't match the one found in the file. + +Options: + + -d skips rewriting files and returns exitcode 1 if any discrepancies are found. + -exclude value + path to exclude (can be specified multiple times). + -ext string + sets the file extension to scan for. (default ".go") + -license string + sets the license type to check: ASL2, Elastic (default "ASL2") + -version + prints out the binary version. +``` + +## Contributing + +See [CONTRIBUTING.md](./CONTRIBUTING.md). + diff --git a/vendor/github.com/elastic/go-licenser/appveyor.yml b/vendor/github.com/elastic/go-licenser/appveyor.yml new file mode 100644 index 000000000000..2292bcb2d933 --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/appveyor.yml @@ -0,0 +1,38 @@ +version: "{build}" + +# Source Config + +clone_folder: c:\gopath\src\github.com\elastic\go-licenser + +# Build host + +environment: + GOPATH: c:\gopath + GOVERSION: 1.10 + +# Build + +install: + # Install the specific Go version. + - rmdir c:\go /s /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi + - msiexec /i go%GOVERSION%.windows-amd64.msi /q + - choco install bzr + - set Path=c:\go\bin;c:\gopath\bin;C:\Program Files (x86)\Bazaar\;C:\Program Files\Mercurial\%Path% + - go version + - go env + +before_build: + - go get -u golang.org/x/lint/golint + - go get -u golang.org/x/tools/cmd/goimports + - golint -set_exit_status . + - gofmt -d -e -s . + - goimports -d . + +build_script: + - appveyor AddCompilationMessage "Starting Compilation" + - go install github.com/elastic/go-licenser + +test_script: + - go-licenser -d -exclude golden + - go test -timeout 10s -p 4 -race -cover ./... diff --git a/vendor/github.com/elastic/go-licenser/error.go b/vendor/github.com/elastic/go-licenser/error.go new file mode 100644 index 000000000000..5c40faa3b2cb --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/error.go @@ -0,0 +1,39 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package main + +// Error wraps a normal error with an Exitcode. +type Error struct { + err error + code int +} + +func (e Error) Error() string { + if e.err != nil { + return e.err.Error() + } + return "" +} + +// Code returns the exitcode for the error +func Code(e error) int { + if err, ok := e.(*Error); ok { + return err.code + } + return 0 +} diff --git a/vendor/github.com/elastic/go-licenser/go.mod b/vendor/github.com/elastic/go-licenser/go.mod new file mode 100644 index 000000000000..89b964cbf36b --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/go.mod @@ -0,0 +1 @@ +module github.com/elastic/go-licenser diff --git a/vendor/github.com/elastic/go-licenser/licensing/doc.go b/vendor/github.com/elastic/go-licenser/licensing/doc.go new file mode 100644 index 000000000000..3fcc1ac56b34 --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/licensing/doc.go @@ -0,0 +1,20 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +// Package licensing provides a set of functions that read the top +// lines of a file and can determine if they match a specific header. +package licensing diff --git a/vendor/github.com/elastic/go-licenser/licensing/license.go b/vendor/github.com/elastic/go-licenser/licensing/license.go new file mode 100644 index 000000000000..fad14c14ed9a --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/licensing/license.go @@ -0,0 +1,132 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package licensing + +import ( + "bufio" + "bytes" + "errors" + "io" + "io/ioutil" + "os" + "reflect" + "strings" +) + +var ( + startPrefixes = []string{"// Copyright", "// copyright", "// Licensed", "// licensed"} + endPrefixes = []string{"package ", "// Package ", "// +build ", "// Code generated by", "// code generated by"} + + errHeaderIsTooShort = errors.New("header is too short") +) + +// ContainsHeader reads the first N lines of a file and checks if the header +// matches the one that is expected +func ContainsHeader(r io.Reader, headerLines []string) bool { + var found []string + var scanner = bufio.NewScanner(r) + + for scanner.Scan() { + found = append(found, scanner.Text()) + } + + if len(found) < len(headerLines) { + return false + } + + if !reflect.DeepEqual(found[:len(headerLines)], headerLines) { + return false + } + + return true +} + +// RewriteFileWithHeader reads a file from a path and rewrites it with a header +func RewriteFileWithHeader(path string, header []byte) error { + if len(header) < 2 { + return errHeaderIsTooShort + } + + info, err := os.Stat(path) + if err != nil { + return err + } + + origin, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + data := RewriteWithHeader(origin, header) + return ioutil.WriteFile(path, data, info.Mode()) +} + +// RewriteWithHeader rewrites the src byte buffers header with the new header. +func RewriteWithHeader(src []byte, header []byte) []byte { + // Ensures that the header includes two break lines as the last bytes + for !reflect.DeepEqual(header[len(header)-2:], []byte("\n\n")) { + header = append(header, []byte("\n")...) + } + + var oldHeader = headerBytes(bytes.NewReader(src)) + return bytes.Replace(src, oldHeader, header, 1) +} + +// headerBytes detects the header lines of an io.Reader contents and returns +// what it considerst to be the header as a slice of bytes. +func headerBytes(r io.Reader) []byte { + var scanner = bufio.NewScanner(r) + var replaceableHeader []byte + var continuedHeader bool + for scanner.Scan() { + var t = scanner.Text() + + for i := range endPrefixes { + if strings.HasPrefix(t, endPrefixes[i]) { + return replaceableHeader + } + } + + for i := range startPrefixes { + if strings.HasPrefix(t, startPrefixes[i]) { + continuedHeader = true + } + } + + if continuedHeader { + replaceableHeader = append(replaceableHeader, []byte(t+"\n")...) + } + } + + return replaceableHeader +} + +// containsHeaderLine reads the first N lines of a file and checks if the header +// matches the one that is expected +func containsHeaderLine(r io.Reader, headerLines []string) bool { + var scanner = bufio.NewScanner(r) + for scanner.Scan() { + for i := range headerLines { + if scanner.Text() == headerLines[i] { + return true + } + } + } + + return false +} diff --git a/vendor/github.com/elastic/go-licenser/main.go b/vendor/github.com/elastic/go-licenser/main.go new file mode 100644 index 000000000000..e04a421eaf9a --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/main.go @@ -0,0 +1,236 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package main + +import ( + "flag" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/elastic/go-licenser/licensing" +) + +const ( + defaultExt = ".go" + defaultPath = "." + defaultLicense = "ASL2" + defaultFormat = "%s: is missing the license header\n" +) + +const ( + exitDefault = iota + exitSourceNeedsToBeRewritten + exitFailedToStatTree + exitFailedToStatFile + exitFailedToWalkPath + exitFailedToOpenWalkFile + errFailedRewrittingFile + errUnknownLicense +) + +var usageText = ` +Usage: go-licenser [flags] [path] + + go-licenser walks the specified path recursiely and appends a license Header if the current + header doesn't match the one found in the file. + +Options: + +`[1:] + +// Headers is the map of supported licenses +var Headers = map[string][]string{ + "ASL2": { + `// Licensed to Elasticsearch B.V. under one or more contributor`, + `// license agreements. See the NOTICE file distributed with`, + `// this work for additional information regarding copyright`, + `// ownership. Elasticsearch B.V. licenses this file to you 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.`, + }, + "Elastic": { + `// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one`, + `// or more contributor license agreements. Licensed under the Elastic License;`, + `// you may not use this file except in compliance with the Elastic License.`, + }, +} + +var ( + dryRun bool + showVersion bool + extension string + args []string + license string + exclude sliceFlag + defaultExludedDirs = []string{"vendor", ".git"} +) + +type sliceFlag []string + +func (f *sliceFlag) String() string { + var s string + for _, i := range *f { + s += i + " " + } + return s +} + +func (f *sliceFlag) Set(value string) error { + *f = append(*f, value) + return nil +} + +func init() { + flag.Var(&exclude, "exclude", `path to exclude (can be specified multiple times).`) + flag.BoolVar(&dryRun, "d", false, `skips rewriting files and returns exitcode 1 if any discrepancies are found.`) + flag.BoolVar(&showVersion, "version", false, `prints out the binary version.`) + flag.StringVar(&extension, "ext", defaultExt, "sets the file extension to scan for.") + flag.StringVar(&license, "license", defaultLicense, "sets the license type to check: ASL2, Elastic") + flag.Usage = usageFlag + flag.Parse() + args = flag.Args() +} + +func main() { + if showVersion { + fmt.Printf("go-licenser %s (%s)\n", version, commit) + return + } + + err := run(args, license, exclude, extension, dryRun, os.Stdout) + if err != nil && err.Error() != "" { + fmt.Fprint(os.Stderr, err) + } + + os.Exit(Code(err)) +} + +func run(args []string, license string, exclude []string, ext string, dry bool, out io.Writer) error { + header, ok := Headers[license] + if !ok { + return &Error{err: fmt.Errorf("unknown license: %s", license), code: errUnknownLicense} + } + + var headerBytes []byte + for i := range header { + headerBytes = append(headerBytes, []byte(header[i])...) + headerBytes = append(headerBytes, []byte("\n")...) + } + + var path = defaultPath + if len(args) > 0 { + path = args[0] + } + + if _, err := os.Stat(path); err != nil { + return &Error{err: err, code: exitFailedToStatTree} + } + + return walk(path, ext, license, headerBytes, exclude, dry, out) +} + +func reportFile(out io.Writer, f string) { + cwd, _ := filepath.Abs(filepath.Dir(os.Args[0])) + rel, err := filepath.Rel(cwd, f) + if err != nil { + rel = f + } + fmt.Fprintf(out, defaultFormat, rel) +} + +func walk(p, ext, license string, headerBytes []byte, exclude []string, dry bool, out io.Writer) error { + var err error + filepath.Walk(p, func(path string, info os.FileInfo, walkErr error) error { + if walkErr != nil { + err = &Error{err: walkErr, code: exitFailedToWalkPath} + return walkErr + } + + var currentPath = cleanPathPrefixes( + strings.Replace(path, p, "", 1), + []string{string(os.PathSeparator)}, + ) + + var excludedDir = info.IsDir() && stringInSlice(info.Name(), defaultExludedDirs) + if needsExclusion(currentPath, exclude) || excludedDir { + return filepath.SkipDir + } + + if e := addOrCheckLicense(path, ext, license, headerBytes, info, dry, out); e != nil { + err = e + } + + return nil + }) + + return err +} + +func addOrCheckLicense(path, ext, license string, headerBytes []byte, info os.FileInfo, dry bool, out io.Writer) error { + if info.IsDir() || filepath.Ext(path) != ext { + return nil + } + + f, e := os.Open(path) + if e != nil { + return &Error{err: e, code: exitFailedToOpenWalkFile} + } + defer f.Close() + + if licensing.ContainsHeader(f, Headers[license]) { + return nil + } + + if dry { + reportFile(out, path) + return &Error{code: exitSourceNeedsToBeRewritten} + } + + if err := licensing.RewriteFileWithHeader(path, headerBytes); err != nil { + return &Error{err: err, code: errFailedRewrittingFile} + } + + return nil +} + +func stringInSlice(a string, list []string) bool { + for _, b := range list { + if b == a { + return true + } + } + return false +} + +func usageFlag() { + fmt.Fprintf(os.Stderr, usageText) + flag.PrintDefaults() +} diff --git a/vendor/github.com/elastic/go-licenser/path.go b/vendor/github.com/elastic/go-licenser/path.go new file mode 100644 index 000000000000..fad555b0592d --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/path.go @@ -0,0 +1,54 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package main + +import ( + "os" + "strings" +) + +func needsExclusion(path string, exclude []string) bool { + for _, excluded := range exclude { + excluded = cleanPathSuffixes(excluded, []string{"*", string(os.PathSeparator)}) + if strings.HasPrefix(path, excluded) { + return true + } + } + + return false +} + +func cleanPathSuffixes(path string, sufixes []string) string { + for _, suffix := range sufixes { + for strings.HasSuffix(path, suffix) && len(path) > 0 { + path = path[:len(path)-len(suffix)] + } + } + + return path +} + +func cleanPathPrefixes(path string, prefixes []string) string { + for _, prefix := range prefixes { + for strings.HasPrefix(path, prefix) && len(path) > 0 { + path = path[len(prefix):] + } + } + + return path +} diff --git a/vendor/github.com/elastic/go-licenser/version.go b/vendor/github.com/elastic/go-licenser/version.go new file mode 100644 index 000000000000..426d12340859 --- /dev/null +++ b/vendor/github.com/elastic/go-licenser/version.go @@ -0,0 +1,23 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you 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. + +package main + +var ( + version string + commit string +) diff --git a/vendor/vendor.json b/vendor/vendor.json index 78b6d1cd0d10..7a99840feab7 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1366,6 +1366,22 @@ "version": "v0.4.0", "versionExact": "v0.4.0" }, + { + "checksumSHA1": "qM65VcezrEdAS7HdzRAh3RGnwWw=", + "path": "github.com/elastic/go-licenser", + "revision": "2b2abd4ee9b58025ebd0630d7621cfd7619f58ac", + "revisionTime": "2018-08-30T07:58:35Z", + "version": "0.2.0", + "versionExact": "0.2.0" + }, + { + "checksumSHA1": "R/WGo2p8J0KsCMu8nrbemg+iqIw=", + "path": "github.com/elastic/go-licenser/licensing", + "revision": "2b2abd4ee9b58025ebd0630d7621cfd7619f58ac", + "revisionTime": "2018-08-30T07:58:35Z", + "version": "0.2.0", + "versionExact": "0.2.0" + }, { "checksumSHA1": "+nIsRlnG94bUQI6IQd4Mcj4diTY=", "path": "github.com/elastic/go-lookslike",