From e1664fcbc4685906d3dabc66bf947a17bce7efc0 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Sat, 22 Jun 2024 16:30:47 +0200 Subject: feat: Add archive capability --- pkg/git/git.go | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) (limited to 'pkg/git/git.go') diff --git a/pkg/git/git.go b/pkg/git/git.go index b725cd8..591fafb 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -1,9 +1,13 @@ package git import ( + "archive/tar" "errors" "fmt" "io" + "io/fs" + "path" + "time" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" @@ -26,6 +30,13 @@ type ( // this is setRef when ref is setRef setRef bool } + infoWrapper struct { + name string + size int64 + mode fs.FileMode + modTime time.Time + isDir bool + } ) func OpenRepository(dir string) (*GitRepository, error) { @@ -213,3 +224,110 @@ func (g *GitRepository) FileContent(path string) (string, error) { return "Binary file", nil } } + +func (g *GitRepository) WriteTar(w io.Writer, prefix string) error { + tw := tar.NewWriter(w) + defer tw.Close() + + tree, err := g.Tree("") + if err != nil { + return err + } + + walker := object.NewTreeWalker(tree, true, nil) + defer walker.Close() + + name, entry, err := walker.Next() + for ; err == nil; name, entry, err = walker.Next() { + info, err := newInfoWrapper(name, prefix, &entry, tree) + if err != nil { + return err + } + + header, err := tar.FileInfoHeader(info, "") + if err != nil { + return err + } + + err = tw.WriteHeader(header) + if err != nil { + return err + } + + if !info.IsDir() { + c, err := g.FileContent(name) + if err != nil { + return err + } + + _, err = tw.Write([]byte(c)) + if err != nil { + return err + } + } + } + + return nil +} + +func newInfoWrapper( + filename string, + prefix string, + entry *object.TreeEntry, + tree *object.Tree, +) (*infoWrapper, error) { + var ( + size int64 + mode fs.FileMode + isDir bool + ) + + if entry.Mode.IsFile() { + file, err := tree.TreeEntryFile(entry) + if err != nil { + return nil, err + } + mode = fs.FileMode(file.Mode) + + size, err = tree.Size(filename) + if err != nil { + return nil, err + } + } else { + isDir = true + mode = fs.ModeDir | fs.ModePerm + } + + fullname := path.Join(prefix, filename) + return &infoWrapper{ + name: fullname, + size: size, + mode: mode, + modTime: time.Unix(0, 0), + isDir: isDir, + }, nil +} + +func (i *infoWrapper) Name() string { + return i.name +} + +func (i *infoWrapper) Size() int64 { + return i.size +} + +func (i *infoWrapper) Mode() fs.FileMode { + return i.mode +} + +func (i *infoWrapper) ModTime() time.Time { + return i.modTime +} + +func (i *infoWrapper) IsDir() bool { + return i.isDir +} + +func (i *infoWrapper) Sys() any { + return nil +} -- cgit v1.2.3