Skip to content

Commit 5ab0344

Browse files
authored
Merge pull request #2 from infosiftr/manifest-list-tags
Add initial support for an explicit "ManifestListTags" field
2 parents 08ef5a9 + ff63f9d commit 5ab0344

File tree

2 files changed

+122
-2
lines changed

2 files changed

+122
-2
lines changed

manifest/example.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Maintainers: InfoSiftr <[email protected]> (@infosiftr),
2020
Johan Euphrosine <[email protected]> (@proppy)
2121
GitRepo: https://github.com/docker-library/golang.git
2222
GitFetch: refs/heads/master
23+
SharedTags: latest
2324
2425
2526
# hi
@@ -29,18 +30,20 @@ GitFetch: refs/heads/master
2930
3031
3132
# Go 1.6
32-
Tags: 1.6.1, 1.6, 1, latest
33+
Tags: 1.6.1, 1.6, 1
3334
GitCommit: 0ce80411b9f41e9c3a21fc0a1bffba6ae761825a
3435
Directory: 1.6
3536
3637
3738
# Go 1.5
3839
Tags: 1.5.3
40+
SharedTags: 1.5.3-debian, 1.5-debian
3941
GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
4042
Directory: 1.5
4143
4244
4345
Tags: 1.5
46+
SharedTags: 1.5-debian
4447
GitCommit: d7e2a8d90a9b8f5dfd5bcd428e0c33b68c40cc19
4548
Directory: 1.5
4649
@@ -51,6 +54,15 @@ Directory: 1.5
5154
}
5255
fmt.Printf("-------------\n2822:\n%s\n", man)
5356

