Use apiextension v1
- upgrade from apiextension v1beta1 to v1 - generate yaml manifest for crd intead of applying it at runtime - users will have to apply the manifest with kubectl - kg and kgctl log an error if the crd is not present - now validation should actually work Signed-off-by: leonnicolas <leonloechner@gmx.de>
This commit is contained in:
58
vendor/sigs.k8s.io/controller-tools/pkg/genall/doc.go
generated
vendored
Normal file
58
vendor/sigs.k8s.io/controller-tools/pkg/genall/doc.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
// Package genall defines entrypoints for generation tools to hook into and
|
||||
// share the same set of parsing, typechecking, and marker information.
|
||||
//
|
||||
// Generators
|
||||
//
|
||||
// Each Generator knows how to register its markers into a central Registry,
|
||||
// and then how to generate output using a Collector and some root packages.
|
||||
// Each generator can be considered to be the output type of a marker, for easy
|
||||
// command line parsing.
|
||||
//
|
||||
// Output and Input
|
||||
//
|
||||
// Generators output artifacts via an OutputRule. OutputRules know how to
|
||||
// write output for different package-associated (code) files, as well as
|
||||
// config files. Each OutputRule should also be considered to be the output
|
||||
// type as a marker, for easy command-line parsing.
|
||||
//
|
||||
// OutputRules groups together an OutputRule per generator, plus a default
|
||||
// output rule for any not explicitly specified.
|
||||
//
|
||||
// OutputRules are defined for stdout, file writing, and sending to /dev/null
|
||||
// (useful for doing "type-checking" without actually saving the results).
|
||||
//
|
||||
// InputRule defines custom input loading, but its shared across all
|
||||
// Generators. There's currently only a filesystem implementation.
|
||||
//
|
||||
// Runtime and Context
|
||||
//
|
||||
// Runtime maps together Generators, and constructs "contexts" which provide
|
||||
// the common collector and roots, plus the output rule for that generator, and
|
||||
// a handle for reading files (like boilerplate headers).
|
||||
//
|
||||
// It will run all associated generators, printing errors and automatically
|
||||
// skipping type-checking errors (since those are commonly caused by the
|
||||
// partial type-checking of loader.TypeChecker).
|
||||
//
|
||||
// Options
|
||||
//
|
||||
// The FromOptions (and associated helpers) function makes it easy to use generators
|
||||
// and output rules as markers that can be parsed from the command line, producing
|
||||
// a registry from command line args.
|
||||
package genall
|
215
vendor/sigs.k8s.io/controller-tools/pkg/genall/genall.go
generated
vendored
Normal file
215
vendor/sigs.k8s.io/controller-tools/pkg/genall/genall.go
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package genall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/loader"
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
// Generators are a list of Generators.
|
||||
// NB(directxman12): this is a pointer so that we can uniquely identify each
|
||||
// instance of a generator, even if it's not hashable. Different *instances*
|
||||
// of a generator are treated differently.
|
||||
type Generators []*Generator
|
||||
|
||||
// RegisterMarkers registers all markers defined by each of the Generators in
|
||||
// this list into the given registry.
|
||||
func (g Generators) RegisterMarkers(reg *markers.Registry) error {
|
||||
for _, gen := range g {
|
||||
if err := (*gen).RegisterMarkers(reg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckFilters returns the set of NodeFilters for all Generators that
|
||||
// implement NeedsTypeChecking.
|
||||
func (g Generators) CheckFilters() []loader.NodeFilter {
|
||||
var filters []loader.NodeFilter
|
||||
for _, gen := range g {
|
||||
withFilter, needsChecking := (*gen).(NeedsTypeChecking)
|
||||
if !needsChecking {
|
||||
continue
|
||||
}
|
||||
filters = append(filters, withFilter.CheckFilter())
|
||||
}
|
||||
return filters
|
||||
}
|
||||
|
||||
// NeedsTypeChecking indicates that a particular generator needs & has opinions
|
||||
// on typechecking. If this is not implemented, a generator will be given a
|
||||
// context with a nil typechecker.
|
||||
type NeedsTypeChecking interface {
|
||||
// CheckFilter indicates the loader.NodeFilter (if any) that should be used
|
||||
// to prune out unused types/packages when type-checking (nodes for which
|
||||
// the filter returns true are considered "interesting"). This filter acts
|
||||
// as a baseline -- all types the pass through this filter will be checked,
|
||||
// but more than that may also be checked due to other generators' filters.
|
||||
CheckFilter() loader.NodeFilter
|
||||
}
|
||||
|
||||
// Generator knows how to register some set of markers, and then produce
|
||||
// output artifacts based on loaded code containing those markers,
|
||||
// sharing common loaded data.
|
||||
type Generator interface {
|
||||
// RegisterMarkers registers all markers needed by this Generator
|
||||
// into the given registry.
|
||||
RegisterMarkers(into *markers.Registry) error
|
||||
// Generate generates artifacts produced by this marker.
|
||||
// It's called *after* RegisterMarkers has been called.
|
||||
Generate(*GenerationContext) error
|
||||
}
|
||||
|
||||
// HasHelp is some Generator, OutputRule, etc with a help method.
|
||||
type HasHelp interface {
|
||||
// Help returns help for this generator.
|
||||
Help() *markers.DefinitionHelp
|
||||
}
|
||||
|
||||
// Runtime collects generators, loaded program data (Collector, root Packages),
|
||||
// and I/O rules, running them together.
|
||||
type Runtime struct {
|
||||
// Generators are the Generators to be run by this Runtime.
|
||||
Generators Generators
|
||||
// GenerationContext is the base generation context that's copied
|
||||
// to produce the context for each Generator.
|
||||
GenerationContext
|
||||
// OutputRules defines how to output artifacts for each Generator.
|
||||
OutputRules OutputRules
|
||||
}
|
||||
|
||||
// GenerationContext defines the common information needed for each Generator
|
||||
// to run.
|
||||
type GenerationContext struct {
|
||||
// Collector is the shared marker collector.
|
||||
Collector *markers.Collector
|
||||
// Roots are the base packages to be processed.
|
||||
Roots []*loader.Package
|
||||
// Checker is the shared partial type-checker.
|
||||
Checker *loader.TypeChecker
|
||||
// OutputRule describes how to output artifacts.
|
||||
OutputRule
|
||||
// InputRule describes how to load associated boilerplate artifacts.
|
||||
// It should *not* be used to load source files.
|
||||
InputRule
|
||||
}
|
||||
|
||||
// WriteYAML writes the given objects out, serialized as YAML, using the
|
||||
// context's OutputRule. Objects are written as separate documents, separated
|
||||
// from each other by `---` (as per the YAML spec).
|
||||
func (g GenerationContext) WriteYAML(itemPath string, objs ...interface{}) error {
|
||||
out, err := g.Open(nil, itemPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
for _, obj := range objs {
|
||||
yamlContent, err := yaml.Marshal(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := out.Write(append([]byte("\n---\n"), yamlContent...))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n < len(yamlContent) {
|
||||
return io.ErrShortWrite
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFile reads the given boilerplate artifact using the context's InputRule.
|
||||
func (g GenerationContext) ReadFile(path string) ([]byte, error) {
|
||||
file, err := g.OpenForRead(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
return ioutil.ReadAll(file)
|
||||
}
|
||||
|
||||
// ForRoots produces a Runtime to run the given generators against the
|
||||
// given packages. It outputs to /dev/null by default.
|
||||
func (g Generators) ForRoots(rootPaths ...string) (*Runtime, error) {
|
||||
roots, err := loader.LoadRoots(rootPaths...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rt := &Runtime{
|
||||
Generators: g,
|
||||
GenerationContext: GenerationContext{
|
||||
Collector: &markers.Collector{
|
||||
Registry: &markers.Registry{},
|
||||
},
|
||||
Roots: roots,
|
||||
InputRule: InputFromFileSystem,
|
||||
Checker: &loader.TypeChecker{
|
||||
NodeFilters: g.CheckFilters(),
|
||||
},
|
||||
},
|
||||
OutputRules: OutputRules{Default: OutputToNothing},
|
||||
}
|
||||
if err := rt.Generators.RegisterMarkers(rt.Collector.Registry); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rt, nil
|
||||
}
|
||||
|
||||
// Run runs the Generators in this Runtime against its packages, printing
|
||||
// errors (except type errors, which common result from using TypeChecker with
|
||||
// filters), returning true if errors were found.
|
||||
func (r *Runtime) Run() bool {
|
||||
// TODO(directxman12): we could make this parallel,
|
||||
// but we'd need to ensure all underlying machinery is threadsafe
|
||||
if len(r.Generators) == 0 {
|
||||
fmt.Fprintln(os.Stderr, "no generators to run")
|
||||
return true
|
||||
}
|
||||
|
||||
hadErrs := false
|
||||
for _, gen := range r.Generators {
|
||||
ctx := r.GenerationContext // make a shallow copy
|
||||
ctx.OutputRule = r.OutputRules.ForGenerator(gen)
|
||||
|
||||
// don't pass a typechecker to generators that don't provide a filter
|
||||
// to avoid accidents
|
||||
if _, needsChecking := (*gen).(NeedsTypeChecking); !needsChecking {
|
||||
ctx.Checker = nil
|
||||
}
|
||||
|
||||
if err := (*gen).Generate(&ctx); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
hadErrs = true
|
||||
}
|
||||
}
|
||||
|
||||
// skip TypeErrors -- they're probably just from partial typechecking in crd-gen
|
||||
return loader.PrintErrors(r.Roots, packages.TypeError) || hadErrs
|
||||
}
|
23
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/doc.go
generated
vendored
Normal file
23
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/doc.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
// Package help contains utilities for actually writing out marker help.
|
||||
//
|
||||
// Namely, it contains a series of structs (and helpers for producing them)
|
||||
// that represent a merged view of marker definition and help that can be used
|
||||
// for consumption by the pretty subpackage (for terminal help) or serialized
|
||||
// as JSON (e.g. for generating HTML help).
|
||||
package help
|
30
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/doc.go
generated
vendored
Normal file
30
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/doc.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
// Package pretty contains utilities for formatting terminal help output,
|
||||
// and a use of those to display marker help.
|
||||
//
|
||||
// Terminal Output
|
||||
//
|
||||
// The Span interface and Table struct allow you to construct tables with
|
||||
// colored formatting, without causing ANSI formatting characters to mess up width
|
||||
// calculations.
|
||||
//
|
||||
// Marker Help
|
||||
//
|
||||
// The MarkersSummary prints a summary table for marker help, while the MarkersDetails
|
||||
// prints out more detailed information, with explainations of the individual marker fields.
|
||||
package pretty
|
171
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/help.go
generated
vendored
Normal file
171
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/help.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
package pretty
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/genall/help"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
var (
|
||||
headingStyle = Decoration(*color.New(color.Bold, color.Underline))
|
||||
markerNameStyle = Decoration(*color.New(color.Bold))
|
||||
fieldSummaryStyle = Decoration(*color.New(color.FgGreen, color.Italic))
|
||||
markerTargetStyle = Decoration(*color.New(color.Faint))
|
||||
fieldDetailStyle = Decoration(*color.New(color.Italic, color.FgGreen))
|
||||
deprecatedStyle = Decoration(*color.New(color.CrossedOut))
|
||||
)
|
||||
|
||||
// MarkersSummary returns a condensed summary of help for the given markers.
|
||||
func MarkersSummary(groupName string, markers []help.MarkerDoc) Span {
|
||||
out := new(SpanWriter)
|
||||
|
||||
out.Print(Text("\n"))
|
||||
out.Print(headingStyle.Containing(Text(groupName)))
|
||||
out.Print(Text("\n\n"))
|
||||
|
||||
table := &Table{Sizing: &TableCalculator{Padding: 2}}
|
||||
for _, marker := range markers {
|
||||
table.StartRow()
|
||||
table.Column(MarkerSyntaxHelp(marker))
|
||||
table.Column(markerTargetStyle.Containing(Text(marker.Target)))
|
||||
|
||||
summary := new(SpanWriter)
|
||||
if marker.DeprecatedInFavorOf != nil && len(*marker.DeprecatedInFavorOf) > 0 {
|
||||
summary.Print(markerNameStyle.Containing(Text("(use ")))
|
||||
summary.Print(markerNameStyle.Containing(Text(*marker.DeprecatedInFavorOf)))
|
||||
summary.Print(markerNameStyle.Containing(Text(") ")))
|
||||
}
|
||||
summary.Print(Text(marker.Summary))
|
||||
table.Column(summary)
|
||||
|
||||
table.EndRow()
|
||||
}
|
||||
out.Print(table)
|
||||
|
||||
out.Print(Text("\n"))
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// MarkersDetails returns detailed help for the given markers, including detailed field help.
|
||||
func MarkersDetails(fullDetail bool, groupName string, markers []help.MarkerDoc) Span {
|
||||
out := new(SpanWriter)
|
||||
|
||||
out.Print(Line(headingStyle.Containing(Text(groupName))))
|
||||
out.Print(Newlines(2))
|
||||
|
||||
for _, marker := range markers {
|
||||
out.Print(Line(markerName(marker)))
|
||||
out.Print(Text(" "))
|
||||
out.Print(markerTargetStyle.Containing(Text(marker.Target)))
|
||||
|
||||
summary := new(SpanWriter)
|
||||
if marker.DeprecatedInFavorOf != nil && len(*marker.DeprecatedInFavorOf) > 0 {
|
||||
summary.Print(markerNameStyle.Containing(Text("(use ")))
|
||||
summary.Print(markerNameStyle.Containing(Text(*marker.DeprecatedInFavorOf)))
|
||||
summary.Print(markerNameStyle.Containing(Text(") ")))
|
||||
}
|
||||
summary.Print(Text(marker.Summary))
|
||||
|
||||
if !marker.AnonymousField() {
|
||||
out.Print(Indented(1, Line(summary)))
|
||||
if len(marker.Details) > 0 && fullDetail {
|
||||
out.Print(Indented(1, Line(Text(marker.Details))))
|
||||
}
|
||||
}
|
||||
|
||||
if marker.AnonymousField() {
|
||||
out.Print(Indented(1, Line(fieldDetailStyle.Containing(FieldSyntaxHelp(marker.Fields[0])))))
|
||||
out.Print(Text(" "))
|
||||
out.Print(summary)
|
||||
if len(marker.Details) > 0 && fullDetail {
|
||||
out.Print(Indented(2, Line(Text(marker.Details))))
|
||||
}
|
||||
out.Print(Newlines(1))
|
||||
} else if !marker.Empty() {
|
||||
out.Print(Newlines(1))
|
||||
if fullDetail {
|
||||
for _, arg := range marker.Fields {
|
||||
out.Print(Indented(1, Line(fieldDetailStyle.Containing(FieldSyntaxHelp(arg)))))
|
||||
out.Print(Indented(2, Line(Text(arg.Summary))))
|
||||
if len(arg.Details) > 0 && fullDetail {
|
||||
out.Print(Indented(2, Line(Text(arg.Details))))
|
||||
out.Print(Newlines(1))
|
||||
}
|
||||
}
|
||||
out.Print(Newlines(1))
|
||||
} else {
|
||||
table := &Table{Sizing: &TableCalculator{Padding: 2}}
|
||||
for _, arg := range marker.Fields {
|
||||
table.StartRow()
|
||||
table.Column(fieldDetailStyle.Containing(FieldSyntaxHelp(arg)))
|
||||
table.Column(Text(arg.Summary))
|
||||
table.EndRow()
|
||||
}
|
||||
|
||||
out.Print(Indented(1, table))
|
||||
}
|
||||
} else {
|
||||
out.Print(Newlines(1))
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func FieldSyntaxHelp(arg help.FieldHelp) Span {
|
||||
return fieldSyntaxHelp(arg, "")
|
||||
}
|
||||
|
||||
// fieldSyntaxHelp prints the syntax help for a particular marker argument.
|
||||
func fieldSyntaxHelp(arg help.FieldHelp, sep string) Span {
|
||||
if arg.Optional {
|
||||
return FromWriter(func(out io.Writer) error {
|
||||
_, err := fmt.Fprintf(out, "[%s%s=<%s>]", sep, arg.Name, arg.TypeString())
|
||||
return err
|
||||
})
|
||||
}
|
||||
return FromWriter(func(out io.Writer) error {
|
||||
_, err := fmt.Fprintf(out, "%s%s=<%s>", sep, arg.Name, arg.TypeString())
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
// markerName returns a span containing just the appropriately-formatted marker name.
|
||||
func markerName(def help.MarkerDoc) Span {
|
||||
if def.DeprecatedInFavorOf != nil {
|
||||
return deprecatedStyle.Containing(Text("+" + def.Name))
|
||||
}
|
||||
return markerNameStyle.Containing(Text("+" + def.Name))
|
||||
}
|
||||
|
||||
// MarkerSyntaxHelp assembles syntax help for a given marker.
|
||||
func MarkerSyntaxHelp(def help.MarkerDoc) Span {
|
||||
out := new(SpanWriter)
|
||||
|
||||
out.Print(markerName(def))
|
||||
|
||||
if def.Empty() {
|
||||
return out
|
||||
}
|
||||
|
||||
sep := ":"
|
||||
if def.AnonymousField() {
|
||||
sep = ""
|
||||
}
|
||||
|
||||
fieldStyle := fieldSummaryStyle
|
||||
if def.DeprecatedInFavorOf != nil {
|
||||
fieldStyle = deprecatedStyle
|
||||
}
|
||||
|
||||
for _, arg := range def.Fields {
|
||||
out.Print(fieldStyle.Containing(fieldSyntaxHelp(arg, sep)))
|
||||
sep = ","
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
304
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/print.go
generated
vendored
Normal file
304
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/print.go
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
package pretty
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/fatih/color"
|
||||
)
|
||||
|
||||
// NB(directxman12): this isn't particularly elegant, but it's also
|
||||
// sufficiently simple as to be maintained here. Man (roff) would've
|
||||
// probably worked, but it's not necessarily on Windows by default.
|
||||
|
||||
// Span is a chunk of content that is writable to an output, but knows how to
|
||||
// calculate its apparent visual "width" on the terminal (not to be confused
|
||||
// with the raw length, which may include zero-width coloring sequences).
|
||||
type Span interface {
|
||||
// VisualLength reports the "width" as perceived by the user on the terminal
|
||||
// (i.e. widest line, ignoring ANSI escape characters).
|
||||
VisualLength() int
|
||||
// WriteTo writes the full span contents to the given writer.
|
||||
WriteTo(io.Writer) error
|
||||
}
|
||||
|
||||
// Table is a Span that writes its data in table form, with sizing controlled
|
||||
// by the given table calculator. Rows are started with StartRow, followed by
|
||||
// some calls to Column, followed by a call to EndRow. Once all rows are
|
||||
// added, the table can be used as a Span.
|
||||
type Table struct {
|
||||
Sizing *TableCalculator
|
||||
|
||||
cellsByRow [][]Span
|
||||
colSizes []int
|
||||
}
|
||||
|
||||
// StartRow starts a new row.
|
||||
// It must eventually be followed by EndRow.
|
||||
func (t *Table) StartRow() {
|
||||
t.cellsByRow = append(t.cellsByRow, []Span(nil))
|
||||
}
|
||||
|
||||
// EndRow ends the currently started row.
|
||||
func (t *Table) EndRow() {
|
||||
lastRow := t.cellsByRow[len(t.cellsByRow)-1]
|
||||
sizes := make([]int, len(lastRow))
|
||||
for i, cell := range lastRow {
|
||||
sizes[i] = cell.VisualLength()
|
||||
}
|
||||
t.Sizing.AddRowSizes(sizes...)
|
||||
}
|
||||
|
||||
// Column adds the given span as a new column to the current row.
|
||||
func (t *Table) Column(contents Span) {
|
||||
currentRowInd := len(t.cellsByRow) - 1
|
||||
t.cellsByRow[currentRowInd] = append(t.cellsByRow[currentRowInd], contents)
|
||||
}
|
||||
|
||||
// SkipRow prints a span without having it contribute to the table calculation.
|
||||
func (t *Table) SkipRow(contents Span) {
|
||||
t.cellsByRow = append(t.cellsByRow, []Span{contents})
|
||||
}
|
||||
|
||||
func (t *Table) WriteTo(out io.Writer) error {
|
||||
if t.colSizes == nil {
|
||||
t.colSizes = t.Sizing.ColumnWidths()
|
||||
}
|
||||
|
||||
for _, cells := range t.cellsByRow {
|
||||
currentPosition := 0
|
||||
for colInd, cell := range cells {
|
||||
colSize := t.colSizes[colInd]
|
||||
diff := colSize - cell.VisualLength()
|
||||
|
||||
if err := cell.WriteTo(out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if diff > 0 {
|
||||
if err := writePadding(out, columnPadding, diff); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
currentPosition += colSize
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(out, "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) VisualLength() int {
|
||||
if t.colSizes == nil {
|
||||
t.colSizes = t.Sizing.ColumnWidths()
|
||||
}
|
||||
|
||||
res := 0
|
||||
for _, colSize := range t.colSizes {
|
||||
res += colSize
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Text is a span that simply contains raw text. It's a good starting point.
|
||||
type Text string
|
||||
|
||||
func (t Text) VisualLength() int { return len(t) }
|
||||
func (t Text) WriteTo(w io.Writer) error {
|
||||
_, err := w.Write([]byte(t))
|
||||
return err
|
||||
}
|
||||
|
||||
// indented is a span that indents all lines by the given number of tabs.
|
||||
type indented struct {
|
||||
Amount int
|
||||
Content Span
|
||||
}
|
||||
|
||||
func (i *indented) VisualLength() int { return i.Content.VisualLength() }
|
||||
func (i *indented) WriteTo(w io.Writer) error {
|
||||
var out bytes.Buffer
|
||||
if err := i.Content.WriteTo(&out); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lines := bytes.Split(out.Bytes(), []byte("\n"))
|
||||
for lineInd, line := range lines {
|
||||
if lineInd != 0 {
|
||||
if _, err := w.Write([]byte("\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := writePadding(w, indentPadding, i.Amount); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write(line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Indented returns a span that indents all lines by the given number of tabs.
|
||||
func Indented(amt int, content Span) Span {
|
||||
return &indented{Amount: amt, Content: content}
|
||||
}
|
||||
|
||||
// fromWriter is a span that takes content from a function expecting a Writer.
|
||||
type fromWriter struct {
|
||||
cache []byte
|
||||
cacheError error
|
||||
run func(io.Writer) error
|
||||
}
|
||||
|
||||
func (f *fromWriter) VisualLength() int {
|
||||
if f.cache == nil {
|
||||
var buf bytes.Buffer
|
||||
if err := f.run(&buf); err != nil {
|
||||
f.cacheError = err
|
||||
}
|
||||
f.cache = buf.Bytes()
|
||||
}
|
||||
return len(f.cache)
|
||||
}
|
||||
func (f *fromWriter) WriteTo(w io.Writer) error {
|
||||
if f.cache != nil {
|
||||
if f.cacheError != nil {
|
||||
return f.cacheError
|
||||
}
|
||||
_, err := w.Write(f.cache)
|
||||
return err
|
||||
}
|
||||
return f.run(w)
|
||||
}
|
||||
|
||||
// FromWriter returns a span that takes content from a function expecting a Writer.
|
||||
func FromWriter(run func(io.Writer) error) Span {
|
||||
return &fromWriter{run: run}
|
||||
}
|
||||
|
||||
// Decoration represents a terminal decoration.
|
||||
type Decoration color.Color
|
||||
|
||||
// Containing returns a Span that has the given decoration applied.
|
||||
func (d Decoration) Containing(contents Span) Span {
|
||||
return &decorated{
|
||||
Contents: contents,
|
||||
Attributes: color.Color(d),
|
||||
}
|
||||
}
|
||||
|
||||
// decorated is a span that has some terminal decoration applied.
|
||||
type decorated struct {
|
||||
Contents Span
|
||||
Attributes color.Color
|
||||
}
|
||||
|
||||
func (d *decorated) VisualLength() int { return d.Contents.VisualLength() }
|
||||
func (d *decorated) WriteTo(w io.Writer) error {
|
||||
oldOut := color.Output
|
||||
color.Output = w
|
||||
defer func() { color.Output = oldOut }()
|
||||
|
||||
d.Attributes.Set()
|
||||
defer color.Unset()
|
||||
|
||||
return d.Contents.WriteTo(w)
|
||||
}
|
||||
|
||||
// SpanWriter is a span that contains multiple sub-spans.
|
||||
type SpanWriter struct {
|
||||
contents []Span
|
||||
}
|
||||
|
||||
func (m *SpanWriter) VisualLength() int {
|
||||
res := 0
|
||||
for _, span := range m.contents {
|
||||
res += span.VisualLength()
|
||||
}
|
||||
return res
|
||||
}
|
||||
func (m *SpanWriter) WriteTo(w io.Writer) error {
|
||||
for _, span := range m.contents {
|
||||
if err := span.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Print adds a new span to this SpanWriter.
|
||||
func (m *SpanWriter) Print(s Span) {
|
||||
m.contents = append(m.contents, s)
|
||||
}
|
||||
|
||||
// lines is a span that adds some newlines, optionally followed by some content.
|
||||
type lines struct {
|
||||
content Span
|
||||
amountBefore int
|
||||
}
|
||||
|
||||
func (l *lines) VisualLength() int {
|
||||
if l.content == nil {
|
||||
return 0
|
||||
}
|
||||
return l.content.VisualLength()
|
||||
}
|
||||
func (l *lines) WriteTo(w io.Writer) error {
|
||||
if err := writePadding(w, linesPadding, l.amountBefore); err != nil {
|
||||
return err
|
||||
}
|
||||
if l.content != nil {
|
||||
if err := l.content.WriteTo(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Newlines returns a span just containing some newlines.
|
||||
func Newlines(amt int) Span {
|
||||
return &lines{amountBefore: amt}
|
||||
}
|
||||
|
||||
// Line returns a span that emits a newline, followed by the given content.
|
||||
func Line(content Span) Span {
|
||||
return &lines{amountBefore: 1, content: content}
|
||||
}
|
||||
|
||||
var (
|
||||
columnPadding = []byte(" ")
|
||||
indentPadding = []byte("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t")
|
||||
linesPadding = []byte("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
|
||||
)
|
||||
|
||||
// writePadding writes out padding of the given type in the given amount to the writer.
|
||||
// Each byte in the padding buffer contributes 1 to the amount -- the padding being
|
||||
// a buffer is just for efficiency.
|
||||
func writePadding(out io.Writer, typ []byte, amt int) error {
|
||||
if amt <= len(typ) {
|
||||
_, err := out.Write(typ[:amt])
|
||||
return err
|
||||
}
|
||||
|
||||
num := amt / len(typ)
|
||||
rem := amt % len(typ)
|
||||
for i := 0; i < num; i++ {
|
||||
if _, err := out.Write(typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := out.Write(typ[:rem]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
64
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/table.go
generated
vendored
Normal file
64
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/pretty/table.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package pretty
|
||||
|
||||
// TableCalculator calculates column widths (with optional padding)
|
||||
// for a table based on the maximum required column width.
|
||||
type TableCalculator struct {
|
||||
cellSizesByCol [][]int
|
||||
|
||||
Padding int
|
||||
MaxWidth int
|
||||
}
|
||||
|
||||
// AddRowSizes registers a new row with cells of the given sizes.
|
||||
func (c *TableCalculator) AddRowSizes(cellSizes ...int) {
|
||||
if len(cellSizes) > len(c.cellSizesByCol) {
|
||||
for range cellSizes[len(c.cellSizesByCol):] {
|
||||
c.cellSizesByCol = append(c.cellSizesByCol, []int(nil))
|
||||
}
|
||||
}
|
||||
for i, size := range cellSizes {
|
||||
c.cellSizesByCol[i] = append(c.cellSizesByCol[i], size)
|
||||
}
|
||||
}
|
||||
|
||||
// ColumnWidths calculates the appropriate column sizes given the
|
||||
// previously registered rows.
|
||||
func (c *TableCalculator) ColumnWidths() []int {
|
||||
maxColWidths := make([]int, len(c.cellSizesByCol))
|
||||
|
||||
for colInd, cellSizes := range c.cellSizesByCol {
|
||||
max := 0
|
||||
for _, cellSize := range cellSizes {
|
||||
if max < cellSize {
|
||||
max = cellSize
|
||||
}
|
||||
}
|
||||
maxColWidths[colInd] = max
|
||||
}
|
||||
|
||||
actualMaxWidth := c.MaxWidth - c.Padding
|
||||
for i, width := range maxColWidths {
|
||||
if actualMaxWidth > 0 && width > actualMaxWidth {
|
||||
maxColWidths[i] = actualMaxWidth
|
||||
}
|
||||
maxColWidths[i] += c.Padding
|
||||
}
|
||||
|
||||
return maxColWidths
|
||||
}
|
106
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/sort.go
generated
vendored
Normal file
106
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/sort.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package help
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
// SortGroup knows how to sort and group marker definitions.
|
||||
type SortGroup interface {
|
||||
// Less is equivalent to the Less function from sort, and is used to sort the markers.
|
||||
Less(*markers.Definition, *markers.Definition) bool
|
||||
// Group returns the "group" that a given marker belongs to.
|
||||
Group(*markers.Definition, *markers.DefinitionHelp) string
|
||||
}
|
||||
|
||||
var (
|
||||
// SortByCategory sorts the markers by name and groups them by their help category.
|
||||
SortByCategory = sortByCategory{}
|
||||
|
||||
// SortByOption sorts by the generator that the option belongs to.
|
||||
SortByOption = optionsSort{}
|
||||
)
|
||||
|
||||
type sortByCategory struct{}
|
||||
|
||||
func (sortByCategory) Group(_ *markers.Definition, help *markers.DefinitionHelp) string {
|
||||
if help == nil {
|
||||
return ""
|
||||
}
|
||||
return help.Category
|
||||
}
|
||||
func (sortByCategory) Less(i, j *markers.Definition) bool {
|
||||
return i.Name < j.Name
|
||||
}
|
||||
|
||||
type optionsSort struct{}
|
||||
|
||||
func (optionsSort) Less(i, j *markers.Definition) bool {
|
||||
iParts := strings.Split(i.Name, ":")
|
||||
jParts := strings.Split(j.Name, ":")
|
||||
|
||||
iGen := ""
|
||||
iRule := ""
|
||||
jGen := ""
|
||||
jRule := ""
|
||||
|
||||
switch len(iParts) {
|
||||
case 1:
|
||||
iGen = iParts[0]
|
||||
// two means a default output rule, so ignore
|
||||
case 2:
|
||||
iRule = iParts[1]
|
||||
case 3:
|
||||
iGen = iParts[1]
|
||||
iRule = iParts[2]
|
||||
}
|
||||
switch len(jParts) {
|
||||
case 1:
|
||||
jGen = jParts[0]
|
||||
// two means a default output rule, so ignore
|
||||
case 2:
|
||||
jRule = jParts[1]
|
||||
case 3:
|
||||
jGen = jParts[1]
|
||||
jRule = jParts[2]
|
||||
}
|
||||
|
||||
if iGen != jGen {
|
||||
return iGen > jGen
|
||||
}
|
||||
|
||||
return iRule < jRule
|
||||
}
|
||||
func (optionsSort) Group(def *markers.Definition, _ *markers.DefinitionHelp) string {
|
||||
parts := strings.Split(def.Name, ":")
|
||||
|
||||
switch len(parts) {
|
||||
case 1:
|
||||
if parts[0] == "paths" {
|
||||
return "generic"
|
||||
}
|
||||
return "generators"
|
||||
case 2:
|
||||
return "output rules (optionally as output:<generator>:...)"
|
||||
default:
|
||||
return ""
|
||||
// three means a marker-specific output rule, ignore
|
||||
}
|
||||
}
|
215
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/types.go
generated
vendored
Normal file
215
vendor/sigs.k8s.io/controller-tools/pkg/genall/help/types.go
generated
vendored
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package help
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
// DetailedHelp contains both a summary and further details.
|
||||
type DetailedHelp struct {
|
||||
// Summary contains a one-line description.
|
||||
Summary string `json:"summary"`
|
||||
// Details contains further information.
|
||||
Details string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// Argument is the type data for a marker argument.
|
||||
type Argument struct {
|
||||
// Type is the data type of the argument (string, bool, int, slice, any, raw, invalid)
|
||||
Type string `json:"type"`
|
||||
// Optional marks this argument as optional.
|
||||
Optional bool `json:"optional"`
|
||||
// ItemType contains the type of the slice item, if this is a slice
|
||||
ItemType *Argument `json:"itemType,omitempty"`
|
||||
}
|
||||
|
||||
func (a Argument) typeString(out *strings.Builder) {
|
||||
if a.Type == "slice" {
|
||||
out.WriteString("[]")
|
||||
a.ItemType.typeString(out)
|
||||
return
|
||||
}
|
||||
|
||||
out.WriteString(a.Type)
|
||||
}
|
||||
|
||||
// TypeString returns a string roughly equivalent
|
||||
// (but not identical) to the underlying Go type that
|
||||
// this argument would parse to. It's mainly useful
|
||||
// for user-friendly formatting of this argument (e.g.
|
||||
// help strings).
|
||||
func (a Argument) TypeString() string {
|
||||
out := &strings.Builder{}
|
||||
a.typeString(out)
|
||||
return out.String()
|
||||
}
|
||||
|
||||
// FieldHelp contains information required to print documentation for a marker field.
|
||||
type FieldHelp struct {
|
||||
// Name is the field name.
|
||||
Name string `json:"name"`
|
||||
// Argument is the type of the field.
|
||||
Argument `json:",inline"`
|
||||
|
||||
// DetailedHelp contains the textual help for the field.
|
||||
DetailedHelp `json:",inline"`
|
||||
}
|
||||
|
||||
// MarkerDoc contains information required to print documentation for a marker.
|
||||
type MarkerDoc struct {
|
||||
// definition
|
||||
|
||||
// Name is the name of the marker.
|
||||
Name string `json:"name"`
|
||||
// Target is the target (field, package, type) of the marker.
|
||||
Target string `json:"target"`
|
||||
|
||||
// help
|
||||
|
||||
// DetailedHelp is the textual help for the marker.
|
||||
DetailedHelp `json:",inline"`
|
||||
// Category is the general "category" that this marker belongs to.
|
||||
Category string `json:"category"`
|
||||
// DeprecatedInFavorOf marks that this marker shouldn't be used when
|
||||
// non-nil. If also non-empty, another marker should be used instead.
|
||||
DeprecatedInFavorOf *string `json:"deprecatedInFavorOf,omitempty"`
|
||||
// Fields is the type and help data for each field of this marker.
|
||||
Fields []FieldHelp `json:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// Empty checks if this marker has any arguments, returning true if not.
|
||||
func (m MarkerDoc) Empty() bool {
|
||||
return len(m.Fields) == 0
|
||||
}
|
||||
|
||||
// AnonymousField chekcs if this is an single-valued marker
|
||||
// (as opposed to having named fields).
|
||||
func (m MarkerDoc) AnonymousField() bool {
|
||||
return len(m.Fields) == 1 && m.Fields[0].Name == ""
|
||||
}
|
||||
|
||||
// ForArgument returns the equivalent documentation for a marker argument.
|
||||
func ForArgument(argRaw markers.Argument) Argument {
|
||||
res := Argument{
|
||||
Optional: argRaw.Optional,
|
||||
}
|
||||
|
||||
if argRaw.ItemType != nil {
|
||||
itemType := ForArgument(*argRaw.ItemType)
|
||||
res.ItemType = &itemType
|
||||
}
|
||||
|
||||
switch argRaw.Type {
|
||||
case markers.IntType:
|
||||
res.Type = "int"
|
||||
case markers.StringType:
|
||||
res.Type = "string"
|
||||
case markers.BoolType:
|
||||
res.Type = "bool"
|
||||
case markers.AnyType:
|
||||
res.Type = "any"
|
||||
case markers.SliceType:
|
||||
res.Type = "slice"
|
||||
case markers.RawType:
|
||||
res.Type = "raw"
|
||||
case markers.InvalidType:
|
||||
res.Type = "invalid"
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// ForDefinition returns the equivalent marker documentation for a given marker definition and spearate help.
|
||||
func ForDefinition(defn *markers.Definition, maybeHelp *markers.DefinitionHelp) MarkerDoc {
|
||||
var help markers.DefinitionHelp
|
||||
if maybeHelp != nil {
|
||||
help = *maybeHelp
|
||||
}
|
||||
|
||||
res := MarkerDoc{
|
||||
Name: defn.Name,
|
||||
Category: help.Category,
|
||||
DeprecatedInFavorOf: help.DeprecatedInFavorOf,
|
||||
Target: defn.Target.String(),
|
||||
DetailedHelp: DetailedHelp{Summary: help.Summary, Details: help.Details},
|
||||
}
|
||||
|
||||
helpByField := help.FieldsHelp(defn)
|
||||
|
||||
// TODO(directxman12): deterministic ordering
|
||||
for fieldName, fieldHelpRaw := range helpByField {
|
||||
fieldInfo := defn.Fields[fieldName]
|
||||
fieldHelp := FieldHelp{
|
||||
Name: fieldName,
|
||||
DetailedHelp: DetailedHelp{Summary: fieldHelpRaw.Summary, Details: fieldHelpRaw.Details},
|
||||
Argument: ForArgument(fieldInfo),
|
||||
}
|
||||
|
||||
res.Fields = append(res.Fields, fieldHelp)
|
||||
}
|
||||
|
||||
sort.Slice(res.Fields, func(i, j int) bool { return res.Fields[i].Name < res.Fields[j].Name })
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// CategoryDoc contains help information for all markers in a Category.
|
||||
type CategoryDoc struct {
|
||||
Category string `json:"category"`
|
||||
Markers []MarkerDoc `json:"markers"`
|
||||
}
|
||||
|
||||
// ByCategory returns the marker help for markers in the given
|
||||
// registry, grouped and sorted according to the given method.
|
||||
func ByCategory(reg *markers.Registry, sorter SortGroup) []CategoryDoc {
|
||||
groupedMarkers := make(map[string][]*markers.Definition)
|
||||
|
||||
for _, marker := range reg.AllDefinitions() {
|
||||
group := sorter.Group(marker, reg.HelpFor(marker))
|
||||
groupedMarkers[group] = append(groupedMarkers[group], marker)
|
||||
}
|
||||
allGroups := make([]string, 0, len(groupedMarkers))
|
||||
for groupName := range groupedMarkers {
|
||||
allGroups = append(allGroups, groupName)
|
||||
}
|
||||
|
||||
sort.Strings(allGroups)
|
||||
|
||||
res := make([]CategoryDoc, len(allGroups))
|
||||
for i, groupName := range allGroups {
|
||||
markers := groupedMarkers[groupName]
|
||||
sort.Slice(markers, func(i, j int) bool {
|
||||
return sorter.Less(markers[i], markers[j])
|
||||
})
|
||||
|
||||
markerDocs := make([]MarkerDoc, len(markers))
|
||||
for i, marker := range markers {
|
||||
markerDocs[i] = ForDefinition(marker, reg.HelpFor(marker))
|
||||
}
|
||||
|
||||
res[i] = CategoryDoc{
|
||||
Category: groupName,
|
||||
Markers: markerDocs,
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
37
vendor/sigs.k8s.io/controller-tools/pkg/genall/input.go
generated
vendored
Normal file
37
vendor/sigs.k8s.io/controller-tools/pkg/genall/input.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package genall
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// InputRule describes how to load non-code boilerplate artifacts.
|
||||
// It's not used for loading code.
|
||||
type InputRule interface {
|
||||
// OpenForRead opens the given non-code artifact for reading.
|
||||
OpenForRead(path string) (io.ReadCloser, error)
|
||||
}
|
||||
type inputFromFileSystem struct{}
|
||||
|
||||
func (inputFromFileSystem) OpenForRead(path string) (io.ReadCloser, error) {
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
// InputFromFileSystem reads from the filesystem as normal.
|
||||
var InputFromFileSystem = inputFromFileSystem{}
|
192
vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go
generated
vendored
Normal file
192
vendor/sigs.k8s.io/controller-tools/pkg/genall/options.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package genall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
var (
|
||||
InputPathsMarker = markers.Must(markers.MakeDefinition("paths", markers.DescribesPackage, InputPaths(nil)))
|
||||
)
|
||||
|
||||
// +controllertools:marker:generateHelp:category=""
|
||||
|
||||
// InputPaths represents paths and go-style path patterns to use as package roots.
|
||||
type InputPaths []string
|
||||
|
||||
// RegisterOptionsMarkers registers "mandatory" options markers for FromOptions into the given registry.
|
||||
// At this point, that's just InputPaths.
|
||||
func RegisterOptionsMarkers(into *markers.Registry) error {
|
||||
if err := into.Register(InputPathsMarker); err != nil {
|
||||
return err
|
||||
}
|
||||
// NB(directxman12): we make this optional so we don't have a bootstrap problem with helpgen
|
||||
if helpGiver, hasHelp := ((interface{})(InputPaths(nil))).(HasHelp); hasHelp {
|
||||
into.AddHelp(InputPathsMarker, helpGiver.Help())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegistryFromOptions produces just the marker registry that would be used by FromOptions, without
|
||||
// attempting to produce a full Runtime. This can be useful if you want to display help without
|
||||
// trying to load roots.
|
||||
func RegistryFromOptions(optionsRegistry *markers.Registry, options []string) (*markers.Registry, error) {
|
||||
protoRt, err := protoFromOptions(optionsRegistry, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg := &markers.Registry{}
|
||||
if err := protoRt.Generators.RegisterMarkers(reg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
// FromOptions parses the options from markers stored in the given registry out into a runtime.
|
||||
// The markers in the registry must be either
|
||||
//
|
||||
// a) Generators
|
||||
// b) OutputRules
|
||||
// c) InputPaths
|
||||
//
|
||||
// The paths specified in InputPaths are loaded as package roots, and the combined with
|
||||
// the generators and the specified output rules to produce a runtime that can be run or
|
||||
// further modified. Not default generators are used if none are specified -- you can check
|
||||
// the output and rerun for that.
|
||||
func FromOptions(optionsRegistry *markers.Registry, options []string) (*Runtime, error) {
|
||||
|
||||
protoRt, err := protoFromOptions(optionsRegistry, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// make the runtime
|
||||
genRuntime, err := protoRt.Generators.ForRoots(protoRt.Paths...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// attempt to figure out what the user wants without a lot of verbose specificity:
|
||||
// if the user specifies a default rule, assume that they probably want to fall back
|
||||
// to that. Otherwise, assume that they just wanted to customize one option from the
|
||||
// set, and leave the rest in the standard configuration.
|
||||
if protoRt.OutputRules.Default != nil {
|
||||
genRuntime.OutputRules = protoRt.OutputRules
|
||||
return genRuntime, nil
|
||||
}
|
||||
|
||||
outRules := DirectoryPerGenerator("config", protoRt.GeneratorsByName)
|
||||
for gen, rule := range protoRt.OutputRules.ByGenerator {
|
||||
outRules.ByGenerator[gen] = rule
|
||||
}
|
||||
|
||||
genRuntime.OutputRules = outRules
|
||||
return genRuntime, nil
|
||||
}
|
||||
|
||||
// protoFromOptions returns a proto-Runtime from the given options registry and
|
||||
// options set. This can then be used to construct an actual Runtime. See the
|
||||
// FromOptions function for more details about how the options work.
|
||||
func protoFromOptions(optionsRegistry *markers.Registry, options []string) (protoRuntime, error) {
|
||||
var gens Generators
|
||||
rules := OutputRules{
|
||||
ByGenerator: make(map[*Generator]OutputRule),
|
||||
}
|
||||
var paths []string
|
||||
|
||||
// collect the generators first, so that we can key the output on the actual
|
||||
// generator, which matters if there's settings in the gen object and it's not a pointer.
|
||||
outputByGen := make(map[string]OutputRule)
|
||||
gensByName := make(map[string]*Generator)
|
||||
|
||||
for _, rawOpt := range options {
|
||||
if rawOpt[0] != '+' {
|
||||
rawOpt = "+" + rawOpt // add a `+` to make it acceptable for usage with the registry
|
||||
}
|
||||
defn := optionsRegistry.Lookup(rawOpt, markers.DescribesPackage)
|
||||
if defn == nil {
|
||||
return protoRuntime{}, fmt.Errorf("unknown option %q", rawOpt[1:])
|
||||
}
|
||||
|
||||
val, err := defn.Parse(rawOpt)
|
||||
if err != nil {
|
||||
return protoRuntime{}, fmt.Errorf("unable to parse option %q: %w", rawOpt[1:], err)
|
||||
}
|
||||
|
||||
switch val := val.(type) {
|
||||
case Generator:
|
||||
gens = append(gens, &val)
|
||||
gensByName[defn.Name] = &val
|
||||
case OutputRule:
|
||||
_, genName := splitOutputRuleOption(defn.Name)
|
||||
if genName == "" {
|
||||
// it's a default rule
|
||||
rules.Default = val
|
||||
continue
|
||||
}
|
||||
|
||||
outputByGen[genName] = val
|
||||
continue
|
||||
case InputPaths:
|
||||
paths = append(paths, val...)
|
||||
default:
|
||||
return protoRuntime{}, fmt.Errorf("unknown option marker %q", defn.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// actually associate the rules now that we know the generators
|
||||
for genName, outputRule := range outputByGen {
|
||||
gen, knownGen := gensByName[genName]
|
||||
if !knownGen {
|
||||
return protoRuntime{}, fmt.Errorf("non-invoked generator %q", genName)
|
||||
}
|
||||
|
||||
rules.ByGenerator[gen] = outputRule
|
||||
}
|
||||
|
||||
return protoRuntime{
|
||||
Paths: paths,
|
||||
Generators: Generators(gens),
|
||||
OutputRules: rules,
|
||||
GeneratorsByName: gensByName,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// protoRuntime represents the raw pieces needed to compose a runtime, as
|
||||
// parsed from some options.
|
||||
type protoRuntime struct {
|
||||
Paths []string
|
||||
Generators Generators
|
||||
OutputRules OutputRules
|
||||
GeneratorsByName map[string]*Generator
|
||||
}
|
||||
|
||||
// splitOutputRuleOption splits a marker name of "output:rule:gen" or "output:rule"
|
||||
// into its compontent rule and generator name.
|
||||
func splitOutputRuleOption(name string) (ruleName string, genName string) {
|
||||
parts := strings.SplitN(name, ":", 3)
|
||||
if len(parts) == 3 {
|
||||
// output:<generator>:<rule>
|
||||
return parts[2], parts[1]
|
||||
}
|
||||
// output:<rule>
|
||||
return parts[1], ""
|
||||
}
|
160
vendor/sigs.k8s.io/controller-tools/pkg/genall/output.go
generated
vendored
Normal file
160
vendor/sigs.k8s.io/controller-tools/pkg/genall/output.go
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
package genall
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"sigs.k8s.io/controller-tools/pkg/loader"
|
||||
)
|
||||
|
||||
// nopCloser is a WriteCloser whose Close
|
||||
// is a no-op.
|
||||
type nopCloser struct {
|
||||
io.Writer
|
||||
}
|
||||
|
||||
func (n nopCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DirectoryPerGenerator produces output rules mapping output to a different subdirectory
|
||||
// of the given base directory for each generator (with each subdirectory specified as
|
||||
// the key in the input map).
|
||||
func DirectoryPerGenerator(base string, generators map[string]*Generator) OutputRules {
|
||||
rules := OutputRules{
|
||||
Default: OutputArtifacts{Config: OutputToDirectory(base)},
|
||||
ByGenerator: make(map[*Generator]OutputRule, len(generators)),
|
||||
}
|
||||
|
||||
for name, gen := range generators {
|
||||
rules.ByGenerator[gen] = OutputArtifacts{
|
||||
Config: OutputToDirectory(filepath.Join(base, name)),
|
||||
}
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
// OutputRules defines how to output artificats on a per-generator basis.
|
||||
type OutputRules struct {
|
||||
// Default is the output rule used when no specific per-generator overrides match.
|
||||
Default OutputRule
|
||||
// ByGenerator contains specific per-generator overrides.
|
||||
// NB(directxman12): this is a pointer to avoid issues if a given Generator becomes unhashable
|
||||
// (interface values compare by "dereferencing" their internal pointer first, whereas pointers
|
||||
// compare by the actual pointer itself).
|
||||
ByGenerator map[*Generator]OutputRule
|
||||
}
|
||||
|
||||
// ForGenerator returns the output rule that should be used
|
||||
// by the given Generator.
|
||||
func (o OutputRules) ForGenerator(gen *Generator) OutputRule {
|
||||
if forGen, specific := o.ByGenerator[gen]; specific {
|
||||
return forGen
|
||||
}
|
||||
return o.Default
|
||||
}
|
||||
|
||||
// OutputRule defines how to output artifacts from a generator.
|
||||
type OutputRule interface {
|
||||
// Open opens the given artifact path for writing. If a package is passed,
|
||||
// the artifact is considered to be used as part of the package (e.g.
|
||||
// generated code), while a nil package indicates that the artifact is
|
||||
// config (or something else not involved in Go compilation).
|
||||
Open(pkg *loader.Package, path string) (io.WriteCloser, error)
|
||||
}
|
||||
|
||||
// OutputToNothing skips outputting anything.
|
||||
var OutputToNothing = outputToNothing{}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=""
|
||||
|
||||
// outputToNothing skips outputting anything.
|
||||
type outputToNothing struct{}
|
||||
|
||||
func (o outputToNothing) Open(_ *loader.Package, _ string) (io.WriteCloser, error) {
|
||||
return nopCloser{ioutil.Discard}, nil
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=""
|
||||
|
||||
// OutputToDirectory outputs each artifact to the given directory, regardless
|
||||
// of if it's package-associated or not.
|
||||
type OutputToDirectory string
|
||||
|
||||
func (o OutputToDirectory) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) {
|
||||
// ensure the directory exists
|
||||
if err := os.MkdirAll(string(o), os.ModePerm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
path := filepath.Join(string(o), itemPath)
|
||||
return os.Create(path)
|
||||
}
|
||||
|
||||
// OutputToStdout outputs everything to standard-out, with no separation.
|
||||
//
|
||||
// Generally useful for single-artifact outputs.
|
||||
var OutputToStdout = outputToStdout{}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=""
|
||||
|
||||
// outputToStdout outputs everything to standard-out, with no separation.
|
||||
//
|
||||
// Generally useful for single-artifact outputs.
|
||||
type outputToStdout struct{}
|
||||
|
||||
func (o outputToStdout) Open(_ *loader.Package, itemPath string) (io.WriteCloser, error) {
|
||||
return nopCloser{os.Stdout}, nil
|
||||
}
|
||||
|
||||
// +controllertools:marker:generateHelp:category=""
|
||||
|
||||
// OutputArtifacts outputs artifacts to different locations, depending on
|
||||
// whether they're package-associated or not.
|
||||
//
|
||||
// Non-package associated artifacts
|
||||
// are output to the Config directory, while package-associated ones are output
|
||||
// to their package's source files' directory, unless an alternate path is
|
||||
// specified in Code.
|
||||
type OutputArtifacts struct {
|
||||
// Config points to the directory to which to write configuration.
|
||||
Config OutputToDirectory
|
||||
// Code overrides the directory in which to write new code (defaults to where the existing code lives).
|
||||
Code OutputToDirectory `marker:",optional"`
|
||||
}
|
||||
|
||||
func (o OutputArtifacts) Open(pkg *loader.Package, itemPath string) (io.WriteCloser, error) {
|
||||
if pkg == nil {
|
||||
return o.Config.Open(pkg, itemPath)
|
||||
}
|
||||
|
||||
if o.Code != "" {
|
||||
return o.Code.Open(pkg, itemPath)
|
||||
}
|
||||
|
||||
if len(pkg.CompiledGoFiles) == 0 {
|
||||
return nil, fmt.Errorf("cannot output to a package with no path on disk")
|
||||
}
|
||||
outDir := filepath.Dir(pkg.CompiledGoFiles[0])
|
||||
outPath := filepath.Join(outDir, itemPath)
|
||||
return os.Create(outPath)
|
||||
}
|
89
vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go
generated
vendored
Normal file
89
vendor/sigs.k8s.io/controller-tools/pkg/genall/zz_generated.markerhelp.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright2019 The Kubernetes 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
|
||||
|
||||
http://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.
|
||||
*/
|
||||
|
||||
// Code generated by helpgen. DO NOT EDIT.
|
||||
|
||||
package genall
|
||||
|
||||
import (
|
||||
"sigs.k8s.io/controller-tools/pkg/markers"
|
||||
)
|
||||
|
||||
func (InputPaths) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "represents paths and go-style path patterns to use as package roots.",
|
||||
Details: "",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (OutputArtifacts) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "outputs artifacts to different locations, depending on whether they're package-associated or not. ",
|
||||
Details: "Non-package associated artifacts are output to the Config directory, while package-associated ones are output to their package's source files' directory, unless an alternate path is specified in Code.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{
|
||||
"Config": {
|
||||
Summary: "points to the directory to which to write configuration.",
|
||||
Details: "",
|
||||
},
|
||||
"Code": {
|
||||
Summary: "overrides the directory in which to write new code (defaults to where the existing code lives).",
|
||||
Details: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (OutputToDirectory) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "outputs each artifact to the given directory, regardless of if it's package-associated or not.",
|
||||
Details: "",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (outputToNothing) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "skips outputting anything.",
|
||||
Details: "",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
||||
|
||||
func (outputToStdout) Help() *markers.DefinitionHelp {
|
||||
return &markers.DefinitionHelp{
|
||||
Category: "",
|
||||
DetailedHelp: markers.DetailedHelp{
|
||||
Summary: "outputs everything to standard-out, with no separation. ",
|
||||
Details: "Generally useful for single-artifact outputs.",
|
||||
},
|
||||
FieldHelp: map[string]markers.DetailedHelp{},
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user