From a11cef40fdbc8f95942831066edcc6127f2cc885 Mon Sep 17 00:00:00 2001 From: Kirtana Ashok Date: Wed, 31 Jan 2024 15:47:46 -0800 Subject: [PATCH] Add grammar for platform string Platform string to be of the form [()]||[()]/[/] OSVersion is optional only and currently used only by Windows OS. Signed-off-by: Kirtana Ashok --- database.go | 24 +++++++++++++++++++++--- defaults_windows_test.go | 4 +++- platforms.go | 38 ++++++++++++++++++++------------------ platforms_test.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/database.go b/database.go index 2e26fd3..28010f3 100644 --- a/database.go +++ b/database.go @@ -17,6 +17,7 @@ package platforms import ( + "regexp" "runtime" "strings" ) @@ -59,11 +60,28 @@ func isKnownArch(arch string) bool { return false } -func normalizeOS(os string) string { - if os == "" { +// The formart of OS part of the platform specifier is [()] +// OSVersion is optional only and is currently used only by windows OS. +// If OsVersion is not specified, empty string is returned. +func normalizeOSVersion(OSAndVersion string) string { + if OSAndVersion == "" { + return "" + } + + parts := regexp.MustCompile("[()]").Split(OSAndVersion, -1) + if len(parts) > 1 { + if parts[1] != "" { + return parts[1] + } + } + return "" +} + +func normalizeOS(OSAndVersion string) string { + if OSAndVersion == "" { return runtime.GOOS } - os = strings.ToLower(os) + os := strings.Split(strings.ToLower(OSAndVersion), "(")[0] switch os { case "macos": diff --git a/defaults_windows_test.go b/defaults_windows_test.go index ab73ddd..bbef2df 100644 --- a/defaults_windows_test.go +++ b/defaults_windows_test.go @@ -66,7 +66,9 @@ func TestDefaultMatchComparer(t *testing.T) { match: false, }, } { - assert.Equal(t, test.match, defaultMatcher.Match(test.platform)) + //isMatch := defaultMatcher.Match(test.platform) + fmt.Printf("deafultmatcher %v, platform %v", defaultMatcher, test.platform) + assert.Equal(t, test.match, defaultMatcher.Match(test.platform), "expected %v, actial %v", test.match, defaultMatcher.Match(test.platform)) } } diff --git a/platforms.go b/platforms.go index 43e4ad3..6723e7c 100644 --- a/platforms.go +++ b/platforms.go @@ -121,7 +121,8 @@ import ( ) var ( - specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`) + specifierRe = regexp.MustCompile(`^[()A-Za-z0-9_.-]+$`) + OSAndVersionFormat = "%s(%s)" ) // 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) { // Parse parses the platform specifier syntax into a platform declaration. // -// Platform specifiers are in the format `||/[/]`. +// Platform specifiers are in the format `[()]||[()]/[/]`. // The minimum required information for a platform specifier is the operating -// system or architecture. If there is only a single string (no slashes), the +// system or architecture. The OSVersion can be part of the OS like windows(10.0.17763) +// Currently, the OS version is only used by windows. Therefore, if the OS is windows +// and an os version is specified, then specs.Platform.OSVersion is populated. If not it +// is left empty. +// If there is only a single string (no slashes), the // value will be matched against the known set of operating systems, then fall // back to the known set of architectures. The missing component will be // inferred based on the local environment. @@ -197,12 +202,14 @@ func Parse(specifier string) (specs.Platform, error) { var p specs.Platform switch len(parts) { case 1: - // in this case, we will test that the value might be an OS, then look - // it up. If it is not known, we'll treat it as an architecture. Since + // in this case, we will test that the value might be an OS (with or + // without the optional osversion specified) and look it up. + // If it is not known, we'll treat it as an architecture. Since // we have very little information about the platform here, we are // going to be a little more strict if we don't know about the argument // value. p.OS = normalizeOS(parts[0]) + p.OSVersion = normalizeOSVersion(parts[0]) if isKnownOS(p.OS) { // picks a default architecture p.Architecture = runtime.GOARCH @@ -210,10 +217,6 @@ func Parse(specifier string) (specs.Platform, error) { p.Variant = cpuVariant() } - if p.OS == "windows" { - p.OSVersion = GetWindowsOsVersion() - } - return p, nil } @@ -228,31 +231,25 @@ func Parse(specifier string) (specs.Platform, error) { return specs.Platform{}, fmt.Errorf("%q: unknown operating system or architecture: %w", specifier, errInvalidArgument) case 2: - // In this case, we treat as a regular os/arch pair. We don't care + // In this case, we treat as a regular os[(osversion)]/arch pair. We don't care // about whether or not we know of the platform. p.OS = normalizeOS(parts[0]) + p.OSVersion = normalizeOSVersion(parts[0]) p.Architecture, p.Variant = normalizeArch(parts[1], "") if p.Architecture == "arm" && p.Variant == "v7" { p.Variant = "" } - if p.OS == "windows" { - p.OSVersion = GetWindowsOsVersion() - } - return p, nil case 3: // we have a fully specified variant, this is rare p.OS = normalizeOS(parts[0]) + p.OSVersion = normalizeOSVersion(parts[0]) p.Architecture, p.Variant = normalizeArch(parts[1], parts[2]) if p.Architecture == "arm64" && p.Variant == "" { p.Variant = "v8" } - if p.OS == "windows" { - p.OSVersion = GetWindowsOsVersion() - } - return p, nil } @@ -275,6 +272,11 @@ func Format(platform specs.Platform) string { return "unknown" } + if strings.ToLower(platform.OS) == "windows" && platform.OSVersion != "" { + windowsOsVersion := fmt.Sprintf(OSAndVersionFormat, platform.OS, platform.OSVersion) + return path.Join(windowsOsVersion, platform.Architecture, platform.Variant) + } + return path.Join(platform.OS, platform.Architecture, platform.Variant) } diff --git a/platforms_test.go b/platforms_test.go index c2af021..501bc0d 100644 --- a/platforms_test.go +++ b/platforms_test.go @@ -290,6 +290,36 @@ func TestParseSelector(t *testing.T) { }, formatted: path.Join("darwin", defaultArch, defaultVariant), }, + { + input: "windows", + expected: specs.Platform{ + OS: "windows", + OSVersion: "", + Architecture: defaultArch, + Variant: defaultVariant, + }, + formatted: path.Join("windows", defaultArch, defaultVariant), + }, + { + input: "windows()", + expected: specs.Platform{ + OS: "windows", + OSVersion: "", + Architecture: defaultArch, + Variant: defaultVariant, + }, + formatted: path.Join("windows", defaultArch, defaultVariant), + }, + { + input: "windows(10.0.17763)", + expected: specs.Platform{ + OS: "windows", + OSVersion: "10.0.17763", + Architecture: defaultArch, + Variant: defaultVariant, + }, + formatted: path.Join("windows(10.0.17763)", defaultArch, defaultVariant), + }, } { t.Run(testcase.input, func(t *testing.T) { if testcase.skip {