move setters to be available as libraries

This commit is contained in:
Phillip Wittrock
2019-12-21 16:14:19 -08:00
parent 19928abb6f
commit ad4eb87e2e
9 changed files with 23 additions and 23 deletions

View File

@@ -21,9 +21,9 @@ import (
"github.com/olekukonko/tablewriter"
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/internal/sub"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/set"
)
// NewSubRunner returns a command runner.
@@ -55,8 +55,8 @@ func SubCommand(parent string) *cobra.Command {
type SubRunner struct {
Command *cobra.Command
Lookup sub.LookupSubstitutions
Perform sub.PerformSubstitutions
Lookup set.LookupSubstitutions
Perform set.PerformSubstitutions
}
func (r *SubRunner) preRunE(c *cobra.Command, args []string) error {

View File

@@ -17,8 +17,8 @@ package commands
import (
"github.com/spf13/cobra"
"sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands"
"sigs.k8s.io/kustomize/cmd/config/internal/sub"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/set"
)
// NewSubSetRunner returns a command runner.
@@ -62,7 +62,7 @@ func SubSetCommand(parent string) *cobra.Command {
type SubSetRunner struct {
Command *cobra.Command
Set sub.SetSubstitutionMarker
Set set.SetSubstitutionMarker
}
func (r *SubSetRunner) runE(c *cobra.Command, args []string) error {

View File

@@ -1,39 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package sub
import (
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
var _ kio.Filter = &SetSubstitutionMarker{}
// Sub performs substitutions
type SetSubstitutionMarker struct {
// Marker is the marker to set
Marker Marker
// ResourceMeta defines the Resource to set the marker on
ResourceMeta yaml.ResourceMeta
}
func (s *SetSubstitutionMarker) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
for i := range input {
m, err := input[i].GetMeta()
if err != nil {
return nil, err
}
if s.ResourceMeta.Name != "" && m.Name != s.ResourceMeta.Name {
continue
}
if s.ResourceMeta.Kind != "" && m.Kind != s.ResourceMeta.Kind {
continue
}
if err := input[i].PipeE(&s.Marker); err != nil {
return nil, err
}
}
return input, nil
}

View File

@@ -1,105 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package sub
import (
"strings"
"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
var _ yaml.Filter = &Marker{}
// substituteResource substitutes a Marker value on a field
type Marker struct {
// Path is the path of the field to add the substitution for
Field string
// Substitution is the substitution to add
Substitution fieldmeta.Substitution
// PartialMatch if true will match if the Substitution value is a substring of the current
// value.
PartialMatch bool
Description string
OwnedBy string
Type string
// currentFieldName is the name of the current field being processed
currentFieldName string
}
// Filter performs the substitutions for a single object
func (m *Marker) Filter(object *yaml.RNode) (*yaml.RNode, error) {
switch object.YNode().Kind {
case yaml.DocumentNode:
return m.Filter(yaml.NewRNode(object.YNode().Content[0]))
case yaml.MappingNode:
return object, object.VisitFields(func(node *yaml.MapNode) error {
// set the current field name
n := m.currentFieldName
defer func() { m.currentFieldName = n }()
m.currentFieldName = node.Key.YNode().Value
_, err := m.Filter(node.Value)
return err
})
case yaml.SequenceNode:
return object, object.VisitElements(func(node *yaml.RNode) error {
_, err := m.Filter(node)
return err
})
case yaml.ScalarNode:
if m.currentFieldName != m.Field {
return object, nil
}
if err := m.createSub(object); err != nil {
return nil, err
}
return object, nil
default:
return object, nil
}
}
func (as *Marker) createSub(field *yaml.RNode) error {
// doesn't match the supplied value
if field.YNode().Value != as.Substitution.Value {
if !as.PartialMatch || !strings.Contains(field.YNode().Value, as.Substitution.Value) {
return nil
}
}
fm := fieldmeta.FieldMeta{}
if err := fm.Read(field); err != nil {
return errors.Wrap(err)
}
fm.OwnedBy = as.OwnedBy
fm.Description = as.Description
fm.Type = fieldmeta.FieldValueType(as.Type)
if as.Substitution.Marker == "" {
as.Substitution.Marker = "[MARKER]"
}
found := false
for i := range fm.Substitutions {
s := fm.Substitutions[i]
if s.Name == as.Substitution.Name {
// update the substitution if we find it
found = true
fm.Substitutions[i] = as.Substitution
break
}
}
if !found {
// add the substitution if it wasn't found
fm.Substitutions = append(fm.Substitutions, as.Substitution)
}
if err := fm.Write(field); err != nil {
return errors.Wrap(err)
}
return nil
}

View File

@@ -1,53 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package sub
import (
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
var _ kio.Filter = &PerformSubstitutions{}
// Sub performs substitutions
type PerformSubstitutions struct {
// Name is the name of the substitution to perform
Name string
// NewValue is the substitution value
NewValue string
// Override if set to true will re-substitute already fields with a new value
Override bool
// Revert if set to true will substitute fields back to the marker value
Revert bool
// Description, if set will annotate the field with a description.
Description string
// OwnedBy, if set will annotate the field with an owner.
OwnedBy string
// Count is the number of substitutions performed by Filter.
Count int
}
func (s *PerformSubstitutions) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
for i := range input {
p := &performSubstitutions{
Name: s.Name,
Override: s.Override,
Revert: s.Revert,
NewValue: s.NewValue,
OwnedBy: s.OwnedBy,
Description: s.Description,
}
if err := input[i].PipeE(p); err != nil {
return nil, err
}
s.Count += p.Count
}
return input, nil
}

View File

@@ -1,155 +0,0 @@
// Copyright 2019 Google LLC
//
// 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 sub substitutes strings in fields
package sub
import (
"strings"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
var _ yaml.Filter = &performSubstitutions{}
// substituteResource substitutes a Marker value on a field
type performSubstitutions struct {
// Name of the substitution to perform.
Name string
// Override if set to true will replace previously substituted values
Override bool
// Revert if set to true will undo previously substituted values
Revert bool
// NewValue is the new value to set. Mutually exclusive with Revert.
NewValue string
// Description, if set will annotate the field with a description.
Description string
// OwnedBy, if set will annotate the field with an owner.
OwnedBy string
// Count will be incremented for each substituted value.
Count int
}
// Filter performs the substitutions for a single object
func (fs *performSubstitutions) Filter(object *yaml.RNode) (*yaml.RNode, error) {
switch object.YNode().Kind {
case yaml.DocumentNode:
return fs.Filter(yaml.NewRNode(object.YNode().Content[0]))
case yaml.MappingNode:
return object, object.VisitFields(func(node *yaml.MapNode) error {
_, err := fs.Filter(node.Value)
return err
})
case yaml.SequenceNode:
return object, object.VisitElements(func(node *yaml.RNode) error {
_, err := fs.Filter(node)
return err
})
case yaml.ScalarNode:
s, f, err := fs.findSub(object)
if err != nil {
return nil, err
}
if s == nil {
return object, nil
}
return object, fs.substitute(object, s, f)
default:
return object, nil
}
}
// findSub finds the substitution matching the name if one exists
func (fs *performSubstitutions) findSub(field *yaml.RNode) (
*fieldmeta.Substitution, *fieldmeta.FieldMeta, error) {
// check if there are any substitutions for this field
var fm = &fieldmeta.FieldMeta{}
if err := fm.Read(field); err != nil {
return nil, nil, err
}
if fs.OwnedBy != "" {
fm.OwnedBy = fs.OwnedBy
}
if fs.Description != "" {
fm.Description = fs.Description
}
// check if there is a matching substitution
for i := range fm.Substitutions {
if fm.Substitutions[i].Name == fs.Name {
// validate the value if we are not reverting to the marker.
// markers are allowed to be invalid.
// only validate if there is a substitution matching the name
if !fs.Revert {
if err := fm.Type.Validate(fs.NewValue); err != nil {
return nil, nil, err
}
}
return &fm.Substitutions[i], fm, nil
}
}
return nil, nil, nil
}
// substitute performs the substitution for the given field, substitution, and metadata
func (fs *performSubstitutions) substitute(
field *yaml.RNode, s *fieldmeta.Substitution, f *fieldmeta.FieldMeta) error {
// undo or override previous substitutions by substituting the marker back
// NOTE: check if s.Value != "" so we never try to substitute the empty string back
if (fs.Revert || fs.Override) && s.Value != "" {
// revert to the marker value
if strings.Contains(field.YNode().Value, s.Value) {
// revert the substitution
field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Value, s.Marker)
// only use the tag matching the type if the marker parses to that type
field.YNode().Tag = f.Type.TagForValue(s.Marker)
// record that the config has been modified
}
}
if fs.Revert {
fs.Count++
s.Value = "" // value has been cleared and replaced with marker
if err := f.Write(field); err != nil {
return err
}
return nil
}
if s.Value == fs.NewValue || !strings.Contains(field.YNode().Value, s.Marker) {
// no substitutions necessary -- already substituted or doesn't have the marker
return nil
}
// replace the marker with the new value
field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Marker, fs.NewValue)
// be sure to set the tag so the yaml doesn't incorrectly quote ints, bools or floats
field.YNode().Tag = f.Type.Tag()
field.YNode().Style = 0
// record that the config has been modified
fs.Count++
// update the comment on the field
s.Value = fs.NewValue
if err := f.Write(field); err != nil {
return err
}
return nil
}

View File

@@ -1,69 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package sub
import (
"sort"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
var _ kio.Filter = &LookupSubstitutions{}
// Sub performs substitutions
type LookupSubstitutions struct {
// Name is the name of the substitution to match. If unspecified, all substitutions will
// be matched.
Name string
// SubstitutionCounts are the aggregate substitutions matched.
SubstitutionCounts []FieldSubstitutionCount
}
type FieldSubstitutionCount struct {
// Count is the number of substitutions possible to perform
Count int
// CountComplete is the number of substitutions that have already been performed
// independent of this object.
CountComplete int
// FieldSubstitution is the substitution found
FieldSubstitution
}
func (l *LookupSubstitutions) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
subs := map[string]*FieldSubstitutionCount{}
for i := range input {
// lookup substitutions for this object
ls := &lookupSubstitutions{Name: l.Name}
if err := input[i].PipeE(ls); err != nil {
return nil, err
}
// aggregate counts for each substitution
for j := range ls.Substitutions {
sub := ls.Substitutions[j]
curr, found := subs[sub.Name]
if !found {
curr = &FieldSubstitutionCount{FieldSubstitution: sub}
subs[sub.Name] = curr
}
curr.Count++
if sub.CurrentValue != "" {
curr.CountComplete++
}
}
}
// pull out and sort the results
for _, v := range subs {
l.SubstitutionCounts = append(l.SubstitutionCounts, *v)
}
sort.Slice(l.SubstitutionCounts, func(i, j int) bool {
return l.SubstitutionCounts[i].Name < l.SubstitutionCounts[j].Name
})
return input, nil
}

View File

@@ -1,65 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package sub
import (
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
var _ yaml.Filter = &lookupSubstitutions{}
// substituteResource substitutes a Marker value on a field
type lookupSubstitutions struct {
// Name of the substitution to lookup. If unspecified lookup all substitutions.
Name string
// FieldSubstitution is the list of substitutions that were found
Substitutions []FieldSubstitution
}
func (ls *lookupSubstitutions) Filter(object *yaml.RNode) (*yaml.RNode, error) {
switch object.YNode().Kind {
case yaml.DocumentNode:
return ls.Filter(yaml.NewRNode(object.YNode().Content[0]))
case yaml.MappingNode:
return object, object.VisitFields(func(node *yaml.MapNode) error {
_, err := ls.Filter(node.Value)
return err
})
case yaml.SequenceNode:
return object, object.VisitElements(func(node *yaml.RNode) error {
_, err := ls.Filter(node)
return err
})
case yaml.ScalarNode:
return object, ls.lookup(object)
default:
return object, nil
}
}
// lookup finds any substitutions for this field
func (ls *lookupSubstitutions) lookup(field *yaml.RNode) error {
// check if there is a substitution for this field
var fm = &fieldmeta.FieldMeta{}
if err := fm.Read(field); err != nil {
return err
}
for i := range fm.Substitutions {
s := fm.Substitutions[i]
if ls.Name == "" || ls.Name == s.Name {
ls.Substitutions = append(ls.Substitutions, FieldSubstitution{
Name: s.Name,
CurrentValue: s.Value,
Description: fm.Description,
Marker: s.Marker,
Type: fm.Type,
OwnedBy: fm.OwnedBy,
})
}
}
return nil
}

View File

@@ -1,29 +0,0 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package sub
import (
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
)
// FieldSubstitution is a possible field substitution read from a field
type FieldSubstitution struct {
// Name is the name of the substitution
Name string
// Description is a description of the fields current value
Description string
// Value is the current substituted value for the field.
CurrentValue string
// Type is the type of the substitution
Type fieldmeta.FieldValueType
// Marker is the marker used
Marker string
// OwnedBy, if set will annotate the field with an owner.
OwnedBy string
}