This file is indexed.

/usr/lib/python2.7/dist-packages/oslo_utils/specs_matcher.py is in python-oslo.utils 3.16.0-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# Copyright (c) 2011 OpenStack Foundation
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import operator

import pyparsing
from pyparsing import Literal
from pyparsing import OneOrMore
from pyparsing import Regex

op_methods = {
    # This one is special/odd,
    # TODO(harlowja): fix it so that it's not greater than or
    # equal, see here for the original @ https://review.openstack.org/#/c/8089/
    '=': lambda x, y: float(x) >= float(y),
    # More sane ops/methods
    '!=': lambda x, y: float(x) != float(y),
    '<=': lambda x, y: float(x) <= float(y),
    '==': lambda x, y: float(x) == float(y),
    '>=': lambda x, y: float(x) >= float(y),
    's!=': operator.ne,
    's<': operator.lt,
    's<=': operator.le,
    's==': operator.eq,
    's>': operator.gt,
    's>=': operator.ge,
    '<in>': lambda x, y: y in x,
    '<or>': lambda x, *y: any(x == a for a in y),
}


def make_grammar():
    """Creates the grammar to be used by a spec matcher."""
    # This is apparently how pyparsing recommends to be used,
    # as http://pyparsing.wikispaces.com/share/view/644825 states that
    # it is not thread-safe to use a parser across threads.

    unary_ops = (
        # Order matters here (so that '=' doesn't match before '==')
        Literal("==") | Literal("=") |
        Literal("!=") | Literal("<in>") |
        Literal(">=") | Literal("<=") |
        Literal("s==") | Literal("s!=") |
        # Order matters here (so that '<' doesn't match before '<=')
        Literal("s<=") | Literal("s<") |
        # Order matters here (so that '>' doesn't match before '>=')
        Literal("s>=") | Literal("s>"))

    or_ = Literal("<or>")

    # An atom is anything not an keyword followed by anything but whitespace
    atom = ~(unary_ops | or_) + Regex(r"\S+")

    unary = unary_ops + atom
    disjunction = OneOrMore(or_ + atom)

    # Even-numbered tokens will be '<or>', so we drop them
    disjunction.setParseAction(lambda _s, _l, t: ["<or>"] + t[1::2])

    expr = disjunction | unary | atom
    return expr


def match(cmp_value, spec):
    """Match a given value to a given spec DSL."""
    expr = make_grammar()
    try:
        ast = expr.parseString(spec)
    except pyparsing.ParseException:
        ast = [spec]
    if len(ast) == 1:
        return ast[0] == cmp_value
    op = op_methods[ast[0]]
    return op(cmp_value, *ast[1:])