Move the k8s code generator.

This commit is contained in:
monopole
2021-02-08 11:07:50 -08:00
parent a3a11bf3f4
commit 582bc4de01
13 changed files with 404 additions and 243 deletions

View File

@@ -1,27 +1,7 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// Package k8sgen contains code generated by copying bits of k8s.io code.
// The copier is in generator/main.go.
//
// kyaml (and indirectly kustomize) wants to reuse the k/k label selection code.
// Labels and annotations are a key part of k8s metadata.
//
// kyaml cannot depend on it via a normal Go import because kubectl will
// depend on kyaml eventually (see kubernetes-sigs/kustomize/issues/1500).
// While kubectl remains in the k/k repo, it depends on local relative symlinked
// path to a 'staging' version of k8s.io code. No code imported by kubectl can
// refer to any other version of k8s.io code.
//
// So to do what that code does, kyaml must either reimplement it or copy it.
// When/if kubectl is finally extracted from k/k to its own repo, it can
// depend on apimachinery code via normal imports, and so can kyaml.
// At that point, this copy (and copying mechanism) can be dropped.
//
// Until then, if a bug is found in a particular instance of copied k8s.io
// (unlikely, since this code is old and stable), just increment
// apiMachineryVersion below to match the fixed version, possibly change
// the files copied, re-generate, and if need be adjust call points.
//
//go:generate go run generator/main.go
// All code below this directory is generated.
// See {repo}/cmd/k8scopy/main.go for more info.
//go:generate k8scopy k8scopy.yaml
package k8sgen

View File

@@ -1,3 +0,0 @@
module sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/generator
go 1.15

View File

