type Requirements … type Selector … // Everything returns a selector that matches all labels. func Everything() Selector { … } type nothingSelector … func (n nothingSelector) Matches(_ Labels) bool { … } func (n nothingSelector) Empty() bool { … } func (n nothingSelector) String() string { … } func (n nothingSelector) Add(_ ...Requirement) Selector { … } func (n nothingSelector) Requirements() (Requirements, bool) { … } func (n nothingSelector) DeepCopySelector() Selector { … } func (n nothingSelector) RequiresExactMatch(label string) (value string, found bool) { … } // Nothing returns a selector that matches no labels func Nothing() Selector { … } // NewSelector returns a nil selector func NewSelector() Selector { … } type internalSelector … func (s internalSelector) DeepCopy() internalSelector { … } func (s internalSelector) DeepCopySelector() Selector { … } type ByKey … func (a ByKey) Len() int { … } func (a ByKey) Swap(i, j int) { … } func (a ByKey) Less(i, j int) bool { … } type Requirement … // NewRequirement is the constructor for a Requirement. // If any of these rules is violated, an error is returned: // (1) The operator can only be In, NotIn, Equals, DoubleEquals, NotEquals, Exists, or DoesNotExist. // (2) If the operator is In or NotIn, the values set must be non-empty. // (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value. // (4) If the operator is Exists or DoesNotExist, the value set must be empty. // (5) If the operator is Gt or Lt, the values set must contain only one value, which will be interpreted as an integer. // (6) The key is invalid due to its length, or sequence // of characters. See validateLabelKey for more details. // // The empty string is a valid value in the input values set. func NewRequirement(key string, op selection.Operator, vals []string) (*Requirement, error) { … } func (r *Requirement) hasValue(value string) bool { … } // Matches returns true if the Requirement matches the input Labels. // There is a match in the following cases: // (1) The operator is Exists and Labels has the Requirement's key. // (2) The operator is In, Labels has the Requirement's key and Labels' // value for that key is in Requirement's value set. // (3) The operator is NotIn, Labels has the Requirement's key and // Labels' value for that key is not in Requirement's value set. // (4) The operator is DoesNotExist or NotIn and Labels does not have the // Requirement's key. // (5) The operator is GreaterThanOperator or LessThanOperator, and Labels has // the Requirement's key and the corresponding value satisfies mathematical inequality. func (r *Requirement) Matches(ls Labels) bool { … } // Key returns requirement key func (r *Requirement) Key() string { … } // Operator returns requirement operator func (r *Requirement) Operator() selection.Operator { … } // Values returns requirement values func (r *Requirement) Values() sets.String { … } // Empty returns true if the internalSelector doesn't restrict selection space func (lsel internalSelector) Empty() bool { … } // String returns a human-readable string that represents this // Requirement. If called on an invalid Requirement, an error is // returned. See NewRequirement for creating a valid Requirement. func (r *Requirement) String() string { … } // safeSort sort input strings without modification func safeSort(in []string) []string { … } // Add adds requirements to the selector. It copies the current selector returning a new one func (lsel internalSelector) Add(reqs ...Requirement) Selector { … } // Matches for a internalSelector returns true if all // its Requirements match the input Labels. If any // Requirement does not match, false is returned. func (lsel internalSelector) Matches(l Labels) bool { … } func (lsel internalSelector) Requirements() (Requirements, bool) { … } // String returns a comma-separated string of all // the internalSelector Requirements' human-readable strings. func (lsel internalSelector) String() string { … } // RequiresExactMatch introspect whether a given selector requires a single specific field // to be set, and if so returns the value it requires. func (lsel internalSelector) RequiresExactMatch(label string) (value string, found bool) { … } type Token … const ErrorToken … const EndOfStringToken … const ClosedParToken … const CommaToken … const DoesNotExistToken … const DoubleEqualsToken … const EqualsToken … const GreaterThanToken … const IdentifierToken … const InToken … const LessThanToken … const NotEqualsToken … const NotInToken … const OpenParToken … var string2token … type ScannedItem … // isWhitespace returns true if the rune is a space, tab, or newline. func isWhitespace(ch byte) bool { … } // isSpecialSymbol detect if the character ch can be an operator func isSpecialSymbol(ch byte) bool { … } type Lexer … // read return the character currently lexed // increment the position and check the buffer overflow func (l *Lexer) read() (b byte) { … } // unread 'undoes' the last read character func (l *Lexer) unread() { … } // scanIDOrKeyword scans string to recognize literal token (for example 'in') or an identifier. func (l *Lexer) scanIDOrKeyword() (tok Token, lit string) { … } // scanSpecialSymbol scans string starting with special symbol. // special symbol identify non literal operators. "!=", "==", "=" func (l *Lexer) scanSpecialSymbol() (Token, string) { … } // skipWhiteSpaces consumes all blank characters // returning the first non blank character func (l *Lexer) skipWhiteSpaces(ch byte) byte { … } // Lex returns a pair of Token and the literal // literal is meaningfull only for IdentifierToken token func (l *Lexer) Lex() (tok Token, lit string) { … } type Parser … type ParserContext … const KeyAndOperator … const Values … // lookahead func returns the current token and string. No increment of current position func (p *Parser) lookahead(context ParserContext) (Token, string) { … } // consume returns current token and string. Increments the position func (p *Parser) consume(context ParserContext) (Token, string) { … } // scan runs through the input string and stores the ScannedItem in an array // Parser can now lookahead and consume the tokens func (p *Parser) scan() { … } // parse runs the left recursive descending algorithm // on input string. It returns a list of Requirement objects. func (p *Parser) parse() (internalSelector, error) { … } func (p *Parser) parseRequirement() (*Requirement, error) { … } // parseKeyAndInferOperator parse literals. // in case of no operator '!, in, notin, ==, =, !=' are found // the 'exists' operator is inferred func (p *Parser) parseKeyAndInferOperator() (string, selection.Operator, error) { … } // parseOperator return operator and eventually matchType // matchType can be exact func (p *Parser) parseOperator() (op selection.Operator, err error) { … } // parseValues parses the values for set based matching (x,y,z) func (p *Parser) parseValues() (sets.String, error) { … } // parseIdentifiersList parses a (possibly empty) list of // of comma separated (possibly empty) identifiers func (p *Parser) parseIdentifiersList() (sets.String, error) { … } // parseExactValue parses the only value for exact match style func (p *Parser) parseExactValue() (sets.String, error) { … } // Parse takes a string representing a selector and returns a selector // object, or an error. This parsing function differs from ParseSelector // as they parse different selectors with different syntaxes. // The input will cause an error if it does not follow this form: // // <selector-syntax> ::= <requirement> | <requirement> "," <selector-syntax> // <requirement> ::= [!] KEY [ <set-based-restriction> | <exact-match-restriction> ] // <set-based-restriction> ::= "" | <inclusion-exclusion> <value-set> // <inclusion-exclusion> ::= <inclusion> | <exclusion> // <exclusion> ::= "notin" // <inclusion> ::= "in" // <value-set> ::= "(" <values> ")" // <values> ::= VALUE | VALUE "," <values> // <exact-match-restriction> ::= ["="|"=="|"!="] VALUE // // KEY is a sequence of one or more characters following [ DNS_SUBDOMAIN "/" ] DNS_LABEL. Max length is 63 characters. // VALUE is a sequence of zero or more characters "([A-Za-z0-9_-\.])". Max length is 63 characters. // Delimiter is white space: (' ', '\t') // Example of valid syntax: // "x in (foo,,baz),y,z notin ()" // // Note: // (1) Inclusion - " in " - denotes that the KEY exists and is equal to any of the // VALUEs in its requirement // (2) Exclusion - " notin " - denotes that the KEY is not equal to any // of the VALUEs in its requirement or does not exist // (3) The empty string is a valid VALUE // (4) A requirement with just a KEY - as in "y" above - denotes that // the KEY exists and can be any VALUE. // (5) A requirement with just !KEY requires that the KEY not exist. // func Parse(selector string) (Selector, error) { … } // parse parses the string representation of the selector and returns the internalSelector struct. // The callers of this method can then decide how to return the internalSelector struct to their // callers. This function has two callers now, one returns a Selector interface and the other // returns a list of requirements. func parse(selector string) (internalSelector, error) { … } func validateLabelKey(k string) error { … } func validateLabelValue(k, v string) error { … } // SelectorFromSet returns a Selector which will match exactly the given Set. A // nil and empty Sets are considered equivalent to Everything(). // It does not perform any validation, which means the server will reject // the request if the Set contains invalid values. func SelectorFromSet(ls Set) Selector { … } // ValidatedSelectorFromSet returns a Selector which will match exactly the given Set. A // nil and empty Sets are considered equivalent to Everything(). // The Set is validated client-side, which allows to catch errors early. func ValidatedSelectorFromSet(ls Set) (Selector, error) { … } // SelectorFromValidatedSet returns a Selector which will match exactly the given Set. // A nil and empty Sets are considered equivalent to Everything(). // It assumes that Set is already validated and doesn't do any validation. func SelectorFromValidatedSet(ls Set) Selector { … } // ParseToRequirements takes a string representing a selector and returns a list of // requirements. This function is suitable for those callers that perform additional // processing on selector requirements. // See the documentation for Parse() function for more details. // TODO: Consider exporting the internalSelector type instead. func ParseToRequirements(selector string) ([]Requirement, error) { … }