-
Notifications
You must be signed in to change notification settings - Fork 240
/
tag.go
157 lines (136 loc) · 3.89 KB
/
tag.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
package tag
import (
"sort"
"sync"
"time"
"github.com/argoproj-labs/argocd-image-updater/pkg/log"
"github.com/Masterminds/semver"
)
// ImageTag is a representation of an image tag with metadata
// Use NewImageTag to to initialize a new object.
type ImageTag struct {
TagName string
TagDate *time.Time
}
// ImageTagList is a collection of ImageTag objects.
// Use NewImageTagList to to initialize a new object.
type ImageTagList struct {
items map[string]*ImageTag
lock *sync.RWMutex
}
// TagInfo contains information for a tag
type TagInfo struct {
CreatedAt time.Time
}
// SortableImageTagList is just that - a sortable list of ImageTag entries
type SortableImageTagList []*ImageTag
// Len returns the length of an SortableImageList
func (il SortableImageTagList) Len() int {
return len(il)
}
// Swap swaps two entries in the SortableImageList
func (il SortableImageTagList) Swap(i, j int) {
il[i], il[j] = il[j], il[i]
}
// NewImageTag initializes an ImageTag object and returns it
func NewImageTag(tagName string, tagDate time.Time) *ImageTag {
tag := &ImageTag{}
tag.TagName = tagName
tag.TagDate = &tagDate
return tag
}
// NewImageTagList initializes an ImageTagList object and returns it
func NewImageTagList() *ImageTagList {
itl := ImageTagList{}
itl.items = make(map[string]*ImageTag)
itl.lock = &sync.RWMutex{}
return &itl
}
// Tags returns a list of verbatim tag names as string slice
func (il *ImageTagList) Tags() []string {
il.lock.RLock()
defer il.lock.RUnlock()
tagList := []string{}
for k := range il.items {
tagList = append(tagList, k)
}
return tagList
}
// Tags returns a list of verbatim tag names as string slice
func (sil *SortableImageTagList) Tags() []string {
tagList := []string{}
for _, t := range *sil {
tagList = append(tagList, t.TagName)
}
return tagList
}
// String returns the tag name of the ImageTag
func (tag *ImageTag) String() string {
return tag.TagName
}
// Checks whether given tag is contained in tag list in O(n) time
func (il ImageTagList) Contains(tag *ImageTag) bool {
il.lock.RLock()
defer il.lock.RUnlock()
return il.unlockedContains(tag)
}
// Add adds an ImageTag to an ImageTagList, ensuring this will not result in
// an double entry
func (il ImageTagList) Add(tag *ImageTag) {
il.lock.Lock()
defer il.lock.Unlock()
il.items[tag.TagName] = tag
}
// SortByName returns an array of ImageTag objects, sorted by the tag's name
func (il ImageTagList) SortByName() SortableImageTagList {
sil := SortableImageTagList{}
for _, v := range il.items {
sil = append(sil, v)
}
sort.Slice(sil, func(i, j int) bool {
return sil[i].TagName < sil[j].TagName
})
return sil
}
// SortByDate returns a SortableImageTagList, sorted by the tag's date
func (il ImageTagList) SortByDate() SortableImageTagList {
sil := SortableImageTagList{}
for _, v := range il.items {
sil = append(sil, v)
}
sort.Slice(sil, func(i, j int) bool {
if sil[i].TagDate.Equal(*sil[j].TagDate) {
// if an image has two tags, return the same consistently
return sil[i].TagName < sil[j].TagName
}
return sil[i].TagDate.Before(*sil[j].TagDate)
})
return sil
}
func (il ImageTagList) SortBySemVer() SortableImageTagList {
// We need a read lock, because we access the items hash after sorting
il.lock.RLock()
defer il.lock.RUnlock()
sil := SortableImageTagList{}
svl := make([]*semver.Version, 0)
for _, v := range il.items {
svi, err := semver.NewVersion(v.TagName)
if err != nil {
log.Debugf("could not parse input tag %s as semver: %v", v.TagName, err)
continue
}
svl = append(svl, svi)
}
sort.Sort(semver.Collection(svl))
for _, svi := range svl {
sil = append(sil, NewImageTag(svi.Original(), *il.items[svi.Original()].TagDate))
}
return sil
}
// Should only be used in a method that holds a lock on the ImageTagList
func (il ImageTagList) unlockedContains(tag *ImageTag) bool {
if _, ok := il.items[tag.TagName]; ok {
return true
}
return false
}