master
go 106 lines 1.89 KB
Raw
1 package migrations
2
3 import (
4 "archive/tar"
5 "archive/zip"
6 "compress/gzip"
7 "errors"
8 "fmt"
9 "io"
10 "os"
11 )
12
13 func unpackArchive(arcPath, atype, root, name, out string) error {
14 var err error
15 switch atype {
16 case "tar.gz":
17 err = unpackTgz(arcPath, root, name, out)
18 case "zip":
19 err = unpackZip(arcPath, root, name, out)
20 default:
21 err = fmt.Errorf("unrecognized archive type: %s", atype)
22 }
23 if err != nil {
24 return err
25 }
26 return nil
27 }
28
29 func unpackTgz(arcPath, root, name, out string) error {
30 fi, err := os.Open(arcPath)
31 if err != nil {
32 return fmt.Errorf("cannot open archive file: %w", err)
33 }
34 defer fi.Close()
35
36 gzr, err := gzip.NewReader(fi)
37 if err != nil {
38 return fmt.Errorf("error opening gzip reader: %w", err)
39 }
40 defer gzr.Close()
41
42 var bin io.Reader
43 tarr := tar.NewReader(gzr)
44
45 lookFor := root + "/" + name
46 for {
47 th, err := tarr.Next()
48 if err != nil {
49 if err == io.EOF {
50 break
51 }
52 return fmt.Errorf("cannot read archive: %w", err)
53 }
54
55 if th.Name == lookFor {
56 bin = tarr
57 break
58 }
59 }
60
61 if bin == nil {
62 return errors.New("no binary found in archive")
63 }
64
65 return writeToPath(bin, out)
66 }
67
68 func unpackZip(arcPath, root, name, out string) error {
69 zipr, err := zip.OpenReader(arcPath)
70 if err != nil {
71 return fmt.Errorf("error opening zip reader: %w", err)
72 }
73 defer zipr.Close()
74
75 lookFor := root + "/" + name
76 var bin io.ReadCloser
77 for _, fis := range zipr.File {
78 if fis.Name == lookFor {
79 rc, err := fis.Open()
80 if err != nil {
81 return fmt.Errorf("error extracting binary from archive: %w", err)
82 }
83
84 bin = rc
85 break
86 }
87 }
88
89 if bin == nil {
90 return errors.New("no binary found in archive")
91 }
92
93 return writeToPath(bin, out)
94 }
95
96 func writeToPath(rc io.Reader, out string) error {
97 binfi, err := os.Create(out)
98 if err != nil {
99 return fmt.Errorf("error creating output file '%s': %w", out, err)
100 }
101 defer binfi.Close()
102
103 _, err = io.Copy(binfi, rc)
104
105 return err
106 }