summaryrefslogtreecommitdiff
path: root/lib/python/qmk
diff options
context:
space:
mode:
authorNick Brassel <nick@tzarc.org>2023-10-17 09:43:50 +1100
committerGitHub <noreply@github.com>2023-10-17 09:43:50 +1100
commitf6c70c40af502923594e76bf079f602ed88a2341 (patch)
treeda27fe0d9c8c4fa24e39afd82d1a479b02e06e60 /lib/python/qmk
parent81a3aa025cda52732e847af8db256cb132605ce0 (diff)
Allow for disabling of parallel processing of qmk find and `qmk mass-compile`. (#22160)
Co-authored-by: Duncan Sutherland <dunk2k_2000@hotmail.com>
Diffstat (limited to 'lib/python/qmk')
-rw-r--r--lib/python/qmk/cli/find.py2
-rwxr-xr-xlib/python/qmk/cli/mass_compile.py4
-rw-r--r--lib/python/qmk/search.py30
-rw-r--r--lib/python/qmk/util.py56
4 files changed, 73 insertions, 19 deletions
diff --git a/lib/python/qmk/cli/find.py b/lib/python/qmk/cli/find.py
index 2836eb8a54..f2135bbc16 100644
--- a/lib/python/qmk/cli/find.py
+++ b/lib/python/qmk/cli/find.py
@@ -23,7 +23,7 @@ def find(cli):
23 if len(cli.args.filter) == 0 and len(cli.args.print) > 0: 23 if len(cli.args.filter) == 0 and len(cli.args.print) > 0:
24 cli.log.warning('No filters supplied -- keymaps not parsed, unable to print requested values.') 24 cli.log.warning('No filters supplied -- keymaps not parsed, unable to print requested values.')
25 25
26 targets = search_keymap_targets(cli.args.keymap, cli.args.filter, cli.args.print) 26 targets = search_keymap_targets([('all', cli.config.find.keymap)], cli.args.filter, cli.args.print)
27 for keyboard, keymap, print_vals in targets: 27 for keyboard, keymap, print_vals in targets:
28 print(f'{keyboard}:{keymap}') 28 print(f'{keyboard}:{keymap}')
29 29
diff --git a/lib/python/qmk/cli/mass_compile.py b/lib/python/qmk/cli/mass_compile.py
index 1227f435e7..06e6e411a7 100755
--- a/lib/python/qmk/cli/mass_compile.py
+++ b/lib/python/qmk/cli/mass_compile.py
@@ -97,6 +97,6 @@ def mass_compile(cli):
97 if len(cli.args.builds) > 0: 97 if len(cli.args.builds) > 0:
98 targets = search_make_targets(cli.args.builds, cli.args.filter) 98 targets = search_make_targets(cli.args.builds, cli.args.filter)
99 else: 99 else:
100 targets = search_keymap_targets(cli.args.keymap, cli.args.filter) 100 targets = search_keymap_targets([('all', cli.config.mass_compile.keymap)], cli.args.filter)
101 101
102 return mass_compile_targets(targets, cli.args.clean, cli.args.dry_run, cli.args.no_temp, cli.args.parallel, cli.args.env) 102 return mass_compile_targets(targets, cli.args.clean, cli.args.dry_run, cli.config.mass_compile.no_temp, cli.config.mass_compile.parallel, cli.args.env)
diff --git a/lib/python/qmk/search.py b/lib/python/qmk/search.py
index 0b5d489218..a74450ca87 100644
--- a/lib/python/qmk/search.py
+++ b/lib/python/qmk/search.py
@@ -4,12 +4,12 @@ import contextlib
4import functools 4import functools
5import fnmatch 5import fnmatch
6import logging 6import logging
7import multiprocessing
8import re 7import re
9from typing import List, Tuple 8from typing import List, Tuple
10from dotty_dict import dotty 9from dotty_dict import dotty
11from milc import cli 10from milc import cli
12 11
12from qmk.util import parallel_map
13from qmk.info import keymap_json 13from qmk.info import keymap_json
14import qmk.keyboard 14import qmk.keyboard
15import qmk.keymap 15import qmk.keymap
@@ -78,17 +78,16 @@ def _expand_keymap_target(keyboard: str, keymap: str, all_keyboards: List[str] =
78 all_keyboards = qmk.keyboard.list_keyboards() 78 all_keyboards = qmk.keyboard.list_keyboards()
79 79
80 if keyboard == 'all': 80 if keyboard == 'all':
81 with multiprocessing.Pool() as pool: 81 if keymap == 'all':
82 if keymap == 'all': 82 cli.log.info('Retrieving list of all keyboards and keymaps...')
83 cli.log.info('Retrieving list of all keyboards and keymaps...') 83 targets = []
84 targets = [] 84 for kb in parallel_map(_all_keymaps, all_keyboards):
85 for kb in pool.imap_unordered(_all_keymaps, all_keyboards): 85 targets.extend(kb)
86 targets.extend(kb) 86 return targets
87 return targets 87 else:
88 else: 88 cli.log.info(f'Retrieving list of keyboards with keymap "{keymap}"...')
89 cli.log.info(f'Retrieving list of keyboards with keymap "{keymap}"...') 89 keyboard_filter = functools.partial(_keymap_exists, keymap=keymap)
90 keyboard_filter = functools.partial(_keymap_exists, keymap=keymap) 90 return [(kb, keymap) for kb in filter(lambda e: e is not None, parallel_map(keyboard_filter, all_keyboards))]
91 return [(kb, keymap) for kb in filter(lambda e: e is not None, pool.imap_unordered(keyboard_filter, all_keyboards))]
92 else: 91 else:
93 if keymap == 'all': 92 if keymap == 'all':
94 keyboard = qmk.keyboard.resolve_keyboard(keyboard) 93 keyboard = qmk.keyboard.resolve_keyboard(keyboard)
@@ -117,8 +116,7 @@ def _filter_keymap_targets(target_list: List[Tuple[str, str]], filters: List[str
117 targets = [(kb, km, {}) for kb, km in target_list] 116 targets = [(kb, km, {}) for kb, km in target_list]
118 else: 117 else:
119 cli.log.info('Parsing data for all matching keyboard/keymap combinations...') 118 cli.log.info('Parsing data for all matching keyboard/keymap combinations...')
120 with multiprocessing.Pool() as pool: 119 valid_keymaps = [(e[0], e[1], dotty(e[2])) for e in parallel_map(_load_keymap_info, target_list)]
121 valid_keymaps = [(e[0], e[1], dotty(e[2])) for e in pool.imap_unordered(_load_keymap_info, target_list)]
122 120
123 function_re = re.compile(r'^(?P<function>[a-zA-Z]+)\((?P<key>[a-zA-Z0-9_\.]+)(,\s*(?P<value>[^#]+))?\)$') 121 function_re = re.compile(r'^(?P<function>[a-zA-Z]+)\((?P<key>[a-zA-Z0-9_\.]+)(,\s*(?P<value>[^#]+))?\)$')
124 equals_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*=\s*(?P<value>[^#]+)$') 122 equals_re = re.compile(r'^(?P<key>[a-zA-Z0-9_\.]+)\s*=\s*(?P<value>[^#]+)$')
@@ -179,10 +177,10 @@ def _filter_keymap_targets(target_list: List[Tuple[str, str]], filters: List[str
179 return targets 177 return targets
180 178
181 179
182def search_keymap_targets(keymap='default', filters: List[str] = [], print_vals: List[str] = []) -> List[Tuple[str, str, List[Tuple[str, str]]]]: 180def search_keymap_targets(targets: List[Tuple[str, str]] = [('all', 'default')], filters: List[str] = [], print_vals: List[str] = []) -> List[Tuple[str, str, List[Tuple[str, str]]]]:
183 """Search for build targets matching the supplied criteria. 181 """Search for build targets matching the supplied criteria.
184 """ 182 """
185 return list(sorted(_filter_keymap_targets(expand_keymap_targets([('all', keymap)]), filters, print_vals), key=lambda e: (e[0], e[1]))) 183 return list(sorted(_filter_keymap_targets(expand_keymap_targets(targets), filters, print_vals), key=lambda e: (e[0], e[1])))
186 184
187 185
188def search_make_targets(targets: List[str], filters: List[str] = [], print_vals: List[str] = []) -> List[Tuple[str, str, List[Tuple[str, str]]]]: 186def search_make_targets(targets: List[str], filters: List[str] = [], print_vals: List[str] = []) -> List[Tuple[str, str, List[Tuple[str, str]]]]:
diff --git a/lib/python/qmk/util.py b/lib/python/qmk/util.py
new file mode 100644
index 0000000000..db7debd578
--- /dev/null
+++ b/lib/python/qmk/util.py
@@ -0,0 +1,56 @@
1"""Utility functions.
2"""
3import contextlib
4import multiprocessing
5
6from milc import cli
7
8
9@contextlib.contextmanager
10def parallelize():
11 """Returns a function that can be used in place of a map() call.
12
13 Attempts to use `mpire`, falling back to `multiprocessing` if it's not
14 available. If parallelization is not requested, returns the original map()
15 function.
16 """
17
18 # Work out if we've already got a config value for parallel searching
19 if cli.config.user.parallel_search is None:
20 parallel_search = True
21 else:
22 parallel_search = cli.config.user.parallel_search
23
24 # Non-parallel searches use `map()`
25 if not parallel_search:
26 yield map
27 return
28
29 # Prefer mpire's `WorkerPool` if it's available
30 with contextlib.suppress(ImportError):
31 from mpire import WorkerPool
32 from mpire.utils import make_single_arguments
33 with WorkerPool() as pool:
34
35 def _worker(func, *args):
36 # Ensure we don't unpack tuples -- mpire's `WorkerPool` tries to do so normally so we tell it not to.
37 for r in pool.imap_unordered(func, make_single_arguments(*args, generator=False), progress_bar=True):
38 yield r
39
40 yield _worker
41 return
42
43 # Otherwise fall back to multiprocessing's `Pool`
44 with multiprocessing.Pool() as pool:
45 yield pool.imap_unordered
46
47
48def parallel_map(*args, **kwargs):
49 """Effectively runs `map()` but executes it in parallel if necessary.
50 """
51 with parallelize() as map_fn:
52 # This needs to be enclosed in a `list()` as some implementations return
53 # a generator function, which means the scope of the pool is closed off
54 # before the results are returned. Returning a list ensures results are
55 # materialised before any worker pool is shut down.
56 return list(map_fn(*args, **kwargs))