forked from d2iq-archive/cake-builder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.go
151 lines (123 loc) · 3.92 KB
/
utils.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
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
"strings"
"github.com/cbroglie/mustache"
)
const GeneratedDockerFileNamePrefix = "Dockerfile.generated"
func (image *Image) renderDockerfileFromTemplate(config BuildConfig) error {
directory := filepath.Dir(image.ImageConfig.Template)
templateProperties := image.ImageConfig.Properties
if len(templateProperties) == 0 {
log.Printf("No properties provided for templating")
templateProperties = make(map[string]string)
}
if image.Parent != nil {
templateProperties["parent"] = fmt.Sprintf("%s:%s", image.Parent.getFullName(), image.Parent.getStableTag(config))
}
mustache.AllowMissingVariables = false
rendered, err := mustache.RenderFile(image.ImageConfig.Template, templateProperties)
if err != nil {
return fmt.Errorf("error while rendering template: %v", err)
}
dockerfile := fmt.Sprintf("%s/%s", directory, GeneratedDockerFileNamePrefix)
if len(image.ImageConfig.TagSuffix) > 0 {
dockerfile = fmt.Sprintf("%s.%s", dockerfile, image.ImageConfig.TagSuffix)
}
err = ioutil.WriteFile(dockerfile, []byte(rendered), os.ModePerm)
if err != nil {
return fmt.Errorf("failed while writing templated file: %v", err)
}
image.Dockerfile = dockerfile
return nil
}
func (image *Image) calculateChecksum() error {
directory := filepath.Dir(image.Dockerfile)
files, err := listFiles(directory)
if err != nil {
return fmt.Errorf("error while listing files in directory: %s. %v", directory, err)
}
// Filtering out generated Dockerfiles not belonging to the current image.
// This is required for the cases when a single Dockerfile.template is used for multiple images
// with different parameters. Each image defined in cake.yaml using the same Dockerfile.template
// will generate Dockerfile.generated[<tag suffix>] used in checksum for that specific image.
filteredFiles := make([]string, 0)
for _, file := range files {
if !strings.Contains(file, GeneratedDockerFileNamePrefix) || file == image.Dockerfile {
filteredFiles = append(filteredFiles, file)
}
}
files = filteredFiles
for _, file := range image.ImageConfig.ExtraFiles {
info, err := os.Stat(file)
if os.IsNotExist(err) {
return fmt.Errorf("one of the extra paths specified for checksum doesn't exist: %s", file)
}
if info.IsDir() {
dirFiles, err := listFiles(file)
if err != nil {
return fmt.Errorf("error while listing files in directory: %s. %v", directory, err)
}
files = append(files, dirFiles...)
} else {
files = append(files, file)
}
}
sort.Strings(files)
tagSuffix := ""
if len(image.ImageConfig.TagSuffix) > 0 {
tagSuffix = fmt.Sprintf("(%s)", image.ImageConfig.TagSuffix)
}
log.Printf("Files used for content checksum for %s%s:", image.ImageConfig.Name, tagSuffix)
for _, file := range files {
log.Println(file)
}
checksums := ""
for _, file := range files {
contentChecksum, err := getContentChecksum(file)
if err != nil {
return err
} else {
checksums = checksums + contentChecksum
}
}
hash := sha256.New()
hash.Write([]byte(checksums))
checksum := hex.EncodeToString(hash.Sum(nil))
log.Printf("Resulting checksum for %s%s: %s", image.ImageConfig.Name, tagSuffix, checksum)
image.Checksum = checksum
return nil
}
func getContentChecksum(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", fmt.Errorf("error reading file: %v", err)
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return "", fmt.Errorf("failed calculating checksum: %v", err)
}
return hex.EncodeToString(hash.Sum(nil)), nil
}
func listFiles(directory string) ([]string, error) {
files := make([]string, 0)
err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
if !info.IsDir() {
files = append(files, path)
}
return nil
})
if err != nil {
return nil, err
}
return files, nil
}