#!/usr/bin/env python3 import os import yaml import re import __py_include from pprint import pprint from argparse import ArgumentParser, ArgumentError from homekit.pio import get_products, platformio_ini from homekit.pio.exceptions import ProductConfigNotFoundError def get_config(product: str) -> dict: config_path = os.path.join( os.getenv('HOME'), '.config', 'homekit_pio', f'{product}.yaml' ) if not os.path.exists(config_path): raise ProductConfigNotFoundError(f'{config_path}: product config not found') with open(config_path, 'r') as f: return yaml.safe_load(f) def bsd_walk(product_config: dict, f: callable): try: for define_name, define_extra_params in product_config['build_specific_defines'].items(): define_name = re.sub(r'^CONFIG_', '', define_name) kwargs = {} if isinstance(define_extra_params, dict): kwargs = define_extra_params f(define_name, **kwargs) except KeyError: pass # 'bsd' means 'build_specific_defines' def bsd_parser(product_config: dict, parser: ArgumentParser): def f(define_name, **kwargs): arg_kwargs = {} define_name = define_name.lower().replace('_', '-') if 'type' in kwargs: if kwargs['type'] in ('str', 'enum'): arg_kwargs['type'] = str if kwargs['type'] == 'enum' and 'list_config_key' in kwargs: if not isinstance(product_config[kwargs['list_config_key']], list): raise TypeError(f'product_config[{kwargs["list_config_key"]}] enum is not list') if not product_config[kwargs['list_config_key']]: raise ValueError(f'product_config[{kwargs["list_config_key"]}] enum cannot be empty') arg_kwargs['choices'] = product_config[kwargs['list_config_key']] if isinstance(product_config[kwargs['list_config_key']][0], int): arg_kwargs['type'] = int elif kwargs['type'] == 'int': arg_kwargs['type'] = int elif kwargs['type'] == 'bool': arg_kwargs['action'] = 'store_true' arg_kwargs['required'] = False else: raise TypeError(f'unsupported type {kwargs["type"]} for define {define_name}') else: arg_kwargs['action'] = 'store_true' if 'required' not in arg_kwargs: arg_kwargs['required'] = True parser.add_argument(f'--{define_name}', **arg_kwargs) bsd_walk(product_config, f) def bsd_get(product_config: dict, arg: object): defines = {} enums = [] def f(define_name, **kwargs): attr_name = define_name.lower() attr_value = getattr(arg, attr_name) if 'type' in kwargs: if kwargs['type'] == 'enum': enums.append(f'CONFIG_{define_name}') defines[f'CONFIG_{define_name}'] = f'HOMEKIT_{attr_value.upper()}' return if kwargs['type'] == 'bool': defines[f'CONFIG_{define_name}'] = True return defines[f'CONFIG_{define_name}'] = str(attr_value) bsd_walk(product_config, f) return defines, enums if __name__ == '__main__': products = get_products() # first, get the product product_parser = ArgumentParser(add_help=False) product_parser.add_argument('--product', type=str, choices=products, required=True, help='PIO product name') arg, _ = product_parser.parse_known_args() if not arg.product: product = os.path.basename(os.path.realpath(os.getcwd())) if product not in products: raise ArgumentError(None, 'invalid product') else: product = arg.product product_config = get_config(product) # then everythingm else parser = ArgumentParser(parents=[product_parser]) parser.add_argument('--target', type=str, required=True, choices=product_config['targets'], help='PIO build target') parser.add_argument('--platform', default='espressif8266', type=str) parser.add_argument('--framework', default='arduino', type=str) parser.add_argument('--upload-port', default='/dev/ttyUSB0', type=str) parser.add_argument('--monitor-speed', default=115200) parser.add_argument('--debug', action='store_true') parser.add_argument('--debug-network', action='store_true') bsd_parser(product_config, parser) arg = parser.parse_args() if arg.target not in product_config['targets']: raise ArgumentError(None, f'target {arg.target} not found for product {product}') bsd, bsd_enums = bsd_get(product_config, arg) ini = platformio_ini(product_config=product_config, target=arg.target, build_specific_defines=bsd, build_specific_defines_enums=bsd_enums, platform=arg.platform, framework=arg.framework, upload_port=arg.upload_port, monitor_speed=arg.monitor_speed, debug=arg.debug, debug_network=arg.debug_network) print(ini)