Exemplo n.º 1
0
        /// <summary>
        /// Returns the set of items that satisfy a label selector.
        /// </summary>
        /// <param name="labelSelector">The label selector condistions(s).</param>
        /// <returns>The set of items whose meet the query requirements.</returns>
        /// <exception cref="FormatException">Thrown when the label selector is not valid.</exception>
        /// <remarks>
        /// <para>
        /// This class supports Kubernetes style label selectors:
        /// </para>
        /// <para>
        /// <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/">Kubernetes: Labels and Selectors</a>
        /// </para>
        /// <para>
        /// Label selectors must include zero or more label conditions separated by commas. All label
        /// conditions must be satisfied for an item to be selected. The conditions are essentially AND-ed together.
        /// We'll support two basic types of label conditions: equality/inequality and set based.
        /// </para>
        /// <note>
        /// A <c>null</c> or empty <paramref name="labelSelector"/> simply returns all items.
        /// </note>
        /// <para><b>equality/inequality conditions:</b></para>
        /// <code language="none">
        /// [label] = [value]
        /// [label] == [value]
        /// [label] != [value]
        /// </code>
        /// <para>
        /// The first two examples two compare label value equality and the last compares for inequality.
        /// Note that it is not currently possible to compare an empty or null string.
        /// </para>
        /// <para><b>set conditions:</b></para>
        /// <code language="none">
        /// [label] in ([value1], [value2],,...)
        /// notin([value1], [value2],...)
        /// [label]
        /// ![label]
        /// </code>
        /// <para>
        /// The first example selects items if they have a label with any of the values listed and the second
        /// selects items that have the label that doesn't have any of the values. The last two examples select
        /// items when they have or don't have a label, regardless of its value.
        /// </para>
        /// <note>
        /// The <b>in</b> and <b>notin</b> operators both require that the item have the target label for a match.
        /// </note>
        /// <note>
        /// <b>Case Sensitivity:</b> Label name lookups are actually determined by the dictionary returned
        /// by each item.  .NET string dictionaries are typically case sensitive by default but you can
        /// change this behavior by having your item implementations construct case insenstive dictionaries.
        /// By default, this class performs case insensitive comparisions for label values.  You can override
        /// this by passing <see cref="LabelSelectorOptions.CaseInsensitiveValues"/> to the
        /// <see cref="LabelSelector{TItem}.LabelSelector(IEnumerable{TItem}, LabelSelectorOptions)"/> constructor.
        /// </note>
        /// <note>
        /// <para>
        /// <b>Label Name Constraints:</b> Label keys are checked to ensure that they match Kubernetes conventions
        /// by default.  You can override this by passing <see cref="LabelSelectorOptions.UnConstraintedLabels"/> to the
        /// <see cref="LabelSelector{TItem}.LabelSelector(IEnumerable{TItem}, LabelSelectorOptions)"/> constructor.
        /// </para>
        /// <para>
        /// <b>Label Value Constraints:</b> Label values are also checked to ensure that they match Kubernetes conventions
        /// by default.  This behavior can also be overriden by passing to the constructor.
        /// </para>
        /// </note>
        /// </remarks>
        public IEnumerable <TItem> Select(string labelSelector)
        {
            if (items == null || items.Count() == 0)
            {
                return(Array.Empty <TItem>());
            }

            if (string.IsNullOrWhiteSpace(labelSelector))
            {
                return(items);
            }

            if (items == null)
            {
                return(Array.Empty <TItem>());
            }

            // Parse the label conditions.

            var lexer      = new Lexer(labelSelector);
            var conditions = new List <LabelCondition>();

            while (!lexer.Eof)
            {
                var token = lexer.Next();

                switch (token.Type)
                {
                case TokenType.Not:

                    // Expecting: !label

                    conditions.Add(LabelCondition.NotHas(lexer.Next(TokenType.String).Value, options));
                    lexer.Next(TokenType.Comma, TokenType.Eof);
                    break;

                case TokenType.String:

                    var label = token.Value;

                    token = lexer.Next(TokenType.Equal, TokenType.NotEqual, TokenType.String, TokenType.Comma, TokenType.Eof);

                    switch (token.Type)
                    {
                    case TokenType.Equal:

                        token = lexer.Next(TokenType.String);

                        conditions.Add(LabelCondition.Equal(label, token.Value, options));
                        lexer.Next(TokenType.Comma, TokenType.Eof);
                        break;

                    case TokenType.NotEqual:

                        token = lexer.Next(TokenType.String);

                        conditions.Add(LabelCondition.NotEqual(label, token.Value, options));
                        lexer.Next(TokenType.Comma, TokenType.Eof);
                        break;

                    case TokenType.Eof:
                    case TokenType.Comma:

                        conditions.Add(LabelCondition.Has(label, options));
                        break;

                    case TokenType.String:

                        bool inOperator;

                        if (token.Value.Equals("in", StringComparison.CurrentCultureIgnoreCase))
                        {
                            inOperator = true;
                        }
                        else if (token.Value.Equals("notin", StringComparison.CurrentCultureIgnoreCase))
                        {
                            inOperator = false;
                        }
                        else
                        {
                            throw new FormatException($"Invalid Label Selector: Invalid [{token.Value}] set operator in [{labelSelector}].");
                        }

                        var values = new List <string>();

                        lexer.Next(TokenType.LParen);

                        while (true)
                        {
                            token = lexer.Next(TokenType.String);

                            values.Add(token.Value);

                            token = lexer.Next(TokenType.Comma, TokenType.RParen);

                            if (token.Type == TokenType.RParen)
                            {
                                break;
                            }
                        }

                        conditions.Add(inOperator ? LabelCondition.In(label, values, options) : LabelCondition.NotIn(label, values, options));
                        lexer.Next(TokenType.Comma, TokenType.Eof);
                        break;
                    }
                    break;

                default:

                    throw new FormatException($"Invalid Label Selector: Unexpected [{token.Type}] in [{labelSelector}].");
                }
            }

            // Execute the conditsions against the items.  Those items with labels that
            // satisfy all conditions will be returned.

            return(items.Where(
                       item =>
            {
                var stringComparison = CaseInsensitive ? StringComparison.InvariantCultureIgnoreCase : StringComparison.InvariantCulture;

                foreach (var condition in conditions)
                {
                    if (!condition.Execute(item, stringComparison))
                    {
                        return false;
                    }
                }

                return true;
            }));
        }
 public void Parse(GameBitBuffer buffer)
 {
     Field0 = buffer.ReadCharArray(128);
     Field1 = new LabelCondition();
     Field1.Parse(buffer);
     Field2 = buffer.ReadInt(32);
     Field3 = buffer.ReadInt(32);
     Field4 = new DT_VARIABLEARRAY();
     Field4.Parse(buffer);
     serEntries = new SerializeData();
     serEntries.Parse(buffer);
 }