-
Notifications
You must be signed in to change notification settings - Fork 2
/
pack.go
193 lines (170 loc) · 4.19 KB
/
pack.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package main
import (
"bytes"
"flag"
"io"
"io/fs"
"log"
"mime"
"net/http"
"os"
"path"
"strings"
"github.com/schwarzlichtbezirk/wpk"
)
// command line settings
var (
srcpath string
SrcList []string
DstFile string
PutMIME bool
PutLink bool
ShowLog bool
Split bool
)
func parseargs() {
flag.StringVar(&srcpath, "src", "", "full path to folder with source files to be packaged, or list of folders divided by ';'")
flag.StringVar(&DstFile, "dst", "", "full path to output package file")
flag.BoolVar(&PutMIME, "mime", false, "put content MIME type defined by file extension to each file tagset")
flag.BoolVar(&PutLink, "link", false, "put full path to the original file to each file tagset")
flag.BoolVar(&ShowLog, "log", true, "show process log for each extracting file")
flag.BoolVar(&Split, "split", false, "write package to splitted files")
flag.Parse()
}
func checkargs() (ec int) { // returns error counter
for i, fpath := range strings.Split(srcpath, ";") {
if fpath == "" {
continue
}
fpath = wpk.ToSlash(wpk.Envfmt(fpath, nil))
if !strings.HasSuffix(fpath, "/") {
fpath += "/"
}
if ok, _ := wpk.DirExists(fpath); !ok {
log.Printf("source path #%d '%s' does not exist", i+1, fpath)
ec++
continue
}
SrcList = append(SrcList, fpath)
}
if len(SrcList) == 0 {
log.Println("source path does not specified")
ec++
}
DstFile = wpk.ToSlash(wpk.Envfmt(DstFile, nil))
if DstFile == "" {
log.Println("destination file does not specified")
ec++
} else if ok, _ := wpk.DirExists(path.Dir(DstFile)); !ok {
log.Println("destination path does not exist")
ec++
}
return
}
func writepackage() (err error) {
var fwpk, fwpf wpk.WriteSeekCloser
var pkgfile, datfile = DstFile, DstFile
var pkg = wpk.NewPackage()
if Split {
pkgfile, datfile = wpk.MakeTagsPath(pkgfile), wpk.MakeDataPath(datfile)
}
// open package file to write
if fwpk, err = os.OpenFile(pkgfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
return
}
defer fwpk.Close()
if Split {
if fwpf, err = os.OpenFile(datfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644); err != nil {
return
}
defer fwpf.Close()
log.Printf("destination tags part: %s\n", pkgfile)
log.Printf("destination files part: %s\n", datfile)
} else {
log.Printf("destination file: %s\n", pkgfile)
}
// starts new package
if err = pkg.Begin(fwpk, fwpf); err != nil {
return
}
// data writer
var w = fwpk
if fwpf != nil {
w = fwpf
}
// write all source folders
for i, srcpath := range SrcList {
log.Printf("source folder #%d: %s", i+1, srcpath)
var num, sum int64
fs.WalkDir(os.DirFS(srcpath), ".", func(fkey string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil // file is directory
}
var fpath = wpk.JoinPath(srcpath, fkey)
var file wpk.RFile
var ts wpk.TagsetRaw
if file, err = os.Open(fpath); err != nil {
return err
}
defer file.Close()
if ts, err = pkg.PackFile(w, file, fkey); err != nil {
return err
}
var size = ts.Size()
num++
sum += size
if ShowLog {
log.Printf("#%-4d %7d bytes %s", num, size, fkey)
}
// adjust tags
if PutMIME {
const sniffLen = 512
var ctype = mime.TypeByExtension(path.Ext(fkey))
if ctype == "" {
// rewind to file start
if _, err = file.Seek(0, io.SeekStart); err != nil {
return err
}
// read a chunk to decide between utf-8 text and binary
var buf [sniffLen]byte
var n int64
if n, err = io.CopyN(bytes.NewBuffer(buf[:]), file, sniffLen); err != nil && err != io.EOF {
return err
}
ctype = http.DetectContentType(buf[:n])
}
if ctype != "" {
ts = ts.Put(wpk.TIDmime, wpk.StrTag(ctype))
}
}
if PutLink {
ts = ts.Put(wpk.TIDlink, wpk.StrTag(fpath))
}
pkg.SetTagset(fkey, ts)
return nil
})
log.Printf("packed: %d files on %d bytes", num, sum)
}
// finalize
log.Printf("write tags table")
if err = pkg.Sync(fwpk, fwpf); err != nil {
return
}
return
}
func main() {
parseargs()
if checkargs() > 0 {
return
}
log.Println("starts")
if err := writepackage(); err != nil {
log.Println(err.Error())
return
}
log.Println("done.")
}
// The End.