#!/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