141 lines
5.4 KiB
Python
Executable File
141 lines
5.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import os
|
|
import yaml
|
|
import re
|
|
import include_homekit
|
|
|
|
from argparse import ArgumentParser, ArgumentError
|
|
from homekit.pio import get_products, platformio_ini
|
|
from homekit.pio.exceptions import ProductConfigNotFoundError
|
|
from homekit.config import CONFIG_DIRECTORIES
|
|
|
|
|
|
def get_config(product: str) -> dict:
|
|
path = None
|
|
for directory in CONFIG_DIRECTORIES:
|
|
config_path = os.path.join(directory, 'pio', f'{product}.yaml')
|
|
if os.path.exists(config_path) and os.path.isfile(config_path):
|
|
path = config_path
|
|
break
|
|
if not path:
|
|
raise ProductConfigNotFoundError(f'pio/{product}.yaml not found')
|
|
with open(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':
|
|
if attr_value is True:
|
|
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 everything 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)
|