-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharchiver.go
More file actions
119 lines (102 loc) · 2.83 KB
/
Copy patharchiver.go
File metadata and controls
119 lines (102 loc) · 2.83 KB
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
// Copyright (c) 2019-2023 Vincent Cheung ([email protected]).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package lork
import (
"archive/zip"
"compress/gzip"
"fmt"
"io"
"os"
"strings"
"time"
)
type Archiver interface {
// Archive makes an archiver with given filename and archive filename.
Archive(filename, archiveFilename string) error
}
func newArchiver(filenamePattern string) Archiver {
if strings.HasSuffix(filenamePattern, "gz") {
return &gzipArchiver{}
} else if strings.HasSuffix(filenamePattern, "zip") {
return &zipArchiver{}
} else {
return &noneArchiver{}
}
}
type noneArchiver struct {
}
func (a *noneArchiver) Archive(filename, archiveFilename string) error {
return rename(filename, archiveFilename)
}
type gzipArchiver struct {
}
func (a *gzipArchiver) Archive(filename, archiveFilename string) error {
origin, target, err := renameOpenFile(filename, archiveFilename)
if err != nil {
return err
}
w := gzip.NewWriter(target)
w.Header = gzip.Header{
ModTime: time.Now(),
Name: strings.TrimSuffix(archiveFilename, ".gz"),
}
go func() {
_, _ = io.Copy(w, origin)
_ = w.Close()
_ = origin.Close()
if err = os.Remove(origin.Name()); err != nil {
Reportf("archiver remove file error: %v", err)
}
}()
return nil
}
type zipArchiver struct {
}
func (a *zipArchiver) Archive(filename, archiveFilename string) error {
origin, target, err := renameOpenFile(filename, archiveFilename)
if err != nil {
return err
}
entryName := strings.TrimSuffix(archiveFilename, ".zip")
zw := zip.NewWriter(target)
w, err := zw.CreateHeader(&zip.FileHeader{
Name: entryName,
Modified: time.Now(),
Method: zip.Deflate,
})
if err != nil {
return err
}
go func() {
_, _ = io.Copy(w, origin)
_ = zw.Close()
_ = origin.Close()
if err = os.Remove(origin.Name()); err != nil {
Reportf("archiver remove file error: %v", err)
}
}()
return nil
}
func renameOpenFile(filename, archiveFilename string) (*os.File, *os.File, error) {
tmpFilename := fmt.Sprintf("%s-%v.%s", archiveFilename, time.Now().UnixNano(), "tmp")
if err := rename(filename, tmpFilename); err != nil {
return nil, nil, err
}
origin, err := os.Open(tmpFilename)
if err != nil {
return nil, nil, err
}
target, err := os.OpenFile(archiveFilename, os.O_RDWR|os.O_CREATE, os.ModePerm)
return origin, target, err
}