1#!/usr/bin/env python3
2
3import os
4import re
5import argparse
6
7DIR_SCRIPTS = os.path.dirname(__file__)
8REPO_ROOT = os.path.join(DIR_SCRIPTS, "..")
9DIR_CWD = os.getcwd()
10
11
12def fatal(msg):
13    print()
14    print("ERROR! " + msg)
15    exit(1)
16
17
18def get_args():
19    parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description=""
20                                     "Update the configuration file of your existing project based on default parameters and latest LVGL template. Eg.:\n"
21                                     " python3 generate_lv_conf.py ./src \n"
22                                     " python3 generate_lv_conf.py --template modules/lvgl/lv_conf_template.h ./my_config_folder"
23                                     )
24
25    parser.add_argument('--template', type=str, default=REPO_ROOT, nargs='?',
26                        help='Path of "lv_conf_template.h" file or the folder containing it\n(optional, 1 folder above the python script by default)')
27
28    parser.add_argument('--config', type=str, default=None, nargs='?',
29                        help='Path of "lv_conf.h" file (optional)')
30
31    parser.add_argument('--defaults', type=str, default=None, nargs='?',
32                        help='Path of "lv_conf.defaults" file (optional)')
33
34    parser.add_argument('target', metavar='target', type=str, default=DIR_CWD, nargs='?',
35                        help='Folder containing "lv_conf.h" and "lv_conf.defaults" files\n(optional, current work folder by default)')
36
37    args = parser.parse_args()
38
39    if os.path.isdir(args.template):
40        args.template = os.path.join(args.template, "lv_conf_template.h")
41
42    if not args.config:
43        args.config = os.path.join(args.target, "lv_conf.h")
44
45    if not args.defaults:
46        args.defaults = os.path.join(args.target, "lv_conf.defaults")
47
48    if not os.path.exists(args.template):
49        fatal(f"Template file not found at {args.template}")
50    if not os.path.exists(args.config):
51        fatal(f"User config file not found at {args.config}")
52    if not os.path.exists(args.defaults):
53        fatal(f"User defaults not found at {args.defaults}")
54
55    return args
56
57
58def parse_defaults(path: str):
59    defaults = {}
60
61    with open(path, 'r', encoding='utf-8') as file:
62        for line in file.readlines():
63            if len(line.strip()) == 0 or line.startswith('#'):
64                continue
65            groups = re.search(r'([A-Z0-9_]+)\s+(.+)', line).groups()
66            defaults[groups[0]] = groups[1]
67
68    return defaults
69
70
71def generate_config(path_destination: str, path_source: str, defaults: dict):
72    with open(path_source, 'r', encoding='utf-8') as f_src:
73        src_lines = f_src.readlines()
74
75    keys_used = set()
76    dst_lines = []
77
78    for src_line in src_lines:
79        res = re.search(r'#define\s+([A-Z0-9_]+)\s+(.+)', src_line)
80        key = res.groups()[0] if res else None
81
82        if key in defaults.keys():
83            value = defaults[key]
84            pattern = r'(#define\s+[A-Z0-9_]+\s+)(.+)'
85            repl = r'\g<1>' + value
86            dst_line, _ = re.subn(pattern, repl, src_line)
87
88            if not dst_line:
89                fatal(f"Failed to apply key '{key}' to line '{src_line}'")
90
91            print(f"Applying: {key} = {value}")
92            keys_used.add(key)
93        elif 'Set this to "1" to enable content' in src_line:
94            dst_line = '#if 1 /* Enable content */'
95        else:
96            dst_line = src_line
97
98        dst_lines.append(dst_line)
99
100    if len(keys_used) != len(defaults):
101        unused_keys = [k for k in defaults.keys() if k not in keys_used]
102        fatal('The following keys are deprecated:\n  ' + '\n  '.join(unused_keys))
103
104    with open(path_destination, 'w', encoding='utf-8') as f_dst:
105        for dst_line in dst_lines:
106            f_dst.write(dst_line)
107
108
109if __name__ == '__main__':
110    args = get_args()
111
112    print("Template:", args.template)
113    print("User config:", args.config)
114    print("User defaults:", args.defaults)
115
116    defaults = parse_defaults(args.defaults)
117    print(f"Loaded {len(defaults)} defaults")
118
119    generate_config(args.config, args.template, defaults)
120    print()
121    print('New config successfully generated!')
122