@@ -1,213 +0,0 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
// A code copier launched via `go generate`.
// See k8segen/doc.go for further discussion.
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
const (
// Splitting this so it doesn't show up in grep.
apiMachineryModule = "k8s.io" + "/" + "apimachinery"
apiMachineryVersion = "v0.17.0"
sigsK8sIo = "sigs.k8s.io"
)
var (
filesToCopy = map[string][]string{
filepath.Join("pkg", "labels"): {
"labels.go",
"selector.go",
"zz_generated.deepcopy.go",
},
filepath.Join("pkg", "selection"): {
"operator.go",
},
filepath.Join("pkg", "util", "sets"): {
"empty.go",
"string.go",
},
filepath.Join("pkg", "util", "errors"): {
"errors.go",
},
filepath.Join("pkg", "util", "validation"): {
"validation.go",
},
filepath.Join("pkg", "util", "validation", "field"): {
"errors.go",
"path.go",
},
}
)
func main() {
c := newCopier()
// c.print()
runNoOutputCommand("go", "get", c.apiMachineryModSpec())
for dir, files := range filesToCopy {
for _, n := range files {
if err := c.copyFile(dir, n); err != nil {
log.Fatal(err)
}
}
}
runNoOutputCommand(
"go", "mod", "edit", "-droprequire="+apiMachineryModule)
runNoOutputCommand("go", "mod", "tidy")
runGetOutputCommand("go", "fmt", "./...")
}
type copier struct {
goModCache string
topPackage string
srcDir string
pgmName string
}
func (c copier) apiMachineryModSpec() string {
return apiMachineryModule + "@" + apiMachineryVersion
}
func (c copier) replacementPath() string {
return filepath.Join(c.topPackage, c.subPath())
}
func (c copier) subPath() string {
return filepath.Join("internal", c.pgmName)
}
func (c copier) print() {
fmt.Printf(" apiMachineryModule: %s\n", apiMachineryModule)
fmt.Printf(" replacementPath: %s\n", c.replacementPath())
fmt.Printf(" goModCache: %s\n", c.goModCache)
fmt.Printf(" topPackage: %s\n", c.topPackage)
fmt.Printf(" subPath: %s\n", c.subPath())
fmt.Printf(" srcDir: %s\n", c.srcDir)
fmt.Printf(" apiMachineryModSpec: %s\n", c.apiMachineryModSpec())
fmt.Printf(" pgmName: %s\n", c.pgmName)
fmt.Printf(" pwd: %s\n", os.Getenv("PWD"))
}
func newCopier() copier {
tmp := copier{
pgmName: os.Getenv("GOPACKAGE"),
goModCache: runGetOutputCommand("go", "env", "GOMODCACHE"),
}
goMod := runGetOutputCommand("go", "env", "GOMOD")
topPackage := filepath.Join(goMod[:len(goMod)-len("go.mod")-1], "yaml")
k := strings.Index(topPackage, sigsK8sIo)
if k < 1 {
log.Fatalf("cannot find %s in %s", sigsK8sIo, topPackage)
}
tmp.srcDir = topPackage[:k-1]
tmp.topPackage = topPackage[k:]
return tmp
}
func (c copier) copyFile(dir, name string) error {
inFile, err := os.Open(
filepath.Join(c.goModCache, c.apiMachineryModSpec(), dir, name))
if err != nil {
return err
}
defer inFile.Close()
scanner := bufio.NewScanner(inFile)
w, err := newWriter(dir, name)
if err != nil {
return err
}
defer w.close()
w.write(
fmt.Sprintf(
// This particular phrasing is required.
"// Code generated by %s/generator from %s; DO NOT EDIT.",
c.pgmName, c.apiMachineryModSpec()))
w.write(
fmt.Sprintf(
"// Copied from %s\n",
filepath.Join(c.apiMachineryModSpec(), dir, name)))
for scanner.Scan() {
l := scanner.Text()
// Disallow recursive generation.
if strings.HasPrefix(l, "//go:generate") {
continue
}
// Don't want it to appear double generated.
if strings.HasPrefix(l, "// Code generated") {
continue
}
// Fix self-imports.
l = strings.Replace(l, apiMachineryModule, c.replacementPath(), 1)
// Replace klog with generic log (eschewing k8s.io entirely).
l = strings.Replace(l, "\"k8s.io/klog\"", "\"log\"", 1)
l = strings.Replace(l, "klog.V(10).Infof(", "log.Printf(", 1)
w.write(l)
}
if err := scanner.Err(); err != nil {
return err
}
w.write("")
return nil
}
type writer struct {
root string
f *os.File
}
func newWriter(toDir, name string) (*writer, error) {
if err := os.MkdirAll(toDir, 0755); err != nil {
log.Printf("unable to create directory: %s", toDir)
return nil, err
}
n := filepath.Join(toDir, name)
f, err := os.Create(n)
if err != nil {
return nil, fmt.Errorf("unable to create `%s`; %v", n, err)
}
return &writer{root: toDir, f: f}, nil
}
func (w *writer) close() {
w.f.Close()
}
func (w *writer) write(line string) {
if _, err := w.f.WriteString(line + "\n"); err != nil {
log.Printf("Trouble writing: %s", line)
log.Fatalf("Error: %s", err)
}
}
func runNoOutputCommand(n string, args ...string) {
o := runGetOutputCommand(n, args...)
if len(o) > 0 {
log.Fatalf("unexpected output: %q", o)
}
}
func runGetOutputCommand(n string, args ...string) string {
cmd := exec.Command(n, args...)
var outBuf bytes.Buffer
cmd.Stdout = &outBuf
var errBuf bytes.Buffer
cmd.Stderr = &errBuf
if err := cmd.Run(); err != nil {
fmt.Printf("err: %q\n", errBuf.String())
log.Fatal(err)
}
return strings.TrimSpace(outBuf.String())
}

View File

@@ -0,0 +1,30 @@
# Copyright 2020 The Kubernetes Authors.
# SPDX-License-Identifier: Apache-2.0
#
# The files to vendor (copy).
# See {repo}/cmd/k8scopy/main.go for more info.
module: k8s.io/apimachinery
version: v0.17.0
packages:
- name: pkg/labels
files:
- labels.go
- selector.go
- zz_generated.deepcopy.go
- name: pkg/selection
files:
- operator.go
- name: pkg/util/sets
files:
- empty.go
- string.go
- name: pkg/util/errors
files:
- errors.go
- name: pkg/util/validation
files:
- validation.go
- name: pkg/util/validation/field
files:
- errors.go
- path.go