Skip to content

Commit

Permalink
Add label and annotation selector code.
Browse files Browse the repository at this point in the history
  • Loading branch information
monopole committed Nov 26, 2020
1 parent 50cd01e commit caac3f7
Show file tree
Hide file tree
Showing 20 changed files with 3,026 additions and 7 deletions.
1 change: 1 addition & 0 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphD
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f h1:Cq7MalBHYACRd6EesksG1Q8EoIAKOsiZviGKbOLIej4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
sigs.k8s.io/kustomize/api v0.6.5/go.mod h1:Z96Z48h3nOWgVAmd4JGABszi5znhEnz7xoWHy+Bl7L4=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
Expand Down
8 changes: 4 additions & 4 deletions api/internal/wrappy/wnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@ func (wn *WNode) MarshalJSON() ([]byte, error) {
}

// MatchesAnnotationSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesAnnotationSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesAnnotationSelector; implement or drop from API")
func (wn *WNode) MatchesAnnotationSelector(selector string) (bool, error) {
return wn.node.MatchesAnnotationSelector(selector)
}

// MatchesLabelSelector implements ifc.Kunstructured.
func (wn *WNode) MatchesLabelSelector(string) (bool, error) {
panic("TODO(#WNode) MatchesLabelSelector; implement or drop from API")
func (wn *WNode) MatchesLabelSelector(selector string) (bool, error) {
return wn.node.MatchesLabelSelector(selector)
}

// SetAnnotations implements ifc.Kunstructured.
Expand Down
12 changes: 9 additions & 3 deletions kyaml/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
MYGOBIN := $(shell go env GOPATH)/bin
export PATH := $(MYGOBIN):$(PATH)

.PHONY: generate license fix vet fmt test lint tidy
.PHONY: generate license fix vet fmt test lint tidy clean
all: generate license fix vet fmt test lint tidy

fix:
Expand All @@ -25,11 +25,17 @@ tidy:
go mod tidy

lint:
(which $(MYGOBIN)/golangci-lint || go get github.com/golangci/golangci-lint/cmd/[email protected])
$(MYGOBIN)/golangci-lint run ./...
(which $(MYGOBIN)/golangci-lint || \
go get github.com/golangci/golangci-lint/cmd/[email protected])
$(MYGOBIN)/golangci-lint \
--skip-dirs yaml/internal/k8sgen/pkg \
run ./...

test:
go test -cover ./...

vet:
go vet ./...

clean:
rm -rf yaml/internal/k8sgen/pkg
1 change: 1 addition & 0 deletions kyaml/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ require (
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 // indirect
gopkg.in/yaml.v2 v2.3.0
gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71
sigs.k8s.io/kustomize/api v0.6.5
)
238 changes: 238 additions & 0 deletions kyaml/go.sum

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions kyaml/yaml/internal/k8sgen/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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
package k8sgen
3 changes: 3 additions & 0 deletions kyaml/yaml/internal/k8sgen/generator/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module sigs.k8s.io/kustomize/kyaml/yaml/internal/k8sgen/generator

go 1.15
209 changes: 209 additions & 0 deletions kyaml/yaml/internal/k8sgen/generator/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
// Copyright 2020 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

// This is 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.
apiMachineryRepo = "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.apiMachineryModule())
for dir, files := range filesToCopy {
for _, n := range files {
if err := c.copyFile(dir, n); err != nil {
log.Fatal(err)
}
}
}
}

type copier struct {
goModCache string
topPackage string
srcDir string
pgmName string
}

func (c copier) apiMachineryModule() string {
return apiMachineryRepo + "@" + 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(" apiMachineryRepo: %s\n", apiMachineryRepo)
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(" apiMachineryModule: %s\n", c.apiMachineryModule())
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.apiMachineryModule(), 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.apiMachineryModule()))
w.write(
fmt.Sprintf(
"// Copied from %s\n",
filepath.Join(c.apiMachineryModule(), 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, apiMachineryRepo, 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())
}
Loading

0 comments on commit caac3f7

Please sign in to comment.