#!/usr/bin/env python3 import yaml import argparse import math import os import sys # flake8: noqa: E127 def type_to_cxx(t): return f'Option::TYPE_{t.upper()}' def level_to_cxx(lv): return f'Option::LEVEL_{lv.upper()}' def eval_str(v): if v == "": return v v = v.strip('"').replace('"', '\\"') return f'"{v}"' def eval_value(v, typ): try: if typ == 'str': return eval_str(v) if typ == 'float': return float(v) if typ in ('uint', 'int', 'size', 'secs', 'millisecs'): return int(v) if typ == 'bool': return 'true' if v else 'false' else: return f'"{v}"' except ValueError: times = dict(_min=60, _hr=60*60, _day=24*60*60, _K=1 << 10, _M=1 << 20, _G=1 << 30, _T=1 << 40) for unit, m in times.items(): if v.endswith(unit): int(v[:-len(unit)]) # user defined literals return v raise ValueError(f'unknown value: {v}') def set_default(default, typ): if default is None: return '' v = eval_value(default, typ) return f'.set_default({v})\n' def set_daemon_default(default, typ): if default is None: return '' v = eval_value(default, typ) return f'.set_daemon_default({v})\n' def add_tags(tags): if tags is None: return '' cxx = '' for tag in tags: v = eval_str(tag) cxx += f'.add_tag({v})\n' return cxx def add_services(services): if services is None: return '' if len(services) == 1: return f'.add_service("{services[0]}")\n' else: param = ', '.join(f'"{s}"' for s in services) return f'.add_service({{{param}}})\n' def add_see_also(see_also): if see_also is None: return '' param = ', '.join(f'"{v}"' for v in see_also) return f'.add_see_also({{{param}}})\n' def set_desc(desc): if desc is None: return '' v = eval_str(desc) return f'.set_description({v})\n' def set_long_desc(desc): if desc is None: return '' v = eval_str(desc) return f'.set_long_description({v})\n' def set_min_max(mi, ma, typ): if mi is None and ma is None: return '' if mi is not None and ma is not None: min_v = eval_value(mi, typ) max_v = eval_value(ma, typ) if isinstance(min_v, str) and isinstance(max_v, int): return f'.set_min_max({min_v}, {max_v}ULL)\n' elif isinstance(min_v, int) and isinstance(max_v, str): return f'.set_min_max({min_v}ULL, {max_v})\n' else: return f'.set_min_max({min_v}, {max_v})\n' if mi is not None: min_v = eval_value(mi, typ) return f'.set_min({min_v})\n' raise ValueError('set_max() is not implemented') def set_enum_allowed(values): if values is None: return '' param = ', '.join(f'"{v}"' for v in values) return f'.set_enum_allowed({{{param}}})\n' def add_flags(flags): if flags is None: return '' cxx = '' for flag in flags: cxx += f'.set_flag(Option::FLAG_{flag.upper()})\n' return cxx def set_validator(validator): if validator is None: return '' validator = validator.rstrip() return f'.set_validator({validator})\n' def add_verbatim(verbatim): if verbatim is None: return '' return verbatim + '\n' def yaml_to_cxx(opt, indent): name = opt['name'] typ = opt['type'] ctyp = type_to_cxx(typ) level = level_to_cxx(opt['level']) cxx = f'Option("{name}", {ctyp}, {level})\n' cxx += set_desc(opt.get('desc')) cxx += set_long_desc(opt.get('long_desc')) cxx += set_default(opt.get('default'), typ) cxx += set_daemon_default(opt.get('daemon_default'), typ) cxx += set_min_max(opt.get('min'), opt.get('max'), typ) cxx += set_enum_allowed(opt.get('enum_values')) cxx += set_validator(opt.get('validator')) cxx += add_flags(opt.get('flags')) cxx += add_services(opt.get('services')) cxx += add_tags(opt.get('tags')) cxx += add_see_also(opt.get('see_also')) verbatim = add_verbatim(opt.get('verbatim')) cxx += verbatim if verbatim: cxx += '\n' else: cxx = cxx.rstrip() cxx += ',\n' if indent > 0: indented = [] for line in cxx.split('\n'): if line: indented.append(' ' * indent + line + '\n') cxx = ''.join(indented) return cxx def type_to_h(t): if t == 'uint': return 'OPT_U32' return f'OPT_{t.upper()}' def yaml_to_h(opt): if opt.get('with_legacy', False): name = opt['name'] typ = opt['type'] htyp = type_to_h(typ) return f'OPTION({name}, {htyp})' else: return '' TEMPLATE_CC = '''#include "common/options.h" {headers} std::vector