summaryrefslogtreecommitdiff
path: root/bin/pio_ini.py
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.io>2023-09-27 00:54:57 +0300
committerEvgeny Zinoviev <me@ch1p.io>2023-09-27 00:54:57 +0300
commitd3a295872c49defb55fc8e4e43e55550991e0927 (patch)
treeb9dca15454f9027d5a9dad0d4443a20de04dbc5d /bin/pio_ini.py
parentb7cbc2571c1870b4582ead45277d0aa7f961bec8 (diff)
parentbdbb296697f55f4c3a07af43c9aaf7a9ea86f3d0 (diff)
Merge branch 'master' of ch1p.io:homekit
Diffstat (limited to 'bin/pio_ini.py')
-rwxr-xr-xbin/pio_ini.py140
1 files changed, 140 insertions, 0 deletions
diff --git a/bin/pio_ini.py b/bin/pio_ini.py
new file mode 100755
index 0000000..ee85732
--- /dev/null
+++ b/bin/pio_ini.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+import os
+import yaml
+import re
+import __py_include
+
+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)