|
|
|
@ -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
|
|
|
|
|
}
|
|
|
|
|