57+
fmt.Printf("\nShared Tag Groups:\n")
58+
for _, group := range man.GetSharedTagGroups() {
59+
fmt.Printf("\n - %s\n", strings.Join(group.SharedTags, ", "))
60+
for _, entry := range group.Entries {
61+
fmt.Printf(" - %s\n", entry.TagsString())
62+
}
63+
}
64+
fmt.Printf("\n")
65+
5466
man, err = manifest.Parse(bufio.NewReader(strings.NewReader(`
5567
# first set
5668
a: b@c d

manifest/rfc2822.go

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ type Manifest2822Entry struct {
2727

2828
Maintainers []string `delim:"," strip:"\n\r\t "`
2929

30-
Tags []string `delim:"," strip:"\n\r\t "`
30+
Tags []string `delim:"," strip:"\n\r\t "`
31+
SharedTags []string `delim:"," strip:"\n\r\t "`
3132

3233
GitRepo string
3334
GitFetch string
@@ -46,6 +47,7 @@ func (entry Manifest2822Entry) Clone() Manifest2822Entry {
4647
// SLICES! grr
4748
entry.Maintainers = append([]string{}, entry.Maintainers...)
4849
entry.Tags = append([]string{}, entry.Tags...)
50+
entry.SharedTags = append([]string{}, entry.SharedTags...)
4951
entry.Constraints = append([]string{}, entry.Constraints...)
5052
return entry
5153
}
@@ -60,6 +62,10 @@ func (entry Manifest2822Entry) TagsString() string {
6062
return strings.Join(entry.Tags, StringSeparator2822)
6163
}
6264

65+
func (entry Manifest2822Entry) SharedTagsString() string {
66+
return strings.Join(entry.SharedTags, StringSeparator2822)
67+
}
68+
6369
func (entry Manifest2822Entry) ConstraintsString() string {
6470
return strings.Join(entry.Constraints, StringSeparator2822)
6571
}
@@ -77,6 +83,9 @@ func (entry Manifest2822Entry) ClearDefaults(defaults Manifest2822Entry) Manifes
7783
if entry.TagsString() == defaults.TagsString() {
7884
entry.Tags = nil
7985
}
86+
if entry.SharedTagsString() == defaults.SharedTagsString() {
87+
entry.SharedTags = nil
88+
}
8089
if entry.GitRepo == defaults.GitRepo {
8190
entry.GitRepo = ""
8291
}
@@ -103,6 +112,9 @@ func (entry Manifest2822Entry) String() string {
103112
if str := entry.TagsString(); str != "" {
104113
ret = append(ret, "Tags: "+str)
105114
}
115+
if str := entry.SharedTagsString(); str != "" {
116+
ret = append(ret, "SharedTags: "+str)
117+
}
106118
if str := entry.GitRepo; str != "" {
107119
ret = append(ret, "GitRepo: "+str)
108120
}
@@ -145,6 +157,16 @@ func (entry Manifest2822Entry) HasTag(tag string) bool {
145157
return false
146158
}
147159

160+
// HasSharedTag returns true if the given tag exists in entry.SharedTags.
161+
func (entry Manifest2822Entry) HasSharedTag(tag string) bool {
162+
for _, existingTag := range entry.SharedTags {
163+
if tag == existingTag {
164+
return true
165+
}
166+
}
167+
return false
168+
}
169+
148170
func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
149171
for _, entry := range manifest.Entries {
150172
if entry.HasTag(tag) {
@@ -154,6 +176,62 @@ func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
154176
return nil
155177
}
156178

179+
// GetSharedTag returns a list of entries with the given tag in entry.SharedTags (or the empty list if there are no entries with the given tag).
180+
func (manifest Manifest2822) GetSharedTag(tag string) []Manifest2822Entry {
181+
ret := []Manifest2822Entry{}
182+
for _, entry := range manifest.Entries {
183+
if entry.HasSharedTag(tag) {
184+
ret = append(ret, entry)
185+
}
186+
}
187+
return ret
188+
}
189+
190+
// GetAllSharedTags returns a list of the sum of all SharedTags in all entries of this image manifest (in the order they appear in the file).
191+
func (manifest Manifest2822) GetAllSharedTags() []string {
192+
fakeEntry := Manifest2822Entry{}
193+
for _, entry := range manifest.Entries {
194+
fakeEntry.SharedTags = append(fakeEntry.SharedTags, entry.SharedTags...)
195+
}
196+
fakeEntry.DeduplicateSharedTags()
197+
return fakeEntry.SharedTags
198+
}
199+
200+
type SharedTagGroup struct {
201+
SharedTags []string
202+
Entries []*Manifest2822Entry
203+
}
204+
205+
// GetSharedTagGroups returns a map of shared tag groups to the list of entries they share (as described in https://github.com/docker-library/go-dockerlibrary/pull/2#issuecomment-277853597).
206+
func (manifest Manifest2822) GetSharedTagGroups() []SharedTagGroup {
207+
inter := map[string][]string{}
208+
interOrder := []string{} // order matters, and maps randomize order
209+
interKeySep := ","
210+
for _, sharedTag := range manifest.GetAllSharedTags() {
211+
interKeyParts := []string{}
212+
for _, entry := range manifest.GetSharedTag(sharedTag) {
213+
interKeyParts = append(interKeyParts, entry.Tags[0])
214+
}
215+
interKey := strings.Join(interKeyParts, interKeySep)
216+
if _, ok := inter[interKey]; !ok {
217+
interOrder = append(interOrder, interKey)
218+
}
219+
inter[interKey] = append(inter[interKey], sharedTag)
220+
}
221+
ret := []SharedTagGroup{}
222+
for _, tags := range interOrder {
223+
group := SharedTagGroup{
224+
SharedTags: inter[tags],
225+
Entries: []*Manifest2822Entry{},
226+
}
227+
for _, tag := range strings.Split(tags, interKeySep) {
228+
group.Entries = append(group.Entries, manifest.GetTag(tag))
229+
}
230+
ret = append(ret, group)
231+
}
232+
return ret
233+
}
234+
157235
func (manifest *Manifest2822) AddEntry(entry Manifest2822Entry) error {
158236
if len(entry.Tags) < 1 {
159237
return fmt.Errorf("missing Tags")
@@ -165,20 +243,36 @@ func (manifest *Manifest2822) AddEntry(entry Manifest2822Entry) error {
165243
return fmt.Errorf("Tags %q has invalid Maintainers: %q (expected format %q)", strings.Join(invalidMaintainers, ", "), MaintainersFormat)
166244
}
167245

246+
entry.DeduplicateSharedTags()
247+
168248
seenTag := map[string]bool{}
169249
for _, tag := range entry.Tags {
170250
if otherEntry := manifest.GetTag(tag); otherEntry != nil {
171251
return fmt.Errorf("Tags %q includes duplicate tag: %q (duplicated in %q)", entry.TagsString(), tag, otherEntry.TagsString())
172252
}
253+
if otherEntries := manifest.GetSharedTag(tag); len(otherEntries) > 0 {
254+
return fmt.Errorf("Tags %q includes tag conflicting with a shared tag: %q (shared tag in %q)", entry.TagsString(), tag, otherEntries[0].TagsString())
255+
}
173256
if seenTag[tag] {
174257
return fmt.Errorf("Tags %q includes duplicate tag: %q", entry.TagsString(), tag)
175258
}
176259
seenTag[tag] = true
177260
}
261+
for _, tag := range entry.SharedTags {
262+
if otherEntry := manifest.GetTag(tag); otherEntry != nil {
263+
return fmt.Errorf("Tags %q includes conflicting shared tag: %q (duplicated in %q)", entry.TagsString(), tag, otherEntry.TagsString())
264+
}
265+
if seenTag[tag] {
266+
return fmt.Errorf("Tags %q includes duplicate tag: %q (in SharedTags)", entry.TagsString(), tag)
267+
}
268+
seenTag[tag] = true
269+
}
178270

179271
for i, existingEntry := range manifest.Entries {
180272
if existingEntry.SameBuildArtifacts(entry) {
181273
manifest.Entries[i].Tags = append(existingEntry.Tags, entry.Tags...)
274+
manifest.Entries[i].SharedTags = append(existingEntry.SharedTags, entry.SharedTags...)
275+
manifest.Entries[i].DeduplicateSharedTags()
182276
return nil
183277
}
184278
}
@@ -210,6 +304,20 @@ func (entry Manifest2822Entry) InvalidMaintainers() []string {
210304
return invalid
211305
}
212306

307+
// DeduplicateSharedTags will remove duplicate values from entry.SharedTags, preserving order.
308+
func (entry *Manifest2822Entry) DeduplicateSharedTags() {
309+
aggregate := []string{}
310+
seen := map[string]bool{}
311+
for _, tag := range entry.SharedTags {
312+
if seen[tag] {
313+
continue
314+
}
315+
seen[tag] = true
316+
aggregate = append(aggregate, tag)
317+
}
318+
entry.SharedTags = aggregate
319+
}
320+
213321
type decoderWrapper struct {
214322
*control.Decoder
215323
}

0 commit comments

Comments
 (0)