mbligh | 2b67253 | 2007-11-05 19:24:51 +0000 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | """ |
| 3 | This library provides a bunch of miscellaneous parameter parsing, |
| 4 | sql generating and list cleanup library functions that are used |
| 5 | by both the reporting cli and web interface. |
| 6 | """ |
| 7 | |
| 8 | import sys, os, re |
| 9 | |
| 10 | tko = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) |
| 11 | sys.path.insert(0, tko) |
| 12 | |
| 13 | import display, frontend, db |
| 14 | |
| 15 | db = db.db() |
| 16 | |
mbligh | 12eebfa | 2008-01-03 02:01:53 +0000 | [diff] [blame^] | 17 | def dprint(str): |
| 18 | pass |
| 19 | #print "! %s<br>" % str |
| 20 | |
| 21 | def parse_scrub_and_gen_condition(condition, valid_field_dict): |
| 22 | me = parse_scrub_and_gen_condition # shorten the name |
| 23 | compare_ops = {'=':'=', '<>':'<>', '==':'=', '!=':'<>', '>':'>', |
| 24 | '<':'<', '>=':'>=', '<=':'<=', '~':'LIKE', '#':'REGEXP'} |
| 25 | |
| 26 | # strip white space |
| 27 | condition = condition.strip() |
| 28 | |
| 29 | # ()'s |
| 30 | #match = re.match(r'^[(](.+)[)]$', condition) |
| 31 | #if match: |
| 32 | # dprint("Matched () on %s" % condition) |
| 33 | # depth = 0 |
| 34 | # for c in match.group(1): |
| 35 | # if c == '(': depth += 1 |
| 36 | # if c == ')': depth -= 1 |
| 37 | # if depth < 0: break |
| 38 | # dprint("Depth is %d" % depth) |
| 39 | # if depth == 0: |
| 40 | # dprint("Match...stripping ()'s") |
| 41 | # return me(match.group(1), valid_field_dict) |
| 42 | |
| 43 | # OR |
| 44 | match = re.match(r'^(.+)[|](.+)$', condition) |
| 45 | if match: |
| 46 | dprint("Matched | on %s" % condition) |
| 47 | (a_sql, a_values) = me(match.group(1), valid_field_dict) |
| 48 | (b_sql, b_values) = me(match.group(2), valid_field_dict) |
| 49 | return (" (%s) OR (%s) " % (a_sql, b_sql), |
| 50 | a_values + b_values) |
| 51 | |
| 52 | # AND |
| 53 | match = re.match(r'^(.+)[&](.+)$', condition) |
| 54 | if match: |
| 55 | dprint("Matched & on %s" % condition) |
| 56 | (a_sql, a_values) = me(match.group(1), valid_field_dict) |
| 57 | (b_sql, b_values) = me(match.group(2), valid_field_dict) |
| 58 | return (" (%s) AND (%s) " % (a_sql, b_sql), |
| 59 | a_values + b_values) |
| 60 | |
| 61 | # NOT |
| 62 | #match = re.match(r'^[!](.+)$', condition) |
| 63 | #if match: |
| 64 | # dprint("Matched ! on %s" % condition) |
| 65 | # (sql, values) = me(match.group(1), valid_field_dict) |
| 66 | # return (" NOT (%s) " % (sql,), values) |
| 67 | |
| 68 | # '<field> <op> <value>' where value can be quoted |
| 69 | # double quotes are escaped....i.e. '''' is the same as "'" |
| 70 | regex = r'^(%s)[ \t]*(%s)[ \t]*' + \ |
| 71 | r'(\'((\'\'|[^\'])*)\'|"((""|[^"])*)"|([^\'"].*))$' |
| 72 | regex = regex % ('|'.join(valid_field_dict.keys()), |
| 73 | '|'.join(compare_ops.keys())) |
| 74 | match = re.match(regex, condition) |
| 75 | if match: |
| 76 | field = valid_field_dict[match.group(1)] |
| 77 | op = compare_ops[match.group(2)] |
| 78 | if match.group(5): |
| 79 | val = match.group(4).replace("''", "'") |
| 80 | elif match.group(7): |
| 81 | val = match.group(6).replace('""', '"') |
| 82 | elif match.group(8): |
| 83 | val = match.group(8) |
| 84 | else: |
| 85 | raise "Internal error" |
| 86 | return ("%s %s %%s" % (field, op), [val]) |
| 87 | |
| 88 | |
| 89 | raise "Could not parse '%s' (%s)" % (condition, regex) |
| 90 | |
| 91 | |
| 92 | ### |
| 93 | ### Everything past here is depricated. |
| 94 | ### |
| 95 | |
mbligh | 2b67253 | 2007-11-05 19:24:51 +0000 | [diff] [blame] | 96 | def generate_sql_condition(condition_list): |
| 97 | """ generate the sql for the condition list.""" |
| 98 | sql = '' |
| 99 | value = [] |
| 100 | for field, operator, values in condition_list: |
| 101 | if len(values) == 1: |
| 102 | if sql != '': |
| 103 | sql += " and " |
| 104 | sql += " %s%s%%s" % (field, operator) |
| 105 | value.append(values[0][0]) |
| 106 | elif len(values) > 1: |
| 107 | expression = [" %s %s %%s" % (field, operator) for val in values] |
| 108 | for val in values: |
| 109 | value.append(val[0]) |
| 110 | if sql != '': |
| 111 | sql += " and " |
| 112 | sql += "(%s)" % " or ".join(expression) |
| 113 | return sql, value |
| 114 | |
| 115 | |
| 116 | def prune_list(thelist, condition_sql, condition_value): |
| 117 | """ keep track of which columns do not have any elements.""" |
| 118 | pruned_list = [] |
| 119 | for g in thelist: |
| 120 | # check for multiple index values in the db. |
| 121 | sql = "t where " |
| 122 | expr = [" %s = %%s" % (g.idx_name) for val in g.idx_value] |
| 123 | sql += " (%s) " % " or ".join(expr) |
| 124 | value = [] |
| 125 | value.extend(g.idx_value) |
| 126 | if condition_sql: |
| 127 | sql += " and " |
| 128 | sql += condition_sql |
| 129 | value.extend(condition_value) |
| 130 | tests = frontend.test.select_sql(db, sql, value) |
| 131 | if len(tests) > 0: |
| 132 | pruned_list.append(g) |
| 133 | return pruned_list |
| 134 | |
| 135 | |
| 136 | def parse_condition(condition): |
| 137 | """ parse the condition into independent clauses.""" |
| 138 | condition_list = [] |
| 139 | if not condition: |
| 140 | return condition_list |
| 141 | attribute_re = r"(\w+)" |
| 142 | op_re = r"(=|!=)" |
| 143 | value_re = r"('[^']*')" |
| 144 | # condition is clause & clause & .. |
| 145 | clause_re = r"%s\s*%s\s*%s" % (attribute_re, op_re, value_re) |
| 146 | condition_re = re.compile(r"^\s*%s(\s*&\s*%s)*\s*$" % (clause_re, clause_re)) |
| 147 | if not condition_re.match(condition): |
| 148 | print "Condition not in the correct format: %s" % condition |
| 149 | sys.exit(0) |
| 150 | triples = [] |
| 151 | for clause in [c.strip() for c in condition.split('&')]: |
| 152 | attribute, op, value = re.match(clause_re, clause).groups() |
| 153 | triples.append((attribute, op, value)) |
| 154 | for (field_name, operator, value) in triples: |
| 155 | match, field = frontend.select(db, field_name, value, distinct=True) |
| 156 | if len(match) > 0: |
| 157 | condition_list.append((field, operator, match)) |
| 158 | else: |
| 159 | print "No matching results found for condition %s." % \ |
| 160 | condition |
| 161 | sys.exit(0) |
| 162 | return condition_list |
| 163 | |
| 164 | |
| 165 | def get_value(test, field): |
| 166 | """ get specific field values from the given test object.""" |
| 167 | if field == 'test': |
| 168 | return test.testname |
| 169 | elif field == 'kernel_idx': |
| 170 | return test.kernel_idx |
| 171 | elif field == 'machine_idx': |
| 172 | return test.machine_idx |
| 173 | elif field == 'status': |
| 174 | return test.status_num |
| 175 | |
| 176 | |
| 177 | def get_tests(condition_sql, condition_value): |
| 178 | # get all the tests that satify the given condition. |
| 179 | if condition_sql: |
| 180 | sql = "t where " |
| 181 | sql += condition_sql |
| 182 | value = [str(val) for val in condition_value] |
| 183 | #print sql , value |
| 184 | tests = frontend.test.select_sql(db, sql, value) |
| 185 | else: |
| 186 | sql = None |
| 187 | value = None |
| 188 | tests = frontend.test.select_sql(db, " t ", None) |
| 189 | return tests |