@@ -33,26 +33,23 @@ import (
33
33
// path to the components yaml on the local filesystem.
34
34
// In order to support different versions, the directories containing provider
35
35
// specific data must adhere to the following layout:
36
- // {basepath}/{owner}/{ provider-name}/releases/ {version}/{path/ components.yaml}
36
+ // {basepath}/{provider-name}/{version}/{components.yaml}
37
37
//
38
38
// (1): {provider-name} must match the value returned by Provider.Name()
39
39
// (2): {version} must exactly obey the syntax and semantics of
40
40
// the "Semantic Versioning" specification (http://semver.org/).
41
41
//
42
42
// Concrete example:
43
- // /home/user/go/src/sigs.k8s.io/cluster-api-provider-aws/releases/v0.4.7/infrastructure-components.yaml
44
- // basepath: /home/user/go/src
45
- // owner : sigs.k8s.io
46
- // provider-name: cluster-api-provider-aws
43
+ // /home/user/go/src/sigs.k8s.io/aws/v0.4.7/infrastructure-components.yaml
44
+ // basepath: /home/user/go/src/sigs.k8s.io
45
+ // provider-name: aws
47
46
// version: v0.4.7
48
- // path/component.yaml: infrastructure-components.yaml
49
- //
47
+ // component.yaml: infrastructure-components.yaml
50
48
51
49
type localRepository struct {
52
50
providerConfig config.Provider
53
51
configVariablesClient config.VariablesClient
54
52
basepath string
55
- owner string
56
53
providerName string
57
54
defaultVersion string
58
55
rootPath string
@@ -89,7 +86,7 @@ func (r *localRepository) GetFile(version, fileName string) ([]byte, error) {
89
86
version = r .defaultVersion
90
87
}
91
88
92
- absolutePath := filepath .Join (r .basepath , r .owner , r . providerName , "releases" , version , r .rootPath , fileName )
89
+ absolutePath := filepath .Join (r .basepath , r .providerName , version , r .rootPath , fileName )
93
90
94
91
if f , err := os .Stat (absolutePath ); err == nil {
95
92
if f .IsDir () {
@@ -105,59 +102,64 @@ func (r *localRepository) GetFile(version, fileName string) ([]byte, error) {
105
102
106
103
}
107
104
105
+ // GetVersion returns the list of versions that are available for a local repository
106
+ func (r * localRepository ) GetVersions () ([]string , error ) {
107
+ versions , err := r .getVersions ()
108
+ if err != nil {
109
+ return nil , errors .Wrapf (err , "failed to get local repository versions" )
110
+ }
111
+ return versions , nil
112
+ }
113
+
108
114
// newLocalRepository returns a localRepository implementation
109
115
func newLocalRepository (providerConfig config.Provider , configVariablesClient config.VariablesClient ) (* localRepository , error ) {
110
116
111
117
var err error
112
118
113
- u , err := url .Parse (providerConfig .URL ())
119
+ urlSplit , err := url .Parse (providerConfig .URL ())
114
120
if err != nil {
115
121
return nil , errors .Wrap (err , "invalid url" )
116
122
}
117
- absPath := u .Path
118
- if u .RawPath != "" {
119
- absPath = u .RawPath
123
+ absPath := urlSplit .Path
124
+ if urlSplit .RawPath != "" {
125
+ absPath = urlSplit .RawPath
120
126
}
121
127
122
128
if ! filepath .IsAbs (absPath ) {
123
129
return nil , errors .Errorf ("invalid path: path %q must be an absolute path" , providerConfig .URL ())
124
130
}
125
131
126
132
parts := strings .Split (providerConfig .URL (), "/" )
127
- // find the first occurance of provider name and use it as a seperator between base and layout
128
- providerNameIndex := 0
129
- for i , p := range parts {
130
- if p == providerConfig .Name () {
131
- providerNameIndex = i
133
+ // {basepath}/{provider-name}/{version}/{components.yaml}
134
+ if len (parts ) < 3 {
135
+ return nil , errors .Errorf ("invalid path: path should be in the form {basepath}/{provider-name}/{version}/{components.yaml}" )
136
+ }
137
+ // We work our way backwards with {components.yaml} being the last part of the path
138
+ componentsPath := parts [len (parts )- 1 ]
139
+ defaultVersion := parts [len (parts )- 2 ]
140
+ if defaultVersion != "latest" {
141
+ _ , err = version .ParseSemantic (defaultVersion )
142
+ if err != nil {
143
+ return nil , errors .Errorf ("invalid version: %q. Version must obey the syntax and semantics of the \" Semantic Versioning\" specification (http://semver.org/) and path format {basepath}/{provider-name}/{version}/{components.yaml}" , defaultVersion )
132
144
}
133
145
}
134
- if providerNameIndex < 1 {
135
- return nil , errors .Errorf ("invalid path: path %q must contain provider name %q" , providerConfig .URL (), providerConfig .Name ())
146
+ providerName := parts [len (parts )- 3 ]
147
+ if providerName != providerConfig .Name () {
148
+ return nil , errors .Errorf ("invalid path: path %q must contain provider name %q in the format {basepath}/{provider-name}/{version}/{components.yaml}" , providerConfig .URL (), providerConfig .Name ())
149
+ }
150
+ var basePath string
151
+ if len (parts ) > 3 {
152
+ basePath = filepath .Join (parts [:len (parts )- 3 ]... )
136
153
}
137
-
138
- basePath := filepath .Join (parts [:providerNameIndex - 1 ]... )
139
154
basePath = filepath .Clean ("/" + basePath ) // ensure basePath starts with "/"
140
- layoutPath := filepath .Join (parts [providerNameIndex - 1 :]... )
141
- layoutParts := strings .Split (layoutPath , "/" )
142
- // Check if the layoutPath is in the expected format.
143
- if len (layoutParts ) < 5 {
144
- return nil , errors .Errorf ("invalid path: path should be in the form {basepath}/{owner}/{provider-name}/releases/{version}/{path/components.yaml}" )
145
- }
146
- owner := layoutParts [0 ]
147
- providerName := layoutParts [1 ]
148
- defaultVersion := layoutParts [3 ]
149
- path := filepath .Join (layoutParts [4 :]... )
150
- // rootpath is the relative path starting after {version} directory and excludes component fiename
151
- rootPath , componentsPath := filepath .Split (path )
152
155
153
156
repo := & localRepository {
154
157
providerConfig : providerConfig ,
155
158
configVariablesClient : configVariablesClient ,
156
159
basepath : basePath ,
157
- owner : owner ,
158
160
providerName : providerName ,
159
161
defaultVersion : defaultVersion ,
160
- rootPath : rootPath ,
162
+ rootPath : "" , // Not applicable with localRepository
161
163
componentsPath : componentsPath ,
162
164
}
163
165
@@ -174,36 +176,32 @@ func newLocalRepository(providerConfig config.Provider, configVariablesClient co
174
176
// getLatestRelease returns the latest release for the local repository.
175
177
func (r * localRepository ) getLatestRelease () (string , error ) {
176
178
177
- // get all the sub-directories under {releases} directory
178
- releasesPath := filepath .Join (r .basepath , r .owner , r . providerName , "releases" )
179
+ // get all the sub-directories under {basepath}/{provider-name}/
180
+ releasesPath := filepath .Join (r .basepath , r .providerName )
179
181
files , err := ioutil .ReadDir (releasesPath )
180
182
if err != nil {
181
183
return "" , errors .Wrap (err , "failed to list release directories" )
182
184
}
183
- var releases []string
184
- for _ , f := range files {
185
- if f .IsDir () {
186
- releases = append (releases , f .Name ())
187
- }
188
- }
189
-
190
185
// search for the latest release according to semantic version
191
186
// releases with names that are not semantic version number are ignored
192
187
var latestTag string
193
188
var latestReleaseVersion * version.Version
194
- for _ , r := range releases {
195
- sv , err := version .ParseSemantic (r )
196
- if err != nil {
197
- // discard releases with tags that are not a valid semantic versions (the user can point explicitly to such releases)
198
- continue
199
- }
200
- if sv .PreRelease () != "" || sv .BuildMetadata () != "" {
201
- // discard pre-releases or build releases (the user can point explicitly to such releases)
202
- continue
203
- }
204
- if latestReleaseVersion == nil || latestReleaseVersion .LessThan (sv ) {
205
- latestTag = r
206
- latestReleaseVersion = sv
189
+ for _ , f := range files {
190
+ if f .IsDir () {
191
+ r := f .Name ()
192
+ sv , err := version .ParseSemantic (r )
193
+ if err != nil {
194
+ // discard releases with tags that are not a valid semantic versions (the user can point explicitly to such releases)
195
+ continue
196
+ }
197
+ if sv .PreRelease () != "" || sv .BuildMetadata () != "" {
198
+ // discard pre-releases or build releases (the user can point explicitly to such releases)
199
+ continue
200
+ }
201
+ if latestReleaseVersion == nil || latestReleaseVersion .LessThan (sv ) {
202
+ latestTag = r
203
+ latestReleaseVersion = sv
204
+ }
207
205
}
208
206
}
209
207
@@ -213,3 +211,30 @@ func (r *localRepository) getLatestRelease() (string, error) {
213
211
214
212
return latestTag , nil
215
213
}
214
+
215
+ // getVersions returns all the release versions for a local repository
216
+ func (r * localRepository ) getVersions () ([]string , error ) {
217
+ // get all the sub-directories under {basepath}/{provider-name}/
218
+ releasesPath := filepath .Join (r .basepath , r .providerName )
219
+ files , err := ioutil .ReadDir (releasesPath )
220
+ if err != nil {
221
+ return nil , errors .Wrap (err , "failed to list release directories" )
222
+ }
223
+ var versions []string
224
+ for _ , f := range files {
225
+ if f .IsDir () {
226
+ r := f .Name ()
227
+ sv , err := version .ParseSemantic (r )
228
+ if err != nil {
229
+ // discard releases with tags that are not a valid semantic versions (the user can point explicitly to such releases)
230
+ continue
231
+ }
232
+ if sv .PreRelease () != "" || sv .BuildMetadata () != "" {
233
+ // discard pre-releases or build releases (the user can point explicitly to such releases)
234
+ continue
235
+ }
236
+ versions = append (versions , r )
237
+ }
238
+ }
239
+ return versions , nil
240
+ }
0 commit comments