diff --git a/cmd/cloner/cloner.go b/cmd/cloner/cloner.go index 60126180b..8f886f0a6 100644 --- a/cmd/cloner/cloner.go +++ b/cmd/cloner/cloner.go @@ -80,7 +80,7 @@ func main() { w("}") } cloneOutput := pkg.Name + "_clone.go" - if err := codegen.WritePackageFile("tailscale.com/cmd/cloner", pkg, cloneOutput, it, buf); err != nil { + if err := codegen.WritePackageFile("tailscale.com/cmd/cloner", pkg, cloneOutput, codegen.CopyrightYear("."), it, buf); err != nil { log.Fatal(err) } } diff --git a/cmd/viewer/viewer.go b/cmd/viewer/viewer.go index f8b2e8c13..4ba6d4b56 100644 --- a/cmd/viewer/viewer.go +++ b/cmd/viewer/viewer.go @@ -384,7 +384,7 @@ func main() { genView(buf, it, typ, pkg.Types) } out := pkg.Name + "_view.go" - if err := codegen.WritePackageFile("tailscale/cmd/viewer", pkg, out, it, buf); err != nil { + if err := codegen.WritePackageFile("tailscale/cmd/viewer", pkg, out, codegen.CopyrightYear("."), it, buf); err != nil { log.Fatal(err) } if runCloner { diff --git a/ipn/ipnstate/ipnstate_clone.go b/ipn/ipnstate/ipnstate_clone.go index 52d8d6c7e..438538f2f 100644 --- a/ipn/ipnstate/ipnstate_clone.go +++ b/ipn/ipnstate/ipnstate_clone.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/types/dnstype/dnstype_clone.go b/types/dnstype/dnstype_clone.go index 1ea760c4a..f61bd1ba0 100644 --- a/types/dnstype/dnstype_clone.go +++ b/types/dnstype/dnstype_clone.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/types/dnstype/dnstype_view.go b/types/dnstype/dnstype_view.go index 7f99be2f4..a15c5d526 100644 --- a/types/dnstype/dnstype_view.go +++ b/types/dnstype/dnstype_view.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/types/persist/persist_clone.go b/types/persist/persist_clone.go index 82db9c52b..4cfc667e1 100644 --- a/types/persist/persist_clone.go +++ b/types/persist/persist_clone.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/types/persist/persist_view.go b/types/persist/persist_view.go index 15355abf4..ba7a111f7 100644 --- a/types/persist/persist_view.go +++ b/types/persist/persist_view.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/util/codegen/codegen.go b/util/codegen/codegen.go index 61ec85de8..0e851a7ea 100644 --- a/util/codegen/codegen.go +++ b/util/codegen/codegen.go @@ -6,6 +6,7 @@ package codegen import ( + "bufio" "bytes" "fmt" "go/ast" @@ -13,13 +14,16 @@ import ( "go/types" "io" "os" + "path/filepath" "reflect" + "regexp" + "strconv" "strings" - "time" "golang.org/x/tools/go/packages" "golang.org/x/tools/imports" "tailscale.com/util/mak" + "tailscale.com/util/must" ) // LoadTypes returns all named types in pkgName, keyed by their type name. @@ -104,15 +108,15 @@ func (it *ImportTracker) Write(w io.Writer) { fmt.Fprintf(w, ")\n\n") } -func writeHeader(w io.Writer, tool, pkg string) { - fmt.Fprintf(w, header, time.Now().Year(), tool, pkg) +func writeHeader(w io.Writer, tool, pkg string, copyrightYear int) { + fmt.Fprintf(w, header, copyrightYear, tool, pkg) } // WritePackageFile adds a file with the provided imports and contents to package. // The tool param is used to identify the tool that generated package file. -func WritePackageFile(tool string, pkg *packages.Package, path string, it *ImportTracker, contents *bytes.Buffer) error { +func WritePackageFile(tool string, pkg *packages.Package, path string, copyrightYear int, it *ImportTracker, contents *bytes.Buffer) error { buf := new(bytes.Buffer) - writeHeader(buf, tool, pkg.Name) + writeHeader(buf, tool, pkg.Name, copyrightYear) it.Write(buf) if _, err := buf.Write(contents.Bytes()); err != nil { return err @@ -263,3 +267,53 @@ func IsViewType(typ types.Type) bool { } return t.Field(0).Name() == "ж" } + +// CopyrightYear reports the greatest copyright year in non-generated *.go files +// in the current directory, for use in the copyright line of generated code. +// +// It panics on I/O error, as it's assumed this is only being used by "go +// generate" or GitHub actions. +// +// TODO(bradfitz,dgentry): determine what heuristic to use for all this: latest +// year, earliest, none? don't list years at all? IANAL. Get advice of others. +// For now we just want to unbreak the tree. See Issue 6865. +func CopyrightYear(dir string) (year int) { + files, err := os.ReadDir(dir) + if err != nil { + panic(err) + } + rxYear := regexp.MustCompile(`^// Copyright \(c\) (20\d{2}) `) + rxGenerated := regexp.MustCompile(`^// Code generated .* DO NOT EDIT\.$`) +Files: + for _, f := range files { + name := f.Name() + if f.IsDir() || + !strings.HasSuffix(name, ".go") || + strings.HasSuffix(name, "_clone.go") || + strings.HasSuffix(name, "_view.go") || + strings.HasSuffix(name, "_test.go") { + continue + } + src, err := os.ReadFile(filepath.Join(dir, name)) + if err != nil { + panic(err) + } + bs := bufio.NewScanner(bytes.NewReader(src)) + for bs.Scan() { + line := bs.Bytes() + if m := rxYear.FindSubmatch(line); m != nil { + if y := must.Get(strconv.Atoi(string(m[1]))); y > year { + year = y + } + continue + } + if rxGenerated.Match(line) { + continue Files + } + } + } + if year == 0 { + panic("no Copyright line found in any *.go file in " + dir) + } + return year +} diff --git a/wgengine/filter/filter_clone.go b/wgengine/filter/filter_clone.go index bbae3c451..03fcaa50d 100644 --- a/wgengine/filter/filter_clone.go +++ b/wgengine/filter/filter_clone.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/wgengine/wgcfg/wgcfg_clone.go b/wgengine/wgcfg/wgcfg_clone.go index ed040cde4..853bff4bc 100644 --- a/wgengine/wgcfg/wgcfg_clone.go +++ b/wgengine/wgcfg/wgcfg_clone.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved. +// Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.