diff --git a/ev-dev-tools/src/ev_cli/__init__.py b/ev-dev-tools/src/ev_cli/__init__.py index 4962beba..3e3d5ebe 100644 --- a/ev-dev-tools/src/ev_cli/__init__.py +++ b/ev-dev-tools/src/ev_cli/__init__.py @@ -1,2 +1,2 @@ """EVerest command line utility.""" -__version__ = '0.2.1' +__version__ = '0.3.0' diff --git a/ev-dev-tools/src/ev_cli/ev.py b/ev-dev-tools/src/ev_cli/ev.py index bd10c2bd..aa6269a6 100755 --- a/ev-dev-tools/src/ev_cli/ev.py +++ b/ev-dev-tools/src/ev_cli/ev.py @@ -239,6 +239,7 @@ def generate_module_loader_files(rel_mod_dir, output_dir): 'path': output_dir / mod / 'ld-ev.hpp', 'printable_name': f'{mod}/ld-ev.hpp', 'content': templates['ld-ev.hpp'].render(tmpl_data), + 'template_path': Path(templates['ld-ev.hpp'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -248,6 +249,7 @@ def generate_module_loader_files(rel_mod_dir, output_dir): 'path': output_dir / mod / 'ld-ev.cpp', 'printable_name': f'{mod}/ld-ev.cpp', 'content': templates['ld-ev.cpp'].render(tmpl_data), + 'template_path': Path(templates['ld-ev.cpp'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -367,6 +369,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'path': output_path / impl_hpp_file, 'printable_name': impl_hpp_file, 'content': templates['interface_impl.hpp'].render(if_tmpl_data), + 'template_path': Path(templates['interface_impl.hpp'].filename), 'last_mtime': last_mtime }) @@ -375,6 +378,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'path': output_path / impl_cpp_file, 'printable_name': impl_cpp_file, 'content': templates['interface_impl.cpp'].render(if_tmpl_data), + 'template_path': Path(templates['interface_impl.cpp'].filename), 'last_mtime': last_mtime }) @@ -384,6 +388,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'abbr': 'cmakelists', 'path': cmakelists_file, 'content': templates['cmakelists'].render(tmpl_data), + 'template_path': Path(templates['cmakelists'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -395,6 +400,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'abbr': 'module.hpp', 'path': mod_hpp_file, 'content': templates['module.hpp'].render(tmpl_data), + 'template_path': Path(templates['module.hpp'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -404,6 +410,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'abbr': 'module.cpp', 'path': mod_cpp_file, 'content': templates['module.cpp'].render(tmpl_data), + 'template_path': Path(templates['module.cpp'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -412,6 +419,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'abbr': 'doc.rst', 'path': output_path / 'doc.rst', 'content': templates['doc.rst'].render(tmpl_data), + 'template_path': Path(templates['doc.rst'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -420,6 +428,7 @@ def generate_module_files(rel_mod_dir, update_flag): 'abbr': 'index.rst', 'path': output_path / 'docs' / 'index.rst', 'content': templates['index.rst'].render(tmpl_data), + 'template_path': Path(templates['index.rst'].filename), 'last_mtime': mod_path.stat().st_mtime }) @@ -474,6 +483,7 @@ def generate_interface_headers(interface, all_interfaces_flag, output_dir): if_parts['base'] = { 'path': base_file, 'content': templates['interface_base'].render(tmpl_data), + 'template_path': Path(templates['interface_base'].filename), 'last_mtime': last_mtime, 'printable_name': base_file.relative_to(output_path.parent) } @@ -487,6 +497,7 @@ def generate_interface_headers(interface, all_interfaces_flag, output_dir): if_parts['exports'] = { 'path': exports_file, 'content': templates['interface_exports'].render(tmpl_data), + 'template_path': Path(templates['interface_exports'].filename), 'last_mtime': last_mtime, 'printable_name': exports_file.relative_to(output_path.parent) } @@ -499,6 +510,7 @@ def generate_interface_headers(interface, all_interfaces_flag, output_dir): if_parts['types'] = { 'path': types_file, 'content': templates['types.hpp'].render(tmpl_data), + 'template_path': Path(templates['types.hpp'].filename), 'last_mtime': last_mtime, 'printable_name': types_file.relative_to(output_path.parent) } @@ -576,7 +588,15 @@ def module_genld(args): helpers.clang_format(args.clang_format_file, file_info) for file_info in loader_files: - helpers.write_content_to_file(file_info, 'force-update') + helpers.write_content_to_file_and_check_template(file_info, 'update-if-non-existent') + + +def module_get_templates(args): + interface_files = args.separator.join( + [templates['ld-ev.hpp'].filename, + templates['ld-ev.cpp'].filename]) + + print(f'{interface_files}') def interface_genhdr(args): @@ -607,9 +627,17 @@ def interface_genhdr(args): helpers.clang_format(args.clang_format_file, if_parts['exports']) helpers.clang_format(args.clang_format_file, if_parts['types']) - helpers.write_content_to_file(if_parts['base'], primary_update_strategy, args.diff) - helpers.write_content_to_file(if_parts['exports'], primary_update_strategy, args.diff) - helpers.write_content_to_file(if_parts['types'], primary_update_strategy, args.diff) + helpers.write_content_to_file_and_check_template(if_parts['base'], primary_update_strategy, args.diff) + helpers.write_content_to_file_and_check_template(if_parts['exports'], primary_update_strategy, args.diff) + helpers.write_content_to_file_and_check_template(if_parts['types'], primary_update_strategy, args.diff) + + +def interface_get_templates(args): + interface_files = args.separator.join( + [templates['interface_base'].filename, + templates['interface_exports'].filename]) + + print(f'{interface_files}') def helpers_genuuids(args): @@ -681,7 +709,13 @@ def types_genhdr(args): if not args.disable_clang_format: helpers.clang_format(args.clang_format_file, type_parts['types']) - helpers.write_content_to_file(type_parts['types'], primary_update_strategy, args.diff) + helpers.write_content_to_file_and_check_template(type_parts['types'], primary_update_strategy, args.diff) + + +def types_get_templates(args): + interface_files = templates['types.hpp'].filename + + print(f'{interface_files}') def main(): @@ -779,6 +813,17 @@ def main(): 'will be skipped') types_genhdr_parser.set_defaults(action_handler=types_genhdr) + for sub_parser, get_template_function in [ + (mod_actions, module_get_templates), + (if_actions, interface_get_templates), + (types_actions, types_get_templates) + ]: + get_templates_parser = sub_parser.add_parser( + 'get-templates', aliases=['gt'], parents=[common_parser], help='get paths to template files') + get_templates_parser.add_argument( + '-s', '--separator', type=str, default='\n', help='separator between template files') + get_templates_parser.set_defaults(action_handler=get_template_function) + args = parser.parse_args() if 'everest_dir' in args: diff --git a/ev-dev-tools/src/ev_cli/helpers.py b/ev-dev-tools/src/ev_cli/helpers.py index 0313b2e6..3bb925fe 100644 --- a/ev-dev-tools/src/ev_cli/helpers.py +++ b/ev-dev-tools/src/ev_cli/helpers.py @@ -97,7 +97,6 @@ def primitive_to_sample_value(type): 'object': 'Object', } - def clang_format(config_file_path, file_info): # check if we handle cpp and hpp files if not file_info['path'].suffix in ('.hpp', '.cpp'): @@ -669,8 +668,27 @@ def print_available_mod_files(mod_files): for file_info in category_files: print(f' {file_info["abbr"]}') +def get_mtime(filename: str | Path) -> float: + if isinstance(filename, str): + filename = Path(filename) + + return filename.stat().st_mtime + + +def is_template_newer(file_info) -> Tuple[bool, str]: + template_path = file_info['template_path'] + generated_path = file_info['path'] + + if not generated_path.exists(): + return (True, ' (Generated file did not exist)') -def write_content_to_file(file_info, strategy, only_diff=False): + if get_mtime(template_path) > get_mtime(generated_path): + return (True, ' (Template file has changed since last generation)') + + return (False, '') + + +def write_content_to_file(file_info, strategy, only_diff=False, reason = ''): # strategy: # update: update only if dest older or not existent # force-update: update, even if dest newer @@ -707,9 +725,18 @@ def write_content_to_file(file_info, strategy, only_diff=False): else: raise Exception(f'Invalid strategy "{strategy}"\nSupported strategies: {strategies}') - print(f'{method} file {printable_name}') + print(f'{method} file {printable_name}{reason}') if not file_dir.exists(): file_dir.mkdir(parents=True, exist_ok=True) file_path.write_text(file_info['content']) + + +def write_content_to_file_and_check_template(file_info, strategy, only_diff=False): + # check if template is newer and force-update file if it is + update_strategy = strategy + (newer, reason) = is_template_newer(file_info) + if newer: + update_strategy = 'force-update' + write_content_to_file(file_info, update_strategy, only_diff, reason) diff --git a/ev-dev-tools/src/ev_cli/type_parsing.py b/ev-dev-tools/src/ev_cli/type_parsing.py index 34813490..e0bf59d5 100644 --- a/ev-dev-tools/src/ev_cli/type_parsing.py +++ b/ev-dev-tools/src/ev_cli/type_parsing.py @@ -187,6 +187,7 @@ def generate_type_headers(cls, type_with_namespace, all_types, output_dir): 'path': types_file, 'content': TypeParser.templates['types.hpp'].render(tmpl_data), 'last_mtime': last_mtime, + 'template_path': Path(TypeParser.templates['types.hpp'].filename), 'printable_name': types_file.relative_to(output_path.parent) }