/
zip.go
138 lines (115 loc) · 3.39 KB
/
zip.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
138
// Copyright (c) 2016 OpenM++
// This code is licensed under the MIT license (see LICENSE.txt for details)
package helper
import (
"archive/zip"
"errors"
"io"
"os"
"path/filepath"
)
// PackZip create new (overwrite) zip archive from specified file or directory and all subdirs.
// If dstDir is "" empty then result located in source base directory.
func PackZip(srcPath string, dstDir string) (string, error) {
// create output directory if not exist and make archive name as base.zip
cleanPath := filepath.Clean(srcPath)
baseDir, base := filepath.Split(cleanPath)
var zipPath string
if dstDir == "" {
zipPath = filepath.Join(baseDir, base+".zip")
} else {
zipPath = filepath.Join(dstDir, base+".zip")
if err := os.MkdirAll(dstDir, 0750); err != nil {
return "", errors.New("make directory failed at pack to zip: " + err.Error())
}
}
// create zip file
zf, err := os.OpenFile(zipPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
return "", errors.New("create file failed at pack to zip: " + err.Error())
}
defer zf.Close()
zwr := zip.NewWriter(zf)
defer zwr.Close()
// walk in source directory and compress files and subdirs
err = filepath.Walk(cleanPath, func(src string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// make archive name relative to source base directory
rel, err := filepath.Rel(baseDir, src)
if err != nil {
return err
}
rel = filepath.ToSlash(rel)
// if this is directory add it to header to store empty dirs
if info.IsDir() {
_, err := zwr.Create(rel + "/")
return err
}
// else: add file to archive
w, err := zwr.Create(rel)
if err != nil {
return err
}
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(w, f) // do compression
return err
})
if err != nil {
return "", errors.New("failed pack to zip: " + err.Error())
}
return zipPath, nil
}
// UnpackZip unpack zip archive into specified directory, creating it if not exist.
// If dstDir is "" empty then result located in source base directory.
func UnpackZip(zipPath string, dstDir string) error {
// create output directory if not exist
var baseDir string
if dstDir == "" {
baseDir = filepath.Dir(zipPath)
} else {
baseDir = filepath.Clean(dstDir)
if err := os.MkdirAll(baseDir, 0750); err != nil {
return errors.New("make directory failed at unpack from zip: " + err.Error())
}
}
// open zip archive
zr, err := zip.OpenReader(zipPath)
if err != nil {
return errors.New("open zip file failed at unpack from zip: " + err.Error())
}
defer zr.Close()
// for all zipped files and directories
for _, znext := range zr.File {
err := func(zf *zip.File) error {
// if this is empty directory then create it
info := zf.FileInfo()
p := filepath.Join(baseDir, zf.Name)
if info.IsDir() {
return os.MkdirAll(p, info.Mode())
}
// else unpack file
f, err := os.OpenFile(p, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
if err != nil {
return err
}
defer f.Close()
r, err := zf.Open()
if err != nil {
return err
}
defer r.Close()
_, err = io.Copy(f, r) // do unpack
return err
}(znext)
if err != nil {
return errors.New("unpack from zip failed: " + err.Error())
}
}
return nil
}