This repository has been archived by the owner on Feb 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
shpc.go
235 lines (207 loc) · 6.08 KB
/
shpc.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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
package parsers
import (
"strings"
"github.com/DataDrake/cuppa/results"
"github.com/DataDrake/cuppa/version"
lookout "github.com/alecbcs/lookout/update"
"gopkg.in/yaml.v2"
)
type SHPC struct {
}
func init() {
registerParser(SHPC{}, "container.yaml")
}
// Decode decodes a Container YAML Spec using a yaml parser.
func (s SHPC) Decode(content string) (pkg Package, err error) {
// Parse YAML file
internal := &ContainerSpec{}
err = yaml.Unmarshal([]byte(content), &internal)
if err != nil {
return internal, err
}
// Attempt to decode aliases by map
aMap := AliasMap{}
err = yaml.Unmarshal([]byte(content), &aMap)
if err != nil {
aStruct := AliasStruct{}
err = yaml.Unmarshal([]byte(content), &aStruct)
if err != nil {
return internal, err
}
internal.AliasesStruct = aStruct.Aliases
} else {
internal.Aliases = aMap.Aliases
}
// Generate name from URI
if internal.Docker != "" {
internal.Name = internal.Docker
}
if internal.Gh != "" {
internal.Name = internal.Gh
}
return internal, err
}
// Encode encodes an updated container.yml using a yaml parser.
func (s SHPC) Encode(pkg Package) (result string, err error) {
internal := pkg.(*ContainerSpec)
internal.Name = ""
output, err := yaml.Marshal(internal)
if err != nil {
return result, err
}
result = result + string(output)
// encode aliases
aliasesMap, err := yaml.Marshal(&AliasMap{internal.Aliases})
if err != nil {
return result, err
}
if string(aliasesMap) != "" && string(aliasesMap) != "{}\n" {
result = result + string(aliasesMap)
}
aliasesStruct, err := yaml.Marshal(&AliasStruct{internal.AliasesStruct})
if string(aliasesStruct) != "" && string(aliasesStruct) != "{}\n" {
result = result + string(aliasesStruct)
}
return result, err
}
// ContainerSpec is a wrapper struct for a container.yaml
type ContainerSpec struct {
Name string `yaml:"name,omitempty"`
Docker string `yaml:"docker,omitempty"`
Gh string `yaml:"gh,omitempty"`
Url string `yaml:"url,omitempty"`
Maintainer string `yaml:"maintainer"`
Description string `yaml:"description"`
Latest map[string]string `yaml:"latest"`
Versions map[string]string `yaml:"tags"`
Filter []string `yaml:"filter,omitempty"`
Aliases map[string]string `yaml:"-"`
AliasesStruct []Alias `yaml:"-"`
Features map[string]bool `yaml:"features,omitempty"`
}
type AliasMap struct {
Aliases map[string]string `yaml:"aliases,omitempty"`
}
type AliasStruct struct {
Aliases []Alias `yaml:"aliases,omitempty"`
}
type Alias struct {
Name string `yaml:"name,omitempty"`
Command string `yaml:"command,omitempty"`
Options string `yaml:"options,omitempty"`
SingularityOpts string `yaml:"singularity_options,omitempty"`
DockerOpts string `yaml:"docker_options,omitempty"`
}
// AddVersion adds a tagged version to a container.
func (s *ContainerSpec) AddVersion(input results.Result) (err error) {
// Add version to versions.
s.Versions[input.Version.String()] = input.Name
s.Latest = map[string]string{}
// Presume that added version is latest and make latest.
s.Latest[input.Version.String()] = input.Name
return nil
}
// GetLatestVersion returns the latest known tag of the container.
func (s *ContainerSpec) GetLatestVersion() (result results.Result) {
for k := range s.Latest {
return results.Result{
Version: version.Version{k},
Location: s.Url,
}
}
return
}
func (s *ContainerSpec) GetAllVersions() (result []results.Result) {
for v := range s.Versions {
result = append(result, results.Result{
Version: version.Version{v},
Location: s.Url,
})
}
return result
}
// GetURL returns the location of a container for Lookout
func (s *ContainerSpec) GetURL() (result string) {
if s.Docker != "" {
result = "docker://" + s.Docker
if len(s.Filter) > 0 {
result = result + ":" + s.Filter[0]
}
} else {
result = "https://github.com/" + s.Gh
}
return result
}
// GetGitURL just returns the normal url for a container
func (s *ContainerSpec) GetGitURL() (result string) {
return s.GetURL()
}
// GetName is a wrapper which returns the name of a container
func (s *ContainerSpec) GetName() string {
return s.Name
}
// GetDependencies for containers doesn't do anything.
func (s *ContainerSpec) GetDependencies() []string {
return []string{}
}
// GetDescription returns the package's description.
func (s *ContainerSpec) GetDescription() string {
return s.Description
}
// CheckUpdate checks for an update to the container
func (s *ContainerSpec) CheckUpdate() (outOfDate bool, output results.Result) {
outOfDate = false
url := s.GetURL()
docker := strings.HasPrefix(url, "docker://")
// Check for new latest version
out, found := lookout.CheckUpdate(url)
if found {
result := *out
latestKey := s.GetLatestVersion().Version.String()
latest := version.Version{latestKey + "@" + s.Latest[latestKey]}
var new version.Version
if docker {
new = version.Version{result.Version.String() + "@" + result.Name}
} else {
new = version.Version{latestKey + "@" + result.Version.String()}
// A gh release expects the "tag" as the recipe extension
result.Name = result.Version.String()
// And the digest as the release version
result.Version = version.NewVersion(latestKey)
}
if latest.String() != new.String() {
outOfDate = true
s.AddVersion(result)
output = result
}
}
if docker {
// Iteratively check previous labels for digest updates
var baseUrl string
if len(s.Filter) > 0 {
baseUrl = strings.TrimSuffix(url, ":"+s.Filter[0])
} else {
baseUrl = url
}
for tag, digest := range s.Versions {
out, found := lookout.CheckUpdate(baseUrl + ":" + tag)
if found {
result := *out
if digest != result.Name {
outOfDate = true
s.Versions[tag] = result.Name
if output.Location == "" {
output = result
}
if s.Latest[tag] != "" {
s.Latest[tag] = result.Name
}
}
}
}
}
return outOfDate, output
}
func (s *ContainerSpec) UpdatePackage(input results.Result) (err error) {
return nil
}