at master 3.1 kB view raw
1import os 2 3from pathlib import Path 4from functools import lru_cache 5 6from milc.attrdict import AttrDict 7 8from qmk.json_schema import json_load, validate, merge_ordered_dicts 9from qmk.util import truthy 10from qmk.constants import QMK_FIRMWARE, QMK_USERSPACE, HAS_QMK_USERSPACE 11from qmk.path import under_qmk_firmware, under_qmk_userspace 12 13COMMUNITY_MODULE_JSON_FILENAME = 'qmk_module.json' 14 15 16class ModuleAPI(AttrDict): 17 def __init__(self, **kwargs): 18 super().__init__() 19 for key, value in kwargs.items(): 20 self[key] = value 21 22 23@lru_cache(maxsize=1) 24def module_api_list(): 25 module_definition_files = sorted(set(QMK_FIRMWARE.glob('data/constants/module_hooks/*.hjson'))) 26 module_definition_jsons = [json_load(f) for f in module_definition_files] 27 module_definitions = merge_ordered_dicts(module_definition_jsons) 28 latest_module_version = module_definition_files[-1].stem 29 latest_module_version_parts = latest_module_version.split('.') 30 31 api_list = [] 32 for name, mod in module_definitions.items(): 33 api_list.append(ModuleAPI( 34 ret_type=mod['ret_type'], 35 name=name, 36 args=mod['args'], 37 call_params=mod.get('call_params', ''), 38 guard=mod.get('guard', None), 39 header=mod.get('header', None), 40 )) 41 42 return api_list, latest_module_version, latest_module_version_parts[0], latest_module_version_parts[1], latest_module_version_parts[2] 43 44 45def find_available_module_paths(): 46 """Find all available modules. 47 """ 48 search_dirs = [] 49 if HAS_QMK_USERSPACE: 50 search_dirs.append(QMK_USERSPACE / 'modules') 51 search_dirs.append(QMK_FIRMWARE / 'modules') 52 53 modules = [] 54 for search_dir in search_dirs: 55 for module_json_path in search_dir.rglob(COMMUNITY_MODULE_JSON_FILENAME): 56 modules.append(module_json_path.parent) 57 return modules 58 59 60def find_module_path(module): 61 """Find a module by name. 62 """ 63 for module_path in find_available_module_paths(): 64 # Ensure the module directory is under QMK Firmware or QMK Userspace 65 relative_path = under_qmk_firmware(module_path) 66 if not relative_path: 67 relative_path = under_qmk_userspace(module_path) 68 if not relative_path: 69 continue 70 71 lhs = str(relative_path.as_posix())[len('modules/'):] 72 rhs = str(Path(module).as_posix()) 73 74 if relative_path and lhs == rhs: 75 return module_path 76 return None 77 78 79def load_module_json(module): 80 """Load a module JSON file. 81 """ 82 module_path = find_module_path(module) 83 if not module_path: 84 raise FileNotFoundError(f'Module not found: {module}') 85 86 module_json = json_load(module_path / COMMUNITY_MODULE_JSON_FILENAME) 87 88 if not truthy(os.environ.get('SKIP_SCHEMA_VALIDATION'), False): 89 validate(module_json, 'qmk.community_module.v1') 90 91 module_json['module'] = module 92 module_json['module_path'] = module_path 93 94 return module_json 95 96 97def load_module_jsons(modules): 98 """Load the module JSON files, matching the specified order. 99 """ 100 return list(map(load_module_json, modules))