diff --git a/ev-dev-tools/src/ev_cli/__init__.py b/ev-dev-tools/src/ev_cli/__init__.py index be4d338..04bbb7b 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.4.2' +__version__ = '0.4.3' diff --git a/ev-dev-tools/src/ev_cli/ev.py b/ev-dev-tools/src/ev_cli/ev.py index c661f5c..b75ed13 100755 --- a/ev-dev-tools/src/ev_cli/ev.py +++ b/ev-dev-tools/src/ev_cli/ev.py @@ -256,13 +256,25 @@ def generate_module_loader_files(rel_mod_dir, output_dir): return loader_files -def generate_module_files(rel_mod_dir, update_flag): +def generate_module_files(rel_mod_dir, update_flag, licenses): (_, _, mod) = rel_mod_dir.rpartition('/') mod_files = {'core': [], 'interfaces': [], 'docs': []} mod_path = work_dir / f'modules/{rel_mod_dir}/manifest.yaml' mod_def = helpers.load_validated_module_def(mod_path, validators['module']) + default_license_dir = Path(__file__).parent / 'licenses' + current_license_dir = work_dir / 'licenses' + additional_license_dir = Path(licenses) + license_dirs = [default_license_dir, current_license_dir, additional_license_dir] + license_url = mod_def['metadata']['license'] + license_header = helpers.get_license_header(license_dirs, license_url) + + if not license_header: + print(f'Could not find license "{license_url}" in {license_dirs}.') + print('Consider providing a additonal custom license directory with --licenses') + exit(1) + tmpl_data = generate_tmpl_data_for_module(mod, mod_def) output_path = mod_path.parent # FIXME (aw): we might move the following function into generate_tmp_data_for_module @@ -362,6 +374,7 @@ def generate_module_files(rel_mod_dir, update_flag): if_tmpl_data['info']['blocks'] = helpers.load_tmpl_blocks( impl_hpp_blocks, output_path / impl_hpp_file, update_flag) + if_tmpl_data['info']['license_header'] = license_header # FIXME (aw): time stamp should include parent interfaces modification dates mod_files['interfaces'].append({ @@ -370,7 +383,8 @@ def generate_module_files(rel_mod_dir, update_flag): '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 + 'last_mtime': last_mtime, + 'license_header': license_header }) mod_files['interfaces'].append({ @@ -379,11 +393,13 @@ def generate_module_files(rel_mod_dir, update_flag): '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 + 'last_mtime': last_mtime, + 'license_header': license_header }) cmakelists_file = output_path / 'CMakeLists.txt' tmpl_data['info']['blocks'] = helpers.load_tmpl_blocks(cmakelists_blocks, cmakelists_file, update_flag) + tmpl_data['info']['license_header'] = license_header mod_files['core'].append({ 'abbr': 'cmakelists', 'path': cmakelists_file, @@ -401,7 +417,8 @@ def generate_module_files(rel_mod_dir, update_flag): '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 + 'last_mtime': mod_path.stat().st_mtime, + 'license_header': license_header }) # module.cpp @@ -411,7 +428,8 @@ def generate_module_files(rel_mod_dir, update_flag): '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 + 'last_mtime': mod_path.stat().st_mtime, + 'license_header': license_header }) # doc.rst @@ -521,7 +539,7 @@ def generate_interface_headers(interface, all_interfaces_flag, output_dir): def module_create(args): create_strategy = 'force-create' if args.force else 'create' - mod_files = generate_module_files(args.module, False) + mod_files = generate_module_files(args.module, False, args.licenses) if args.only == 'which': helpers.print_available_mod_files(mod_files) @@ -551,7 +569,7 @@ def module_update(args): update_strategy[file_name] = primary_update_strategy # FIXME (aw): refactor out this only handling and rename it properly - mod_files = generate_module_files(args.module, True) + mod_files = generate_module_files(args.module, True, args.licenses) if args.only == 'which': helpers.print_available_mod_files(mod_files) @@ -568,13 +586,13 @@ def module_update(args): helpers.clang_format(args.clang_format_file, file_info) for file_info in mod_files['core']: - helpers.write_content_to_file(file_info, update_strategy[file_info['abbr']], args.diff) + helpers.write_content_to_file(file_info, update_strategy[file_info['abbr']], args.diff, '', True) for file_info in mod_files['interfaces']: if file_info['abbr'].endswith('.hpp'): - helpers.write_content_to_file(file_info, primary_update_strategy, args.diff) + helpers.write_content_to_file(file_info, primary_update_strategy, args.diff, '', True) else: - helpers.write_content_to_file(file_info, 'update-if-non-existent', args.diff) + helpers.write_content_to_file(file_info, 'update-if-non-existent', args.diff, '', True) def module_genld(args): @@ -734,6 +752,9 @@ def main(): common_parser.add_argument('--schemas-dir', '-sd', type=str, help='everest framework directory containing the schema definitions (default: ../everest-framework/schemas)', default=str(Path.cwd() / '../everest-framework/schemas')) + common_parser.add_argument('--licenses', '-lc', type=str, + help='license directory from which ev-cli will attempt to parse custom license texts (default ../licenses)', + default=str(Path.cwd() / '../licenses')) common_parser.add_argument('--build-dir', '-bd', type=str, help='everest build directory from which ev-cli will attempt to parse the everest framework schema definitions (default ./build)', default=str(Path.cwd() / 'build')) diff --git a/ev-dev-tools/src/ev_cli/helpers.py b/ev-dev-tools/src/ev_cli/helpers.py index 3bb925f..20a9673 100644 --- a/ev-dev-tools/src/ev_cli/helpers.py +++ b/ev-dev-tools/src/ev_cli/helpers.py @@ -688,7 +688,7 @@ def is_template_newer(file_info) -> Tuple[bool, str]: return (False, '') -def write_content_to_file(file_info, strategy, only_diff=False, reason = ''): +def write_content_to_file(file_info, strategy, only_diff=False, reason = '', check_license_header=False): # strategy: # update: update only if dest older or not existent # force-update: update, even if dest newer @@ -730,6 +730,23 @@ def write_content_to_file(file_info, strategy, only_diff=False, reason = ''): if not file_dir.exists(): file_dir.mkdir(parents=True, exist_ok=True) + # check if file header is different from license header + if check_license_header: + if 'license_header' in file_info: + original_content = file_path.read_text() + if not original_content.startswith(file_info['license_header']): + # determine likely end of license header + search_terms = ['#ifndef', '#pragma once', '#include'] + original_license_header = '' + for search in search_terms: + index = original_content.find(search) + if index >= 0: + original_license_header = original_content[0:index] + break + print(f'Keeping the existing licence header:\n{original_license_header}') + file_info['content'] = file_info['content'].replace( + file_info['license_header'], original_license_header.strip()) + file_path.write_text(file_info['content']) @@ -740,3 +757,21 @@ def write_content_to_file_and_check_template(file_info, strategy, only_diff=Fals if newer: update_strategy = 'force-update' write_content_to_file(file_info, update_strategy, only_diff, reason) + + +def get_license_header(license_dirs, license_url): + url_schemas = ['http://', 'https://'] + for url_schema in url_schemas: + if license_url.startswith(url_schema): + license_url = license_url.replace(url_schema, '', 1) + license_path = None + for license_dir in license_dirs: + check_license_path = license_dir / license_url + print(f'Checking if license "{check_license_path}" exists...') + if check_license_path.exists(): + license_path = check_license_path + + if not license_path: + return None + with open(license_path, 'r') as custom_license_file: + return custom_license_file.read().strip() diff --git a/ev-dev-tools/src/ev_cli/licenses/opensource.org/licenses/Apache-2.0 b/ev-dev-tools/src/ev_cli/licenses/opensource.org/licenses/Apache-2.0 new file mode 100644 index 0000000..754962c --- /dev/null +++ b/ev-dev-tools/src/ev_cli/licenses/opensource.org/licenses/Apache-2.0 @@ -0,0 +1,2 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Pionix GmbH and Contributors to EVerest diff --git a/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 b/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 index 15ce34a..6dc7a31 100644 --- a/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 +++ b/ev-dev-tools/src/ev_cli/templates/helper_macros.j2 @@ -89,6 +89,9 @@ void publish_{{ var.name }}({% if var.json_type != 'null' %}{{ cpp_type(var) }} // Copyright{% if year_tag %} {{ year_tag }}{% endif %} Pionix GmbH and Contributors to EVerest {%- endmacro %} +{% macro print_license_header(license) %} +{{ license }} +{%- endmacro %} {% macro print_template_info(version, title='DO NOT EDIT!', comment_sep='//') %} {{ comment_sep }} diff --git a/ev-dev-tools/src/ev_cli/templates/interface-Impl.cpp.j2 b/ev-dev-tools/src/ev_cli/templates/interface-Impl.cpp.j2 index f4e58e7..cf111df 100644 --- a/ev-dev-tools/src/ev_cli/templates/interface-Impl.cpp.j2 +++ b/ev-dev-tools/src/ev_cli/templates/interface-Impl.cpp.j2 @@ -1,5 +1,5 @@ -{% from "helper_macros.j2" import handle_cmd_signature, print_spdx_line %} -{{ print_spdx_line('Apache-2.0') }} +{% from "helper_macros.j2" import handle_cmd_signature, print_license_header %} +{{ print_license_header(info.license_header) }} #include "{{ info.class_name}}.hpp" diff --git a/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 b/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 index 0023a8b..20650e2 100644 --- a/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 +++ b/ev-dev-tools/src/ev_cli/templates/interface-Impl.hpp.j2 @@ -1,5 +1,5 @@ -{% from "helper_macros.j2" import handle_cmd_signature, print_template_info, insert_block, cpp_type, print_spdx_line %} -{{ print_spdx_line('Apache-2.0') }} +{% from "helper_macros.j2" import handle_cmd_signature, print_template_info, insert_block, cpp_type, print_license_header %} +{{ print_license_header(info.license_header) }} #ifndef {{ info.hpp_guard }} #define {{ info.hpp_guard }} diff --git a/ev-dev-tools/src/ev_cli/templates/module.cpp.j2 b/ev-dev-tools/src/ev_cli/templates/module.cpp.j2 index fa6729b..209c749 100644 --- a/ev-dev-tools/src/ev_cli/templates/module.cpp.j2 +++ b/ev-dev-tools/src/ev_cli/templates/module.cpp.j2 @@ -1,5 +1,5 @@ -{% from "helper_macros.j2" import print_spdx_line %} -{{ print_spdx_line('Apache-2.0') }} +{% from "helper_macros.j2" import print_license_header %} +{{ print_license_header(info.license_header) }} #include "{{ info.module_header }}" namespace module { diff --git a/ev-dev-tools/src/ev_cli/templates/module.hpp.j2 b/ev-dev-tools/src/ev_cli/templates/module.hpp.j2 index 0d076b6..f95967e 100644 --- a/ev-dev-tools/src/ev_cli/templates/module.hpp.j2 +++ b/ev-dev-tools/src/ev_cli/templates/module.hpp.j2 @@ -1,5 +1,5 @@ -{% from "helper_macros.j2" import print_template_info, insert_block, cpp_type, print_spdx_line %} -{{ print_spdx_line('Apache-2.0') }} +{% from "helper_macros.j2" import print_template_info, insert_block, cpp_type, print_license_header %} +{{ print_license_header(info.license_header) }} #ifndef {{ info.hpp_guard }} #define {{ info.hpp_guard }}