forked from mholt/archiver
-
Notifications
You must be signed in to change notification settings - Fork 0
/
targz.go
137 lines (119 loc) · 3.42 KB
/
targz.go
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
134
135
136
137
package archiver
import (
"fmt"
"io"
"strings"
"github.com/klauspost/compress/gzip"
"github.com/klauspost/pgzip"
)
// TarGz facilitates gzip compression
// (RFC 1952) of tarball archives.
type TarGz struct {
*Tar
// The compression level to use, as described
// in the compress/gzip package.
CompressionLevel int
// Disables parallel gzip.
SingleThreaded bool
}
// CheckExt ensures the file extension matches the format.
func (*TarGz) CheckExt(filename string) error {
if !strings.HasSuffix(filename, ".tar.gz") &&
!strings.HasSuffix(filename, ".tgz") {
return fmt.Errorf("filename must have a .tar.gz or .tgz extension")
}
return nil
}
// Archive creates a compressed tar file at destination
// containing the files listed in sources. The destination
// must end with ".tar.gz" or ".tgz". File paths can be
// those of regular files or directories; directories will
// be recursively added.
func (tgz *TarGz) Archive(sources []string, destination string) error {
err := tgz.CheckExt(destination)
if err != nil {
return fmt.Errorf("output %s", err.Error())
}
tgz.wrapWriter()
return tgz.Tar.Archive(sources, destination)
}
// Unarchive unpacks the compressed tarball at
// source to destination. Destination will be
// treated as a folder name.
func (tgz *TarGz) Unarchive(source, destination string) error {
tgz.wrapReader()
return tgz.Tar.Unarchive(source, destination)
}
// Walk calls walkFn for each visited item in archive.
func (tgz *TarGz) Walk(archive string, walkFn WalkFunc) error {
tgz.wrapReader()
return tgz.Tar.Walk(archive, walkFn)
}
// Create opens txz for writing a compressed
// tar archive to out.
func (tgz *TarGz) Create(out io.Writer) error {
tgz.wrapWriter()
return tgz.Tar.Create(out)
}
// Open opens t for reading a compressed archive from
// in. The size parameter is not used.
func (tgz *TarGz) Open(in io.Reader, size int64) error {
tgz.wrapReader()
return tgz.Tar.Open(in, size)
}
// Extract extracts a single file from the tar archive.
// If the target is a directory, the entire folder will
// be extracted into destination.
func (tgz *TarGz) Extract(source, target, destination string) error {
tgz.wrapReader()
return tgz.Tar.Extract(source, target, destination)
}
func (tgz *TarGz) wrapWriter() {
var gzw io.WriteCloser
tgz.Tar.writerWrapFn = func(w io.Writer) (io.Writer, error) {
var err error
if tgz.SingleThreaded {
gzw, err = gzip.NewWriterLevel(w, tgz.CompressionLevel)
} else {
gzw, err = pgzip.NewWriterLevel(w, tgz.CompressionLevel)
}
return gzw, err
}
tgz.Tar.cleanupWrapFn = func() {
gzw.Close()
}
}
func (tgz *TarGz) wrapReader() {
var gzr io.ReadCloser
tgz.Tar.readerWrapFn = func(r io.Reader) (io.Reader, error) {
var err error
if tgz.SingleThreaded {
gzr, err = gzip.NewReader(r)
} else {
gzr, err = pgzip.NewReader(r)
}
return gzr, err
}
tgz.Tar.cleanupWrapFn = func() {
gzr.Close()
}
}
func (tgz *TarGz) String() string { return "tar.gz" }
// NewTarGz returns a new, default instance ready to be customized and used.
func NewTarGz() *TarGz {
return &TarGz{
CompressionLevel: gzip.DefaultCompression,
Tar: NewTar(),
}
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = Reader(new(TarGz))
_ = Writer(new(TarGz))
_ = Archiver(new(TarGz))
_ = Unarchiver(new(TarGz))
_ = Walker(new(TarGz))
_ = Extractor(new(TarGz))
)
// DefaultTarGz is a convenient archiver ready to use.
var DefaultTarGz = NewTarGz()