@@ -3,6 +3,7 @@ package compression
3
3
import (
4
4
"archive/zip"
5
5
"bufio"
6
+ "compress/gzip"
6
7
"errors"
7
8
"io"
8
9
"os"
@@ -19,12 +20,20 @@ import (
19
20
"github.com/ulikunitz/xz"
20
21
)
21
22
23
+ // Decompress is a generic wrapper for various decompression algos
24
+ // TODO this needs some love. in the various decompression functions that are
25
+ // called, the same uncompressed path is being opened multiple times.
22
26
func Decompress (localPath * define.VMFile , uncompressedPath string ) error {
23
27
var isZip bool
24
28
uncompressedFileWriter , err := os .OpenFile (uncompressedPath , os .O_CREATE | os .O_RDWR , 0600 )
25
29
if err != nil {
26
30
return err
27
31
}
32
+ defer func () {
33
+ if err := uncompressedFileWriter .Close (); err != nil {
34
+ logrus .Errorf ("unable to to close decompressed file %s: %q" , uncompressedPath , err )
35
+ }
36
+ }()
28
37
sourceFile , err := localPath .Read ()
29
38
if err != nil {
30
39
return err
@@ -44,6 +53,11 @@ func Decompress(localPath *define.VMFile, uncompressedPath string) error {
44
53
if isZip && runtime .GOOS == "windows" {
45
54
return decompressZip (prefix , localPath .GetPath (), uncompressedFileWriter )
46
55
}
56
+
57
+ // Unfortunately GZ is not sparse capable. Lets handle it differently
58
+ if compressionType == archive .Gzip && runtime .GOOS == "darwin" {
59
+ return decompressGzWithSparse (prefix , localPath , uncompressedPath )
60
+ }
47
61
return decompressEverythingElse (prefix , localPath .GetPath (), uncompressedFileWriter )
48
62
}
49
63
@@ -182,3 +196,56 @@ func decompressZip(prefix string, src string, output io.WriteCloser) error {
182
196
p .Wait ()
183
197
return err
184
198
}
199
+
200
+ func decompressGzWithSparse (prefix string , compressedPath * define.VMFile , uncompressedPath string ) error {
201
+ stat , err := os .Stat (compressedPath .GetPath ())
202
+ if err != nil {
203
+ return err
204
+ }
205
+
206
+ dstFile , err := os .OpenFile (uncompressedPath , os .O_CREATE | os .O_TRUNC | os .O_WRONLY , stat .Mode ())
207
+ if err != nil {
208
+ return err
209
+ }
210
+ defer func () {
211
+ if err := dstFile .Close (); err != nil {
212
+ logrus .Errorf ("unable to close uncompressed file %s: %q" , uncompressedPath , err )
213
+ }
214
+ }()
215
+
216
+ f , err := os .Open (compressedPath .GetPath ())
217
+ if err != nil {
218
+ return err
219
+ }
220
+ defer func () {
221
+ if err := f .Close (); err != nil {
222
+ logrus .Errorf ("unable to close on compressed file %s: %q" , compressedPath .GetPath (), err )
223
+ }
224
+ }()
225
+
226
+ gzReader , err := gzip .NewReader (f )
227
+ if err != nil {
228
+ return err
229
+ }
230
+ defer func () {
231
+ if err := gzReader .Close (); err != nil {
232
+ logrus .Errorf ("unable to close gzreader: %q" , err )
233
+ }
234
+ }()
235
+
236
+ // TODO remove the following line when progress bars work
237
+ _ = prefix
238
+ // p, bar := utils.ProgressBar(prefix, stat.Size(), prefix+": done")
239
+ // proxyReader := bar.ProxyReader(f)
240
+ // defer func() {
241
+ // if err := proxyReader.Close(); err != nil {
242
+ // logrus.Error(err)
243
+ // }
244
+ // }()
245
+
246
+ logrus .Debugf ("decompressing %s" , compressedPath .GetPath ())
247
+ _ , err = CopySparse (dstFile , gzReader )
248
+ logrus .Debug ("decompression complete" )
249
+ // p.Wait()
250
+ return err
251
+ }
0 commit comments