Skip to content

Commit

Permalink
Change kustomize edit fix to split patchesStrategicMerge entries befo…
Browse files Browse the repository at this point in the history
…re converting them to patch entries.
  • Loading branch information
brianpursley committed Mar 8, 2023
1 parent 22dbd3e commit d7510ea
Show file tree
Hide file tree
Showing 3 changed files with 798 additions and 21 deletions.
149 changes: 137 additions & 12 deletions api/types/kustomization.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ package types

import (
"fmt"
"path/filepath"
"strings"

"sigs.k8s.io/kustomize/kyaml/errors"
"sigs.k8s.io/kustomize/kyaml/filesys"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/yaml"
)

Expand Down Expand Up @@ -263,18 +266,9 @@ func (k *Kustomization) FixKustomizationPreMarshalling(fSys filesys.FileSystem)
k.Patches = append(k.Patches, k.PatchesJson6902...)
k.PatchesJson6902 = nil

if k.PatchesStrategicMerge != nil {
for _, patchStrategicMerge := range k.PatchesStrategicMerge {
// check this patch is file path select.
if _, err := fSys.ReadFile(string(patchStrategicMerge)); err == nil {
// path patch
k.Patches = append(k.Patches, Patch{Path: string(patchStrategicMerge)})
} else {
// inline string patch
k.Patches = append(k.Patches, Patch{Patch: string(patchStrategicMerge)})
}
}
k.PatchesStrategicMerge = nil
// Convert patchesStrategicMerge to patches.
if err := k.fixPatchesStrategicMerge(fSys); err != nil {
return err
}

// this fix is not in FixKustomizationPostUnmarshalling because
Expand All @@ -296,6 +290,39 @@ func (k *Kustomization) FixKustomizationPreMarshalling(fSys filesys.FileSystem)
return nil
}

// fixPatchesStrategicMerge converts PatchesStrategicMerge to Patches.
func (k *Kustomization) fixPatchesStrategicMerge(fSys filesys.FileSystem) error {
if k.PatchesStrategicMerge == nil {
return nil
}

for _, patchStrategicMerge := range k.PatchesStrategicMerge {
// check this patch is file path select.
if _, err := fSys.ReadFile(string(patchStrategicMerge)); err == nil {
// path patch
patches, err := splitPatchStrategicMerge(patchStrategicMerge, fSys)
if err != nil {
return err
}
for _, patch := range patches {
k.Patches = append(k.Patches, Patch{Path: string(patch)})
}
} else {
// inline string patch
patches, err := splitInlinePatchStrategicMerge(patchStrategicMerge)
if err != nil {
return err
}
for _, patch := range patches {
k.Patches = append(k.Patches, Patch{Patch: string(patch)})
}
}
}
k.PatchesStrategicMerge = nil

return nil
}

func (k *Kustomization) EnforceFields() []string {
var errs []string
if k.Kind != "" && k.Kind != KustomizationKind && k.Kind != ComponentKind {
Expand All @@ -318,3 +345,101 @@ func (k *Kustomization) Unmarshal(y []byte) error {
}
return nil
}

// splitPatchStrategicMerge splits a single PatchStrategicMerge file into multiple PatchStrategicMerge files, if the
// file contains multiple documents separated by the yaml separator.
func splitPatchStrategicMerge(p PatchStrategicMerge, fSys filesys.FileSystem) ([]PatchStrategicMerge, error) {
patchContentBytes, err := fSys.ReadFile(string(p))
if err != nil {
return nil, fmt.Errorf("failed to read file %v: %w", p, err)
}

splitPatchContent, err := kio.SplitDocuments(string(patchContentBytes))
if err != nil {
return nil, fmt.Errorf("failed to split patch file %v: %w", p, err)
}

// If the split resulted in only one document, there is nothing to do, so just return the original patch without any changes.
if len(splitPatchContent) == 1 {
return []PatchStrategicMerge{p}, nil
}

// Find the new patches, removing any empty ones.
var newPatches []string
for _, pc := range splitPatchContent {
trimmedPatchContent := strings.TrimSpace(pc)
if len(trimmedPatchContent) > 0 {
newPatches = append(newPatches, trimmedPatchContent+"\n")
}
}

// If there is only one new patch, that means there was one or more empty ones that were discarded. In this case,
// overwrite the original patch file with the new patch content and return it.
if len(newPatches) == 1 {
err := fSys.WriteFile(string(p), []byte(newPatches[0]))
if err != nil {
return nil, fmt.Errorf("failed to write file %v: %w", p, err)
}
return []PatchStrategicMerge{p}, nil
}

// If there are multiple new patches, create new patch files for each one, remove the original patch file, and
// return the list of new patch files.
result := make([]PatchStrategicMerge, len(newPatches))
for i, newPatchContent := range newPatches {
newPatchPath, err := availableFilename(string(p), i+1, fSys)
if err != nil {
return nil, fmt.Errorf("failed to find available filename for %v: %w", p, err)
}
err = fSys.WriteFile(newPatchPath, []byte(newPatchContent))
if err != nil {
return nil, fmt.Errorf("failed to write file %v: %w", newPatchPath, err)
}
result[i] = PatchStrategicMerge(newPatchPath)
}

err = fSys.RemoveAll(string(p))
if err != nil {
return nil, fmt.Errorf("failed to remove file %v: %w", p, err)
}

return result, nil
}

// splitInlinePatchStrategicMerge splits a single inline PatchStrategicMerge into multiple inline PatchStrategicMerges,
// if it contains multiple documents separated by the yaml separator.
func splitInlinePatchStrategicMerge(p PatchStrategicMerge) ([]PatchStrategicMerge, error) {
splitPatchContent, err := kio.SplitDocuments(string(p))
if err != nil {
return nil, fmt.Errorf("failed to split inline patch: %w", err)
}

// If the split resulted in only one document, there is nothing to do, so just return the original patch without any changes.
if len(splitPatchContent) == 1 {
return []PatchStrategicMerge{p}, nil
}

// Find the new patches, removing any empty ones.
var newPatches []PatchStrategicMerge
for _, pc := range splitPatchContent {
trimmedPatchContent := strings.TrimSpace(pc)
if len(trimmedPatchContent) > 0 {
newPatches = append(newPatches, PatchStrategicMerge(trimmedPatchContent+"\n"))
}
}
return newPatches, nil
}

// availableFilename returns a filename that does not already exist in the filesystem, by repeatedly appending a suffix
// to the filename until a non-existing filename is found.
func availableFilename(originalFilename string, suffix int, fSys filesys.FileSystem) (string, error) {
ext := filepath.Ext(originalFilename)
base := strings.TrimSuffix(originalFilename, ext)
for i := 0; i < 100; i++ {
base += fmt.Sprintf("-%d", suffix)
if !fSys.Exists(base + ext) {
return base + ext, nil
}
}
return "", fmt.Errorf("unable to find available filename for %s and suffix %d", originalFilename, suffix)
}
Loading

0 comments on commit d7510ea

Please sign in to comment.