def generate_plugin_template( specs_path: str, caption: str, plugin_id: str, author_email: str, author_name: str, dst_path: Path, ): """ Generate a plugin starting template with the necessary structure and files to create a plugin. SPECS_PATH Path to where the hook_specs.py file is located. CAPTION Caption to be used across the application to identify the plugin. PLUGIN_ID A unique string to identify the plugin. AUTHOR_NAME Name of the plugin author to be displayed. AUTHOR_EMAIL Email of the plugin author to be displayed. """ hm_generator = HookManGenerator(hook_spec_file_path=specs_path) hm_generator.generate_plugin_template( caption=caption, plugin_id=plugin_id, author_email=author_email, author_name=author_name, dst_path=Path(dst_path), ) return 0
def test_generate_plugin_template(datadir, file_regression): plugin_dir = datadir / 'test_generate_plugin_template' hg = HookManGenerator(hook_spec_file_path=Path(datadir / 'hook_specs.py')) hg.generate_plugin_template( caption='Acme', plugin_id='acme', author_name='FOO', author_email='*****@*****.**', dst_path=plugin_dir ) obtained_hook_specs_file = datadir / 'test_generate_plugin_template/acme/src/hook_specs.h' file_regression.check(obtained_hook_specs_file.read_text(), basename='generate_hook_specs', extension='.h') obtained_plugin_yaml = datadir / 'test_generate_plugin_template/acme/assets/plugin.yaml' file_regression.check(obtained_plugin_yaml.read_text(), basename='generate_plugin', extension='.yaml') obtained_plugin_file = datadir / 'test_generate_plugin_template/acme/src/acme.cpp' file_regression.check(obtained_plugin_file.read_text(), basename='generate_plugin', extension='.cpp') obtained_readme = datadir / 'test_generate_plugin_template/acme/assets/README.md' file_regression.check(obtained_readme.read_text(), basename='generate_README', extension='.md') obtained_cmake_list = datadir / 'test_generate_plugin_template/acme/CMakeLists.txt' file_regression.check(obtained_cmake_list.read_text(), basename='generate_CMakeLists', extension='.txt') obtained_cmake_list_src = datadir / 'test_generate_plugin_template/acme/src/CMakeLists.txt' file_regression.check(obtained_cmake_list_src.read_text(), basename='generate_src_CMakeLists', extension='.txt') obtained_compile_script = datadir / 'test_generate_plugin_template/acme/compile.py' file_regression.check(obtained_compile_script.read_text(), basename='generate_compile', extension='.py')
def template(dst, caption, plugin_id, author_name, author_email): r""" Generate a template with the necessary files and structure to create a plugin. The template folder will be placed on the ``dst`` option, that by default is the current directory from where the command was invoked. The files generated and their contents are ready to be used or customized and have the following structure: .. code-block:: bash \---myplugin | CMakeLists.txt | compile.py | +---assets | plugin.yaml | README.md | \---src | CMakeLists.txt | hook_specs.h | myplugin.cpp | \---python myplugin.py """ dst = Path(dst) hook_specs_file_path = _get_hook_specs_file_path() hm = HookManGenerator(hook_spec_file_path=hook_specs_file_path) alfasim_sdk_include = ["<alfasim_sdk_api/alfasim_sdk.h>"] default_impls_for_hooks = [ "HOOK_INITIALIZE(ctx){", " return 0;", "}", "HOOK_FINALIZE(ctx){", " return 0;", "}", ] hm.generate_plugin_template( caption, plugin_id, author_email, author_name, dst, extra_includes=alfasim_sdk_include, extra_body_lines=default_impls_for_hooks, exclude_hooks=["HOOK_FINALIZE", "HOOK_INITIALIZE"], ) source_folder = dst / plugin_id / "src" python_folder = source_folder / "python" python_folder.mkdir() Path(python_folder / f"{plugin_id}.py").touch()
def generate_plugin_template(specs_path: str, plugin_name: str, shared_lib_name: str, author_email: str, author_name: str, dst_path: Path): """Generate a plugin starting template.""" hm_generator = HookManGenerator(hook_spec_file_path=specs_path) hm_generator.generate_plugin_template(plugin_name=plugin_name, shared_lib_name=shared_lib_name, author_email=author_email, author_name=author_name, dst_path=Path(dst_path)) return 0
def test_generate_plugin_package_invalid_version(acme_hook_specs_file, tmp_path, mocker, mock_plugin_id_from_dll): hg = HookManGenerator(hook_spec_file_path=acme_hook_specs_file) plugin_id = 'acme' hg.generate_plugin_template(plugin_id, plugin_id, 'acme1', 'acme2', tmp_path) plugin_yaml = tmp_path / 'acme/assets/plugin.yaml' new_content = plugin_yaml.read_text().replace("version: '1.0.0'", "version: '1'") plugin_yaml.write_text(new_content) mocker.patch('hookman.hookman_generator.HookManGenerator._validate_package_folder', return_value=None) with pytest.raises(ValueError, match="Version attribute does not follow semantic version, got '1'"): hg.generate_plugin_package(plugin_id, plugin_dir=tmp_path / plugin_id)
def test_generate_plugin_template_source_content_with_extra_includes (datadir, file_regression): plugin_dir = datadir / 'test_generate_plugin_template_with_extra_include' hg = HookManGenerator(hook_spec_file_path=Path(datadir / 'hook_specs.py')) hg.generate_plugin_template( caption='Acme', plugin_id='acme', author_name='FOO', author_email='*****@*****.**', dst_path=plugin_dir, extra_includes=['<my_sdk/sdk.h>'], ) obtained_plugin_file = datadir / 'test_generate_plugin_template_with_extra_include/acme/src/acme.cpp' file_regression.check(obtained_plugin_file.read_text(), basename='plugin_file_with_extra_includes', extension='.cpp')
def test_generate_plugin_template(datadir, file_regression): plugin_dir = datadir / "test_generate_plugin_template" hg = HookManGenerator(hook_spec_file_path=Path(datadir / "hook_specs.py")) hg.generate_plugin_template( caption="Acme", plugin_id="acme", author_name="FOO", author_email="*****@*****.**", dst_path=plugin_dir, ) obtained_hook_specs_file = datadir / "test_generate_plugin_template/acme/src/hook_specs.h" file_regression.check( obtained_hook_specs_file.read_text(), basename="generate_hook_specs", extension=".h" ) obtained_plugin_yaml = datadir / "test_generate_plugin_template/acme/assets/plugin.yaml" file_regression.check( obtained_plugin_yaml.read_text(), basename="generate_plugin", extension=".yaml" ) obtained_plugin_file = datadir / "test_generate_plugin_template/acme/src/acme.cpp" file_regression.check( obtained_plugin_file.read_text(), basename="generate_plugin", extension=".cpp" ) obtained_readme = datadir / "test_generate_plugin_template/acme/assets/README.md" file_regression.check(obtained_readme.read_text(), basename="generate_README", extension=".md") obtained_cmake_list = datadir / "test_generate_plugin_template/acme/CMakeLists.txt" file_regression.check( obtained_cmake_list.read_text(), basename="generate_CMakeLists", extension=".txt" ) obtained_cmake_list_src = datadir / "test_generate_plugin_template/acme/src/CMakeLists.txt" file_regression.check( obtained_cmake_list_src.read_text(), basename="generate_src_CMakeLists", extension=".txt" ) obtained_compile_script = datadir / "test_generate_plugin_template/acme/compile.py" file_regression.check( obtained_compile_script.read_text(), basename="generate_compile", extension=".py" )
def test_generate_plugin_package(acme_hook_specs_file, tmpdir, mock_plugin_id_from_dll): hg = HookManGenerator(hook_spec_file_path=acme_hook_specs_file) plugin_id = 'acme' hg.generate_plugin_template( caption='acme', plugin_id='acme', author_email='acme1', author_name='acme2', dst_path=Path(tmpdir) ) plugin_dir = Path(tmpdir) / 'acme' artifacts_dir = plugin_dir / 'artifacts' artifacts_dir.mkdir() import sys shared_lib_name = f"{plugin_id}.dll" if sys.platform == 'win32' else f"lib{plugin_id}.so" shared_lib_path = artifacts_dir / shared_lib_name shared_lib_path.write_text('') hg.generate_plugin_package( package_name='acme', plugin_dir=plugin_dir, ) from hookman.plugin_config import PluginInfo version = PluginInfo(Path(tmpdir / 'acme/assets/plugin.yaml'), None).version win_plugin_name = f"{plugin_id}-{version}-win64.hmplugin" linux_plugin_name = f"{plugin_id}-{version}-linux64.hmplugin" hm_plugin_name = win_plugin_name if sys.platform == 'win32' else linux_plugin_name compressed_plugin = plugin_dir / hm_plugin_name assert compressed_plugin.exists() from zipfile import ZipFile plugin_file_zip = ZipFile(compressed_plugin) list_of_files = [file.filename for file in plugin_file_zip.filelist] assert 'assets/plugin.yaml' in list_of_files assert 'assets/README.md' in list_of_files assert f'artifacts/{shared_lib_name}' in list_of_files
def test_generate_plugin_template(datadir): plugin_dir = datadir / 'test_generate_plugin_template' hg = HookManGenerator(hook_spec_file_path=Path(datadir / 'hook_specs.py')) hg.generate_plugin_template(plugin_name='Acme', shared_lib_name='acme', author_name='FOO', author_email='*****@*****.**', dst_path=plugin_dir) obtained_hook_specs_file = datadir / 'test_generate_plugin_template/acme/src/hook_specs.h' expected_hook_specs_file = datadir / 'test_generate_plugin_template/expected_hook_specs.h' obtained_plugin_yaml = datadir / 'test_generate_plugin_template/acme/assets/plugin.yaml' expected_plugin_yaml = datadir / 'test_generate_plugin_template/expected_plugin.yaml' obtained_plugin_c = datadir / 'test_generate_plugin_template/acme/src/plugin.c' expected_plugin_c = datadir / 'test_generate_plugin_template/expected_plugin.c' obtained_readme = datadir / 'test_generate_plugin_template/acme/assets/README.md' expected_readme = datadir / 'test_generate_plugin_template/expected_readme.md' obtained_cmake_list = datadir / 'test_generate_plugin_template/acme/CMakeLists.txt' expected_cmake_list = datadir / 'test_generate_plugin_template/expected_cmakelists.txt' obtained_cmake_list_src = datadir / 'test_generate_plugin_template/acme/src/CMakeLists.txt' expected_cmake_list_src = datadir / 'test_generate_plugin_template/expected_cmakelists_src.txt' obtained_compile_script = datadir / 'test_generate_plugin_template/acme/compile.py' expected_compile_script = datadir / 'test_generate_plugin_template/expected_compile.py' assert obtained_hook_specs_file.read_text( ) == expected_hook_specs_file.read_text() assert obtained_plugin_yaml.read_text() == expected_plugin_yaml.read_text() assert obtained_plugin_c.read_text() == expected_plugin_c.read_text() assert obtained_readme.read_text() == expected_readme.read_text() assert obtained_cmake_list.read_text() == expected_cmake_list.read_text() assert obtained_compile_script.read_text( ) == expected_compile_script.read_text() assert obtained_cmake_list_src.read_text( ) == expected_cmake_list_src.read_text()
def test_generate_plugin_template_source_content_with_extra_includes(datadir, file_regression): plugin_dir = datadir / "test_generate_plugin_template_with_extra_include" hg = HookManGenerator(hook_spec_file_path=Path(datadir / "hook_specs.py")) hg.generate_plugin_template( caption="Acme", plugin_id="acme", author_name="FOO", author_email="*****@*****.**", dst_path=plugin_dir, extra_includes=["<my_sdk/sdk.h>"], ) obtained_plugin_file = ( datadir / "test_generate_plugin_template_with_extra_include/acme/src/acme.cpp" ) file_regression.check( obtained_plugin_file.read_text(), basename="plugin_file_with_extra_includes", extension=".cpp", )
def test_generate_plugin_package_invalid_shared_lib_name(acme_hook_specs_file, tmpdir): hg = HookManGenerator(hook_spec_file_path=acme_hook_specs_file) from hookman.exceptions import HookmanError with pytest.raises(HookmanError): hg.generate_plugin_template( caption='acme', plugin_id='acm#e', author_email='acme1', author_name='acme2', dst_path=Path(tmpdir) ) with pytest.raises(HookmanError): hg.generate_plugin_template( caption='acme', plugin_id='acm e', author_email='acme1', author_name='acme2', dst_path=Path(tmpdir) ) with pytest.raises(HookmanError): hg.generate_plugin_template( caption='1acme', plugin_id='acm e', author_email='acme1', author_name='acme2', dst_path=Path(tmpdir) )
def test_generate_plugin_package(acme_hook_specs_file, tmpdir): hg = HookManGenerator(hook_spec_file_path=acme_hook_specs_file) hg.generate_plugin_template(plugin_name='acme', shared_lib_name='acme', author_email='acme1', author_name='acme2', dst_path=Path(tmpdir)) plugin_dir = Path(tmpdir) / 'acme' artifacts_dir = plugin_dir / 'artifacts' artifacts_dir.mkdir() import sys if sys.platform == 'win32': shared_lib_name = 'acme.dll' hm_plugin_name = 'acme-win64.hmplugin' else: shared_lib_name = 'libacme.so' hm_plugin_name = 'acme-linux64.hmplugin' test_dll = artifacts_dir / shared_lib_name test_dll.write_text('') hg.generate_plugin_package( package_name='acme', plugin_dir=plugin_dir, ) compressed_plugin = plugin_dir / hm_plugin_name assert compressed_plugin.exists() from zipfile import ZipFile plugin_file_zip = ZipFile(compressed_plugin) list_of_files = [file.filename for file in plugin_file_zip.filelist] assert 'assets/plugin.yaml' in list_of_files assert 'assets/README.md' in list_of_files assert f'artifacts/{shared_lib_name}' in list_of_files
def test_generate_plugin_template_source_content_with_default_impls(datadir, file_regression): plugin_dir = datadir / 'test_generate_plugin_template_source_content_with_default_impls' hg = HookManGenerator(hook_spec_file_path=Path(datadir / 'hook_specs.py')) extra_body_lines = [ 'HOOK_FRICTION_FACTOR(v1, v2)', '{', ' return 0;', '}', ] hg.generate_plugin_template( caption='Acme', plugin_id='acme', author_name='FOO', author_email='*****@*****.**', dst_path=plugin_dir, extra_body_lines=extra_body_lines, exclude_hooks=['HOOK_FRICTION_FACTOR'] ) obtained_plugin_file = datadir / 'test_generate_plugin_template_source_content_with_default_impls/acme/src/acme.cpp' file_regression.check(obtained_plugin_file.read_text(), basename='plugin_file_with_default_impl', extension='.cpp')
def test_generate_plugin_template_source_content_with_default_impls(datadir, file_regression): plugin_dir = datadir / "test_generate_plugin_template_source_content_with_default_impls" hg = HookManGenerator(hook_spec_file_path=Path(datadir / "hook_specs.py")) extra_body_lines = ["HOOK_FRICTION_FACTOR(v1, v2)", "{", " return 0;", "}"] hg.generate_plugin_template( caption="Acme", plugin_id="acme", author_name="FOO", author_email="*****@*****.**", dst_path=plugin_dir, extra_body_lines=extra_body_lines, exclude_hooks=["HOOK_FRICTION_FACTOR"], ) obtained_plugin_file = ( datadir / "test_generate_plugin_template_source_content_with_default_impls/acme/src/acme.cpp" ) file_regression.check( obtained_plugin_file.read_text(), basename="plugin_file_with_default_impl", extension=".cpp" )
def test_generate_plugin_package(acme_hook_specs_file, tmpdir, mock_plugin_id_from_dll): hg = HookManGenerator(hook_spec_file_path=acme_hook_specs_file) plugin_id = "acme" hg.generate_plugin_template( caption="acme", plugin_id="acme", author_email="acme1", author_name="acme2", dst_path=Path(tmpdir), extras={"key": "override", "key2": "value2"}, ) plugin_dir = Path(tmpdir) / "acme" artifacts_dir = plugin_dir / "artifacts" artifacts_dir.mkdir() import sys shared_lib_name = f"{plugin_id}.dll" if sys.platform == "win32" else f"lib{plugin_id}.so" shared_lib_path = artifacts_dir / shared_lib_name shared_lib_path.write_text("") hg.generate_plugin_package( package_name="acme", plugin_dir=plugin_dir, extras_defaults={"key": "default", "key3": "default"}, ) from hookman.plugin_config import PluginInfo version = PluginInfo(Path(tmpdir / "acme/assets/plugin.yaml"), None).version win_plugin_name = f"{plugin_id}-{version}-win64.hmplugin" linux_plugin_name = f"{plugin_id}-{version}-linux64.hmplugin" hm_plugin_name = win_plugin_name if sys.platform == "win32" else linux_plugin_name compressed_plugin = plugin_dir / hm_plugin_name assert compressed_plugin.exists() from zipfile import ZipFile plugin_file_zip = ZipFile(compressed_plugin) list_of_files = [file.filename for file in plugin_file_zip.filelist] assert "assets/plugin.yaml" in list_of_files assert "assets/README.md" in list_of_files assert f"artifacts/{shared_lib_name}" in list_of_files with plugin_file_zip.open("assets/plugin.yaml", "r") as f: contents = f.read().decode("utf-8") from textwrap import dedent assert contents == dedent( """\ author: acme2 caption: acme email: acme1 id: acme version: 1.0.0 extras: key: override key2: value2 key3: default """ )