Skip to content

Commit a11cef4

Browse files
committed
Add grammar for platform string
Platform string to be of the form <os>[(<osversion>)]|<arch>|<os>[(<OSVersion>)]/<arch>[/<variant>] OSVersion is optional only and currently used only by Windows OS. Signed-off-by: Kirtana Ashok <kiashok@microsoft.com>
1 parent db76a43 commit a11cef4

4 files changed

Lines changed: 74 additions & 22 deletions

File tree

database.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package platforms
1818

1919
import (
20+
"regexp"
2021
"runtime"
2122
"strings"
2223
)
@@ -59,11 +60,28 @@ func isKnownArch(arch string) bool {
5960
return false
6061
}
6162

62-
func normalizeOS(os string) string {
63-
if os == "" {
63+
// The formart of OS part of the platform specifier is <OS>[(<OSVersion>)]
64+
// OSVersion is optional only and is currently used only by windows OS.
65+
// If OsVersion is not specified, empty string is returned.
66+
func normalizeOSVersion(OSAndVersion string) string {
67+
if OSAndVersion == "" {
68+
return ""
69+
}
70+
71+
parts := regexp.MustCompile("[()]").Split(OSAndVersion, -1)
72+
if len(parts) > 1 {
73+
if parts[1] != "" {
74+
return parts[1]
75+
}
76+
}
77+
return ""
78+
}
79+
80+
func normalizeOS(OSAndVersion string) string {
81+
if OSAndVersion == "" {
6482
return runtime.GOOS
6583
}
66-
os = strings.ToLower(os)
84+
os := strings.Split(strings.ToLower(OSAndVersion), "(")[0]
6785

6886
switch os {
6987
case "macos":

defaults_windows_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ func TestDefaultMatchComparer(t *testing.T) {
6666
match: false,
6767
},
6868
} {
69-
assert.Equal(t, test.match, defaultMatcher.Match(test.platform))
69+
//isMatch := defaultMatcher.Match(test.platform)
70+
fmt.Printf("deafultmatcher %v, platform %v", defaultMatcher, test.platform)
71+
assert.Equal(t, test.match, defaultMatcher.Match(test.platform), "expected %v, actial %v", test.match, defaultMatcher.Match(test.platform))
7072
}
7173

7274
}

platforms.go

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ import (
121121
)
122122

123123
var (
124-
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
124+
specifierRe = regexp.MustCompile(`^[()A-Za-z0-9_.-]+$`)
125+
OSAndVersionFormat = "%s(%s)"
125126
)
126127

127128
// Platform is a type alias for convenience, so there is no need to import image-spec package everywhere.
@@ -174,9 +175,13 @@ func ParseAll(specifiers []string) ([]specs.Platform, error) {
174175

175176
// Parse parses the platform specifier syntax into a platform declaration.
176177
//
177-
// Platform specifiers are in the format `<os>|<arch>|<os>/<arch>[/<variant>]`.
178+
// Platform specifiers are in the format `<os>[(<OSVersion>)]|<arch>|<os>[(<OSVersion>)]/<arch>[/<variant>]`.
178179
// The minimum required information for a platform specifier is the operating
179-
// system or architecture. If there is only a single string (no slashes), the
180+
// system or architecture. The OSVersion can be part of the OS like windows(10.0.17763)
181+
// Currently, the OS version is only used by windows. Therefore, if the OS is windows
182+
// and an os version is specified, then specs.Platform.OSVersion is populated. If not it
183+
// is left empty.
184+
// If there is only a single string (no slashes), the
180185
// value will be matched against the known set of operating systems, then fall
181186
// back to the known set of architectures. The missing component will be
182187
// inferred based on the local environment.
@@ -197,23 +202,21 @@ func Parse(specifier string) (specs.Platform, error) {
197202
var p specs.Platform
198203
switch len(parts) {
199204
case 1:
200-
// in this case, we will test that the value might be an OS, then look
201-
// it up. If it is not known, we'll treat it as an architecture. Since
205+
// in this case, we will test that the value might be an OS (with or
206+
// without the optional osversion specified) and look it up.
207+
// If it is not known, we'll treat it as an architecture. Since
202208
// we have very little information about the platform here, we are
203209
// going to be a little more strict if we don't know about the argument
204210
// value.
205211
p.OS = normalizeOS(parts[0])
212+
p.OSVersion = normalizeOSVersion(parts[0])
206213
if isKnownOS(p.OS) {
207214
// picks a default architecture
208215
p.Architecture = runtime.GOARCH
209216
if p.Architecture == "arm" && cpuVariant() != "v7" {
210217
p.Variant = cpuVariant()
211218
}
212219

213-
if p.OS == "windows" {
214-
p.OSVersion = GetWindowsOsVersion()
215-
}
216-
217220
return p, nil
218221
}
219222

@@ -228,31 +231,25 @@ func Parse(specifier string) (specs.Platform, error) {
228231

229232
return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument)
230233
case 2:
231-
// In this case, we treat as a regular os/arch pair. We don't care
234+
// In this case, we treat as a regular os[(osversion)]/arch pair. We don't care
232235
// about whether or not we know of the platform.
233236
p.OS = normalizeOS(parts[0])
237+
p.OSVersion = normalizeOSVersion(parts[0])
234238
p.Architecture, p.Variant = normalizeArch(parts[1], "")
235239
if p.Architecture == "arm" && p.Variant == "v7" {
236240
p.Variant = ""
237241
}
238242

239-
if p.OS == "windows" {
240-
p.OSVersion = GetWindowsOsVersion()
241-
}
242-
243243
return p, nil
244244
case 3:
245245
// we have a fully specified variant, this is rare
246246
p.OS = normalizeOS(parts[0])
247+
p.OSVersion = normalizeOSVersion(parts[0])
247248
p.Architecture, p.Variant = normalizeArch(parts[1], parts[2])
248249
if p.Architecture == "arm64" && p.Variant == "" {
249250
p.Variant = "v8"
250251
}
251252

252-
if p.OS == "windows" {
253-
p.OSVersion = GetWindowsOsVersion()
254-
}
255-
256253
return p, nil
257254
}
258255

@@ -275,6 +272,11 @@ func Format(platform specs.Platform) string {
275272
return "unknown"
276273
}
277274

275+
if strings.ToLower(platform.OS) == "windows" && platform.OSVersion != "" {
276+
windowsOsVersion := fmt.Sprintf(OSAndVersionFormat, platform.OS, platform.OSVersion)
277+
return path.Join(windowsOsVersion, platform.Architecture, platform.Variant)
278+
}
279+
278280
return path.Join(platform.OS, platform.Architecture, platform.Variant)
279281
}
280282

platforms_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,36 @@ func TestParseSelector(t *testing.T) {
290290
},
291291
formatted: path.Join("darwin", defaultArch, defaultVariant),
292292
},
293+
{
294+
input: "windows",
295+
expected: specs.Platform{
296+
OS: "windows",
297+
OSVersion: "",
298+
Architecture: defaultArch,
299+
Variant: defaultVariant,
300+
},
301+
formatted: path.Join("windows", defaultArch, defaultVariant),
302+
},
303+
{
304+
input: "windows()",
305+
expected: specs.Platform{
306+
OS: "windows",
307+
OSVersion: "",
308+
Architecture: defaultArch,
309+
Variant: defaultVariant,
310+
},
311+
formatted: path.Join("windows", defaultArch, defaultVariant),
312+
},
313+
{
314+
input: "windows(10.0.17763)",
315+
expected: specs.Platform{
316+
OS: "windows",
317+
OSVersion: "10.0.17763",
318+
Architecture: defaultArch,
319+
Variant: defaultVariant,
320+
},
321+
formatted: path.Join("windows(10.0.17763)", defaultArch, defaultVariant),
322+
},
293323
} {
294324
t.Run(testcase.input, func(t *testing.T) {
295325
if testcase.skip {

0 commit comments

Comments
 (0)