diff --git a/cmd/gradleExecuteBuild.go b/cmd/gradleExecuteBuild.go index 8a635adf2b..e1d0d387ed 100644 --- a/cmd/gradleExecuteBuild.go +++ b/cmd/gradleExecuteBuild.go @@ -121,38 +121,22 @@ type Artifact struct { Name string `json:"name,omitempty"` } -type WalkDir func(root string, fn fs.WalkDirFunc) error - -type Filepath interface { - WalkDir(root string, fn fs.WalkDirFunc) error -} - -type WalkDirFunc func(root string, fn fs.WalkDirFunc) error - -func (f WalkDirFunc) WalkDir(root string, fn fs.WalkDirFunc) error { - return f(root, fn) -} - type gradleExecuteBuildUtils interface { command.ExecRunner piperutils.FileUtils - Filepath } type gradleExecuteBuildUtilsBundle struct { *command.Command *piperutils.Files - Filepath } func newGradleExecuteBuildUtils() gradleExecuteBuildUtils { - var walkDirFunc WalkDirFunc = filepath.WalkDir utils := gradleExecuteBuildUtilsBundle{ Command: &command.Command{ StepName: "gradleExecuteBuild", }, - Files: &piperutils.Files{}, - Filepath: walkDirFunc, + Files: &piperutils.Files{}, } utils.Stdout(log.Writer()) utils.Stderr(log.Writer()) diff --git a/cmd/gradleExecuteBuild_test.go b/cmd/gradleExecuteBuild_test.go index 525e53f923..af2ccab0fd 100644 --- a/cmd/gradleExecuteBuild_test.go +++ b/cmd/gradleExecuteBuild_test.go @@ -21,7 +21,6 @@ const moduleFileContent = `{"variants": [{"name": "apiElements","files": [{"name type gradleExecuteBuildMockUtils struct { *mock.ExecMockRunner *mock.FilesMock - Filepath } type isDirEntryMock func() bool @@ -121,16 +120,9 @@ func TestRunGradleExecuteBuild(t *testing.T) { }) t.Run("success case - publishing of artifacts", func(t *testing.T) { - var walkDir WalkDirFunc = func(root string, fn fs.WalkDirFunc) error { - var dirMock isDirEntryMock = func() bool { - return false - } - return fn(filepath.Join("test_subproject_path", "build", "publications", "maven", "module.json"), dirMock, nil) - } utils := gradleExecuteBuildMockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, - Filepath: walkDir, } utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) utils.FilesMock.AddFile(filepath.Join("test_subproject_path", "build", "publications", "maven", "module.json"), []byte(moduleFileContent)) diff --git a/pkg/cnbutils/copy_project.go b/pkg/cnbutils/copy_project.go index 1d20892afd..9c8441deb5 100644 --- a/pkg/cnbutils/copy_project.go +++ b/pkg/cnbutils/copy_project.go @@ -1,72 +1,57 @@ package cnbutils import ( + "io/fs" "os" - "path" "path/filepath" "strings" "github.com/SAP/jenkins-library/pkg/log" - "github.com/pkg/errors" ignore "github.com/sabhiram/go-gitignore" ) func CopyProject(source, target string, include, exclude *ignore.GitIgnore, utils BuildUtils) error { - sourceFiles, _ := utils.Glob(path.Join(source, "**")) - for _, sourceFile := range sourceFiles { - relPath, err := filepath.Rel(source, sourceFile) + log.Entry().Debugf("Copying project from '%s' to '%s'", source, target) + + utils.WalkDir(source, func(path string, d fs.DirEntry, err error) error { + log.Entry().Debugf("Processing file '%s' (%s)", path, d.Type()) + target := filepath.Join(target, strings.ReplaceAll(path, source, "")) + if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Calculating relative path for '%s' failed", sourceFile) + return err } - if !isIgnored(relPath, include, exclude) { - target := path.Join(target, strings.ReplaceAll(sourceFile, source, "")) - dir, err := utils.DirExists(sourceFile) + + relPath, err := filepath.Rel(source, path) + if isIgnored(relPath, include, exclude) { + return nil + } + + switch d.Type() { + case fs.ModeDir: + log.Entry().Debugf("Creating directpry '%s'", path) + err := utils.MkdirAll(target, os.ModePerm) if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Checking file info '%s' failed", target) + return err } - - if dir { - err = utils.MkdirAll(target, os.ModePerm) - if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Creating directory '%s' failed", target) - } - } else { - log.Entry().Debugf("Copying '%s' to '%s'", sourceFile, target) - err = copyFile(sourceFile, target, utils) - if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Copying '%s' to '%s' failed", sourceFile, target) - } + case fs.ModeSymlink: + linkTarget, err := utils.Readlink(path) + log.Entry().Debugf("Creating symlink from '%s' to '%s'", target, linkTarget) + if err != nil { + return err + } + os.Symlink(linkTarget, target) + default: + log.Entry().Debugf("Copying file from '%s' to '%s'", path, target) + _, err = utils.Copy(path, target) + if err != nil { + return err } - } - } + return nil + }) return nil } -func copyFile(source, target string, utils BuildUtils) error { - targetDir := filepath.Dir(target) - - exists, err := utils.DirExists(targetDir) - if err != nil { - return err - } - - if !exists { - log.Entry().Debugf("Creating directory %s", targetDir) - err = utils.MkdirAll(targetDir, os.ModePerm) - if err != nil { - return err - } - } - - _, err = utils.Copy(source, target) - return err -} - func isIgnored(find string, include, exclude *ignore.GitIgnore) bool { if exclude != nil { filtered := exclude.MatchesPath(find) diff --git a/pkg/cnbutils/copy_project_test.go b/pkg/cnbutils/copy_project_test.go index abd706fa4a..1a2492a240 100644 --- a/pkg/cnbutils/copy_project_test.go +++ b/pkg/cnbutils/copy_project_test.go @@ -13,27 +13,18 @@ import ( ) func TestCopyProject(t *testing.T) { - t.Run("copies file according to doublestart globs", func(t *testing.T) { + t.Run("project is copied successfully", func(t *testing.T) { mockUtils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } - mockUtils.AddFile("workdir/src/test.yaml", []byte("")) - mockUtils.AddFile("workdir/src/subdir1/test2.yaml", []byte("")) - mockUtils.AddFile("workdir/src/subdir1/subdir2/test3.yaml", []byte("")) - err := cnbutils.CopyProject("workdir/src", "/dest", ignore.CompileIgnoreLines([]string{"**/*.yaml"}...), nil, mockUtils) + mockUtils.AddFile("/workdir/src/test.yaml", []byte("")) + mockUtils.Symlink("/workdir/src/test.yaml", "/workdir/src/test-symlink.yaml") + mockUtils.AddFile("/workdir/src/subdir1/test2.yaml", []byte("")) + mockUtils.AddFile("/workdir/src/subdir1/subdir2/test3.yaml", []byte("")) + err := cnbutils.CopyProject("/workdir/src", "/dest", ignore.CompileIgnoreLines([]string{"**/*.yaml"}...), nil, mockUtils) assert.NoError(t, err) assert.True(t, mockUtils.HasCopiedFile("workdir/src/test.yaml", "/dest/test.yaml")) assert.True(t, mockUtils.HasCopiedFile("workdir/src/subdir1/test2.yaml", "/dest/subdir1/test2.yaml")) assert.True(t, mockUtils.HasCopiedFile("workdir/src/subdir1/subdir2/test3.yaml", "/dest/subdir1/subdir2/test3.yaml")) }) - - t.Run("copies file according to simple globs", func(t *testing.T) { - mockUtils := &cnbutils.MockUtils{ - FilesMock: &mock.FilesMock{}, - } - mockUtils.AddFile("src/test.yaml", []byte("")) - err := cnbutils.CopyProject("src", "/dest", ignore.CompileIgnoreLines([]string{"*.yaml"}...), nil, mockUtils) - assert.NoError(t, err) - assert.True(t, mockUtils.HasCopiedFile("src/test.yaml", "/dest/test.yaml")) - }) } diff --git a/pkg/mock/fileUtils.go b/pkg/mock/fileUtils.go index ab36a5d001..761ed32645 100644 --- a/pkg/mock/fileUtils.go +++ b/pkg/mock/fileUtils.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "io" + "io/fs" "os" "path/filepath" "sort" @@ -700,3 +701,53 @@ func (f *FilesMockRelativeGlob) Glob(pattern string) ([]string, error) { sort.Strings(matches) return matches, nil } + +type dirEntry struct { + name string + isDir bool + mode fs.FileMode +} + +func (d dirEntry) Name() string { + return "foo" +} + +func (d dirEntry) IsDir() bool { + return false +} + +func (d dirEntry) Type() fs.FileMode { + return d.mode +} + +func (d dirEntry) Info() (fs.FileInfo, error) { + return nil, nil +} + +func (f *FilesMock) Readlink(name string) (string, error) { + properties, ok := f.files[name] + if ok && properties.isLink { + return properties.target, nil + } + return "", fmt.Errorf("could not retrieve target for %s", name) +} + +func (f *FilesMock) WalkDir(root string, fn fs.WalkDirFunc) error { + for name, properties := range f.files { + dirEntry := dirEntry{ + name: filepath.Base(name), + } + dirEntry.mode = fs.ModePerm + + if properties.isLink { + dirEntry.mode = fs.ModeSymlink + } + if properties.isDir() { + dirEntry.mode = fs.ModeDir + dirEntry.isDir = true + } + + fn(name, dirEntry, nil) + } + return nil +} diff --git a/pkg/piperutils/fileUtils.go b/pkg/piperutils/fileUtils.go index 4cc5091ba6..91293a1a30 100644 --- a/pkg/piperutils/fileUtils.go +++ b/pkg/piperutils/fileUtils.go @@ -43,6 +43,8 @@ type FileUtils interface { CurrentTime(format string) string Open(name string) (io.ReadWriteCloser, error) Create(name string) (io.ReadWriteCloser, error) + WalkDir(root string, fn fs.WalkDirFunc) error + Readlink(name string) (string, error) } // Files ... @@ -513,3 +515,13 @@ func (f Files) Open(name string) (io.ReadWriteCloser, error) { func (f Files) Create(name string) (io.ReadWriteCloser, error) { return os.Create(name) } + +// WalkDir wraps filepath.WalkDir +func (f Files) WalkDir(root string, fn fs.WalkDirFunc) error { + return filepath.WalkDir(root, fn) +} + +// Readlink wraps os.Readlink +func (f Files) Readlink(name string) (string, error) { + return os.Readlink(name) +}