/
bundle_archive_writer.go
152 lines (124 loc) · 3.85 KB
/
bundle_archive_writer.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
package bundles
import (
"archive/tar"
"bytes"
"compress/gzip"
"fmt"
"io"
"os"
"time"
"github.com/google/uuid"
)
type BundleArchiveWriter interface {
Open() error
WriteChartArchive(data []byte) error
WriteImageArchive(imageTag string, data []byte) error
Save() error
}
type BundleArchiveFileWriter struct {
Path string
tmpArchivePath string
tmpArchiveWriter *tar.Writer
tmpArchiveCloser func() error
}
func NewBundleArchiveFileWriter(path string) *BundleArchiveFileWriter {
return &BundleArchiveFileWriter{Path: path}
}
func (writer *BundleArchiveFileWriter) Open() error {
p := fmt.Sprintf("%s.%s.tmp", writer.Path, uuid.New().String())
f, err := os.Create(p)
if err != nil {
return fmt.Errorf("unable to open tmp archive file %q: %w", p, err)
}
zipper := gzip.NewWriter(f)
zipper.Header.Comment = "bundle-archive"
twriter := tar.NewWriter(zipper)
writer.tmpArchivePath = p
writer.tmpArchiveWriter = twriter
writer.tmpArchiveCloser = func() error {
if err := twriter.Close(); err != nil {
return fmt.Errorf("unable to close tar writer for %q: %w", writer.tmpArchivePath, err)
}
if err := zipper.Close(); err != nil {
return fmt.Errorf("unable to close zipper for %q: %w", writer.tmpArchivePath, err)
}
if err := f.Close(); err != nil {
return fmt.Errorf("unable to close %q: %w", writer.tmpArchivePath, err)
}
return nil
}
now := time.Now()
header := &tar.Header{
Name: "images",
Typeflag: tar.TypeDir,
Mode: 0o777,
ModTime: now,
AccessTime: now,
ChangeTime: now,
}
if err := writer.tmpArchiveWriter.WriteHeader(header); err != nil {
return fmt.Errorf("unable to write images dir header: %w", err)
}
return nil
}
func (writer *BundleArchiveFileWriter) Save() error {
if writer.tmpArchiveWriter == nil {
panic(fmt.Sprintf("bundle archive %q is not opened", writer.Path))
}
if err := writer.tmpArchiveCloser(); err != nil {
return fmt.Errorf("unable to close tmp archive %q: %w", writer.tmpArchivePath, err)
}
if err := os.RemoveAll(writer.Path); err != nil {
return fmt.Errorf("unable to cleanup destination archive path %q: %w", writer.Path, err)
}
if err := os.Rename(writer.tmpArchivePath, writer.Path); err != nil {
return fmt.Errorf("unable to rename tmp bundle archive %q to %q: %w", writer.tmpArchivePath, writer.Path, err)
}
return nil
}
func (writer *BundleArchiveFileWriter) WriteChartArchive(data []byte) error {
now := time.Now()
header := &tar.Header{
Name: chartArchiveFileName,
Typeflag: tar.TypeReg,
Mode: 0o777,
Size: int64(len(data)),
ModTime: now,
AccessTime: now,
ChangeTime: now,
}
if err := writer.tmpArchiveWriter.WriteHeader(header); err != nil {
return fmt.Errorf("unable to write %q header: %w", chartArchiveFileName, err)
}
if _, err := writer.tmpArchiveWriter.Write(data); err != nil {
return fmt.Errorf("unable to write %q data: %w", chartArchiveFileName, err)
}
return nil
}
func (writer *BundleArchiveFileWriter) WriteImageArchive(imageTag string, data []byte) error {
now := time.Now()
buf := bytes.NewBuffer(nil)
zipper := gzip.NewWriter(buf)
if _, err := io.Copy(zipper, bytes.NewReader(data)); err != nil {
return fmt.Errorf("unable to gzip image archive data: %w", err)
}
if err := zipper.Close(); err != nil {
return fmt.Errorf("unable to close gzip image archive: %w", err)
}
header := &tar.Header{
Name: fmt.Sprintf("images/%s.tar.gz", imageTag),
Typeflag: tar.TypeReg,
Mode: 0o777,
Size: int64(len(buf.Bytes())),
ModTime: now,
AccessTime: now,
ChangeTime: now,
}
if err := writer.tmpArchiveWriter.WriteHeader(header); err != nil {
return fmt.Errorf("unable to write image %q header: %w", imageTag, err)
}
if _, err := writer.tmpArchiveWriter.Write(buf.Bytes()); err != nil {
return fmt.Errorf("unable to write chart.tar.gz data: %w", err)
}
return nil
}