-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrite.go
More file actions
120 lines (101 loc) · 2.67 KB
/
write.go
File metadata and controls
120 lines (101 loc) · 2.67 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
120
package play
import "path"
// BundleWriter materialises rendered bundles without binding to a concrete host filesystem.
// EnsureDirectory should behave like mkdir -p for the provided relative path.
type BundleWriter interface {
EnsureDirectory(path string) error
WriteFile(path string, data []byte) error
}
// Write materialises a rendered bundle through the provided writer.
func (rendered RenderedBundle) Write(writer BundleWriter) error {
if writer == nil {
return WriteError{
Kind: "bundle/writer-missing",
Path: rendered.Path,
Message: "bundle writer is required",
}
}
rootPath, err := cleanWriteRoot(rendered.Path)
if err != nil {
return err
}
if rootPath != "." {
if err := writer.EnsureDirectory(rootPath); err != nil {
return WriteError{
Kind: "bundle/root-create-failed",
Path: rootPath,
Message: err.Error(),
}
}
}
createdDirectories := map[string]struct{}{}
if rootPath != "." {
createdDirectories[rootPath] = struct{}{}
}
for _, file := range rendered.Files {
if !validBundlePath(file.Path) {
return WriteError{
Kind: "bundle/file-path-invalid",
Path: file.Path,
Message: "rendered file path must be a relative bundle path",
}
}
fullPath := joinWritePath(rootPath, file.Path)
dirPath := path.Dir(fullPath)
if dirPath != "." {
if _, exists := createdDirectories[dirPath]; !exists {
if err := writer.EnsureDirectory(dirPath); err != nil {
return WriteError{
Kind: "bundle/directory-create-failed",
Path: dirPath,
Message: err.Error(),
}
}
createdDirectories[dirPath] = struct{}{}
}
}
if err := writer.WriteFile(fullPath, cloneBytes(file.Data)); err != nil {
return WriteError{
Kind: "bundle/file-write-failed",
Path: fullPath,
Message: err.Error(),
}
}
}
return nil
}
func cleanWriteRoot(rootPath string) (string, error) {
if rootPath == "" {
return "", WriteError{
Kind: "bundle/path-required",
Message: "bundle path is required",
}
}
return cleanBundlePath(rootPath)
}
func joinWritePath(rootPath string, filePath string) string {
if rootPath == "." {
return filePath
}
return path.Join(rootPath, filePath)
}
func cloneBytes(data []byte) []byte {
if len(data) == 0 {
return nil
}
cloned := make([]byte, len(data))
copy(cloned, data)
return cloned
}
// WriteError reports bundle materialisation failures.
type WriteError struct {
Kind string
Path string
Message string
}
func (writeError WriteError) Error() string {
if writeError.Path == "" {
return writeError.Kind + ": " + writeError.Message
}
return writeError.Kind + ": " + writeError.Path + ": " + writeError.Message
}