@@ -4,76 +4,94 @@ import (
4
4
"encoding/json"
5
5
"io"
6
6
"os"
7
+ "path"
7
8
8
9
"github.com/gofrs/flock"
9
10
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
10
11
"github.com/pkg/errors"
11
12
)
12
13
13
14
const (
14
- // IndexJSONLockFileSuffix is the suffix of the lock file
15
- IndexJSONLockFileSuffix = ".lock"
15
+ // indexFile is the name of the index file
16
+ indexFile = "index.json"
17
+
18
+ // lockFileSuffix is the suffix of the lock file
19
+ lockFileSuffix = ".lock"
16
20
)
17
21
18
- // PutDescToIndex puts desc to index with tag.
19
- // Existing manifests with the same tag will be removed from the index.
20
- func PutDescToIndex (index * ocispecs.Index , desc ocispecs.Descriptor , tag string ) error {
21
- if index == nil {
22
- index = & ocispecs.Index {}
22
+ type StoreIndex struct {
23
+ indexPath string
24
+ lockPath string
25
+ }
26
+
27
+ func NewStoreIndex (storePath string ) StoreIndex {
28
+ indexPath := path .Join (storePath , indexFile )
29
+ return StoreIndex {
30
+ indexPath : indexPath ,
31
+ lockPath : indexPath + lockFileSuffix ,
23
32
}
24
- if index .SchemaVersion == 0 {
25
- index .SchemaVersion = 2
33
+ }
34
+
35
+ func (s StoreIndex ) Read () (* ocispecs.Index , error ) {
36
+ lock := flock .New (s .lockPath )
37
+ locked , err := lock .TryRLock ()
38
+ if err != nil {
39
+ return nil , errors .Wrapf (err , "could not lock %s" , s .lockPath )
26
40
}
27
- if tag != "" {
28
- if desc .Annotations == nil {
29
- desc .Annotations = make (map [string ]string )
30
- }
31
- desc .Annotations [ocispecs .AnnotationRefName ] = tag
32
- // remove existing manifests with the same tag
33
- var manifests []ocispecs.Descriptor
34
- for _ , m := range index .Manifests {
35
- if m .Annotations [ocispecs .AnnotationRefName ] != tag {
36
- manifests = append (manifests , m )
37
- }
38
- }
39
- index .Manifests = manifests
41
+ if ! locked {
42
+ return nil , errors .Errorf ("could not lock %s" , s .lockPath )
40
43
}
41
- index .Manifests = append (index .Manifests , desc )
42
- return nil
44
+ defer func () {
45
+ lock .Unlock ()
46
+ os .RemoveAll (s .lockPath )
47
+ }()
48
+
49
+ b , err := os .ReadFile (s .indexPath )
50
+ if err != nil {
51
+ return nil , errors .Wrapf (err , "could not read %s" , s .indexPath )
52
+ }
53
+ var idx ocispecs.Index
54
+ if err := json .Unmarshal (b , & idx ); err != nil {
55
+ return nil , errors .Wrapf (err , "could not unmarshal %s (%q)" , s .indexPath , string (b ))
56
+ }
57
+ return & idx , nil
43
58
}
44
59
45
- func PutDescToIndexJSONFileLocked (indexJSONPath string , desc ocispecs.Descriptor , tag string ) error {
46
- lockPath := indexJSONPath + IndexJSONLockFileSuffix
47
- lock := flock .New (lockPath )
60
+ func (s StoreIndex ) Put (tag string , desc ocispecs.Descriptor ) error {
61
+ lock := flock .New (s .lockPath )
48
62
locked , err := lock .TryLock ()
49
63
if err != nil {
50
- return errors .Wrapf (err , "could not lock %s" , lockPath )
64
+ return errors .Wrapf (err , "could not lock %s" , s . lockPath )
51
65
}
52
66
if ! locked {
53
- return errors .Errorf ("could not lock %s" , lockPath )
67
+ return errors .Errorf ("could not lock %s" , s . lockPath )
54
68
}
55
69
defer func () {
56
70
lock .Unlock ()
57
- os .RemoveAll (lockPath )
71
+ os .RemoveAll (s . lockPath )
58
72
}()
59
- f , err := os .OpenFile (indexJSONPath , os .O_RDWR | os .O_CREATE , 0644 )
73
+
74
+ f , err := os .OpenFile (s .indexPath , os .O_RDWR | os .O_CREATE , 0644 )
60
75
if err != nil {
61
- return errors .Wrapf (err , "could not open %s" , indexJSONPath )
76
+ return errors .Wrapf (err , "could not open %s" , s . indexPath )
62
77
}
63
78
defer f .Close ()
79
+
64
80
var idx ocispecs.Index
65
81
b , err := io .ReadAll (f )
66
82
if err != nil {
67
- return errors .Wrapf (err , "could not read %s" , indexJSONPath )
83
+ return errors .Wrapf (err , "could not read %s" , s . indexPath )
68
84
}
69
85
if len (b ) > 0 {
70
86
if err := json .Unmarshal (b , & idx ); err != nil {
71
- return errors .Wrapf (err , "could not unmarshal %s (%q)" , indexJSONPath , string (b ))
87
+ return errors .Wrapf (err , "could not unmarshal %s (%q)" , s . indexPath , string (b ))
72
88
}
73
89
}
74
- if err = PutDescToIndex (& idx , desc , tag ); err != nil {
90
+
91
+ if err = insertDesc (& idx , desc , tag ); err != nil {
75
92
return err
76
93
}
94
+
77
95
b , err = json .Marshal (idx )
78
96
if err != nil {
79
97
return err
@@ -87,27 +105,56 @@ func PutDescToIndexJSONFileLocked(indexJSONPath string, desc ocispecs.Descriptor
87
105
return nil
88
106
}
89
107
90
- func ReadIndexJSONFileLocked (indexJSONPath string ) (* ocispecs.Index , error ) {
91
- lockPath := indexJSONPath + IndexJSONLockFileSuffix
92
- lock := flock .New (lockPath )
93
- locked , err := lock .TryRLock ()
108
+ func (s StoreIndex ) Get (tag string ) (* ocispecs.Descriptor , error ) {
109
+ idx , err := s .Read ()
94
110
if err != nil {
95
- return nil , errors . Wrapf ( err , "could not lock %s" , lockPath )
111
+ return nil , err
96
112
}
97
- if ! locked {
98
- return nil , errors .Errorf ("could not lock %s" , lockPath )
113
+
114
+ for _ , m := range idx .Manifests {
115
+ if t , ok := m .Annotations [ocispecs .AnnotationRefName ]; ok && t == tag {
116
+ return & m , nil
117
+ }
99
118
}
100
- defer func () {
101
- lock . Unlock ()
102
- os . RemoveAll ( lockPath )
103
- }()
104
- b , err := os . ReadFile ( indexJSONPath )
119
+ return nil , nil
120
+ }
121
+
122
+ func ( s StoreIndex ) GetSingle () ( * ocispecs. Descriptor , error ) {
123
+ idx , err := s . Read ( )
105
124
if err != nil {
106
- return nil , errors . Wrapf ( err , "could not read %s" , indexJSONPath )
125
+ return nil , err
107
126
}
108
- var idx ocispecs. Index
109
- if err := json . Unmarshal ( b , & idx ); err != nil {
110
- return nil , errors . Wrapf ( err , "could not unmarshal %s (%q)" , indexJSONPath , string ( b ))
127
+
128
+ if len ( idx . Manifests ) == 1 {
129
+ return & idx . Manifests [ 0 ], nil
111
130
}
112
- return & idx , nil
131
+ return nil , nil
132
+ }
133
+
134
+ // insertDesc puts desc to index with tag.
135
+ // Existing manifests with the same tag will be removed from the index.
136
+ func insertDesc (index * ocispecs.Index , desc ocispecs.Descriptor , tag string ) error {
137
+ if index == nil {
138
+ return nil
139
+ }
140
+
141
+ if index .SchemaVersion == 0 {
142
+ index .SchemaVersion = 2
143
+ }
144
+ if tag != "" {
145
+ if desc .Annotations == nil {
146
+ desc .Annotations = make (map [string ]string )
147
+ }
148
+ desc .Annotations [ocispecs .AnnotationRefName ] = tag
149
+ // remove existing manifests with the same tag
150
+ var manifests []ocispecs.Descriptor
151
+ for _ , m := range index .Manifests {
152
+ if m .Annotations [ocispecs .AnnotationRefName ] != tag {
153
+ manifests = append (manifests , m )
154
+ }
155
+ }
156
+ index .Manifests = manifests
157
+ }
158
+ index .Manifests = append (index .Manifests , desc )
159
+ return nil
113
160
}
0 commit comments