#!/usr/bin/env python3 # Copyright (c) 2023 Egor Tensin # This file is part of the "cimple" project. # For details, see https://github.com/egor-tensin/cimple. # Distributed under the MIT License. import argparse from contextlib import contextmanager from glob import glob import os import sys class Generator: def __init__(self, fd, dir): self.fd = fd if not os.path.isdir(dir): raise RuntimeError("must be a directory: " + dir) self.dir = os.path.abspath(dir) self.name = os.path.basename(self.dir) def write(self, line): self.fd.write(f"{line}\n") def do(self): self.include_guard_start() self.include_sql_files() self.include_guard_end() def include_guard_start(self): self.write(f"#ifndef __{self.name.upper()}_SQL_H__") self.write(f"#define __{self.name.upper()}_SQL_H__") self.write("") def include_guard_end(self): self.write("") self.write(f"#endif") def enum_sql_files(self): return [ os.path.join(self.dir, path) for path in sorted(glob("*.sql", root_dir=self.dir)) ] @property def var_name_prefix(self): return f"{self.name}" def sql_file_to_var_name(self, path): name = os.path.splitext(os.path.basename(path))[0] return f"{self.var_name_prefix}_schema_{name}" @staticmethod def sql_file_to_string_literal(path): with open(path) as fd: sql = fd.read() sql = sql.encode().hex().upper() sql = "".join((f"\\x{sql[i:i + 2]}" for i in range(0, len(sql), 2))) return sql def include_sql_files(self): vars = [] for path in self.enum_sql_files(): name = self.sql_file_to_var_name(path) vars.append(name) value = self.sql_file_to_string_literal(path) self.write(f'static const char *const {name} = "{value}";') self.write("") self.write(f"static const char *const {self.var_name_prefix}_schemas[] = {{") for var in vars: self.write(f"\t{var},") self.write("};") @contextmanager def open_output(path): if path is None: yield sys.stdout else: path = os.path.abspath(path) os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, "w") as fd: yield fd def parse_args(argv=None): if argv is None: argv = sys.argv[1:] parser = argparse.ArgumentParser() parser.add_argument("-o", "--output", metavar="PATH", help="set output file path") parser.add_argument("dir", metavar="INPUT_DIR", help="input directory") return parser.parse_args() def main(argv=None): args = parse_args(argv) with open_output(args.output) as fd: generator = Generator(fd, args.dir) generator.do() if __name__ == "__main__": main()