mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
Delete diff command and code it uses.
This commit is contained in:
@@ -86,20 +86,6 @@ func (a *Application) MakeCustomizedResMap() (resmap.ResMap, error) {
|
|||||||
return a.resolveRefsToGeneratedResources(m)
|
return a.resolveRefsToGeneratedResources(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeUncustomizedResMap purports to create a ResMap without customization.
|
|
||||||
// The Resources in the returned ResMap include all resources mentioned
|
|
||||||
// in the kustomization file and transitively reachable via its Bases,
|
|
||||||
// and all generated secrets and configMaps.
|
|
||||||
// Meant for use in generating a diff against customized resources.
|
|
||||||
// TODO: See https://github.com/kubernetes-sigs/kustomize/issues/85
|
|
||||||
func (a *Application) MakeUncustomizedResMap() (resmap.ResMap, error) {
|
|
||||||
m, err := a.loadResMapFromBasesAndResources()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return a.resolveRefsToGeneratedResources(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveRefsToGeneratedResources fixes all name references.
|
// resolveRefsToGeneratedResources fixes all name references.
|
||||||
func (a *Application) resolveRefsToGeneratedResources(m resmap.ResMap) (resmap.ResMap, error) {
|
func (a *Application) resolveRefsToGeneratedResources(m resmap.ResMap) (resmap.ResMap, error) {
|
||||||
err := transformers.NewNameHashTransformer().Transform(m)
|
err := transformers.NewNameHashTransformer().Transform(m)
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ var deploy = schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deploy
|
|||||||
var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}
|
var cmap = schema.GroupVersionKind{Version: "v1", Kind: "ConfigMap"}
|
||||||
var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"}
|
var secret = schema.GroupVersionKind{Version: "v1", Kind: "Secret"}
|
||||||
var ns = schema.GroupVersionKind{Version: "v1", Kind: "Namespace"}
|
var ns = schema.GroupVersionKind{Version: "v1", Kind: "Namespace"}
|
||||||
var svc = schema.GroupVersionKind{Version: "v1", Kind: "Service"}
|
|
||||||
|
|
||||||
func TestResources1(t *testing.T) {
|
func TestResources1(t *testing.T) {
|
||||||
expected := resmap.ResMap{
|
expected := resmap.ResMap{
|
||||||
@@ -227,153 +226,6 @@ func TestResourceNotFound(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRawResources1(t *testing.T) {
|
|
||||||
expected := resmap.ResMap{
|
|
||||||
resource.NewResId(deploy, "dply1"): resource.NewResourceFromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "dply1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resource.NewResId(ns, "ns1"): resource.NewResourceFromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "Namespace",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "ns1",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
l := makeLoader1(t)
|
|
||||||
app, err := NewApplication(l, fs.MakeFakeFS())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected construction error %v", err)
|
|
||||||
}
|
|
||||||
actual, err := app.MakeUncustomizedResMap()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected RawResources error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := expected.ErrorIfNotEqual(actual); err != nil {
|
|
||||||
t.Fatalf("unexpected inequality: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
kustomizationContentBase = `
|
|
||||||
namePrefix: foo-
|
|
||||||
commonLabels:
|
|
||||||
app: banana
|
|
||||||
resources:
|
|
||||||
- deployment.yaml
|
|
||||||
`
|
|
||||||
kustomizationContentOverlay = `
|
|
||||||
commonLabels:
|
|
||||||
env: staging
|
|
||||||
resources:
|
|
||||||
- service.yaml
|
|
||||||
bases:
|
|
||||||
- base
|
|
||||||
`
|
|
||||||
serviceContent = `apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: svc
|
|
||||||
spec:
|
|
||||||
type: LoadBalancer
|
|
||||||
`
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeLoader2(t *testing.T) loader.Loader {
|
|
||||||
ldr := loadertest.NewFakeLoader("/testpath")
|
|
||||||
err := ldr.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContentOverlay))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err = ldr.AddFile("/testpath/service.yaml", []byte(serviceContent))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
err = ldr.AddDirectory("/testpath/base")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
err = ldr.AddFile("/testpath/base/"+constants.KustomizationFileName, []byte(kustomizationContentBase))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
err = ldr.AddFile("/testpath/base/deployment.yaml", []byte(deploymentContent))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to setup fake ldr.")
|
|
||||||
}
|
|
||||||
return ldr
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: This test covers incorrect behavior; it should not pass.
|
|
||||||
// It asks for raw resources. The Service resource is returned in raw form,
|
|
||||||
// but the resources in the base are modified to have the banana label,
|
|
||||||
// the 'foo' name prefix, etc. This method exists only to support the
|
|
||||||
// diff command comparing customized to non-customized resources;
|
|
||||||
// perhaps it's not worth supporting the command.
|
|
||||||
func TestRawResources2(t *testing.T) {
|
|
||||||
expected := resmap.ResMap{
|
|
||||||
resource.NewResIdWithPrefix(deploy, "dply1", "foo-"): resource.NewResourceFromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "apps/v1",
|
|
||||||
"kind": "Deployment",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "foo-dply1",
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"app": "banana",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"selector": map[string]interface{}{
|
|
||||||
"matchLabels": map[string]interface{}{
|
|
||||||
"app": "banana",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"template": map[string]interface{}{
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"labels": map[string]interface{}{
|
|
||||||
"app": "banana",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
resource.NewResId(svc, "svc"): resource.NewResourceFromMap(
|
|
||||||
map[string]interface{}{
|
|
||||||
"apiVersion": "v1",
|
|
||||||
"kind": "Service",
|
|
||||||
"metadata": map[string]interface{}{
|
|
||||||
"name": "svc",
|
|
||||||
},
|
|
||||||
"spec": map[string]interface{}{
|
|
||||||
"type": "LoadBalancer",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
l := makeLoader2(t)
|
|
||||||
app, err := NewApplication(l, fs.MakeFakeFS())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected construction error %v", err)
|
|
||||||
}
|
|
||||||
actual, err := app.MakeUncustomizedResMap()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected RawResources error %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := expected.ErrorIfNotEqual(actual); err != nil {
|
|
||||||
t.Fatalf("unexpected inequality: %v", err)
|
|
||||||
}
|
|
||||||
if !loadertest.CleanupCalled {
|
|
||||||
t.Fatalf("Cleanup should be called")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSecretTimeout(t *testing.T) {
|
func TestSecretTimeout(t *testing.T) {
|
||||||
l := loadertest.NewFakeLoader("/testpath")
|
l := loadertest.NewFakeLoader("/testpath")
|
||||||
err := l.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContent2))
|
err := l.AddFile("/testpath/"+constants.KustomizationFileName, []byte(kustomizationContent2))
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import (
|
|||||||
// NewDefaultCommand returns the default (aka root) command for kustomize command.
|
// NewDefaultCommand returns the default (aka root) command for kustomize command.
|
||||||
func NewDefaultCommand() *cobra.Command {
|
func NewDefaultCommand() *cobra.Command {
|
||||||
fsys := fs.MakeRealFS()
|
fsys := fs.MakeRealFS()
|
||||||
stdOut, stdErr := os.Stdout, os.Stderr
|
stdOut := os.Stdout
|
||||||
|
|
||||||
c := &cobra.Command{
|
c := &cobra.Command{
|
||||||
Use: "kustomize",
|
Use: "kustomize",
|
||||||
@@ -43,7 +43,6 @@ See https://github.com/kubernetes-sigs/kustomize
|
|||||||
c.AddCommand(
|
c.AddCommand(
|
||||||
// TODO: Make consistent API for newCmd* functions.
|
// TODO: Make consistent API for newCmd* functions.
|
||||||
newCmdBuild(stdOut, fsys),
|
newCmdBuild(stdOut, fsys),
|
||||||
newCmdDiff(stdOut, stdErr, fsys),
|
|
||||||
newCmdEdit(fsys),
|
newCmdEdit(fsys),
|
||||||
newCmdVersion(stdOut),
|
newCmdVersion(stdOut),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 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 commands
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/app"
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/constants"
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/diff"
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/loader"
|
|
||||||
)
|
|
||||||
|
|
||||||
type diffOptions struct {
|
|
||||||
kustomizationPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newCmdDiff makes the diff command.
|
|
||||||
func newCmdDiff(out, errOut io.Writer, fs fs.FileSystem) *cobra.Command {
|
|
||||||
var o diffOptions
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "diff [path]",
|
|
||||||
Short: "diff between customized resources and uncustomized resources",
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
err := o.Validate(args)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return o.RunDiff(out, errOut, fs)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate validates diff command.
|
|
||||||
func (o *diffOptions) Validate(args []string) error {
|
|
||||||
if len(args) > 1 {
|
|
||||||
return errors.New("specify one path to " + constants.KustomizationFileName)
|
|
||||||
}
|
|
||||||
if len(args) == 0 {
|
|
||||||
o.kustomizationPath = "./"
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
o.kustomizationPath = args[0]
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunDiff gets the differences between Application.MakeCustomizedResMap() and Application.MakeUncustomizedResMap().
|
|
||||||
func (o *diffOptions) RunDiff(out, errOut io.Writer, fSys fs.FileSystem) error {
|
|
||||||
|
|
||||||
rootLoader, err := loader.NewLoader(o.kustomizationPath, "", fSys)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer rootLoader.Cleanup()
|
|
||||||
|
|
||||||
application, err := app.NewApplication(rootLoader, fSys)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
transformedResources, err := application.MakeCustomizedResMap()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawResources, err := application.MakeUncustomizedResMap()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return diff.RunDiff(rawResources, transformedResources, out, errOut)
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 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 commands
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
|
||||||
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/fs"
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DiffTestCase struct {
|
|
||||||
Description string `yaml:"description"`
|
|
||||||
Args []string `yaml:"args"`
|
|
||||||
Filename string `yaml:"filename"`
|
|
||||||
// path to the file that contains the expected output
|
|
||||||
ExpectedDiff string `yaml:"expectedDiff"`
|
|
||||||
ExpectedError string `yaml:"expectedError"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDiff(t *testing.T) {
|
|
||||||
const updateEnvVar = "UPDATE_KUSTOMIZE_EXPECTED_DATA"
|
|
||||||
updateKustomizeExpected := os.Getenv(updateEnvVar) == "true"
|
|
||||||
|
|
||||||
tempDir := regexp.QuoteMeta(filepath.Clean(os.TempDir()))
|
|
||||||
noopDir, _ := regexp.Compile(tempDir + `/noop-[0-9]*/`)
|
|
||||||
transformedDir, _ := regexp.Compile(tempDir + `/transformed-[0-9]*/`)
|
|
||||||
timestamp, _ := regexp.Compile(`[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1]) (2[0-3]|[01][0-9]):[0-5][0-9]:[0-5][0-9].[0-9]* [+-]{1}[0-9]{4}`)
|
|
||||||
|
|
||||||
fSys := fs.MakeRealFS()
|
|
||||||
|
|
||||||
testcases := sets.NewString()
|
|
||||||
filepath.Walk("testdata", func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if path == "testdata" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
name := filepath.Base(path)
|
|
||||||
if info.IsDir() {
|
|
||||||
if strings.HasPrefix(name, "testcase-") {
|
|
||||||
testcases.Insert(strings.TrimPrefix(name, "testcase-"))
|
|
||||||
}
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
// sanity check that we found the right folder
|
|
||||||
if !testcases.Has("simple") {
|
|
||||||
t.Fatalf("Error locating testcases")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, testcaseName := range testcases.List() {
|
|
||||||
t.Run(testcaseName, func(t *testing.T) {
|
|
||||||
runDiffTestCase(t, testcaseName, updateKustomizeExpected, fSys,
|
|
||||||
noopDir, transformedDir, timestamp)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func runDiffTestCase(t *testing.T, testcaseName string, updateKustomizeExpected bool, fs fs.FileSystem,
|
|
||||||
noopDir, transformedDir, timestamp *regexp.Regexp) {
|
|
||||||
name := testcaseName
|
|
||||||
testcase := DiffTestCase{}
|
|
||||||
testcaseDir := filepath.Join("testdata", "testcase-"+name)
|
|
||||||
testcaseData, err := ioutil.ReadFile(filepath.Join(testcaseDir, "test.yaml"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s: %v", name, err)
|
|
||||||
}
|
|
||||||
if err := yaml.Unmarshal(testcaseData, &testcase); err != nil {
|
|
||||||
t.Fatalf("%s: %v", name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
diffOps := &diffOptions{
|
|
||||||
kustomizationPath: testcase.Filename,
|
|
||||||
}
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
|
||||||
err = diffOps.RunDiff(buf, os.Stderr, fs)
|
|
||||||
switch {
|
|
||||||
case err != nil && len(testcase.ExpectedError) == 0:
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
case err != nil && len(testcase.ExpectedError) != 0:
|
|
||||||
if !strings.Contains(err.Error(), testcase.ExpectedError) {
|
|
||||||
t.Errorf("expected error to contain %q but got: %v", testcase.ExpectedError, err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
case err == nil && len(testcase.ExpectedError) != 0:
|
|
||||||
t.Errorf("unexpected no error")
|
|
||||||
}
|
|
||||||
|
|
||||||
actualString := string(buf.Bytes())
|
|
||||||
actualString = noopDir.ReplaceAllString(actualString, "/tmp/noop/")
|
|
||||||
actualString = transformedDir.ReplaceAllString(actualString, "/tmp/transformed/")
|
|
||||||
actualString = timestamp.ReplaceAllString(actualString, "YYYY-MM-DD HH:MM:SS")
|
|
||||||
actualBytes := []byte(actualString)
|
|
||||||
if !updateKustomizeExpected {
|
|
||||||
expectedBytes, err := ioutil.ReadFile(testcase.ExpectedDiff)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(actualBytes, expectedBytes) {
|
|
||||||
t.Errorf("%s\ndoesn't equal expected:\n%s\n", actualBytes, expectedBytes)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ioutil.WriteFile(testcase.ExpectedDiff, actualBytes, 0644)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
package diff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// directory represents a new temp directory and lets one create files in it.
|
|
||||||
type directory struct {
|
|
||||||
n string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newDirectory makes a directory instance holding a new temp directory on disk.
|
|
||||||
// The directory name is the given prefix following by a random string.
|
|
||||||
func newDirectory(prefix string) (*directory, error) {
|
|
||||||
name, err := ioutil.TempDir("", prefix+"-")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &directory{n: name}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newFile creates a new file in the directory.
|
|
||||||
func (d *directory) newFile(name string) (*os.File, error) {
|
|
||||||
return os.OpenFile(filepath.Join(d.n, name), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete removes the directory recursively.
|
|
||||||
func (d *directory) delete() error {
|
|
||||||
return os.RemoveAll(d.n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// name is the name of the directory.
|
|
||||||
func (d *directory) name() string {
|
|
||||||
return d.n
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 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 diff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/exec"
|
|
||||||
)
|
|
||||||
|
|
||||||
// program wraps the system diff program.
|
|
||||||
// If specified, the value of KUBERNETES_EXTERNAL_DIFF environment variable
|
|
||||||
// will be used instead of simply `diff(1)`.
|
|
||||||
type program struct {
|
|
||||||
stdout io.Writer
|
|
||||||
stderr io.Writer
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProgram(out, errOut io.Writer) *program {
|
|
||||||
return &program{
|
|
||||||
stdout: out,
|
|
||||||
stderr: errOut,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *program) makeCommand(args ...string) exec.Cmd {
|
|
||||||
diff := "diff"
|
|
||||||
if envDiff := os.Getenv("KUBERNETES_EXTERNAL_DIFF"); envDiff != "" {
|
|
||||||
diff = envDiff
|
|
||||||
} else {
|
|
||||||
args = append([]string{"-u", "-N"}, args...)
|
|
||||||
}
|
|
||||||
cmd := exec.New().Command(diff, args...)
|
|
||||||
cmd.SetStdout(d.stdout)
|
|
||||||
cmd.SetStderr(d.stderr)
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
// run runs the detected diff program. `from` and `to` are the directory to diff.
|
|
||||||
func (d *program) run(from, to string) error {
|
|
||||||
d.makeCommand(from, to).Run() // Ignore diff return code
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2018 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 diff runs system `diff` to compare resource collections.
|
|
||||||
package diff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/ghodss/yaml"
|
|
||||||
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RunDiff runs system diff program to compare two Maps.
|
|
||||||
func RunDiff(raw, transformed resmap.ResMap, out, errOut io.Writer) (err error) {
|
|
||||||
transformedDir, err := writeYamlToNewDir(transformed, "transformed")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = transformedDir.delete()
|
|
||||||
}()
|
|
||||||
|
|
||||||
noopDir, err := writeYamlToNewDir(raw, "noop")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
err = noopDir.delete()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return newProgram(out, errOut).run(noopDir.name(), transformedDir.name())
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeYamlToNewDir writes each obj in ResMap to a file in a new directory.
|
|
||||||
// The directory's name will begin with the given prefix.
|
|
||||||
// Each file is named with GroupVersionKindName.
|
|
||||||
func writeYamlToNewDir(in resmap.ResMap, prefix string) (*directory, error) {
|
|
||||||
dir, err := newDirectory(prefix)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for id, obj := range in {
|
|
||||||
f, err := dir.newFile(id.GvknString())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = write(obj, f)
|
|
||||||
f.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dir, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the object as YAML.
|
|
||||||
func write(obj interface{}, w io.Writer) error {
|
|
||||||
if obj == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
data, err := yaml.Marshal(obj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err = w.Write(data)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user