Skip to content
This repository has been archived by the owner on Aug 22, 2020. It is now read-only.

Commit

Permalink
Add initial support for an explicit "SharedTags" field
Browse files Browse the repository at this point in the history
Things we know we'll need to be able to do with the new `SharedTags` (and are thus included in this initial file format support):

- get list of all shared tags from a manifest (`manifest.GetAllSharedTags()`)
- get list of shared tags from an entry (`entry.SharedTags`)
- get list of entries given a shared tag (`manifest.GetSharedTag(tag)`)
  • Loading branch information
tianon committed Feb 6, 2017
1 parent 08ef5a9 commit 530519c
Showing 1 changed file with 75 additions and 2 deletions.
77 changes: 75 additions & 2 deletions manifest/rfc2822.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ type Manifest2822Entry struct {

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

Tags []string `delim:"," strip:"\n\r\t "`
Tags []string `delim:"," strip:"\n\r\t "`
SharedTags []string `delim:"," strip:"\n\r\t "`

GitRepo string
GitFetch string
Expand All @@ -46,6 +47,7 @@ func (entry Manifest2822Entry) Clone() Manifest2822Entry {
// SLICES! grr
entry.Maintainers = append([]string{}, entry.Maintainers...)
entry.Tags = append([]string{}, entry.Tags...)
entry.SharedTags = append([]string{}, entry.SharedTags...)
entry.Constraints = append([]string{}, entry.Constraints...)
return entry
}
Expand All @@ -60,6 +62,10 @@ func (entry Manifest2822Entry) TagsString() string {
return strings.Join(entry.Tags, StringSeparator2822)
}

func (entry Manifest2822Entry) SharedTagsString() string {
return strings.Join(entry.SharedTags, StringSeparator2822)
}

func (entry Manifest2822Entry) ConstraintsString() string {
return strings.Join(entry.Constraints, StringSeparator2822)
}
Expand All @@ -77,6 +83,9 @@ func (entry Manifest2822Entry) ClearDefaults(defaults Manifest2822Entry) Manifes
if entry.TagsString() == defaults.TagsString() {
entry.Tags = nil
}
if entry.SharedTagsString() == defaults.SharedTagsString() {
entry.SharedTags = nil
}
if entry.GitRepo == defaults.GitRepo {
entry.GitRepo = ""
}
Expand All @@ -103,6 +112,9 @@ func (entry Manifest2822Entry) String() string {
if str := entry.TagsString(); str != "" {
ret = append(ret, "Tags: "+str)
}
if str := entry.SharedTagsString(); str != "" {
ret = append(ret, "SharedTags: "+str)
}
if str := entry.GitRepo; str != "" {
ret = append(ret, "GitRepo: "+str)
}
Expand Down Expand Up @@ -145,6 +157,16 @@ func (entry Manifest2822Entry) HasTag(tag string) bool {
return false
}

// HasSharedTag returns true if the given tag exists in entry.SharedTags.
func (entry Manifest2822Entry) HasSharedTag(tag string) bool {
for _, existingTag := range entry.SharedTags {
if tag == existingTag {
return true
}
}
return false
}

func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
for _, entry := range manifest.Entries {
if entry.HasTag(tag) {
Expand All @@ -154,6 +176,27 @@ func (manifest Manifest2822) GetTag(tag string) *Manifest2822Entry {
return nil
}

// 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).
func (manifest Manifest2822) GetSharedTag(tag string) []Manifest2822Entry {
ret := []Manifest2822Entry{}
for _, entry := range manifest.Entries {
if entry.HasSharedTag(tag) {
ret = append(ret, entry)
}
}
return ret
}

// 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).
func (manifest Manifest2822) GetAllSharedTags() []string {
fakeEntry := Manifest2822Entry{}
for _, entry := range manifest.Entries {
fakeEntry.SharedTags = append(fakeEntry.SharedTags, entry.SharedTags...)
}
fakeEntry.DeduplicateSharedTags()
return fakeEntry.SharedTags
}

func (manifest *Manifest2822) AddEntry(entry Manifest2822Entry) error {
if len(entry.Tags) < 1 {
return fmt.Errorf("missing Tags")
Expand All @@ -165,20 +208,36 @@ func (manifest *Manifest2822) AddEntry(entry Manifest2822Entry) error {
return fmt.Errorf("Tags %q has invalid Maintainers: %q (expected format %q)", strings.Join(invalidMaintainers, ", "), MaintainersFormat)
}

entry.DeduplicateSharedTags()

seenTag := map[string]bool{}
for _, tag := range entry.Tags {
if otherEntry := manifest.GetTag(tag); otherEntry != nil {
return fmt.Errorf("Tags %q includes duplicate tag: %q (duplicated in %q)", entry.TagsString(), tag, otherEntry.TagsString())
}
if otherEntries := manifest.GetSharedTag(tag); len(otherEntries) > 0 {
return fmt.Errorf("Tags %q includes tag conflicting with a shared tag: %q (shared tag in %q)", entry.TagsString(), tag, otherEntries[0].TagsString())
}
if seenTag[tag] {
return fmt.Errorf("Tags %q includes duplicate tag: %q", entry.TagsString(), tag)
}
seenTag[tag] = true
}
for _, tag := range entry.SharedTags {
if otherEntry := manifest.GetTag(tag); otherEntry != nil {
return fmt.Errorf("Tags %q includes conflicting shared tag: %q (duplicated in %q)", entry.TagsString(), tag, otherEntry.TagsString())
}
if seenTag[tag] {
return fmt.Errorf("Tags %q includes duplicate tag: %q (in SharedTags)", entry.TagsString(), tag)
}
seenTag[tag] = true
}

for i, existingEntry := range manifest.Entries {
if existingEntry.SameBuildArtifacts(entry) {
manifest.Entries[i].Tags = append(existingEntry.Tags, entry.Tags...)
manifest.Entries[i].SharedTags = append(existingEntry.SharedTags, entry.SharedTags...)
manifest.Entries[i].DeduplicateSharedTags()
return nil
}
}
Expand Down Expand Up @@ -210,6 +269,20 @@ func (entry Manifest2822Entry) InvalidMaintainers() []string {
return invalid
}

// DeduplicateSharedTags will remove duplicate values from entry.SharedTags, preserving order.
func (entry *Manifest2822Entry) DeduplicateSharedTags() {
aggregate := []string{}
seen := map[string]bool{}
for _, tag := range entry.SharedTags {
if seen[tag] {
continue
}
seen[tag] = true
aggregate = append(aggregate, tag)
}
entry.SharedTags = aggregate
}

type decoderWrapper struct {
*control.Decoder
}
Expand Down Expand Up @@ -249,7 +322,7 @@ func Parse2822(readerIn io.Reader) (*Manifest2822, error) {
if invalidMaintainers := manifest.Global.InvalidMaintainers(); len(invalidMaintainers) > 0 {
return nil, fmt.Errorf("invalid Maintainers: %q (expected format %q)", strings.Join(invalidMaintainers, ", "), MaintainersFormat)
}
if len(manifest.Global.Tags) > 0 {
if len(manifest.Global.Tags) > 0 || len(manifest.Global.SharedTags) > 0 {
return nil, fmt.Errorf("global Tags not permitted")
}

Expand Down

0 comments on commit 530519c

Please sign in to comment.