diff --git a/kyaml/copyutil/copyutil.go b/kyaml/copyutil/copyutil.go index d5ae7dfcd..53e3cd6ff 100644 --- a/kyaml/copyutil/copyutil.go +++ b/kyaml/copyutil/copyutil.go @@ -131,3 +131,49 @@ func Diff(sourceDir, destDir string) (sets.String, error) { // return the differing files return diff, nil } + +// SyncFile copies file from src file path to a dst file path by replacement +// deletes dst file if src file doesn't exist +func SyncFile(src, dst string) error { + srcFileInfo, err := os.Stat(src) + if err != nil { + // delete dst if source doesn't exist + if err = deleteFile(dst); err != nil { + return err + } + return nil + } + + input, err := ioutil.ReadFile(src) + if err != nil { + return err + } + + var filePerm os.FileMode + + // get the destination file perm if file exists + dstFileInfo, err := os.Stat(dst) + if err != nil { + // get source file perm if destination file doesn't exist + filePerm = srcFileInfo.Mode().Perm() + } else { + filePerm = dstFileInfo.Mode().Perm() + } + + err = ioutil.WriteFile(dst, input, filePerm) + if err != nil { + return err + } + + return nil +} + +// deleteFile deletes file from path, returns no error if file doesn't exist +func deleteFile(path string) error { + _, err := os.Stat(path) + if err != nil { + // return nil if file doesn't exist + return nil + } + return os.Remove(path) +} diff --git a/kyaml/copyutil/copyutil_test.go b/kyaml/copyutil/copyutil_test.go index 7f364b1f4..33446572b 100644 --- a/kyaml/copyutil/copyutil_test.go +++ b/kyaml/copyutil/copyutil_test.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -203,3 +204,60 @@ func TestDiff_skipGitDest(t *testing.T) { assert.NoError(t, err) assert.Empty(t, diff.List()) } + +// TestSyncFile tests if destination file is replaced by source file content +func TestSyncFile(t *testing.T) { + d1, err := ioutil.TempDir("", "") + assert.NoError(t, err) + d2, err := ioutil.TempDir("", "") + assert.NoError(t, err) + f1Name := d1 + "/temp.txt" + f2Name := d2 + "/temp.txt" + err = ioutil.WriteFile(f1Name, []byte("abc"), 0600) + assert.NoError(t, err) + err = ioutil.WriteFile(f2Name, []byte("def"), 0644) + assert.NoError(t, err) + err = SyncFile(f1Name, f2Name) + assert.NoError(t, err) + actual, err := ioutil.ReadFile(f2Name) + assert.NoError(t, err) + assert.Equal(t, "abc", string(actual)) + dstFileInfo, _ := os.Stat(f2Name) + assert.Equal(t, "-rw-r--r--", dstFileInfo.Mode().String()) +} + +// TestSyncFileNoDestFile tests if new file is created at destination with source file content +func TestSyncFileNoDestFile(t *testing.T) { + d1, err := ioutil.TempDir("", "") + assert.NoError(t, err) + d2, err := ioutil.TempDir("", "") + assert.NoError(t, err) + f1Name := d1 + "/temp.txt" + f2Name := d2 + "/temp.txt" + err = ioutil.WriteFile(f1Name, []byte("abc"), 0644) + assert.NoError(t, err) + err = SyncFile(f1Name, f2Name) + assert.NoError(t, err) + actual, err := ioutil.ReadFile(f2Name) + assert.NoError(t, err) + assert.Equal(t, "abc", string(actual)) + dstFileInfo, _ := os.Stat(f2Name) + assert.Equal(t, "-rw-r--r--", dstFileInfo.Mode().String()) +} + +// TestSyncFileNoSrcFile tests if destination file is deleted if source file doesn't exist +func TestSyncFileNoSrcFile(t *testing.T) { + d1, err := ioutil.TempDir("", "") + assert.NoError(t, err) + d2, err := ioutil.TempDir("", "") + assert.NoError(t, err) + f1Name := d1 + "/temp.txt" + f2Name := d2 + "/temp.txt" + err = ioutil.WriteFile(f2Name, []byte("abc"), 0644) + assert.NoError(t, err) + err = SyncFile(f1Name, f2Name) + assert.NoError(t, err) + _, err = ioutil.ReadFile(f2Name) + assert.Error(t, err) + assert.True(t, strings.Contains(err.Error(), "no such file or directory")) +} diff --git a/kyaml/kio/pkgio_reader.go b/kyaml/kio/pkgio_reader.go index d4f53265d..a4eeeeac1 100644 --- a/kyaml/kio/pkgio_reader.go +++ b/kyaml/kio/pkgio_reader.go @@ -166,7 +166,7 @@ type LocalPackageReader struct { var _ Reader = LocalPackageReader{} -var defaultMatch = []string{"*.yaml", "*.yml"} +var DefaultMatch = []string{"*.yaml", "*.yml"} // Read reads the Resources. func (r LocalPackageReader) Read() ([]*yaml.RNode, error) { @@ -174,7 +174,7 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) { return nil, fmt.Errorf("must specify package path") } if len(r.MatchFilesGlob) == 0 { - r.MatchFilesGlob = defaultMatch + r.MatchFilesGlob = DefaultMatch } var operand ResourceNodeSlice @@ -201,9 +201,9 @@ func (r LocalPackageReader) Read() ([]*yaml.RNode, error) { // check if we should skip the directory or file if info.IsDir() { - return r.shouldSkipDir(path) + return r.ShouldSkipDir(path) } - if match, err := r.shouldSkipFile(info); err != nil { + if match, err := r.ShouldSkipFile(info); err != nil { return err } else if !match { // skip this file @@ -244,8 +244,8 @@ func (r *LocalPackageReader) readFile(path string, _ os.FileInfo) ([]*yaml.RNode return rr.Read() } -// shouldSkipFile returns true if the file should be skipped -func (r *LocalPackageReader) shouldSkipFile(info os.FileInfo) (bool, error) { +// ShouldSkipFile returns true if the file should be skipped +func (r *LocalPackageReader) ShouldSkipFile(info os.FileInfo) (bool, error) { // check if the files are in scope for _, g := range r.MatchFilesGlob { if match, err := filepath.Match(g, info.Name()); err != nil { @@ -267,8 +267,8 @@ func (r *LocalPackageReader) initReaderAnnotations(path string, _ os.FileInfo) { } } -// shouldSkipDir returns a filepath.SkipDir if the directory should be skipped -func (r *LocalPackageReader) shouldSkipDir(path string) error { +// ShouldSkipDir returns a filepath.SkipDir if the directory should be skipped +func (r *LocalPackageReader) ShouldSkipDir(path string) error { if r.PackageFileName == "" { return nil }