Clean up license-related scripts
Bug: 364634028
Change-Id: I5074c4b2b46ebbf13eb6ff2c7769078f8a845da9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/75853
Reviewed-by: Bob Beck <bbe@google.com>
Reviewed-by: Adam Langley <agl@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/util/copyright_summary.go b/util/copyright_summary.go
deleted file mode 100644
index fa22a5d..0000000
--- a/util/copyright_summary.go
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2024 The BoringSSL Authors
-//
-// 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
-//
-// https://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.
-
-//go:build ignore
-
-package main
-
-import (
- "bufio"
- "cmp"
- _ "embed"
- "encoding/json"
- "flag"
- "fmt"
- "iter"
- "maps"
- "os"
- "regexp"
- "slices"
- "strconv"
-)
-
-var (
- outPath = flag.String("out", "", "The path to write the results in JSON format")
- comparePath = flag.String("compare", "", "The path to a JSON file to compare against")
-)
-
-func sortedKeyValuePairs[K cmp.Ordered, V any](m map[K]V) iter.Seq2[K, V] {
- return func(yield func(K, V) bool) {
- for _, k := range slices.Sorted(maps.Keys(m)) {
- if !yield(k, m[k]) {
- return
- }
- }
- }
-}
-
-var copyrightRE = regexp.MustCompile(
- `Copyright ` +
- // Ignore (c) and (C)
- `(?:\([cC]\) )?` +
- // Capture the starting copyright year.
- `([0-9]+)` +
- // Ignore ending copyright year. OpenSSL's "copyright consolidation"
- // tool rewrites it anyway. We're just interested in looking for which
- // start years changed, to manually double-check.
- `(?:[-,][0-9]+)?` +
- // Some files have a comma after the years.
- `,?` +
- // Skip spaces.
- ` *` +
- // Capture the name. Stop at punctuation and don't pick up trailing
- // spaces. We don't want to pick up things like "All Rights Reserved".
- // This does drop things like ", Inc", but this is good enough for a
- // summary to double-check an otherwise mostly automated process.
- `([-a-zA-Z ]*[-a-zA-Z])`)
-
-type CopyrightInfo struct {
- Name string
- StartYear int
-}
-
-type FileInfo struct {
- CopyrightInfos []CopyrightInfo
-}
-
-func (f *FileInfo) MergeFrom(other FileInfo) {
- f.CopyrightInfos = append(f.CopyrightInfos, other.CopyrightInfos...)
-}
-
-func summarize(info FileInfo) map[string]int {
- ret := map[string]int{}
- for _, c := range info.CopyrightInfos {
- name := c.Name
- // Apply the same mapping as OpenSSL's "copyright consolidation" script.
- if name == "The OpenSSL Project" || name == "Eric Young" {
- name = "The OpenSSL Project Authors"
- }
- if old, ok := ret[name]; !ok || old > c.StartYear {
- ret[name] = c.StartYear
- }
- }
- return ret
-}
-
-func process(path string) (info FileInfo, err error) {
- f, err := os.Open(path)
- if err != nil {
- return
- }
- defer f.Close()
-
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- m := copyrightRE.FindStringSubmatch(scanner.Text())
- if m == nil {
- continue
- }
- var year int
- year, err = strconv.Atoi(m[1])
- if err != nil {
- err = fmt.Errorf("error parsing year %q: %s", m[1], err)
- return
- }
- info.CopyrightInfos = append(info.CopyrightInfos, CopyrightInfo{Name: m[2], StartYear: year})
- }
- err = scanner.Err()
- return
-}
-
-func main() {
- flag.Parse()
-
- infos := map[string]FileInfo{}
- for _, path := range flag.Args() {
- info, err := process(path)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error processing %q: %s\n", path, err)
- os.Exit(1)
- }
- infos[path] = info
- }
-
- if len(*outPath) != 0 {
- data, err := json.Marshal(infos)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error serializing results: %s\n", err)
- os.Exit(1)
- }
- if err := os.WriteFile(*outPath, data, 0666); err != nil {
- fmt.Fprintf(os.Stderr, "Error writing results: %s\n", err)
- os.Exit(1)
- }
- }
-
- if len(*comparePath) == 0 {
- // Print what we have and return.
- for path, info := range sortedKeyValuePairs(infos) {
- for _, c := range info.CopyrightInfos {
- fmt.Printf("%s: %d %s\n", path, c.StartYear, c.Name)
- }
- }
- return
- }
-
- oldData, err := os.ReadFile(*comparePath)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error reading file: %s\n", err)
- os.Exit(1)
- }
- var oldInfos map[string]FileInfo
- if err := json.Unmarshal(oldData, &oldInfos); err != nil {
- fmt.Fprintf(os.Stderr, "Error decoding %q: %s\n", *comparePath, err)
- os.Exit(1)
- }
- // Output in CSV, so it is easy to paste into a spreadsheet.
- fmt.Printf("Path,Name,Old Start Year,New Start Year\n")
- for path, info := range sortedKeyValuePairs(infos) {
- oldInfo, ok := oldInfos[path]
- if !ok {
- fmt.Printf("%s: file not previously present\n", path)
- continue
- }
-
- summary := summarize(info)
- oldSummary := summarize(oldInfo)
- for name, year := range sortedKeyValuePairs(summary) {
- oldYear, ok := oldSummary[name]
- if !ok {
- fmt.Printf("%s,%s,-1,%d\n", path, name, year)
- } else if year != oldYear {
- fmt.Printf("%s,%s,%d,%d\n", path, name, oldYear, year)
- }
- }
- for oldName, oldYear := range sortedKeyValuePairs(oldSummary) {
- if _, ok := summary[oldName]; !ok {
- fmt.Printf("%s,%s,%d,-1\n", path, oldName, oldYear)
- }
- }
- }
-}
diff --git a/util/relicense.go b/util/relicense.go
deleted file mode 100644
index 0e3fd37..0000000
--- a/util/relicense.go
+++ /dev/null
@@ -1,294 +0,0 @@
-// Copyright 2025 The BoringSSL Authors
-//
-// 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
-//
-// https://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.
-
-//go:build ignore
-
-// relicense.go rewrites the license headers of the files it is passed in. It is
-// intended to be run as:
-//
-// git ls-tree -r --name-only HEAD | xargs go run ./util/relicense.go
-package main
-
-import (
- "bytes"
- "errors"
- "fmt"
- "os"
- "regexp"
- "slices"
- "strings"
-)
-
-type commentStyle int
-
-const (
- commentStyleC commentStyle = iota
- commentStyleHash
-)
-
-func lineComment(style commentStyle) string {
- switch style {
- case commentStyleC:
- return "//"
- case commentStyleHash:
- return "#"
- }
- panic("unknown comment type")
-}
-
-func commentBlockLength(style commentStyle, lines []string) int {
- if len(lines) == 0 {
- return 0
- }
-
- if style == commentStyleC && strings.HasPrefix(lines[0], "/*") {
- if idx := strings.Index(lines[0][2:], "*/"); idx >= 0 {
- idx += 2
- if idx+2 != len(lines[0]) {
- // The comment does not reach the end of the line.
- return 0
- }
- return 1
- }
- for i := 1; i < len(lines); i++ {
- if idx := strings.Index(lines[i], "*/"); idx >= 0 {
- if idx+2 != len(lines[i]) {
- // The comment does not reach the end of the line.
- return 0
- }
- return i + 1
- }
- }
- // Could not find the end of the comment
- return 0
- }
-
- // Treat consecutive line comments as
- prefix := lineComment(style)
- l := 0
- for l < len(lines) && strings.HasPrefix(lines[l], prefix) {
- l++
- // Some of our Perl files do not include a blank line at the end of the
- // license notice. Treat that as ending the comment block.
- if strings.HasPrefix(lines[l-1], "# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE") {
- break
- }
- if strings.HasPrefix(lines[l-1], "# https://www.openssl.org/source/license.html") {
- break
- }
- if strings.HasPrefix(lines[l-1], "# found in the LICENSE file.") {
- break
- }
- }
- return l
-}
-
-func commentStyleForPath(path string) (commentStyle, error) {
- for _, suffix := range []string{".c", ".cc", ".h", ".cc.inc", ".go", ".S", ".rs"} {
- if strings.HasSuffix(path, suffix) {
- return commentStyleC, nil
- }
- }
- for _, suffix := range []string{".pl", ".py", ".peg", ".bazel", ".bzl", "/BUILD.toplevel", "/WORKSPACE.toplevel", ".txt", "/DEPS", ".cmake", ".sh", ".bazelrc", ".toml"} {
- if strings.HasSuffix(path, suffix) {
- return commentStyleHash, nil
- }
- }
- return 0, errors.New("unknown comment style")
-}
-
-var licenseRegexp = regexp.MustCompile(`(?i)\b(copyright|authors?|licen[cs]e[ds]?|permission|warranty|warranties)\b`)
-
-func findLicenseKeyword(lines []string) (string, bool) {
- for _, line := range lines {
- m := licenseRegexp.FindString(line)
- if len(m) != 0 {
- return m, true
- }
- }
- return "", false
-}
-
-func process(path string) error {
- inp, err := os.ReadFile(path)
- if err != nil {
- return err
- }
-
- // If the file does not currently have any license or copyright text,
- // ignore it.
- lines := strings.Split(string(inp), "\n")
- if _, ok := findLicenseKeyword(lines); !ok {
- return nil
- }
-
- // Clear a bunch of false positives so the remainder can be looked at by
- // hand.
-
- // gen files are generated and third_party should remain untouched.
- if strings.HasPrefix(path, "gen/") || strings.HasPrefix(path, "third_party/") {
- return nil
- }
- // Fuzzer corpora sometimes contain stray strings.
- if strings.HasPrefix(path, "fuzz/") && strings.Contains(path, "_corpus") {
- return nil
- }
- // These files do not have license headers but are false positives.
- if slices.Contains([]string{"AUTHORS", "CONTRIBUTING.md", "LICENSE", "MODULE.bazel.lock"}, path) {
- return nil
- }
-
- style, err := commentStyleForPath(path)
- if err != nil {
- return err
- }
-
- var b bytes.Buffer
- // Copy over the #! line in perlasm files.
- if style == commentStyleHash && len(lines) > 0 && strings.HasPrefix(lines[0], "#!") {
- fmt.Fprintf(&b, "%s\n", lines[0])
- lines = lines[1:]
- }
- // Copy over the coding= line in Python files.
- if style == commentStyleHash && len(lines) > 0 && strings.HasPrefix(lines[0], "# coding=") {
- fmt.Fprintf(&b, "%s\n", lines[0])
- lines = lines[1:]
- }
- // Sometimes there is a blank line before the license.
- if len(lines) > 0 && len(lines[0]) == 0 {
- fmt.Fprintf(&b, "%s\n", lines[0])
- lines = lines[1:]
- }
-
- // Look for the existing license header.
- n := commentBlockLength(style, lines)
- if n == 0 {
- return errors.New("could not find comment block")
- }
- comment, lines := lines[:n], lines[n:]
-
- // Trim comment markers from comment lines.
- for i := range comment {
- comment[i] = strings.TrimPrefix(comment[i], lineComment(style))
- comment[i] = strings.TrimPrefix(comment[i], "/*")
- comment[i] = strings.TrimSuffix(comment[i], "*/")
- comment[i] = strings.TrimPrefix(comment[i], " *")
- comment[i] = strings.TrimSpace(comment[i])
- }
-
- // Remove leading and trailing whitespace.
- for len(comment) > 0 && len(comment[0]) == 0 {
- comment = comment[1:]
- }
- for len(comment) > 0 && len(comment[len(comment)-1]) == 0 {
- comment = comment[:len(comment)-1]
- }
-
- // Collect copyright lines.
- for n = 0; n < len(comment) && (strings.HasPrefix(comment[n], "Copyright ") || strings.HasPrefix(comment[n], "Author:")); n++ {
- }
- copyright, comment := comment[:n], comment[n:]
- if len(copyright) == 0 {
- return errors.New("could not find copyright notices")
- }
-
- // Leave support code alone for now.
- if strings.HasPrefix(path, "ssl/test/runner/") && strings.HasSuffix(copyright[0], "The Go Authors. All rights reserved.") {
- return nil
- }
- if strings.HasPrefix(path, "util/bot/") && strings.HasSuffix(copyright[0], "The Chromium Authors. All rights reserved.") {
- return nil
- }
-
- // The remainder must be one of the expected licenses.
- license := strings.Join(comment, "\n")
- if !slices.Contains(allowedLicenses, license) {
- const maxLicenseBlock = 25
- trunc := license
- if len(trunc) > maxLicenseBlock {
- trunc = trunc[:maxLicenseBlock] + "..."
- }
- return fmt.Errorf("license block %q unexpected", trunc)
- }
-
- // Assemble the new file contents.
- for _, line := range copyright {
- fmt.Fprintf(&b, "%s %s\n", lineComment(style), line)
- }
- for _, line := range strings.Split(apacheFileHeader, "\n") {
- if len(line) == 0 {
- fmt.Fprintf(&b, "%s\n", lineComment(style))
- } else {
- fmt.Fprintf(&b, "%s %s\n", lineComment(style), line)
- }
- }
- b.WriteString(strings.Join(lines, "\n"))
-
- if err := os.WriteFile(path, b.Bytes(), 0666); err != nil {
- return err
- }
-
- // If any text after the header contains license keywords, warn that we need
- // to check it by hand.
- if keyword, ok := findLicenseKeyword(lines); ok {
- return fmt.Errorf("file body contains %q, double-check by hand", keyword)
- }
-
- return nil
-}
-
-func main() {
- for _, path := range os.Args[1:] {
- if err := process(path); err != nil {
- fmt.Fprintf(os.Stderr, "Error processing %q: %s\n", path, err)
- }
- }
-}
-
-var allowedLicenses = []string{
- `
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
-OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
-CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.`,
- `
-Licensed under the OpenSSL license (the "License"). You may not use
-this file except in compliance with the License. You can obtain a copy
-in the file LICENSE in the source distribution or at
-https://www.openssl.org/source/license.html`,
- `Use of this source code is governed by a BSD-style
-license that can be found in the LICENSE file.`,
- `Use of this source code is governed by a BSD-style license that can be
-found in the LICENSE file.`,
-}
-
-const apacheFileHeader = `
-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
-
- https://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.`