diff options
| author | Ryan <fauxpark@gmail.com> | 2024-11-21 22:57:36 +1100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-11-21 22:57:36 +1100 |
| commit | 65a8a5ff69289a5cb8fce6555b774573e4452a79 (patch) | |
| tree | 24d26aceb9f86e54b6e2cc110a8672f334f7182a /lib/python/qmk | |
| parent | c7a04bd9305c337e9190d5ebdd368c4af49adc43 (diff) | |
`qmk find`: expand operator support (#24468)
Diffstat (limited to 'lib/python/qmk')
| -rw-r--r-- | lib/python/qmk/search.py | 40 | ||||
| -rw-r--r-- | lib/python/qmk/tests/test_cli_commands.py | 2 |
2 files changed, 31 insertions, 11 deletions
diff --git a/lib/python/qmk/search.py b/lib/python/qmk/search.py index 6517bb4951..c7bce344ad 100644 --- a/lib/python/qmk/search.py +++ b/lib/python/qmk/search.py | |||
| @@ -239,11 +239,11 @@ def _filter_keymap_targets(target_list: List[KeyboardKeymapDesc], filters: List[ | |||
| 239 | valid_targets = parallel_map(_load_keymap_info, target_list) | 239 | valid_targets = parallel_map(_load_keymap_info, target_list) |
| 240 | 240 | ||
| 241 | function_re = re.compile(r'^(?P<function>[a-zA-Z]+)\((?P<key>[a-zA-Z0-9_\.]+)(,\s*(?P<value>[^#]+))?\)$') | 241 | function_re = re.compile(r'^(?P<function>[a-zA-Z]+)\((?P<key>[a-zA-Z0-9_\.]+)(,\s*(?P<value>[^#]+))?\)$') |
| 242 | equals_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*=\s*(?P<value>[^#]+)$') | 242 | comparison_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*(?P<op>[\<\>\!=]=|\<|\>)\s*(?P<value>[^#]+)$') |
| 243 | 243 | ||
| 244 | for filter_expr in filters: | 244 | for filter_expr in filters: |
| 245 | function_match = function_re.match(filter_expr) | 245 | function_match = function_re.match(filter_expr) |
| 246 | equals_match = equals_re.match(filter_expr) | 246 | comparison_match = comparison_re.match(filter_expr) |
| 247 | 247 | ||
| 248 | if function_match is not None: | 248 | if function_match is not None: |
| 249 | func_name = function_match.group('function').lower() | 249 | func_name = function_match.group('function').lower() |
| @@ -259,23 +259,43 @@ def _filter_keymap_targets(target_list: List[KeyboardKeymapDesc], filters: List[ | |||
| 259 | value_str = f", {{fg_cyan}}{value}{{fg_reset}}" if value is not None else "" | 259 | value_str = f", {{fg_cyan}}{value}{{fg_reset}}" if value is not None else "" |
| 260 | cli.log.info(f'Filtering on condition: {{fg_green}}{func_name}{{fg_reset}}({{fg_cyan}}{key}{{fg_reset}}{value_str})...') | 260 | cli.log.info(f'Filtering on condition: {{fg_green}}{func_name}{{fg_reset}}({{fg_cyan}}{key}{{fg_reset}}{value_str})...') |
| 261 | 261 | ||
| 262 | elif equals_match is not None: | 262 | elif comparison_match is not None: |
| 263 | key = equals_match.group('key') | 263 | key = comparison_match.group('key') |
| 264 | value = equals_match.group('value') | 264 | op = comparison_match.group('op') |
| 265 | cli.log.info(f'Filtering on condition: {{fg_cyan}}{key}{{fg_reset}} == {{fg_cyan}}{value}{{fg_reset}}...') | 265 | value = comparison_match.group('value') |
| 266 | cli.log.info(f'Filtering on condition: {{fg_cyan}}{key}{{fg_reset}} {op} {{fg_cyan}}{value}{{fg_reset}}...') | ||
| 266 | 267 | ||
| 267 | def _make_filter(k, v): | 268 | def _make_filter(k, o, v): |
| 268 | expr = fnmatch.translate(v) | 269 | expr = fnmatch.translate(v) |
| 269 | rule = re.compile(f'^{expr}$', re.IGNORECASE) | 270 | rule = re.compile(f'^{expr}$', re.IGNORECASE) |
| 270 | 271 | ||
| 271 | def f(e: KeyboardKeymapDesc): | 272 | def f(e: KeyboardKeymapDesc): |
| 272 | lhs = e.dotty.get(k) | 273 | lhs = e.dotty.get(k) |
| 273 | lhs = str(False if lhs is None else lhs) | 274 | rhs = v |
| 274 | return rule.search(lhs) is not None | 275 | |
| 276 | if o in ['<', '>', '<=', '>=']: | ||
| 277 | lhs = int(False if lhs is None else lhs) | ||
| 278 | rhs = int(rhs) | ||
| 279 | |||
| 280 | if o == '<': | ||
| 281 | return lhs < rhs | ||
| 282 | elif o == '>': | ||
| 283 | return lhs > rhs | ||
| 284 | elif o == '<=': | ||
| 285 | return lhs <= rhs | ||
| 286 | elif o == '>=': | ||
| 287 | return lhs >= rhs | ||
| 288 | else: | ||
| 289 | lhs = str(False if lhs is None else lhs) | ||
| 290 | |||
| 291 | if o == '!=': | ||
| 292 | return rule.search(lhs) is None | ||
| 293 | elif o == '==': | ||
| 294 | return rule.search(lhs) is not None | ||
| 275 | 295 | ||
| 276 | return f | 296 | return f |
| 277 | 297 | ||
| 278 | valid_targets = filter(_make_filter(key, value), valid_targets) | 298 | valid_targets = filter(_make_filter(key, op, value), valid_targets) |
| 279 | else: | 299 | else: |
| 280 | cli.log.warning(f'Unrecognized filter expression: {filter_expr}') | 300 | cli.log.warning(f'Unrecognized filter expression: {filter_expr}') |
| 281 | continue | 301 | continue |
diff --git a/lib/python/qmk/tests/test_cli_commands.py b/lib/python/qmk/tests/test_cli_commands.py index f18bd12f82..b10fd8d19d 100644 --- a/lib/python/qmk/tests/test_cli_commands.py +++ b/lib/python/qmk/tests/test_cli_commands.py | |||
| @@ -390,7 +390,7 @@ def test_find_contains(): | |||
| 390 | def test_find_multiple_conditions(): | 390 | def test_find_multiple_conditions(): |
| 391 | # this is intended to match at least 'crkbd/rev1' | 391 | # this is intended to match at least 'crkbd/rev1' |
| 392 | result = check_subcommand( | 392 | result = check_subcommand( |
| 393 | 'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin=D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p', | 393 | 'find', '-f', 'exists(rgb_matrix.split_count)', '-f', 'contains(matrix_pins.cols, B1)', '-f', 'length(matrix_pins.cols, 6)', '-f', 'absent(eeprom.driver)', '-f', 'ws2812.pin == D3', '-p', 'rgb_matrix.split_count', '-p', 'matrix_pins.cols', '-p', |
| 394 | 'eeprom.driver', '-p', 'ws2812.pin' | 394 | 'eeprom.driver', '-p', 'ws2812.pin' |
| 395 | ) | 395 | ) |
| 396 | check_returncode(result) | 396 | check_returncode(result) |
