Skip to content

Commit

Permalink
Support dots in Kind name segment
Browse files Browse the repository at this point in the history
CDI spec states that dots ('.') are allowed.
Add support in parser for this.

Signed-off-by: adrianc <[email protected]>
  • Loading branch information
adrianchiris committed Apr 25, 2023
1 parent b5ab017 commit 94b7d45
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 41 deletions.
8 changes: 2 additions & 6 deletions pkg/cdi/qualified-device.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,10 @@ import (
//
// "<vendor>/<class>=<name>".
//
// A valid vendor name may contain the following runes:
// A valid vendor and class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
//
// A valid class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_'.
//
// A valid device name may containe the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
Expand Down Expand Up @@ -98,7 +94,7 @@ func ValidateVendorName(vendor string) error {
// A class name may contain the following ASCII characters:
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
// - digits ('0'-'9')
// - underscore and dash ('_', '-')
// - underscore, dash, and dot ('_', '-', and '.')
//
// Deprecated: use parser.ValidateClassName instead
func ValidateClassName(class string) error {
Expand Down
7 changes: 7 additions & 0 deletions pkg/cdi/qualified-device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func TestQualifiedName(t *testing.T) {
name: "dev1",
isQualified: true,
},
{
device: "vendor1.com/class.subclass=dev1",
vendor: "vendor1.com",
class: "class.subclass",
name: "dev1",
isQualified: true,
},
{
device: "other-vendor1.com/class_1=dev_1",
vendor: "other-vendor1.com",
Expand Down
7 changes: 7 additions & 0 deletions pkg/cdi/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,13 @@ func TestRequiredVersion(t *testing.T) {
},
expectedVersion: "0.6.0",
},
{
description: "dotted name (class) label require v0.6.0",
spec: &cdi.Spec{
Kind: "vendor.com/class.sub",
},
expectedVersion: "0.6.0",
},
}

for _, tc := range testCases {
Expand Down
8 changes: 8 additions & 0 deletions pkg/cdi/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,14 @@ func requiresV060(spec *cdi.Spec) bool {
}
}

// The v0.6.0 spec allows dots "." in Kind name label (class)
vendor, class := parser.ParseQualifier(spec.Kind)
if vendor != "" {
if strings.ContainsRune(class, '.') {
return true
}
}

return false
}

Expand Down
65 changes: 30 additions & 35 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@ import (
//
// "<vendor>/<class>=<name>".
//
// A valid vendor name may contain the following runes:
// A valid vendor and class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
//
// A valid class name may contain the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_'.
//
// A valid device name may containe the following runes:
//
// 'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
Expand Down Expand Up @@ -122,52 +118,51 @@ func ParseQualifier(kind string) (string, string) {
// - digits ('0'-'9')
// - underscore, dash, and dot ('_', '-', and '.')
func ValidateVendorName(vendor string) error {
if vendor == "" {
return fmt.Errorf("invalid (empty) vendor name")
}
if !IsLetter(rune(vendor[0])) {
return fmt.Errorf("invalid vendor %q, should start with letter", vendor)
}
for _, c := range string(vendor[1 : len(vendor)-1]) {
switch {
case IsAlphaNumeric(c):
case c == '_' || c == '-' || c == '.':
default:
return fmt.Errorf("invalid character '%c' in vendor name %q",
c, vendor)
}
}
if !IsAlphaNumeric(rune(vendor[len(vendor)-1])) {
return fmt.Errorf("invalid vendor %q, should end with a letter or digit", vendor)
err := validateVendorOrClassName(vendor)
if err != nil {
err = fmt.Errorf("invalid vendor. %w", err)
}

return nil
return err
}

// ValidateClassName checks the validity of class name.
// A class name may contain the following ASCII characters:
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
// - digits ('0'-'9')
// - underscore and dash ('_', '-')
// - underscore, dash, and dot ('_', '-', and '.')
func ValidateClassName(class string) error {
if class == "" {
return fmt.Errorf("invalid (empty) device class")
err := validateVendorOrClassName(class)
if err != nil {
err = fmt.Errorf("invalid class. %w", err)
}
if !IsLetter(rune(class[0])) {
return fmt.Errorf("invalid class %q, should start with letter", class)
return err
}

// validateVendorOrClassName checks the validity of vendor or class name.
// A name may contain the following ASCII characters:
// - upper- and lowercase letters ('A'-'Z', 'a'-'z')
// - digits ('0'-'9')
// - underscore, dash, and dot ('_', '-', and '.')
func validateVendorOrClassName(name string) error {
if name == "" {
return fmt.Errorf("empty name")
}
for _, c := range string(class[1 : len(class)-1]) {
if !IsLetter(rune(name[0])) {
return fmt.Errorf("%q, should start with letter", name)
}
for _, c := range string(name[1 : len(name)-1]) {
switch {
case IsAlphaNumeric(c):
case c == '_' || c == '-':
case c == '_' || c == '-' || c == '.':
default:
return fmt.Errorf("invalid character '%c' in device class %q",
c, class)
return fmt.Errorf("invalid character '%c' in name %q",
c, name)
}
}
if !IsAlphaNumeric(rune(class[len(class)-1])) {
return fmt.Errorf("invalid class %q, should end with a letter or digit", class)
if !IsAlphaNumeric(rune(name[len(name)-1])) {
return fmt.Errorf("%q, should end with a letter or digit", name)
}

return nil
}

Expand Down
7 changes: 7 additions & 0 deletions pkg/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func TestQualifiedName(t *testing.T) {
name: "dev1",
isQualified: true,
},
{
device: "vendor1.com/class.subclass=dev1",
vendor: "vendor1.com",
class: "class.subclass",
name: "dev1",
isQualified: true,
},
{
device: "other-vendor1.com/class_1=dev_1",
vendor: "other-vendor1.com",
Expand Down

0 comments on commit 94b7d45

Please sign in to comment.