diff options
Diffstat (limited to 'pkg/git')
| -rw-r--r-- | pkg/git/git.go | 118 | 
1 files changed, 118 insertions, 0 deletions
| 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 +} | 
