command-runner/internal/containers/shared/tar.go (80 lines of code) (raw):
package shared
import (
"archive/tar"
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/aws/codecatalyst-runner-cli/command-runner/internal/containers/types"
"github.com/aws/codecatalyst-runner-cli/command-runner/internal/fs"
"github.com/go-git/go-billy/v5/helper/polyfill"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/rs/zerolog/log"
)
func TarDirectory(ctx context.Context, srcPath string, dstDir string, useGitIgnore bool, uid int, gid int) (*os.File, error) {
tarFile, err := os.CreateTemp(fs.TmpDir(), "tardir")
if err != nil {
return nil, err
}
tw := tar.NewWriter(tarFile)
srcPrefix := filepath.Dir(srcPath)
if !strings.HasSuffix(srcPrefix, string(filepath.Separator)) {
srcPrefix += string(filepath.Separator)
}
log.Ctx(ctx).Printf("Stripping prefix:%s src:%s", srcPrefix, srcPath)
var ignorer gitignore.Matcher
if useGitIgnore {
ps, err := gitignore.ReadPatterns(polyfill.New(osfs.New(srcPath)), nil)
if err != nil {
log.Ctx(ctx).Printf("Error loading .gitignore: %v", err)
}
ignorer = gitignore.NewMatcher(ps)
}
fc := &fs.FileCollector{
Fs: &fs.DefaultFs{},
Ignorer: ignorer,
SrcPath: srcPath,
SrcPrefix: srcPrefix,
Handler: &fs.TarCollector{
TarWriter: tw,
UID: uid,
GID: gid,
DstDir: dstDir,
},
}
err = filepath.Walk(srcPath, fc.CollectFiles(ctx, []string{}))
if err != nil {
return nil, err
}
if err := tw.Close(); err != nil {
return nil, err
}
_, err = tarFile.Seek(0, 0)
if err != nil {
return nil, fmt.Errorf("failed to seek tar archive: %w", err)
}
return tarFile, nil
}
func TarFiles(ctx context.Context, out io.Writer, uid int, gid int, files ...*types.FileEntry) error {
tw := tar.NewWriter(out)
for _, file := range files {
log.Ctx(ctx).Printf("Writing entry to tarball %s len:%d", file.Name, len(file.Body))
hdr := &tar.Header{
Name: file.Name,
Mode: file.Mode,
Size: int64(len(file.Body)),
Uid: uid,
Gid: gid,
}
if err := tw.WriteHeader(hdr); err != nil {
return err
}
if _, err := tw.Write([]byte(file.Body)); err != nil {
return err
}
}
return tw.Close()
}