refactor: filecollector into new package (#2174)
* refactor: filecollector into new package * Add test for symlinks * add test fix bug of GetContainerArchive * add test data
This commit is contained in:
parent
4ca35d2192
commit
5a80a044f9
6 changed files with 160 additions and 35 deletions
|
@ -35,6 +35,7 @@ import (
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
|
||||||
"github.com/nektos/act/pkg/common"
|
"github.com/nektos/act/pkg/common"
|
||||||
|
"github.com/nektos/act/pkg/filecollector"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewContainer creates a reference to a container
|
// NewContainer creates a reference to a container
|
||||||
|
@ -735,12 +736,12 @@ func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgno
|
||||||
ignorer = gitignore.NewMatcher(ps)
|
ignorer = gitignore.NewMatcher(ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
fc := &fileCollector{
|
fc := &filecollector.FileCollector{
|
||||||
Fs: &defaultFs{},
|
Fs: &filecollector.DefaultFs{},
|
||||||
Ignorer: ignorer,
|
Ignorer: ignorer,
|
||||||
SrcPath: srcPath,
|
SrcPath: srcPath,
|
||||||
SrcPrefix: srcPrefix,
|
SrcPrefix: srcPrefix,
|
||||||
Handler: &tarCollector{
|
Handler: &filecollector.TarCollector{
|
||||||
TarWriter: tw,
|
TarWriter: tw,
|
||||||
UID: cr.UID,
|
UID: cr.UID,
|
||||||
GID: cr.GID,
|
GID: cr.GID,
|
||||||
|
@ -748,7 +749,7 @@ func (cr *containerReference) copyDir(dstPath string, srcPath string, useGitIgno
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = filepath.Walk(srcPath, fc.collectFiles(ctx, []string{}))
|
err = filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
|
||||||
"github.com/nektos/act/pkg/common"
|
"github.com/nektos/act/pkg/common"
|
||||||
|
"github.com/nektos/act/pkg/filecollector"
|
||||||
"github.com/nektos/act/pkg/lookpath"
|
"github.com/nektos/act/pkg/lookpath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -65,7 +66,7 @@ func (e *HostEnvironment) CopyTarStream(ctx context.Context, destPath string, ta
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tr := tar.NewReader(tarStream)
|
tr := tar.NewReader(tarStream)
|
||||||
cp := ©Collector{
|
cp := &filecollector.CopyCollector{
|
||||||
DstDir: destPath,
|
DstDir: destPath,
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
|
@ -104,16 +105,16 @@ func (e *HostEnvironment) CopyDir(destPath string, srcPath string, useGitIgnore
|
||||||
|
|
||||||
ignorer = gitignore.NewMatcher(ps)
|
ignorer = gitignore.NewMatcher(ps)
|
||||||
}
|
}
|
||||||
fc := &fileCollector{
|
fc := &filecollector.FileCollector{
|
||||||
Fs: &defaultFs{},
|
Fs: &filecollector.DefaultFs{},
|
||||||
Ignorer: ignorer,
|
Ignorer: ignorer,
|
||||||
SrcPath: srcPath,
|
SrcPath: srcPath,
|
||||||
SrcPrefix: srcPrefix,
|
SrcPrefix: srcPrefix,
|
||||||
Handler: ©Collector{
|
Handler: &filecollector.CopyCollector{
|
||||||
DstDir: destPath,
|
DstDir: destPath,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return filepath.Walk(srcPath, fc.collectFiles(ctx, []string{}))
|
return filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,21 +127,21 @@ func (e *HostEnvironment) GetContainerArchive(ctx context.Context, srcPath strin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
tc := &tarCollector{
|
tc := &filecollector.TarCollector{
|
||||||
TarWriter: tw,
|
TarWriter: tw,
|
||||||
}
|
}
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
srcPrefix := filepath.Dir(srcPath)
|
srcPrefix := srcPath
|
||||||
if !strings.HasSuffix(srcPrefix, string(filepath.Separator)) {
|
if !strings.HasSuffix(srcPrefix, string(filepath.Separator)) {
|
||||||
srcPrefix += string(filepath.Separator)
|
srcPrefix += string(filepath.Separator)
|
||||||
}
|
}
|
||||||
fc := &fileCollector{
|
fc := &filecollector.FileCollector{
|
||||||
Fs: &defaultFs{},
|
Fs: &filecollector.DefaultFs{},
|
||||||
SrcPath: srcPath,
|
SrcPath: srcPath,
|
||||||
SrcPrefix: srcPrefix,
|
SrcPrefix: srcPrefix,
|
||||||
Handler: tc,
|
Handler: tc,
|
||||||
}
|
}
|
||||||
err = filepath.Walk(srcPath, fc.collectFiles(ctx, []string{}))
|
err = filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,71 @@
|
||||||
package container
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
// Type assert HostEnvironment implements ExecutionsEnvironment
|
// Type assert HostEnvironment implements ExecutionsEnvironment
|
||||||
var _ ExecutionsEnvironment = &HostEnvironment{}
|
var _ ExecutionsEnvironment = &HostEnvironment{}
|
||||||
|
|
||||||
|
func TestCopyDir(t *testing.T) {
|
||||||
|
dir, err := os.MkdirTemp("", "test-host-env-*")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
ctx := context.Background()
|
||||||
|
e := &HostEnvironment{
|
||||||
|
Path: filepath.Join(dir, "path"),
|
||||||
|
TmpDir: filepath.Join(dir, "tmp"),
|
||||||
|
ToolCache: filepath.Join(dir, "tool_cache"),
|
||||||
|
ActPath: filepath.Join(dir, "act_path"),
|
||||||
|
StdOut: os.Stdout,
|
||||||
|
Workdir: path.Join("testdata", "scratch"),
|
||||||
|
}
|
||||||
|
_ = os.MkdirAll(e.Path, 0700)
|
||||||
|
_ = os.MkdirAll(e.TmpDir, 0700)
|
||||||
|
_ = os.MkdirAll(e.ToolCache, 0700)
|
||||||
|
_ = os.MkdirAll(e.ActPath, 0700)
|
||||||
|
err = e.CopyDir(e.Workdir, e.Path, true)(ctx)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetContainerArchive(t *testing.T) {
|
||||||
|
dir, err := os.MkdirTemp("", "test-host-env-*")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
ctx := context.Background()
|
||||||
|
e := &HostEnvironment{
|
||||||
|
Path: filepath.Join(dir, "path"),
|
||||||
|
TmpDir: filepath.Join(dir, "tmp"),
|
||||||
|
ToolCache: filepath.Join(dir, "tool_cache"),
|
||||||
|
ActPath: filepath.Join(dir, "act_path"),
|
||||||
|
StdOut: os.Stdout,
|
||||||
|
Workdir: path.Join("testdata", "scratch"),
|
||||||
|
}
|
||||||
|
_ = os.MkdirAll(e.Path, 0700)
|
||||||
|
_ = os.MkdirAll(e.TmpDir, 0700)
|
||||||
|
_ = os.MkdirAll(e.ToolCache, 0700)
|
||||||
|
_ = os.MkdirAll(e.ActPath, 0700)
|
||||||
|
expectedContent := []byte("sdde/7sh")
|
||||||
|
err = os.WriteFile(filepath.Join(e.Path, "action.yml"), expectedContent, 0600)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
archive, err := e.GetContainerArchive(ctx, e.Path)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
defer archive.Close()
|
||||||
|
reader := tar.NewReader(archive)
|
||||||
|
h, err := reader.Next()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "action.yml", h.Name)
|
||||||
|
content, err := io.ReadAll(reader)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, expectedContent, content)
|
||||||
|
_, err = reader.Next()
|
||||||
|
assert.ErrorIs(t, err, io.EOF)
|
||||||
|
}
|
||||||
|
|
1
pkg/container/testdata/scratch/test.txt
vendored
Normal file
1
pkg/container/testdata/scratch/test.txt
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
testfile
|
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package filecollector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
@ -17,18 +17,18 @@ import (
|
||||||
"github.com/go-git/go-git/v5/plumbing/format/index"
|
"github.com/go-git/go-git/v5/plumbing/format/index"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fileCollectorHandler interface {
|
type Handler interface {
|
||||||
WriteFile(path string, fi fs.FileInfo, linkName string, f io.Reader) error
|
WriteFile(path string, fi fs.FileInfo, linkName string, f io.Reader) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type tarCollector struct {
|
type TarCollector struct {
|
||||||
TarWriter *tar.Writer
|
TarWriter *tar.Writer
|
||||||
UID int
|
UID int
|
||||||
GID int
|
GID int
|
||||||
DstDir string
|
DstDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc tarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
|
func (tc TarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
|
||||||
// create a new dir/file header
|
// create a new dir/file header
|
||||||
header, err := tar.FileInfoHeader(fi, linkName)
|
header, err := tar.FileInfoHeader(fi, linkName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -59,11 +59,11 @@ func (tc tarCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type copyCollector struct {
|
type CopyCollector struct {
|
||||||
DstDir string
|
DstDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *copyCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
|
func (cc *CopyCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string, f io.Reader) error {
|
||||||
fdestpath := filepath.Join(cc.DstDir, fpath)
|
fdestpath := filepath.Join(cc.DstDir, fpath)
|
||||||
if err := os.MkdirAll(filepath.Dir(fdestpath), 0o777); err != nil {
|
if err := os.MkdirAll(filepath.Dir(fdestpath), 0o777); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -82,29 +82,29 @@ func (cc *copyCollector) WriteFile(fpath string, fi fs.FileInfo, linkName string
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileCollector struct {
|
type FileCollector struct {
|
||||||
Ignorer gitignore.Matcher
|
Ignorer gitignore.Matcher
|
||||||
SrcPath string
|
SrcPath string
|
||||||
SrcPrefix string
|
SrcPrefix string
|
||||||
Fs fileCollectorFs
|
Fs Fs
|
||||||
Handler fileCollectorHandler
|
Handler Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileCollectorFs interface {
|
type Fs interface {
|
||||||
Walk(root string, fn filepath.WalkFunc) error
|
Walk(root string, fn filepath.WalkFunc) error
|
||||||
OpenGitIndex(path string) (*index.Index, error)
|
OpenGitIndex(path string) (*index.Index, error)
|
||||||
Open(path string) (io.ReadCloser, error)
|
Open(path string) (io.ReadCloser, error)
|
||||||
Readlink(path string) (string, error)
|
Readlink(path string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultFs struct {
|
type DefaultFs struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*defaultFs) Walk(root string, fn filepath.WalkFunc) error {
|
func (*DefaultFs) Walk(root string, fn filepath.WalkFunc) error {
|
||||||
return filepath.Walk(root, fn)
|
return filepath.Walk(root, fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*defaultFs) OpenGitIndex(path string) (*index.Index, error) {
|
func (*DefaultFs) OpenGitIndex(path string) (*index.Index, error) {
|
||||||
r, err := git.PlainOpen(path)
|
r, err := git.PlainOpen(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -116,16 +116,16 @@ func (*defaultFs) OpenGitIndex(path string) (*index.Index, error) {
|
||||||
return i, nil
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*defaultFs) Open(path string) (io.ReadCloser, error) {
|
func (*DefaultFs) Open(path string) (io.ReadCloser, error) {
|
||||||
return os.Open(path)
|
return os.Open(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*defaultFs) Readlink(path string) (string, error) {
|
func (*DefaultFs) Readlink(path string) (string, error) {
|
||||||
return os.Readlink(path)
|
return os.Readlink(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo
|
//nolint:gocyclo
|
||||||
func (fc *fileCollector) collectFiles(ctx context.Context, submodulePath []string) filepath.WalkFunc {
|
func (fc *FileCollector) CollectFiles(ctx context.Context, submodulePath []string) filepath.WalkFunc {
|
||||||
i, _ := fc.Fs.OpenGitIndex(path.Join(fc.SrcPath, path.Join(submodulePath...)))
|
i, _ := fc.Fs.OpenGitIndex(path.Join(fc.SrcPath, path.Join(submodulePath...)))
|
||||||
return func(file string, fi os.FileInfo, err error) error {
|
return func(file string, fi os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -166,7 +166,7 @@ func (fc *fileCollector) collectFiles(ctx context.Context, submodulePath []strin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil && entry.Mode == filemode.Submodule {
|
if err == nil && entry.Mode == filemode.Submodule {
|
||||||
err = fc.Fs.Walk(file, fc.collectFiles(ctx, split))
|
err = fc.Fs.Walk(file, fc.CollectFiles(ctx, split))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package container
|
package filecollector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
|
@ -95,16 +95,16 @@ func TestIgnoredTrackedfile(t *testing.T) {
|
||||||
tw := tar.NewWriter(tmpTar)
|
tw := tar.NewWriter(tmpTar)
|
||||||
ps, _ := gitignore.ReadPatterns(worktree, []string{})
|
ps, _ := gitignore.ReadPatterns(worktree, []string{})
|
||||||
ignorer := gitignore.NewMatcher(ps)
|
ignorer := gitignore.NewMatcher(ps)
|
||||||
fc := &fileCollector{
|
fc := &FileCollector{
|
||||||
Fs: &memoryFs{Filesystem: fs},
|
Fs: &memoryFs{Filesystem: fs},
|
||||||
Ignorer: ignorer,
|
Ignorer: ignorer,
|
||||||
SrcPath: "mygitrepo",
|
SrcPath: "mygitrepo",
|
||||||
SrcPrefix: "mygitrepo" + string(filepath.Separator),
|
SrcPrefix: "mygitrepo" + string(filepath.Separator),
|
||||||
Handler: &tarCollector{
|
Handler: &TarCollector{
|
||||||
TarWriter: tw,
|
TarWriter: tw,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := fc.Fs.Walk("mygitrepo", fc.collectFiles(context.Background(), []string{}))
|
err := fc.Fs.Walk("mygitrepo", fc.CollectFiles(context.Background(), []string{}))
|
||||||
assert.NoError(t, err, "successfully collect files")
|
assert.NoError(t, err, "successfully collect files")
|
||||||
tw.Close()
|
tw.Close()
|
||||||
_, _ = tmpTar.Seek(0, io.SeekStart)
|
_, _ = tmpTar.Seek(0, io.SeekStart)
|
||||||
|
@ -115,3 +115,58 @@ func TestIgnoredTrackedfile(t *testing.T) {
|
||||||
_, err = tr.Next()
|
_, err = tr.Next()
|
||||||
assert.ErrorIs(t, err, io.EOF, "tar must only contain one element")
|
assert.ErrorIs(t, err, io.EOF, "tar must only contain one element")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSymlinks(t *testing.T) {
|
||||||
|
fs := memfs.New()
|
||||||
|
_ = fs.MkdirAll("mygitrepo/.git", 0o777)
|
||||||
|
dotgit, _ := fs.Chroot("mygitrepo/.git")
|
||||||
|
worktree, _ := fs.Chroot("mygitrepo")
|
||||||
|
repo, _ := git.Init(filesystem.NewStorage(dotgit, cache.NewObjectLRUDefault()), worktree)
|
||||||
|
// This file shouldn't be in the tar
|
||||||
|
f, err := worktree.Create(".env")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = f.Write([]byte("test=val1\n"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
f.Close()
|
||||||
|
err = worktree.Symlink(".env", "test.env")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
w, err := repo.Worktree()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
// .gitignore is in the tar after adding it to the index
|
||||||
|
_, err = w.Add(".env")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, err = w.Add("test.env")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
tmpTar, _ := fs.Create("temp.tar")
|
||||||
|
tw := tar.NewWriter(tmpTar)
|
||||||
|
ps, _ := gitignore.ReadPatterns(worktree, []string{})
|
||||||
|
ignorer := gitignore.NewMatcher(ps)
|
||||||
|
fc := &FileCollector{
|
||||||
|
Fs: &memoryFs{Filesystem: fs},
|
||||||
|
Ignorer: ignorer,
|
||||||
|
SrcPath: "mygitrepo",
|
||||||
|
SrcPrefix: "mygitrepo" + string(filepath.Separator),
|
||||||
|
Handler: &TarCollector{
|
||||||
|
TarWriter: tw,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = fc.Fs.Walk("mygitrepo", fc.CollectFiles(context.Background(), []string{}))
|
||||||
|
assert.NoError(t, err, "successfully collect files")
|
||||||
|
tw.Close()
|
||||||
|
_, _ = tmpTar.Seek(0, io.SeekStart)
|
||||||
|
tr := tar.NewReader(tmpTar)
|
||||||
|
h, err := tr.Next()
|
||||||
|
files := map[string]tar.Header{}
|
||||||
|
for err == nil {
|
||||||
|
files[h.Name] = *h
|
||||||
|
h, err = tr.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, ".env", files[".env"].Name)
|
||||||
|
assert.Equal(t, "test.env", files["test.env"].Name)
|
||||||
|
assert.Equal(t, ".env", files["test.env"].Linkname)
|
||||||
|
assert.ErrorIs(t, err, io.EOF, "tar must be read cleanly to EOF")
|
||||||
|
}
|
Loading…
Reference in a new issue