Skip to content

Commit

Permalink
Merge pull request #174 from hibell/add-sherpa-copy-dir
Browse files Browse the repository at this point in the history
Add CopyDir function to sherpa
  • Loading branch information
Daniel Mikusa authored Sep 9, 2022
2 parents 652169b + 854f2f8 commit 48f2645
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 0 deletions.
71 changes: 71 additions & 0 deletions sherpa/copy_dir.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2018-2022 the original author or 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
*
* https://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 sherpa

import (
"fmt"
"os"
"path/filepath"
)

// CopyDir copies the source directory to the destination. It ensures that the source and destination permissions match.
func CopyDir(source string, destination string) error {
entries, err := os.ReadDir(source)
if err != nil {
return fmt.Errorf("unable to read dir '%s'\n%w", source, err)
}

info, err := os.Stat(source)
if err != nil {
return fmt.Errorf("unable to stat %s\n%w", source, err)
}
if err := os.MkdirAll(destination, info.Mode()); err != nil {
return fmt.Errorf("unable to create directory %s\n%w", destination, err)
}

for _, entry := range entries {
sourceEntry := filepath.Join(source, entry.Name())
destinationEntry := filepath.Join(destination, entry.Name())
if entry.IsDir() {
entryInfo, err := entry.Info()
if err != nil {
return fmt.Errorf("unable to get directory info for %s\n%w", destinationEntry, err)
}
if err := os.Mkdir(destinationEntry, entryInfo.Mode().Perm()); err != nil {
return fmt.Errorf("unable to create directory %s\n%w", destinationEntry, err)
}
if err := CopyDir(sourceEntry, destinationEntry); err != nil {
return fmt.Errorf("unable to copy directory %s to %s\n%w", sourceEntry, destinationEntry, err)
}
} else {
if err := copyFile(sourceEntry, destinationEntry); err != nil {
return fmt.Errorf("unable to copy from %s to %s\n%w", sourceEntry, destinationEntry, err)
}
}
}

return nil
}

func copyFile(source string, destination string) error {
file, err := os.Open(source)
if err != nil {
return fmt.Errorf("unable to open source file %s\n%w", source, err)
}
defer file.Close()
return CopyFile(file, destination)
}
120 changes: 120 additions & 0 deletions sherpa/copy_dir_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2018-2022 the original author or 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
*
* https://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 sherpa_test

import (
"github.com/paketo-buildpacks/libpak/sherpa"
"os"
"path/filepath"
"testing"

. "github.com/onsi/gomega"
"github.com/sclevine/spec"
)

func testCopyDir(t *testing.T, context spec.G, it spec.S) {
var (
Expect = NewWithT(t).Expect

testPath string
destPath string

testDirs = []struct {
path string
perm os.FileMode
}{
{"foo", 0755},
{"bar", 0755},
{"baz", 0755},
{filepath.Join("baz", "qux"), 0700},
}

testFiles = []struct {
path string
perm os.FileMode
}{
{filepath.Join("foo", "foo-test-file"), 0644},
{filepath.Join("bar", "bar-test-file"), 0644},
{filepath.Join("baz", "baz-test-file"), 0644},
{filepath.Join("baz", "qux", "qux-test-file"), 0600},
}
)

it.Before(func() {
var err error

testPath, err = os.MkdirTemp("", "sherpa-copy-dir")
Expect(err).ToNot(HaveOccurred())

destPath, err = os.MkdirTemp("", "sherpa-dest-dir")
Expect(err).ToNot(HaveOccurred())

// Test directory:
//
// .
// ├── bar
// │ └── bar-test-file
// ├── baz
// │ ├── baz-test-file
// │ └── qux
// │ └── qux-test-file
// └── foo
// └── foo-test-file

for _, testDir := range testDirs {
Expect(os.Mkdir(filepath.Join(testPath, testDir.path), testDir.perm)).To(Succeed())
}

for _, testFile := range testFiles {
path := filepath.Join(testPath, testFile.path)
Expect(os.WriteFile(path, []byte(testFile.path), testFile.perm)).To(Succeed())
}
})

it.After(func() {
Expect(os.RemoveAll(testPath)).To(Succeed())
Expect(os.RemoveAll(destPath)).To(Succeed())
})

it("copies a directory", func() {
dest := filepath.Join(destPath, "test-dir")
Expect(sherpa.CopyDir(testPath, dest)).To(Succeed())
for _, testDir := range testDirs {
dir := filepath.Join(dest, testDir.path)
Expect(dir).To(BeADirectory())

// Verify directory permissions
info, err := os.Stat(dir)
Expect(err).ToNot(HaveOccurred())
Expect(info.Mode().Perm()).To(Equal(testDir.perm))
}
for _, testFile := range testFiles {
file := filepath.Join(dest, testFile.path)
Expect(file).To(BeARegularFile())

// Verify file permissions
info, err := os.Stat(file)
Expect(err).ToNot(HaveOccurred())
Expect(info.Mode().Perm()).To(Equal(testFile.perm))

// Verify file content
content, err := os.ReadFile(file)
Expect(err).ToNot(HaveOccurred())
Expect(content).To(Equal([]byte(testFile.path)))
}
})
}
1 change: 1 addition & 0 deletions sherpa/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
func TestUnit(t *testing.T) {
suite := spec.New("libpak/sherpa", spec.Report(report.Terminal{}))
suite("CopyFile", testCopyFile)
suite("CopyDir", testCopyDir)
suite("EnvVar", testEnvVar)
suite("Exists", testExists)
suite("FileListing", testFileListing)
Expand Down

0 comments on commit 48f2645

Please sign in to comment.