1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
package tgz
import (
"archive/tar"
"compress/gzip"
"fmt"
"io"
"os"
"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/util"
)
const (
useDefaultTempDir = ""
tmpPrefix = "tmp-tgz-"
)
// Extract decompress a gziped tarball into a new temporal directory
// created just for this purpose.
//
// On success, the path of the newly created directory and a nil error
// is returned.
//
// A non-nil error is returned if the method fails to complete. The
// returned path will be an empty string if no information was extracted
// before the error and the temporal directory has not been created.
// Otherwise, a non-empty string with the temporal directory holding
// whatever information was extracted before the error is returned.
func Extract(fs billy.Filesystem, tgz string) (d billy.Filesystem, err error, cleanup func()) {
dirName := ""
cleanup = func() {
if dirName != "" {
_ = os.RemoveAll(dirName)
}
}
f, err := fs.Open(tgz)
if err != nil {
return
}
defer func() {
errClose := f.Close()
if err == nil {
err = errClose
}
}()
dirName, err = util.TempDir(fs, useDefaultTempDir, tmpPrefix)
if err != nil {
return
}
tar, err := zipTarReader(f)
if err != nil {
return
}
if err = unTar(fs, tar, dirName); err != nil {
return
}
d, err = fs.Chroot(dirName)
return
}
func zipTarReader(r io.Reader) (*tar.Reader, error) {
zip, err := gzip.NewReader(r)
if err != nil {
return nil, err
}
return tar.NewReader(zip), nil
}
func unTar(fs billy.Filesystem, src *tar.Reader, dstPath string) error {
for {
header, err := src.Next()
if err != nil {
if err == io.EOF {
break
}
return err
}
dst := dstPath + "/" + header.Name
mode := os.FileMode(header.Mode)
switch header.Typeflag {
case tar.TypeDir:
err := fs.MkdirAll(dst, mode)
if err != nil {
return err
}
case tar.TypeReg:
err := makeFile(fs, dst, mode, src)
if err != nil {
return err
}
default:
return fmt.Errorf("Unable to untar type : %c in file %s",
header.Typeflag, header.Name)
}
}
return nil
}
func makeFile(fs billy.Filesystem, path string, mode os.FileMode, contents io.Reader) (err error) {
w, err := fs.Create(path)
if err != nil {
return err
}
defer func() {
errClose := w.Close()
if err == nil {
err = errClose
}
}()
_, err = io.Copy(w, contents)
if err != nil {
return err
}
if fs, ok := fs.(billy.Change); ok {
if err = fs.Chmod(path, mode); err != nil {
return err
}
}
return nil
}
|