From 83b04f9f14491576bfac774a576d26ac6791b8e0 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Mon, 26 Aug 2024 07:01:04 -0700 Subject: [PATCH 01/12] initial idea --- PluginGenerator/generator.py | 130 ++++++++++++++++++ PluginGenerator/plugin.txt | 14 ++ PluginGenerator/templates/module_cpp_file.txt | 5 + .../templates/module_header_template.txt | 12 ++ PluginGenerator/templates/plugin.conf.in | 1 + PluginGenerator/templates/plugin_cmake.txt | 1 + .../templates/plugin_header_template.txt | 46 +++++++ 7 files changed, 209 insertions(+) create mode 100755 PluginGenerator/generator.py create mode 100644 PluginGenerator/plugin.txt create mode 100644 PluginGenerator/templates/module_cpp_file.txt create mode 100644 PluginGenerator/templates/module_header_template.txt create mode 100644 PluginGenerator/templates/plugin.conf.in create mode 100644 PluginGenerator/templates/plugin_cmake.txt create mode 100644 PluginGenerator/templates/plugin_header_template.txt diff --git a/PluginGenerator/generator.py b/PluginGenerator/generator.py new file mode 100755 index 0000000..688336d --- /dev/null +++ b/PluginGenerator/generator.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +''' +- thunder version (not in the first version as it will only support Thunder R5.0). But we also need to take into account generated skeleton the code could be slightly different for future Thunder versions. +- plugin name +- COMRPC interface (if any) +- json rpc interface (header names required) +- Does the plugin require the possibility to run OOP +- does the plugin use JSONRPC events ? +- does the plugin specific configuration options (is configuration code needed)? +- other plugin access required (use new PluginSmartInterfaceType type for this) +- compile time implementation differentiation needed (e.g. like DisplayInfo) +- special trace categories required (create new category for this plugin) +- subsystems support needed (dependend en set) +- needs workerpool jobs (scheduled or not), so we can generate an example job + +''' +import os + +class PluginGenerator: + + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + self.plugin_name = plugin_name + self.comrpc_interfaces = comrpc_interface if comrpc_interface else [] + self.jsonrpc_interfaces = jsonrpc_interface if jsonrpc_interface else [] + self.run_oop = run_oop + self.json_events = json_events + self.map_of_keyword = {} + + def load_template(self, template_name): + with open(template_name, 'r') as template_file: + return template_file + + def generate_header(self, template_path, output_path): + pass + + def generate_plugin(self): + ''' + Generate the following: + - Module .h/.cpp + - Plugin .h/.cpp + - OOP implementation .cpp + - Plugin .conf.in + - CMake .txt + - Plugin .json + ''' + + os.makedirs("HelloWorld", exist_ok=True) + + def add_includes(self): + + includes = [] + + for jsonrpc in self.jsonrpc_interface: + includes.append(f'#include ') + + for comrpc in self.comrpc_interface: + includes.append(f'#include ') + + return '\n'.join(includes) + + def add_inherited_classes(self): + + # TODO: Implement differentiation between filetypes + # Implement indent multiplier + + inhertance = '' + if comrpc_interface: + first_inheritance = f'public {self.comrpc_interfaces[0]}' + if len(first_inheritance > 1): + for inherited_class in self.comrpc_interfaces[1:]: + next_inheritance = "\n".join(f" public {inherited_class}") + inhertance = f'{first_inheritance}, {next_inheritance}' + else: + inheritance = f": {first_inheritance}" + return inheritance + + def add_inherited_methods(self): + pass + + def add_thunder_license(self): + return "ADD_THUNDER_LICENSE" + + def add_forward_declarations(self): + pass + + def add_plugin_methods(self): + pass + + def add_interface_entry(self): + + pass + + def add_interface_aggregate(self): + + if(run_oop == True): + + else: + pass + + def add_data_members(self): + pass + + def map_of_keywords(self): + + self.map_of_keywords = { + '{{THUNDER_LICENSE}}' : self.add_thunder_license(), + '{{PLUGIN_NAME}}' : self.plugin_name, + '{{INCLUDE}}' : self.add_includes(), + '{{FORWARD_DECLARATIONS}}' : self.add_forward_declarations(), + '{{INHERITED_CLASS}}' : self.add_inherited_classes(), + '{{INHERITED_METHOD}}' : self.add_inherited_methods(), + '{{PLUGIN_METHOD}}' : self.add_plugin_methods(), + '{{INTERFACE_ENTRY}}' : self.add_interface_entry(), + '{{INTERFACE_AGGREGATE}}' : self.add_interface_aggregate(), + '{{DATA_MEMBERS}}' : self.add_data_members() + } + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# + + +plugin_name = "HelloWorld" +comrpc_interface = ["COMRPC1", "COMRPC2"] +jsonrpc_interface = ["JSONRPC1", "JSONRPC2"] +run_oop = True +jsonrpc_events = True + + +print("hello world") + diff --git a/PluginGenerator/plugin.txt b/PluginGenerator/plugin.txt new file mode 100644 index 0000000..3b1335b --- /dev/null +++ b/PluginGenerator/plugin.txt @@ -0,0 +1,14 @@ +# NOTE: THIS FILE IS READ ONLY AND SHOULD NOT BE EDITED +# THIS FILE SERVES AS AN EXAMPLE TEMPLATE TO FILL IN +# +# +# +# GUIDE: +# 1. ANSWER ALL QUESTIONS ACCORDINGLY TO HOW THEY ARE FORMATTED +# 2. ANY ANSWERS WITH A PREFIX '#' WILL BE IGNORED +# +# +# 1. WHAT IS THE PLUGIN NAME? +["HelloWorld"] +# 2. LIST ANY COMRPC INTERFACES: +[{"PluginHost","path/to/PluginHost"},{"IBlueTooth","path/to/Bluetooth"}] \ No newline at end of file diff --git a/PluginGenerator/templates/module_cpp_file.txt b/PluginGenerator/templates/module_cpp_file.txt new file mode 100644 index 0000000..c322043 --- /dev/null +++ b/PluginGenerator/templates/module_cpp_file.txt @@ -0,0 +1,5 @@ +{{THUNDER_LICENSE}} + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/templates/module_header_template.txt b/PluginGenerator/templates/module_header_template.txt new file mode 100644 index 0000000..c0823f8 --- /dev/null +++ b/PluginGenerator/templates/module_header_template.txt @@ -0,0 +1,12 @@ +{{THUNDER_LICENSE}} + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME {MODULE_PLUGIN_NAME} +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/templates/plugin.conf.in b/PluginGenerator/templates/plugin.conf.in new file mode 100644 index 0000000..49bfb5e --- /dev/null +++ b/PluginGenerator/templates/plugin.conf.in @@ -0,0 +1 @@ +startmode = ... \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_cmake.txt b/PluginGenerator/templates/plugin_cmake.txt new file mode 100644 index 0000000..1915fff --- /dev/null +++ b/PluginGenerator/templates/plugin_cmake.txt @@ -0,0 +1 @@ +to do.. \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_header_template.txt b/PluginGenerator/templates/plugin_header_template.txt new file mode 100644 index 0000000..c0f2550 --- /dev/null +++ b/PluginGenerator/templates/plugin_header_template.txt @@ -0,0 +1,46 @@ +{{THUNDER_LICENSE}} + +#pragma once + +{{INCLUDE}} + +{{FORWARD DECLARATIONS}} + +namespace Thunder { +namespace Plugin { + + class {{PLUGIN_NAME}} : public {{INHERITED_CLASS}} { + public: + {{PLUGIN_NAME}}(const {{PLUGIN_NAME}}&) = delete; + {{PLUGIN_NAME}} &operator=(const {{PLUGIN_NAME}}&) = delete; + + {{PLUGIN_NAME}}() : + {{CONSTRUCTOR_VALUES}} + { + + } + + ~{{PLUGIN_NAME}} override + { + + } + + {{NESTED_CLASS}} + + // Inherited Methods + {INHERITED_METHOD} + + // Plugin Methods + {PLUGIN_METHOD} + + BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) + {{INTERFACE_ENTRY}} + {{INTERFACE_AGGREGATE}} + END_INTERFACE_MAP + + private: + + {{DATA_MEMBERS}} + }; +} +} From da147d98bab92f7337cf5b87259d6efd4e54ce12 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Tue, 27 Aug 2024 06:58:19 -0700 Subject: [PATCH 02/12] inital source file build --- PluginGenerator/HelloWorld/HelloWorld.cpp | 27 ++++ PluginGenerator/HelloWorld/HelloWorld.h | 53 +++++++ PluginGenerator/HelloWorld/Module.cpp | 5 + PluginGenerator/HelloWorld/Module.h | 12 ++ PluginGenerator/blueprint_data.py | 130 +++++++++++++++++ PluginGenerator/generator.py | 131 +++++++----------- PluginGenerator/plugin.txt | 2 +- .../templates/module_header_template.txt | 2 +- .../templates/plugin_header_template.txt | 4 +- .../templates/plugin_source_template.txt | 27 ++++ 10 files changed, 308 insertions(+), 85 deletions(-) create mode 100644 PluginGenerator/HelloWorld/HelloWorld.cpp create mode 100644 PluginGenerator/HelloWorld/HelloWorld.h create mode 100644 PluginGenerator/HelloWorld/Module.cpp create mode 100644 PluginGenerator/HelloWorld/Module.h create mode 100644 PluginGenerator/blueprint_data.py create mode 100644 PluginGenerator/templates/plugin_source_template.txt diff --git a/PluginGenerator/HelloWorld/HelloWorld.cpp b/PluginGenerator/HelloWorld/HelloWorld.cpp new file mode 100644 index 0000000..07e0123 --- /dev/null +++ b/PluginGenerator/HelloWorld/HelloWorld.cpp @@ -0,0 +1,27 @@ +ADD_THUNDER_LICENSE + +#include "HelloWorld".h + +namespace Thunder{ +namespace Plugin{ + + namespace { + + static Metadata<{{PLUGIN_NAME}}> metadata( + // Version + 1, 0, 0, + // Preconditions + {conditions} + // Terminations + {terminations} + // Controls + {controls} + ) + } + +test method + +test inherited method + +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginGenerator/HelloWorld/HelloWorld.h b/PluginGenerator/HelloWorld/HelloWorld.h new file mode 100644 index 0000000..1c17ee5 --- /dev/null +++ b/PluginGenerator/HelloWorld/HelloWorld.h @@ -0,0 +1,53 @@ +ADD_THUNDER_LICENSE + +#pragma once + +#include +#include +#include +#include + +{{FORWARD DECLARATIONS}} + +namespace Thunder { +namespace Plugin { + + class HelloWorld : public COMRPC1,public COMRPC2 { + public: + HelloWorld(const HelloWorld&) = delete; + HelloWorld &operator=(const HelloWorld&) = delete; + + HelloWorld() : + {{CONSTRUCTOR_VALUES}} + { + + } + + ~HelloWorld override + { + + } + + {{NESTED_CLASS}} + + // Inherited Methods + void COMRPC1Method1() override; +void COMRPC1Method2() override; +void COMRPC2Method1() override; +void COMRPC2Method2() override; + + // Plugin Methods + void HelloWorldMethod(1); + + BEGIN_INTERFACE_MAP(HelloWorld) + INTERFACE_ENTRY(COMRPC1) +INTERFACE_ENTRY(COMRPC2) + + END_INTERFACE_MAP + + private: + + DATA_MEMBER + }; +} +} diff --git a/PluginGenerator/HelloWorld/Module.cpp b/PluginGenerator/HelloWorld/Module.cpp new file mode 100644 index 0000000..af44534 --- /dev/null +++ b/PluginGenerator/HelloWorld/Module.cpp @@ -0,0 +1,5 @@ +ADD_THUNDER_LICENSE + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/HelloWorld/Module.h b/PluginGenerator/HelloWorld/Module.h new file mode 100644 index 0000000..fd92b82 --- /dev/null +++ b/PluginGenerator/HelloWorld/Module.h @@ -0,0 +1,12 @@ +ADD_THUNDER_LICENSE + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_HelloWorld +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/blueprint_data.py b/PluginGenerator/blueprint_data.py new file mode 100644 index 0000000..bc9c2e6 --- /dev/null +++ b/PluginGenerator/blueprint_data.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +class BlueprintData: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + self.plugin_name = plugin_name + self.comrpc_interfaces = comrpc_interfaces if comrpc_interfaces else [] + self.jsonrpc_interfaces = jsonrpc_interfaces if jsonrpc_interfaces else [] + self.run_oop = run_oop + self.json_events = json_events + + self.keywords = {} + + + def generate_thunder_license(self): + return "ADD_THUNDER_LICENSE" + + def generate_inherited_methods(self): + raise NotImplementedError("Method: generate_inherited_methods not implemented for class") + + def generate_plugin_methods(self): + raise NotImplementedError("Method: generate_plugin_methods not implemented for class") + + +class HeaderData(BlueprintData): + + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) + self.keywords = self.generate_keywords_map() + + def generate_include_statements(self): + includes = [] + + for jsonrpc in self.jsonrpc_interfaces: + includes.append(f'#include ') + + for comrpc in self.comrpc_interfaces: + includes.append(f'#include ') + + return '\n'.join(includes) + + def generate_inherited_classes(self): + + # TODO: Implement differentiation between filetypes + # Implement indent multiplier + + if not self.comrpc_interfaces: + return '' + + inheritance = [f'{self.comrpc_interfaces[0]}'] + + for inherited_class in self.comrpc_interfaces[1:]: + inheritance.append(f'public {inherited_class}') + + all_inheritance = ','.join(inheritance) + return all_inheritance + + def generate_inherited_methods(self): + methods = [] + for inherited in self.comrpc_interfaces: + method1 = f'void {inherited}Method1() override;' + method2 = f'void {inherited}Method2() override;' + methods.extend([method1,method2]) + return '\n'.join(methods) + + def generate_plugin_methods(self): + method = f'void {self.plugin_name}Method(1);' + return method + + def generate_interface_entry(self): + + entries = [] + for comrpc in self.comrpc_interfaces: + entry = f'INTERFACE_ENTRY({comrpc})' + entries.append(entry) + return '\n'.join(entries) + + def generate_interface_aggregate(self): + + return " " + + def generate_data_members(self): + return 'DATA_MEMBER' + + def generate_module_plugin_name(self): + return f'Plugin_{self.plugin_name}' + + def generate_forward_declarations(self): + return " " + + def generate_keywords_map(self): + return { + '{{THUNDER_LICENSE}}' : self.generate_thunder_license(), + '{{PLUGIN_NAME}}' : self.plugin_name, + '{{INCLUDE}}' : self.generate_include_statements(), + '{{FORWARD_DECLARATIONS}}' : self.generate_forward_declarations(), + '{{INHERITED_CLASS}}' : self.generate_inherited_classes(), + '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), + '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), + '{{INTERFACE_ENTRY}}' : self.generate_interface_entry(), + '{{INTERFACE_AGGREGATE}}' : self.generate_interface_aggregate(), + '{{DATA_MEMBERS}}' : self.generate_data_members(), + '{{MODULE_PLUGIN_NAME}}' : self.generate_module_plugin_name() + } + +class SourceData(BlueprintData): + + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) + self.keywords = self.generate_keywords_map() + + def generate_include_statements(self): + return f'#include "{self.plugin_name}".h' + + def generate_plugin_methods(self): + return "test method" + + def generate_inherited_methods(self): + return "test inherited method" + + def generate_keywords_map(self): + return { + '{{THUNDER_LICENSE}}' : self.generate_thunder_license(), + '{{INCLUDE}}' : self.generate_include_statements(), + '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), + '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), + '{{PRECONDITIONS}}' : "conditions", + '{{TERMINATIONS}}' : "terminations", + '{{CONTROLS}}' : "controls" + + } \ No newline at end of file diff --git a/PluginGenerator/generator.py b/PluginGenerator/generator.py index 688336d..a896b57 100755 --- a/PluginGenerator/generator.py +++ b/PluginGenerator/generator.py @@ -16,22 +16,47 @@ ''' import os +from blueprint_data import BlueprintData, HeaderData, SourceData + + +header_template_paths = [] class PluginGenerator: - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: - self.plugin_name = plugin_name - self.comrpc_interfaces = comrpc_interface if comrpc_interface else [] - self.jsonrpc_interfaces = jsonrpc_interface if jsonrpc_interface else [] - self.run_oop = run_oop - self.json_events = json_events - self.map_of_keyword = {} + def __init__(self, blueprint_data) -> None: + self.blueprint_data = blueprint_data + self.directory = self.blueprint_data.plugin_name + os.makedirs(self.blueprint_data.plugin_name, exist_ok=True) def load_template(self, template_name): - with open(template_name, 'r') as template_file: - return template_file + try: + with open(template_name, 'r') as template_file: + return template_file.read() + except FileNotFoundError: + print("no file") + return None - def generate_header(self, template_path, output_path): + def generate_file(self, template_path, output_path): + + template = self.load_template(template_path) + + if template: + + code = self.replace_code(template) + header_path = os.path.join(self.directory, output_path) + + with open(header_path, 'w') as f: + f.write(code) + + def generate_source(self): + + self.generate_file("templates/plugin_source_template.txt", f'{self.blueprint_data.plugin_name}.cpp') + self.generate_file("templates/module_cpp_file.txt", "Module.cpp") + pass + + def generate_headers(self): + self.generate_file("templates/plugin_header_template.txt", f'{self.blueprint_data.plugin_name}.h') + self.generate_file("templates/module_header_template.txt", "Module.h") pass def generate_plugin(self): @@ -44,87 +69,31 @@ def generate_plugin(self): - CMake .txt - Plugin .json ''' - - os.makedirs("HelloWorld", exist_ok=True) - - def add_includes(self): - - includes = [] - - for jsonrpc in self.jsonrpc_interface: - includes.append(f'#include ') - - for comrpc in self.comrpc_interface: - includes.append(f'#include ') - - return '\n'.join(includes) - - def add_inherited_classes(self): - - # TODO: Implement differentiation between filetypes - # Implement indent multiplier - - inhertance = '' - if comrpc_interface: - first_inheritance = f'public {self.comrpc_interfaces[0]}' - if len(first_inheritance > 1): - for inherited_class in self.comrpc_interfaces[1:]: - next_inheritance = "\n".join(f" public {inherited_class}") - inhertance = f'{first_inheritance}, {next_inheritance}' - else: - inheritance = f": {first_inheritance}" - return inheritance - - def add_inherited_methods(self): - pass - - def add_thunder_license(self): - return "ADD_THUNDER_LICENSE" - - def add_forward_declarations(self): - pass - - def add_plugin_methods(self): - pass - - def add_interface_entry(self): - - pass - - def add_interface_aggregate(self): - - if(run_oop == True): - - else: pass - def add_data_members(self): - pass + def replace_code(self,template): + code = template + data = self.blueprint_data.keywords + for keyword, value in data.items(): + code = code.replace(keyword,value) + return code - def map_of_keywords(self): - - self.map_of_keywords = { - '{{THUNDER_LICENSE}}' : self.add_thunder_license(), - '{{PLUGIN_NAME}}' : self.plugin_name, - '{{INCLUDE}}' : self.add_includes(), - '{{FORWARD_DECLARATIONS}}' : self.add_forward_declarations(), - '{{INHERITED_CLASS}}' : self.add_inherited_classes(), - '{{INHERITED_METHOD}}' : self.add_inherited_methods(), - '{{PLUGIN_METHOD}}' : self.add_plugin_methods(), - '{{INTERFACE_ENTRY}}' : self.add_interface_entry(), - '{{INTERFACE_AGGREGATE}}' : self.add_interface_aggregate(), - '{{DATA_MEMBERS}}' : self.add_data_members() - } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# - plugin_name = "HelloWorld" comrpc_interface = ["COMRPC1", "COMRPC2"] jsonrpc_interface = ["JSONRPC1", "JSONRPC2"] -run_oop = True +run_oop = False jsonrpc_events = True +#blueprint_data = BlueprintData(plugin_name, comrpc_interface, jsonrpc_interface, run_oop, jsonrpc_events) +header_data = HeaderData(plugin_name, comrpc_interface, jsonrpc_interface, run_oop, jsonrpc_events) +source_data = SourceData(plugin_name, comrpc_interface, jsonrpc_interface, run_oop, jsonrpc_events) + +plugin_generator = PluginGenerator(header_data) +plugin_generator.generate_headers() -print("hello world") +plugin_generator.blueprint_data = source_data +plugin_generator.generate_source() diff --git a/PluginGenerator/plugin.txt b/PluginGenerator/plugin.txt index 3b1335b..b711fb9 100644 --- a/PluginGenerator/plugin.txt +++ b/PluginGenerator/plugin.txt @@ -1,5 +1,5 @@ # NOTE: THIS FILE IS READ ONLY AND SHOULD NOT BE EDITED -# THIS FILE SERVES AS AN EXAMPLE TEMPLATE TO FILL IN +# THIS FILE SERVES AS AN EXAMPLE TEMPLATE # # # diff --git a/PluginGenerator/templates/module_header_template.txt b/PluginGenerator/templates/module_header_template.txt index c0823f8..378b56d 100644 --- a/PluginGenerator/templates/module_header_template.txt +++ b/PluginGenerator/templates/module_header_template.txt @@ -3,7 +3,7 @@ #pragma once #ifndef MODULE_NAME -#define MODULE_NAME {MODULE_PLUGIN_NAME} +#define MODULE_NAME {{MODULE_PLUGIN_NAME}} #endif #include diff --git a/PluginGenerator/templates/plugin_header_template.txt b/PluginGenerator/templates/plugin_header_template.txt index c0f2550..f8b27d6 100644 --- a/PluginGenerator/templates/plugin_header_template.txt +++ b/PluginGenerator/templates/plugin_header_template.txt @@ -28,10 +28,10 @@ namespace Plugin { {{NESTED_CLASS}} // Inherited Methods - {INHERITED_METHOD} + {{INHERITED_METHOD}} // Plugin Methods - {PLUGIN_METHOD} + {{PLUGIN_METHOD}} BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) {{INTERFACE_ENTRY}} diff --git a/PluginGenerator/templates/plugin_source_template.txt b/PluginGenerator/templates/plugin_source_template.txt new file mode 100644 index 0000000..9f7ab83 --- /dev/null +++ b/PluginGenerator/templates/plugin_source_template.txt @@ -0,0 +1,27 @@ +{{THUNDER_LICENSE}} + +{{INCLUDE}} + +namespace Thunder{ +namespace Plugin{ + + namespace { + + static Metadata<{{PLUGIN_NAME}}> metadata( + // Version + 1, 0, 0, + // Preconditions + {{{PRECONDITIONS}}} + // Terminations + {{{TERMINATIONS}}} + // Controls + {{{CONTROLS}}} + ) + } + +{{PLUGIN_METHOD}} + +{{INHERITED_METHOD}} + +} // Plugin +} // Thunder \ No newline at end of file From 9f7a92bde4b5009e1df32063d792544c966576cd Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Thu, 29 Aug 2024 03:33:11 -0700 Subject: [PATCH 03/12] working oop --- PluginGenerator/HelloWorld/HelloWorld.cpp | 27 ---- PluginGenerator/HelloWorld/HelloWorld.h | 53 ------- PluginGenerator/HelloWorld/Module.cpp | 5 - PluginGenerator/HelloWorld/Module.h | 12 -- PluginGenerator/blueprint_data.py | 137 ++++++++++++++---- .../examples/HelloWorld/CMakeLists.txt | 65 +++++++++ .../examples/HelloWorld/HelloWorld.conf.in | 1 + .../examples/HelloWorld/HelloWorld.cpp | 42 ++++++ .../examples/HelloWorld/HelloWorld.h | 55 +++++++ .../HelloWorld/HelloWorldImplementation.cpp | 49 +++++++ .../examples/HelloWorld/Module.cpp | 22 +++ PluginGenerator/examples/HelloWorld/Module.h | 29 ++++ .../examples/HelloWorldNotOOP/CMakeLists.txt | 63 ++++++++ .../HelloWorldNotOOP/HelloWorldNotOOP.conf.in | 1 + .../HelloWorldNotOOP/HelloWorldNotOOP.cpp | 42 ++++++ .../HelloWorldNotOOP/HelloWorldNotOOP.h | 56 +++++++ .../examples/HelloWorldNotOOP/Module.cpp | 22 +++ .../examples/HelloWorldNotOOP/Module.h | 29 ++++ PluginGenerator/generator.py | 107 +++++++++----- PluginGenerator/helper.py | 37 +++++ PluginGenerator/plugin.txt | 14 -- PluginGenerator/templates/cmake.txt | 63 ++++++++ .../templates/module/module_header.txt | 29 ++++ .../templates/module/module_source.txt | 22 +++ PluginGenerator/templates/module_cpp_file.txt | 5 - .../templates/module_header_template.txt | 12 -- PluginGenerator/templates/plugin.conf.in | 1 - PluginGenerator/templates/plugin_cmake.txt | 1 - PluginGenerator/templates/plugin_conf_in.txt | 1 + PluginGenerator/templates/plugin_header.txt | 55 +++++++ .../templates/plugin_header_template.txt | 46 ------ .../templates/plugin_implementation.txt | 49 +++++++ PluginGenerator/templates/plugin_source.txt | 42 ++++++ .../templates/plugin_source_template.txt | 27 ---- 34 files changed, 952 insertions(+), 269 deletions(-) delete mode 100644 PluginGenerator/HelloWorld/HelloWorld.cpp delete mode 100644 PluginGenerator/HelloWorld/HelloWorld.h delete mode 100644 PluginGenerator/HelloWorld/Module.cpp delete mode 100644 PluginGenerator/HelloWorld/Module.h create mode 100644 PluginGenerator/examples/HelloWorld/CMakeLists.txt create mode 100644 PluginGenerator/examples/HelloWorld/HelloWorld.conf.in create mode 100644 PluginGenerator/examples/HelloWorld/HelloWorld.cpp create mode 100644 PluginGenerator/examples/HelloWorld/HelloWorld.h create mode 100644 PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp create mode 100644 PluginGenerator/examples/HelloWorld/Module.cpp create mode 100644 PluginGenerator/examples/HelloWorld/Module.h create mode 100644 PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt create mode 100644 PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in create mode 100644 PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp create mode 100644 PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h create mode 100644 PluginGenerator/examples/HelloWorldNotOOP/Module.cpp create mode 100644 PluginGenerator/examples/HelloWorldNotOOP/Module.h create mode 100644 PluginGenerator/helper.py delete mode 100644 PluginGenerator/plugin.txt create mode 100644 PluginGenerator/templates/cmake.txt create mode 100644 PluginGenerator/templates/module/module_header.txt create mode 100644 PluginGenerator/templates/module/module_source.txt delete mode 100644 PluginGenerator/templates/module_cpp_file.txt delete mode 100644 PluginGenerator/templates/module_header_template.txt delete mode 100644 PluginGenerator/templates/plugin.conf.in delete mode 100644 PluginGenerator/templates/plugin_cmake.txt create mode 100644 PluginGenerator/templates/plugin_conf_in.txt create mode 100644 PluginGenerator/templates/plugin_header.txt delete mode 100644 PluginGenerator/templates/plugin_header_template.txt create mode 100644 PluginGenerator/templates/plugin_implementation.txt create mode 100644 PluginGenerator/templates/plugin_source.txt delete mode 100644 PluginGenerator/templates/plugin_source_template.txt diff --git a/PluginGenerator/HelloWorld/HelloWorld.cpp b/PluginGenerator/HelloWorld/HelloWorld.cpp deleted file mode 100644 index 07e0123..0000000 --- a/PluginGenerator/HelloWorld/HelloWorld.cpp +++ /dev/null @@ -1,27 +0,0 @@ -ADD_THUNDER_LICENSE - -#include "HelloWorld".h - -namespace Thunder{ -namespace Plugin{ - - namespace { - - static Metadata<{{PLUGIN_NAME}}> metadata( - // Version - 1, 0, 0, - // Preconditions - {conditions} - // Terminations - {terminations} - // Controls - {controls} - ) - } - -test method - -test inherited method - -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginGenerator/HelloWorld/HelloWorld.h b/PluginGenerator/HelloWorld/HelloWorld.h deleted file mode 100644 index 1c17ee5..0000000 --- a/PluginGenerator/HelloWorld/HelloWorld.h +++ /dev/null @@ -1,53 +0,0 @@ -ADD_THUNDER_LICENSE - -#pragma once - -#include -#include -#include -#include - -{{FORWARD DECLARATIONS}} - -namespace Thunder { -namespace Plugin { - - class HelloWorld : public COMRPC1,public COMRPC2 { - public: - HelloWorld(const HelloWorld&) = delete; - HelloWorld &operator=(const HelloWorld&) = delete; - - HelloWorld() : - {{CONSTRUCTOR_VALUES}} - { - - } - - ~HelloWorld override - { - - } - - {{NESTED_CLASS}} - - // Inherited Methods - void COMRPC1Method1() override; -void COMRPC1Method2() override; -void COMRPC2Method1() override; -void COMRPC2Method2() override; - - // Plugin Methods - void HelloWorldMethod(1); - - BEGIN_INTERFACE_MAP(HelloWorld) - INTERFACE_ENTRY(COMRPC1) -INTERFACE_ENTRY(COMRPC2) - - END_INTERFACE_MAP - - private: - - DATA_MEMBER - }; -} -} diff --git a/PluginGenerator/HelloWorld/Module.cpp b/PluginGenerator/HelloWorld/Module.cpp deleted file mode 100644 index af44534..0000000 --- a/PluginGenerator/HelloWorld/Module.cpp +++ /dev/null @@ -1,5 +0,0 @@ -ADD_THUNDER_LICENSE - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/HelloWorld/Module.h b/PluginGenerator/HelloWorld/Module.h deleted file mode 100644 index fd92b82..0000000 --- a/PluginGenerator/HelloWorld/Module.h +++ /dev/null @@ -1,12 +0,0 @@ -ADD_THUNDER_LICENSE - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_HelloWorld -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/blueprint_data.py b/PluginGenerator/blueprint_data.py index bc9c2e6..7c49840 100644 --- a/PluginGenerator/blueprint_data.py +++ b/PluginGenerator/blueprint_data.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 +import helper + class BlueprintData: def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: self.plugin_name = plugin_name @@ -8,31 +10,41 @@ def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, self.run_oop = run_oop self.json_events = json_events - self.keywords = {} + self.indenter = helper.Helper() + + self.keywords = self.generate_keywords_map() - def generate_thunder_license(self): - return "ADD_THUNDER_LICENSE" + return helper.THUNDER_LICENSE def generate_inherited_methods(self): - raise NotImplementedError("Method: generate_inherited_methods not implemented for class") + pass def generate_plugin_methods(self): - raise NotImplementedError("Method: generate_plugin_methods not implemented for class") - + pass + + def generate_keywords_map(self): + return { + '{{THUNDER_LICENSE}}' : self.generate_thunder_license(), + '{{PLUGIN_NAME}}' : self.plugin_name, + '{{PLUGIN_NAME_CAPS}}' : self.plugin_name.upper(), + } class HeaderData(BlueprintData): def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) self.keywords = self.generate_keywords_map() - - def generate_include_statements(self): + + def generate_jsonrpc_includes(self): includes = [] - for jsonrpc in self.jsonrpc_interfaces: includes.append(f'#include ') - + + return '\n'.join(includes) + + def generate_comrpc_includes(self): + includes = [] for comrpc in self.comrpc_interfaces: includes.append(f'#include ') @@ -46,37 +58,57 @@ def generate_inherited_classes(self): if not self.comrpc_interfaces: return '' - inheritance = [f'{self.comrpc_interfaces[0]}'] + inheritance = ["PluginHost::IPlugin"] + + if not self.run_oop: + for inherited_class in self.comrpc_interfaces: + inheritance.append(f'public {inherited_class}') + + all_inheritance = ', '.join(inheritance) + return all_inheritance + + def generate_oop_inherited_classes(self): + if not self.comrpc_interfaces: + return '' + + inheritance = [self.comrpc_interfaces[0]] - for inherited_class in self.comrpc_interfaces[1:]: - inheritance.append(f'public {inherited_class}') + if self.run_oop: + for inherited_class in self.comrpc_interfaces[1:]: + inheritance.append(f'public {inherited_class}') - all_inheritance = ','.join(inheritance) + all_inheritance = ', '.join(inheritance) return all_inheritance def generate_inherited_methods(self): methods = [] - for inherited in self.comrpc_interfaces: - method1 = f'void {inherited}Method1() override;' - method2 = f'void {inherited}Method2() override;' - methods.extend([method1,method2]) - return '\n'.join(methods) + self.indent_size = 2 + if not self.run_oop: + for inherited in self.comrpc_interfaces: + method1 = f'void {inherited}Method1() override;' + method2 = f'void {inherited}Method2() override;' + methods.extend([method1,method2]) + return ('\n'+ self.indenter.apply_indent()).join(methods) def generate_plugin_methods(self): method = f'void {self.plugin_name}Method(1);' return method def generate_interface_entry(self): - entries = [] for comrpc in self.comrpc_interfaces: entry = f'INTERFACE_ENTRY({comrpc})' entries.append(entry) - return '\n'.join(entries) + return ('\n'+ self.indenter.apply_indent()).join(entries) def generate_interface_aggregate(self): - - return " " + aggregates = [] + if(self.run_oop): + aggregates = [] + for comrpc in self.comrpc_interfaces: + aggregate = f'INTERFACE_AGGREGATE({comrpc}, _impl)' + aggregates.append(aggregate) + return ('\n'+ self.indenter.apply_indent()).join(aggregates) def generate_data_members(self): return 'DATA_MEMBER' @@ -86,12 +118,15 @@ def generate_module_plugin_name(self): def generate_forward_declarations(self): return " " - + + def generate_comrpc_interface(self): + return "Test_COMRPC" + def generate_keywords_map(self): return { - '{{THUNDER_LICENSE}}' : self.generate_thunder_license(), + '{{JSONRPC_INTERFACE_INCLUDES}}' : self.generate_jsonrpc_includes(), + '{{COMRPC_INTERFACE_INCLUDES}}' : self.generate_comrpc_includes(), '{{PLUGIN_NAME}}' : self.plugin_name, - '{{INCLUDE}}' : self.generate_include_statements(), '{{FORWARD_DECLARATIONS}}' : self.generate_forward_declarations(), '{{INHERITED_CLASS}}' : self.generate_inherited_classes(), '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), @@ -99,7 +134,9 @@ def generate_keywords_map(self): '{{INTERFACE_ENTRY}}' : self.generate_interface_entry(), '{{INTERFACE_AGGREGATE}}' : self.generate_interface_aggregate(), '{{DATA_MEMBERS}}' : self.generate_data_members(), - '{{MODULE_PLUGIN_NAME}}' : self.generate_module_plugin_name() + '{{MODULE_PLUGIN_NAME}}' : self.generate_module_plugin_name(), + '{{COMRPC_INTERFACE}}' : self.generate_comrpc_interface(), + '{{OOP_INHERITED_CLASS}}' : self.generate_oop_inherited_classes() } class SourceData(BlueprintData): @@ -109,7 +146,7 @@ def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, self.keywords = self.generate_keywords_map() def generate_include_statements(self): - return f'#include "{self.plugin_name}".h' + return f'#include "{self.plugin_name}.h"' def generate_plugin_methods(self): return "test method" @@ -119,12 +156,52 @@ def generate_inherited_methods(self): def generate_keywords_map(self): return { - '{{THUNDER_LICENSE}}' : self.generate_thunder_license(), '{{INCLUDE}}' : self.generate_include_statements(), + '{{PLUGIN_NAME}}' : self.plugin_name, '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), '{{PRECONDITIONS}}' : "conditions", '{{TERMINATIONS}}' : "terminations", '{{CONTROLS}}' : "controls" - } \ No newline at end of file + } + +class CMakeData(BlueprintData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) + + def generate_keywords_map(self): + return { + '{{SOURCE_FILES}}' : self.find_source_files() + } + + def find_source_files(self): + if(self.run_oop): + return f'{self.plugin_name}.cpp \n{self.plugin_name}Implementation.cpp' + else: + return f'{self.plugin_name}.cpp' + +class JSONData(BlueprintData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) + +class ConfData(BlueprintData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) + + def generate_keywords_map(self): + return { + '{{PLUGIN_STARTMODE}}' : f'"@PLUGIN_{self.plugin_name.upper()}_STARTMODE@"' + } + + +# Not in use currently, may use later on to track rather than hardcode +class PluginData(): + # todo: store data such as class names, filenames etc + def __init__(self) -> None: + self.classes = [] + self.file_names = [] + + def add_class(self, class_name): + pass + diff --git a/PluginGenerator/examples/HelloWorld/CMakeLists.txt b/PluginGenerator/examples/HelloWorld/CMakeLists.txt new file mode 100644 index 0000000..5a66fc0 --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/CMakeLists.txt @@ -0,0 +1,65 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 Metrological +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +project({{PLUGIN_NAME}}) + +cmake_minimum_required(VERSION 3.15) + +find_package(Thunder) + +project_version(1.0.0) + +set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) + +message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") + +set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") + +if(BUILD_REFERENCE) + add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) +endif() + +find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) +find_package(CompileSettingsDebug CONFIG REQUIRED) + +add_library(${MODULE_NAME} SHARED + HelloWorld.cpp +HelloWorldImplementation.cpp +) + +set_target_properties(${MODULE_NAME} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + +target_link_libraries(${MODULE_NAME} + PRIVATE + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) + + +target_include_directories( ${MODULE_NAME} + PUBLIC + $) + +install(TARGETS ${MODULE_NAME} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) + +write_config() + + diff --git a/PluginGenerator/examples/HelloWorld/HelloWorld.conf.in b/PluginGenerator/examples/HelloWorld/HelloWorld.conf.in new file mode 100644 index 0000000..2e0db2a --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/HelloWorld.conf.in @@ -0,0 +1 @@ +startmode = "@PLUGIN_HELLOWORLD_STARTMODE@" \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/HelloWorld.cpp b/PluginGenerator/examples/HelloWorld/HelloWorld.cpp new file mode 100644 index 0000000..9990a21 --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/HelloWorld.cpp @@ -0,0 +1,42 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "HelloWorld.h" + +namespace Thunder{ +namespace Plugin{ + + namespace { + + static Metadatametadata( + // Version + 1, 0, 0, + // Preconditions + {conditions} + // Terminations + {terminations} + // Controls + {controls} + ) + } + +// Implement all methods from HelloWorld.h + +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/HelloWorld.h b/PluginGenerator/examples/HelloWorld/HelloWorld.h new file mode 100644 index 0000000..cf9b526 --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/HelloWorld.h @@ -0,0 +1,55 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace Thunder { +namespace Plugin { + + class HelloWorld : public PluginHost::IPlugin { + public: + HelloWorld(const HelloWorld&) = delete; + HelloWorld &operator=(const HelloWorld&) = delete; + HelloWorld() {} + ~HelloWorld override {} + + {{NESTED_CLASS}} + + // Inherited Methods + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + + // Plugin Methods + void HelloWorldMethod(1); + + BEGIN_INTERFACE_MAP(HelloWorld) + INTERFACE_ENTRY(com1) + INTERFACE_AGGREGATE(com1, _impl) + END_INTERFACE_MAP + + private: + + DATA_MEMBER + }; +} +} diff --git a/PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp b/PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp new file mode 100644 index 0000000..0b5f14c --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp @@ -0,0 +1,49 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace Thunder { +namespace Plugin { + + SERVICE_REGISTRATION(HelloWorldImplementation, 1, 0) + + class HelloWorldImplementation : public com1 { + public: + + HelloWorldImplementation(const HelloWorldImplementation&) = delete; + HelloWorldImplementation& operator=(const HelloWorldImplementation&) = delete; + + HelloWorldImplementation(); + ~HelloWorldImplementation() override = default; + + BEGIN_INTERFACE_MAP(HelloWorldImplementation) + INTERFACE_ENTRY(com1) + END_INTERFACE_MAP + + // Implement methods from the interface + + + private: + // Add data members, for example: (Core::CriticalSection, std::vector..) +}; +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/Module.cpp b/PluginGenerator/examples/HelloWorld/Module.cpp new file mode 100644 index 0000000..1a6d827 --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/Module.cpp @@ -0,0 +1,22 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/Module.h b/PluginGenerator/examples/HelloWorld/Module.h new file mode 100644 index 0000000..2dbc52e --- /dev/null +++ b/PluginGenerator/examples/HelloWorld/Module.h @@ -0,0 +1,29 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_HelloWorld +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt b/PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt new file mode 100644 index 0000000..416385f --- /dev/null +++ b/PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt @@ -0,0 +1,63 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 Metrological +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +project({{PLUGIN_NAME}}) + +cmake_minimum_required(VERSION 3.15) + +find_package(Thunder) + +project_version(1.0.0) + +set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) + +message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") + +set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") + +if(BUILD_REFERENCE) + add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) +endif() + +find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) +find_package(CompileSettingsDebug CONFIG REQUIRED) + +add_library(${MODULE_NAME} SHARED + HelloWorldNotOOP.cpp +) + +set_target_properties(${MODULE_NAME} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + +target_link_libraries(${MODULE_NAME} + PRIVATE + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) + +target_include_directories( ${MODULE_NAME} + PUBLIC + $) + +install(TARGETS ${MODULE_NAME} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) + +write_config() + + diff --git a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in new file mode 100644 index 0000000..c80c4a6 --- /dev/null +++ b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in @@ -0,0 +1 @@ +startmode = "@PLUGIN_HELLOWORLDNOTOOP_STARTMODE@" \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp new file mode 100644 index 0000000..5532000 --- /dev/null +++ b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp @@ -0,0 +1,42 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "HelloWorldNotOOP.h" + +namespace Thunder{ +namespace Plugin{ + + namespace { + + static Metadatametadata( + // Version + 1, 0, 0, + // Preconditions + {conditions} + // Terminations + {terminations} + // Controls + {controls} + ) + } + +// Implement all methods from HelloWorldNotOOP.h + +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h new file mode 100644 index 0000000..a8a7e0e --- /dev/null +++ b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h @@ -0,0 +1,56 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace Thunder { +namespace Plugin { + + class HelloWorldNotOOP : public PluginHost::IPlugin, public com1 { + public: + HelloWorldNotOOP(const HelloWorldNotOOP&) = delete; + HelloWorldNotOOP &operator=(const HelloWorldNotOOP&) = delete; + HelloWorldNotOOP() {} + ~HelloWorldNotOOP override {} + + {{NESTED_CLASS}} + + // Inherited Methods + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + void com1Method1() override; + void com1Method2() override; + // Plugin Methods + void HelloWorldNotOOPMethod(1); + + BEGIN_INTERFACE_MAP(HelloWorldNotOOP) + INTERFACE_ENTRY(com1) + + END_INTERFACE_MAP + + private: + + DATA_MEMBER + }; +} +} diff --git a/PluginGenerator/examples/HelloWorldNotOOP/Module.cpp b/PluginGenerator/examples/HelloWorldNotOOP/Module.cpp new file mode 100644 index 0000000..1a6d827 --- /dev/null +++ b/PluginGenerator/examples/HelloWorldNotOOP/Module.cpp @@ -0,0 +1,22 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/Module.h b/PluginGenerator/examples/HelloWorldNotOOP/Module.h new file mode 100644 index 0000000..5797311 --- /dev/null +++ b/PluginGenerator/examples/HelloWorldNotOOP/Module.h @@ -0,0 +1,29 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_HelloWorldNotOOP +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/generator.py b/PluginGenerator/generator.py index a896b57..ad85749 100755 --- a/PluginGenerator/generator.py +++ b/PluginGenerator/generator.py @@ -16,10 +16,8 @@ ''' import os -from blueprint_data import BlueprintData, HeaderData, SourceData - - -header_template_paths = [] +from blueprint_data import BlueprintData, HeaderData, SourceData, CMakeData, JSONData, ConfData +from helper import Helper class PluginGenerator: @@ -33,15 +31,13 @@ def load_template(self, template_name): with open(template_name, 'r') as template_file: return template_file.read() except FileNotFoundError: - print("no file") + print(f"Could not load template: {template_name}") return None def generate_file(self, template_path, output_path): template = self.load_template(template_path) - if template: - code = self.replace_code(template) header_path = os.path.join(self.directory, output_path) @@ -50,25 +46,26 @@ def generate_file(self, template_path, output_path): def generate_source(self): - self.generate_file("templates/plugin_source_template.txt", f'{self.blueprint_data.plugin_name}.cpp') - self.generate_file("templates/module_cpp_file.txt", "Module.cpp") - pass + self.generate_file("templates/plugin_source.txt", f'{self.blueprint_data.plugin_name}.cpp') + self.generate_file("templates/module/module_source.txt", "Module.cpp") def generate_headers(self): - self.generate_file("templates/plugin_header_template.txt", f'{self.blueprint_data.plugin_name}.h') - self.generate_file("templates/module_header_template.txt", "Module.h") - pass - def generate_plugin(self): - ''' - Generate the following: - - Module .h/.cpp - - Plugin .h/.cpp - - OOP implementation .cpp - - Plugin .conf.in - - CMake .txt - - Plugin .json - ''' + if(self.blueprint_data.run_oop): + self.generate_file("templates/plugin_implementation.txt", f'{self.blueprint_data.plugin_name}Implementation.cpp') + + self.generate_file("templates/plugin_header.txt", f'{self.blueprint_data.plugin_name}.h') + self.generate_file("templates/module/module_header.txt", "Module.h") + + def generate_cmake(self): + self.generate_file("templates/cmake.txt", "CMakeLists.txt") + + def generate_json(self): + # self.generate_file("templates/cmake.txt", "CMakeLists.txt") + pass + + def generate_conf_in(self): + self.generate_file("templates/plugin_conf_in.txt", f'{self.blueprint_data.plugin_name}.conf.in') pass def replace_code(self,template): @@ -77,23 +74,61 @@ def replace_code(self,template): for keyword, value in data.items(): code = code.replace(keyword,value) return code + +def menu(): + plugin_name = input("What will your plugin be called: \n") -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# + comrpc_interface = [] + jsonrpc_interface = [] + + print(f"Enter any COM-RPC interfaces used: (Enter ! to quit) \nNote: IPlugin is already defined for you") + while True: + comrpc = input("Enter a COM-RPC interface: ") + if comrpc == '!': + break + comrpc_interface.append(comrpc) + + print(f"Enter any JSON-RPC interfaces used: (Enter ! to quit)") + while True: + jsonrpc = input("Enter a JSONRPC-RPC interface: ") + if jsonrpc == '!': + break + jsonrpc_interface.append(jsonrpc) + + out_of_process = False + + while True: + run_oop = input("Is your plugin expected to work out of process: (Enter Y or N)\n") + if(run_oop.lower() == 'y'): + out_of_process = True + break + elif(run_oop.lower() == 'n'): + out_of_process = False + break + else: + print("Unknown character, try again.") -plugin_name = "HelloWorld" -comrpc_interface = ["COMRPC1", "COMRPC2"] -jsonrpc_interface = ["JSONRPC1", "JSONRPC2"] -run_oop = False -jsonrpc_events = True + jsonrpc_events = False -#blueprint_data = BlueprintData(plugin_name, comrpc_interface, jsonrpc_interface, run_oop, jsonrpc_events) -header_data = HeaderData(plugin_name, comrpc_interface, jsonrpc_interface, run_oop, jsonrpc_events) -source_data = SourceData(plugin_name, comrpc_interface, jsonrpc_interface, run_oop, jsonrpc_events) + header_data = HeaderData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) + source_data = SourceData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) + cmake_data = CMakeData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) + conf_data = ConfData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) -plugin_generator = PluginGenerator(header_data) -plugin_generator.generate_headers() + plugin_generator = PluginGenerator(header_data) + plugin_generator.generate_headers() -plugin_generator.blueprint_data = source_data -plugin_generator.generate_source() + plugin_generator.blueprint_data = source_data + plugin_generator.generate_source() + + plugin_generator.blueprint_data = cmake_data + plugin_generator.generate_cmake() + + plugin_generator.blueprint_data = conf_data + plugin_generator.generate_conf_in() + + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# +menu() diff --git a/PluginGenerator/helper.py b/PluginGenerator/helper.py new file mode 100644 index 0000000..d5993f9 --- /dev/null +++ b/PluginGenerator/helper.py @@ -0,0 +1,37 @@ +THUNDER_LICENSE = """ /* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ """ + +# Currently, indent_size remains as 2 due to how the templates are formatted already +# Possibly in the future, this may change depending on complexity, hence why there are helper functions + +class Helper(): + def __init__(self) -> None: + self.indent = ' ' + self.indent_size = 2 + + def increase_indent(self): + self.indent_size = self.indent_size + 1 + + def decrease_indent(self): + self.indent_size = self.indent_size - 1 + if(self.indent_size < 0): + self.indent_size = 0 + + def apply_indent(self): + return self.indent_size * self.indent \ No newline at end of file diff --git a/PluginGenerator/plugin.txt b/PluginGenerator/plugin.txt deleted file mode 100644 index b711fb9..0000000 --- a/PluginGenerator/plugin.txt +++ /dev/null @@ -1,14 +0,0 @@ -# NOTE: THIS FILE IS READ ONLY AND SHOULD NOT BE EDITED -# THIS FILE SERVES AS AN EXAMPLE TEMPLATE -# -# -# -# GUIDE: -# 1. ANSWER ALL QUESTIONS ACCORDINGLY TO HOW THEY ARE FORMATTED -# 2. ANY ANSWERS WITH A PREFIX '#' WILL BE IGNORED -# -# -# 1. WHAT IS THE PLUGIN NAME? -["HelloWorld"] -# 2. LIST ANY COMRPC INTERFACES: -[{"PluginHost","path/to/PluginHost"},{"IBlueTooth","path/to/Bluetooth"}] \ No newline at end of file diff --git a/PluginGenerator/templates/cmake.txt b/PluginGenerator/templates/cmake.txt new file mode 100644 index 0000000..69a4f48 --- /dev/null +++ b/PluginGenerator/templates/cmake.txt @@ -0,0 +1,63 @@ +# If not stated otherwise in this file or this component's license file the +# following copyright and licenses apply: +# +# Copyright 2024 Metrological +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +project({{PLUGIN_NAME}}) + +cmake_minimum_required(VERSION 3.15) + +find_package(Thunder) + +project_version(1.0.0) + +set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) + +message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") + +set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") + +if(BUILD_REFERENCE) + add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) +endif() + +find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) +find_package(CompileSettingsDebug CONFIG REQUIRED) + +add_library(${MODULE_NAME} SHARED + {{SOURCE_FILES}} +) + +set_target_properties(${MODULE_NAME} PROPERTIES + CXX_STANDARD 11 + CXX_STANDARD_REQUIRED YES) + +target_link_libraries(${MODULE_NAME} + PRIVATE + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) + +target_include_directories( ${MODULE_NAME} + PUBLIC + $) + +install(TARGETS ${MODULE_NAME} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) + +write_config() + + diff --git a/PluginGenerator/templates/module/module_header.txt b/PluginGenerator/templates/module/module_header.txt new file mode 100644 index 0000000..5ddf45a --- /dev/null +++ b/PluginGenerator/templates/module/module_header.txt @@ -0,0 +1,29 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2020 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME {{MODULE_PLUGIN_NAME}} +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/templates/module/module_source.txt b/PluginGenerator/templates/module/module_source.txt new file mode 100644 index 0000000..1a6d827 --- /dev/null +++ b/PluginGenerator/templates/module/module_source.txt @@ -0,0 +1,22 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/templates/module_cpp_file.txt b/PluginGenerator/templates/module_cpp_file.txt deleted file mode 100644 index c322043..0000000 --- a/PluginGenerator/templates/module_cpp_file.txt +++ /dev/null @@ -1,5 +0,0 @@ -{{THUNDER_LICENSE}} - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/templates/module_header_template.txt b/PluginGenerator/templates/module_header_template.txt deleted file mode 100644 index 378b56d..0000000 --- a/PluginGenerator/templates/module_header_template.txt +++ /dev/null @@ -1,12 +0,0 @@ -{{THUNDER_LICENSE}} - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME {{MODULE_PLUGIN_NAME}} -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/templates/plugin.conf.in b/PluginGenerator/templates/plugin.conf.in deleted file mode 100644 index 49bfb5e..0000000 --- a/PluginGenerator/templates/plugin.conf.in +++ /dev/null @@ -1 +0,0 @@ -startmode = ... \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_cmake.txt b/PluginGenerator/templates/plugin_cmake.txt deleted file mode 100644 index 1915fff..0000000 --- a/PluginGenerator/templates/plugin_cmake.txt +++ /dev/null @@ -1 +0,0 @@ -to do.. \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_conf_in.txt b/PluginGenerator/templates/plugin_conf_in.txt new file mode 100644 index 0000000..155bbd8 --- /dev/null +++ b/PluginGenerator/templates/plugin_conf_in.txt @@ -0,0 +1 @@ +startmode = {{PLUGIN_STARTMODE}} \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_header.txt b/PluginGenerator/templates/plugin_header.txt new file mode 100644 index 0000000..34cdbe9 --- /dev/null +++ b/PluginGenerator/templates/plugin_header.txt @@ -0,0 +1,55 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +{{JSONRPC_INTERFACE_INCLUDES}} +{{COMRPC_INTERFACE_INCLUDES}} + +namespace Thunder { +namespace Plugin { + + class {{PLUGIN_NAME}} : public {{INHERITED_CLASS}} { + public: + {{PLUGIN_NAME}}(const {{PLUGIN_NAME}}&) = delete; + {{PLUGIN_NAME}} &operator=(const {{PLUGIN_NAME}}&) = delete; + {{PLUGIN_NAME}}() {} + ~{{PLUGIN_NAME}} override {} + + {{NESTED_CLASS}} + + // Inherited Methods + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + {{INHERITED_METHOD}} + // Plugin Methods + {{PLUGIN_METHOD}} + + BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) + {{INTERFACE_ENTRY}} + {{INTERFACE_AGGREGATE}} + END_INTERFACE_MAP + + private: + + {{DATA_MEMBERS}} + }; +} +} diff --git a/PluginGenerator/templates/plugin_header_template.txt b/PluginGenerator/templates/plugin_header_template.txt deleted file mode 100644 index f8b27d6..0000000 --- a/PluginGenerator/templates/plugin_header_template.txt +++ /dev/null @@ -1,46 +0,0 @@ -{{THUNDER_LICENSE}} - -#pragma once - -{{INCLUDE}} - -{{FORWARD DECLARATIONS}} - -namespace Thunder { -namespace Plugin { - - class {{PLUGIN_NAME}} : public {{INHERITED_CLASS}} { - public: - {{PLUGIN_NAME}}(const {{PLUGIN_NAME}}&) = delete; - {{PLUGIN_NAME}} &operator=(const {{PLUGIN_NAME}}&) = delete; - - {{PLUGIN_NAME}}() : - {{CONSTRUCTOR_VALUES}} - { - - } - - ~{{PLUGIN_NAME}} override - { - - } - - {{NESTED_CLASS}} - - // Inherited Methods - {{INHERITED_METHOD}} - - // Plugin Methods - {{PLUGIN_METHOD}} - - BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) - {{INTERFACE_ENTRY}} - {{INTERFACE_AGGREGATE}} - END_INTERFACE_MAP - - private: - - {{DATA_MEMBERS}} - }; -} -} diff --git a/PluginGenerator/templates/plugin_implementation.txt b/PluginGenerator/templates/plugin_implementation.txt new file mode 100644 index 0000000..63c58ad --- /dev/null +++ b/PluginGenerator/templates/plugin_implementation.txt @@ -0,0 +1,49 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +{{COMRPC_INTERFACE_INCLUDES}} + +namespace Thunder { +namespace Plugin { + + SERVICE_REGISTRATION({{PLUGIN_NAME}}Implementation, 1, 0) + + class {{PLUGIN_NAME}}Implementation : public {{OOP_INHERITED_CLASS}} { + public: + + {{PLUGIN_NAME}}Implementation(const {{PLUGIN_NAME}}Implementation&) = delete; + {{PLUGIN_NAME}}Implementation& operator=(const {{PLUGIN_NAME}}Implementation&) = delete; + + {{PLUGIN_NAME}}Implementation(); + ~{{PLUGIN_NAME}}Implementation() override = default; + + BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}Implementation) + {{INTERFACE_ENTRY}} + END_INTERFACE_MAP + + // Implement methods from the interface + {{INHERITED_METHOD}} + + private: + // Add data members, for example: (Core::CriticalSection, std::vector..) +}; +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_source.txt b/PluginGenerator/templates/plugin_source.txt new file mode 100644 index 0000000..86b87d4 --- /dev/null +++ b/PluginGenerator/templates/plugin_source.txt @@ -0,0 +1,42 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{{INCLUDE}} + +namespace Thunder{ +namespace Plugin{ + + namespace { + + static Metadata<{{PLUGIN_NAME}}>metadata( + // Version + 1, 0, 0, + // Preconditions + {{{PRECONDITIONS}}} + // Terminations + {{{TERMINATIONS}}} + // Controls + {{{CONTROLS}}} + ) + } + +// Implement all methods from {{PLUGIN_NAME}}.h + +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_source_template.txt b/PluginGenerator/templates/plugin_source_template.txt deleted file mode 100644 index 9f7ab83..0000000 --- a/PluginGenerator/templates/plugin_source_template.txt +++ /dev/null @@ -1,27 +0,0 @@ -{{THUNDER_LICENSE}} - -{{INCLUDE}} - -namespace Thunder{ -namespace Plugin{ - - namespace { - - static Metadata<{{PLUGIN_NAME}}> metadata( - // Version - 1, 0, 0, - // Preconditions - {{{PRECONDITIONS}}} - // Terminations - {{{TERMINATIONS}}} - // Controls - {{{CONTROLS}}} - ) - } - -{{PLUGIN_METHOD}} - -{{INHERITED_METHOD}} - -} // Plugin -} // Thunder \ No newline at end of file From 8bb99bff031c4cc9a4b9f6024e05e0dc8527d2db Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Wed, 4 Sep 2024 03:11:35 -0700 Subject: [PATCH 04/12] Plugin Skeleton 1.0 --- .../examples/HelloWorld/HelloWorld.conf.in | 1 - .../examples/HelloWorld/HelloWorld.cpp | 42 ----- .../examples/HelloWorld/HelloWorld.h | 55 ------ .../HelloWorld/HelloWorldImplementation.cpp | 49 ----- .../examples/HelloWorld/Module.cpp | 22 --- PluginGenerator/examples/HelloWorld/Module.h | 29 --- .../HelloWorldNotOOP/HelloWorldNotOOP.conf.in | 1 - .../HelloWorldNotOOP/HelloWorldNotOOP.cpp | 42 ----- .../HelloWorldNotOOP/HelloWorldNotOOP.h | 56 ------ .../examples/HelloWorldNotOOP/Module.cpp | 22 --- .../examples/HelloWorldNotOOP/Module.h | 29 --- PluginGenerator/helper.py | 37 ---- PluginGenerator/templates/plugin_header.txt | 55 ------ .../examples/IP_JSONRPC}/CMakeLists.txt | 15 +- .../examples/IP_JSONRPC/IP_JSONRPC.conf.in | 1 + .../examples/IP_JSONRPC/IP_JSONRPC.cpp | 56 ++++++ .../examples/IP_JSONRPC/IP_JSONRPC.h | 72 ++++++++ .../examples/IP_JSONRPC/Module.cpp | 22 +++ .../examples/IP_JSONRPC/Module.h | 29 +++ .../examples/OOP_JSONRPC}/CMakeLists.txt | 18 +- .../examples/OOP_JSONRPC/Module.cpp | 22 +++ .../examples/OOP_JSONRPC/Module.h | 29 +++ .../examples/OOP_JSONRPC/OOP_JSONRPC.conf.in | 1 + .../examples/OOP_JSONRPC/OOP_JSONRPC.cpp | 99 +++++++++++ .../examples/OOP_JSONRPC/OOP_JSONRPC.h | 85 +++++++++ .../OOP_JSONRPC/OOP_JSONRPCImplementation.cpp | 46 +++++ PluginSkeletonGenerator/examples/examples.txt | 6 + .../file_data.py | 168 +++++++++++------- .../generator.py | 90 +++++----- PluginSkeletonGenerator/help.txt | 5 + PluginSkeletonGenerator/helper.py | 47 +++++ .../templates/cmake.txt | 12 ++ .../iplugin_methods/deinitialize_oop.txt | 34 ++++ .../iplugin_methods/initialize_ip.txt | 6 + .../iplugin_methods/initialize_oop.txt | 26 +++ .../templates/module/module_header.txt | 2 +- .../templates/module/module_source.txt | 0 .../templates/nested_class/config_class.txt | 24 +++ .../nested_class/rpc_inotification.txt | 38 ++++ .../templates/plugin_conf_in.txt | 0 .../templates/plugin_header.txt | 69 +++++++ .../templates/plugin_implementation.txt | 11 +- .../templates/plugin_source.txt | 33 +++- 43 files changed, 931 insertions(+), 575 deletions(-) delete mode 100644 PluginGenerator/examples/HelloWorld/HelloWorld.conf.in delete mode 100644 PluginGenerator/examples/HelloWorld/HelloWorld.cpp delete mode 100644 PluginGenerator/examples/HelloWorld/HelloWorld.h delete mode 100644 PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp delete mode 100644 PluginGenerator/examples/HelloWorld/Module.cpp delete mode 100644 PluginGenerator/examples/HelloWorld/Module.h delete mode 100644 PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in delete mode 100644 PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp delete mode 100644 PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h delete mode 100644 PluginGenerator/examples/HelloWorldNotOOP/Module.cpp delete mode 100644 PluginGenerator/examples/HelloWorldNotOOP/Module.h delete mode 100644 PluginGenerator/helper.py delete mode 100644 PluginGenerator/templates/plugin_header.txt rename {PluginGenerator/examples/HelloWorldNotOOP => PluginSkeletonGenerator/examples/IP_JSONRPC}/CMakeLists.txt (81%) create mode 100644 PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in create mode 100644 PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp create mode 100644 PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h create mode 100644 PluginSkeletonGenerator/examples/IP_JSONRPC/Module.cpp create mode 100644 PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h rename {PluginGenerator/examples/HelloWorld => PluginSkeletonGenerator/examples/OOP_JSONRPC}/CMakeLists.txt (80%) create mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.cpp create mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h create mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in create mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp create mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h create mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp create mode 100644 PluginSkeletonGenerator/examples/examples.txt rename PluginGenerator/blueprint_data.py => PluginSkeletonGenerator/file_data.py (60%) rename {PluginGenerator => PluginSkeletonGenerator}/generator.py (64%) create mode 100644 PluginSkeletonGenerator/help.txt create mode 100644 PluginSkeletonGenerator/helper.py rename {PluginGenerator => PluginSkeletonGenerator}/templates/cmake.txt (89%) create mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt create mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt create mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt rename {PluginGenerator => PluginSkeletonGenerator}/templates/module/module_header.txt (96%) rename {PluginGenerator => PluginSkeletonGenerator}/templates/module/module_source.txt (100%) create mode 100644 PluginSkeletonGenerator/templates/nested_class/config_class.txt create mode 100644 PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt rename {PluginGenerator => PluginSkeletonGenerator}/templates/plugin_conf_in.txt (100%) create mode 100644 PluginSkeletonGenerator/templates/plugin_header.txt rename {PluginGenerator => PluginSkeletonGenerator}/templates/plugin_implementation.txt (93%) rename {PluginGenerator => PluginSkeletonGenerator}/templates/plugin_source.txt (61%) diff --git a/PluginGenerator/examples/HelloWorld/HelloWorld.conf.in b/PluginGenerator/examples/HelloWorld/HelloWorld.conf.in deleted file mode 100644 index 2e0db2a..0000000 --- a/PluginGenerator/examples/HelloWorld/HelloWorld.conf.in +++ /dev/null @@ -1 +0,0 @@ -startmode = "@PLUGIN_HELLOWORLD_STARTMODE@" \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/HelloWorld.cpp b/PluginGenerator/examples/HelloWorld/HelloWorld.cpp deleted file mode 100644 index 9990a21..0000000 --- a/PluginGenerator/examples/HelloWorld/HelloWorld.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "HelloWorld.h" - -namespace Thunder{ -namespace Plugin{ - - namespace { - - static Metadatametadata( - // Version - 1, 0, 0, - // Preconditions - {conditions} - // Terminations - {terminations} - // Controls - {controls} - ) - } - -// Implement all methods from HelloWorld.h - -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/HelloWorld.h b/PluginGenerator/examples/HelloWorld/HelloWorld.h deleted file mode 100644 index cf9b526..0000000 --- a/PluginGenerator/examples/HelloWorld/HelloWorld.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace Thunder { -namespace Plugin { - - class HelloWorld : public PluginHost::IPlugin { - public: - HelloWorld(const HelloWorld&) = delete; - HelloWorld &operator=(const HelloWorld&) = delete; - HelloWorld() {} - ~HelloWorld override {} - - {{NESTED_CLASS}} - - // Inherited Methods - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - // Plugin Methods - void HelloWorldMethod(1); - - BEGIN_INTERFACE_MAP(HelloWorld) - INTERFACE_ENTRY(com1) - INTERFACE_AGGREGATE(com1, _impl) - END_INTERFACE_MAP - - private: - - DATA_MEMBER - }; -} -} diff --git a/PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp b/PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp deleted file mode 100644 index 0b5f14c..0000000 --- a/PluginGenerator/examples/HelloWorld/HelloWorldImplementation.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include - -namespace Thunder { -namespace Plugin { - - SERVICE_REGISTRATION(HelloWorldImplementation, 1, 0) - - class HelloWorldImplementation : public com1 { - public: - - HelloWorldImplementation(const HelloWorldImplementation&) = delete; - HelloWorldImplementation& operator=(const HelloWorldImplementation&) = delete; - - HelloWorldImplementation(); - ~HelloWorldImplementation() override = default; - - BEGIN_INTERFACE_MAP(HelloWorldImplementation) - INTERFACE_ENTRY(com1) - END_INTERFACE_MAP - - // Implement methods from the interface - - - private: - // Add data members, for example: (Core::CriticalSection, std::vector..) -}; -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/Module.cpp b/PluginGenerator/examples/HelloWorld/Module.cpp deleted file mode 100644 index 1a6d827..0000000 --- a/PluginGenerator/examples/HelloWorld/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/Module.h b/PluginGenerator/examples/HelloWorld/Module.h deleted file mode 100644 index 2dbc52e..0000000 --- a/PluginGenerator/examples/HelloWorld/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_HelloWorld -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in deleted file mode 100644 index c80c4a6..0000000 --- a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.conf.in +++ /dev/null @@ -1 +0,0 @@ -startmode = "@PLUGIN_HELLOWORLDNOTOOP_STARTMODE@" \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp deleted file mode 100644 index 5532000..0000000 --- a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "HelloWorldNotOOP.h" - -namespace Thunder{ -namespace Plugin{ - - namespace { - - static Metadatametadata( - // Version - 1, 0, 0, - // Preconditions - {conditions} - // Terminations - {terminations} - // Controls - {controls} - ) - } - -// Implement all methods from HelloWorldNotOOP.h - -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h b/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h deleted file mode 100644 index a8a7e0e..0000000 --- a/PluginGenerator/examples/HelloWorldNotOOP/HelloWorldNotOOP.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -namespace Thunder { -namespace Plugin { - - class HelloWorldNotOOP : public PluginHost::IPlugin, public com1 { - public: - HelloWorldNotOOP(const HelloWorldNotOOP&) = delete; - HelloWorldNotOOP &operator=(const HelloWorldNotOOP&) = delete; - HelloWorldNotOOP() {} - ~HelloWorldNotOOP override {} - - {{NESTED_CLASS}} - - // Inherited Methods - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - void com1Method1() override; - void com1Method2() override; - // Plugin Methods - void HelloWorldNotOOPMethod(1); - - BEGIN_INTERFACE_MAP(HelloWorldNotOOP) - INTERFACE_ENTRY(com1) - - END_INTERFACE_MAP - - private: - - DATA_MEMBER - }; -} -} diff --git a/PluginGenerator/examples/HelloWorldNotOOP/Module.cpp b/PluginGenerator/examples/HelloWorldNotOOP/Module.cpp deleted file mode 100644 index 1a6d827..0000000 --- a/PluginGenerator/examples/HelloWorldNotOOP/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorldNotOOP/Module.h b/PluginGenerator/examples/HelloWorldNotOOP/Module.h deleted file mode 100644 index 5797311..0000000 --- a/PluginGenerator/examples/HelloWorldNotOOP/Module.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2020 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_HelloWorldNotOOP -#endif - -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/helper.py b/PluginGenerator/helper.py deleted file mode 100644 index d5993f9..0000000 --- a/PluginGenerator/helper.py +++ /dev/null @@ -1,37 +0,0 @@ -THUNDER_LICENSE = """ /* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ """ - -# Currently, indent_size remains as 2 due to how the templates are formatted already -# Possibly in the future, this may change depending on complexity, hence why there are helper functions - -class Helper(): - def __init__(self) -> None: - self.indent = ' ' - self.indent_size = 2 - - def increase_indent(self): - self.indent_size = self.indent_size + 1 - - def decrease_indent(self): - self.indent_size = self.indent_size - 1 - if(self.indent_size < 0): - self.indent_size = 0 - - def apply_indent(self): - return self.indent_size * self.indent \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_header.txt b/PluginGenerator/templates/plugin_header.txt deleted file mode 100644 index 34cdbe9..0000000 --- a/PluginGenerator/templates/plugin_header.txt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * If not stated otherwise in this file or this component's LICENSE file the - * following copyright and licenses apply: - * - * Copyright 2024 Metrological - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -{{JSONRPC_INTERFACE_INCLUDES}} -{{COMRPC_INTERFACE_INCLUDES}} - -namespace Thunder { -namespace Plugin { - - class {{PLUGIN_NAME}} : public {{INHERITED_CLASS}} { - public: - {{PLUGIN_NAME}}(const {{PLUGIN_NAME}}&) = delete; - {{PLUGIN_NAME}} &operator=(const {{PLUGIN_NAME}}&) = delete; - {{PLUGIN_NAME}}() {} - ~{{PLUGIN_NAME}} override {} - - {{NESTED_CLASS}} - - // Inherited Methods - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - {{INHERITED_METHOD}} - // Plugin Methods - {{PLUGIN_METHOD}} - - BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) - {{INTERFACE_ENTRY}} - {{INTERFACE_AGGREGATE}} - END_INTERFACE_MAP - - private: - - {{DATA_MEMBERS}} - }; -} -} diff --git a/PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt b/PluginSkeletonGenerator/examples/IP_JSONRPC/CMakeLists.txt similarity index 81% rename from PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt rename to PluginSkeletonGenerator/examples/IP_JSONRPC/CMakeLists.txt index 416385f..bd69409 100644 --- a/PluginGenerator/examples/HelloWorldNotOOP/CMakeLists.txt +++ b/PluginSkeletonGenerator/examples/IP_JSONRPC/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -project({{PLUGIN_NAME}}) +project(IP_JSONRPC) cmake_minimum_required(VERSION 3.15) @@ -27,7 +27,7 @@ set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") -set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") +set(PLUGIN_IP_JSONRPC_STARTMODE "Activated" CACHE STRING "Automatically start IP_JSONRPC plugin") if(BUILD_REFERENCE) add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) @@ -38,7 +38,7 @@ find_package(${NAMESPACE}Definitions REQUIRED) find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED - HelloWorldNotOOP.cpp + IP_JSONRPC.cpp ) set_target_properties(${MODULE_NAME} PROPERTIES @@ -47,9 +47,9 @@ set_target_properties(${MODULE_NAME} PROPERTIES target_link_libraries(${MODULE_NAME} PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) target_include_directories( ${MODULE_NAME} PUBLIC @@ -57,7 +57,6 @@ target_include_directories( ${MODULE_NAME} install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) - -write_config() +write_config() diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in new file mode 100644 index 0000000..c367fab --- /dev/null +++ b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in @@ -0,0 +1 @@ +startmode = "@PLUGIN_IP_JSONRPC_STARTMODE@" \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp new file mode 100644 index 0000000..88d386e --- /dev/null +++ b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp @@ -0,0 +1,56 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "IP_JSONRPC.h" + +namespace Thunder{ +namespace Plugin{ + namespace { + static Metadatametadata( + // Version + 1, 0, 0, + // Preconditions + {}, + // Terminations + {}, + // Controls + {} + ) + } + + // Implement all methods from IP_JSONRPC.h + + const string IP_JSONRPC::Initialize(PluginHost::IShell* service) { + string message; + + ASSERT (service != nullptr); + + Config config; + config.FromString(service->ConfigLine()); + } + + void IP_JSONRPC::Deinitialize(PluginHost::IShell* service) { + + } + + string IP_JSONRPC::Information(PluginHost::IShell* service) { + return string() + } +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h new file mode 100644 index 0000000..4c01b8e --- /dev/null +++ b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h @@ -0,0 +1,72 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once +#include +#include + +namespace Thunder { +namespace Plugin { + + class IP_JSONRPC : public PluginHost::IPlugin, public PluginHost::JSONRPC, public COM1 { + public: + IP_JSONRPC(const IP_JSONRPC&) = delete; + IP_JSONRPC &operator=(const IP_JSONRPC&) = delete; + IP_JSONRPC() {} + ~IP_JSONRPC override {} + + private: + + class Config : public Core::JSON::Container { + private: + Config(const Config&) = delete; + Config& operator=(const Config&) = delete; + public: + Config() + : Example("Example") + { + Add(_T("example"), &Example); + } + ~Config(){} + public: + Core::JSON::String Example; + } + + public: + + // Inherited Methods + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + void COM1Method1() override; + void COM1Method2() override; + // Plugin Methods + void IP_JSONRPCMethod(1); + + BEGIN_INTERFACE_MAP(IP_JSONRPC) + INTERFACE_ENTRY(COM1) + + END_INTERFACE_MAP + private: + // Include the correct member variables for your plugin: + // Note this is only an example, you are responsible for adding the correct members: + uint32_t _connectionId; + }; +} +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.cpp b/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.cpp new file mode 100644 index 0000000..c3a1a78 --- /dev/null +++ b/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.cpp @@ -0,0 +1,22 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h b/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h new file mode 100644 index 0000000..f2e0f0b --- /dev/null +++ b/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h @@ -0,0 +1,29 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_IP_JSONRPC +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginGenerator/examples/HelloWorld/CMakeLists.txt b/PluginSkeletonGenerator/examples/OOP_JSONRPC/CMakeLists.txt similarity index 80% rename from PluginGenerator/examples/HelloWorld/CMakeLists.txt rename to PluginSkeletonGenerator/examples/OOP_JSONRPC/CMakeLists.txt index 5a66fc0..365a3d9 100644 --- a/PluginGenerator/examples/HelloWorld/CMakeLists.txt +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -project({{PLUGIN_NAME}}) +project(OOP_JSONRPC) cmake_minimum_required(VERSION 3.15) @@ -27,7 +27,7 @@ set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") -set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") +set(PLUGIN_OOP_JSONRPC_STARTMODE "Activated" CACHE STRING "Automatically start OOP_JSONRPC plugin") if(BUILD_REFERENCE) add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) @@ -38,8 +38,8 @@ find_package(${NAMESPACE}Definitions REQUIRED) find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED - HelloWorld.cpp -HelloWorldImplementation.cpp + OOP_JSONRPC.cpp + OOP_JSONRPCImplementation.cpp ) set_target_properties(${MODULE_NAME} PROPERTIES @@ -48,10 +48,9 @@ set_target_properties(${MODULE_NAME} PROPERTIES target_link_libraries(${MODULE_NAME} PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - + CompileSettingsDebug::CompileSettingsDebug + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions) target_include_directories( ${MODULE_NAME} PUBLIC @@ -59,7 +58,6 @@ target_include_directories( ${MODULE_NAME} install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) - -write_config() +write_config() diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.cpp b/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.cpp new file mode 100644 index 0000000..c3a1a78 --- /dev/null +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.cpp @@ -0,0 +1,22 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h b/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h new file mode 100644 index 0000000..5262400 --- /dev/null +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h @@ -0,0 +1,29 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_OOP_JSONRPC +#endif + +#include + +#undef EXTERNAL +#define EXTERNAL \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in new file mode 100644 index 0000000..c1d52d5 --- /dev/null +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in @@ -0,0 +1 @@ +startmode = "@PLUGIN_OOP_JSONRPC_STARTMODE@" \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp new file mode 100644 index 0000000..5cd1e6d --- /dev/null +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp @@ -0,0 +1,99 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "OOP_JSONRPC.h" + +namespace Thunder{ +namespace Plugin{ + namespace { + static Metadatametadata( + // Version + 1, 0, 0, + // Preconditions + {}, + // Terminations + {}, + // Controls + {} + ) + } + + // Implement all methods from OOP_JSONRPC.h + + const string OOP_JSONRPC::Initialize(PluginHost::IShell* service) { + string message; + + ASSERT (_service == nullptr); + ASSERT (service != nullptr); + ASSERT (_implementation == nullptr); + ASSERT (_connectionId == 0); + + _service = service; + _service->AddRef(); + _service->Register(&_connectionNotification); + + implementation = + service->Root(_connectionId, 2000, _T("OOP_JSONRPCImplementation")); + if (_implementation == nullptr) { + message = _T("Couldn't create instance"); + } else { + // Add registration e.g: + //_implementation->Register(&_volumeNotification); + // Exchange::JVolumeControl::Register(*this, _implementation); + } + + return (message); + } + + void OOP_JSONRPC::Deinitialize(PluginHost::IShell* service) { + if (_service != nullptr) { + ASSERT(_service == service); + + service->Unregister(&_connectionNotification); + + if (_implementation != nullptr) { + // Example if your interface has inotification implemented + //Exchange::JVolumeControl::Unregister(*this); + //_implementation->Unregister(&_volumeNotification); + + RPC::IRemoteConnection* connection(_service->RemoteConnection(_connectionId)); + VARIABLE_IS_NOT_USED uint32_t result = _implementation->Release(); + _implementation = nullptr; + // It should have been the last reference we are releasing, + // so it should endup in a DESTRUCTION_SUCCEEDED, if not we + // are leaking... + ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); + // The process can disappear in the meantime... + if (connection != nullptr) { + // But if it did not dissapear in the meantime, forcefully terminate it. Shoot to kill + connection->Terminate(); + connection->Release(); + } + } + _service->Release(); + _service = nullptr; + _connectionId = 0; + } + } + + string OOP_JSONRPC::Information(PluginHost::IShell* service) { + return string() + } +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h new file mode 100644 index 0000000..eb71bbc --- /dev/null +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h @@ -0,0 +1,85 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once +#include +#include + +namespace Thunder { +namespace Plugin { + + class OOP_JSONRPC : public PluginHost::IPlugin, public PluginHost::JSONRPC { + public: + OOP_JSONRPC(const OOP_JSONRPC&) = delete; + OOP_JSONRPC &operator=(const OOP_JSONRPC&) = delete; + OOP_JSONRPC() {} + ~OOP_JSONRPC override {} + + private: + + + class ConnectionNotification : public RPC::IRemoteConnection::INotification { + public: + explicit ConnectionNotification(OOP_JSONRPC* parent) + : _parent(*parent) + { + ASSERT(parent != nullptr); + } + + ~ConnectionNotification() override = default; + ConnectionNotification() = delete; + ConnectionNotification(const ConnectionNotification&) = delete; + ConnectionNotification& operator=(const ConnectionNotification&) = delete; + + void Activated(RPC::IRemoteConnection*) override + { + } + + void Deactivated(RPC::IRemoteConnection* connection) override + { + _parent.Deactivated(connection); + } + + BEGIN_INTERFACE_MAP(ConnectionNotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP + private: + OOP_JSONRPC& _parent; + } + public: + + // Inherited Methods + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + + // Plugin Methods + void OOP_JSONRPCMethod(1); + + BEGIN_INTERFACE_MAP(OOP_JSONRPC) + INTERFACE_ENTRY(COM1) + INTERFACE_AGGREGATE(COM1, _impl) + END_INTERFACE_MAP + private: + // Include the correct member variables for your plugin: + // Note this is only an example, you are responsible for adding the correct members: + uint32_t _connectionId; + }; +} +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp new file mode 100644 index 0000000..d3bf03a --- /dev/null +++ b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp @@ -0,0 +1,46 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include + +namespace Thunder { +namespace Plugin { + SERVICE_REGISTRATION(OOP_JSONRPCImplementation, 1, 0) + + class OOP_JSONRPCImplementation : public COM1 { + public: + OOP_JSONRPCImplementation(const OOP_JSONRPCImplementation&) = delete; + OOP_JSONRPCImplementation& operator=(const OOP_JSONRPCImplementation&) = delete; + + OOP_JSONRPCImplementation(); + ~OOP_JSONRPCImplementation() override = default; + + BEGIN_INTERFACE_MAP(OOP_JSONRPCImplementation) + INTERFACE_ENTRY(COM1) + END_INTERFACE_MAP + + // Implement methods from the interface + + private: + // Add data members, for example: (Core::CriticalSection, std::vector..) + }; +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/examples.txt b/PluginSkeletonGenerator/examples/examples.txt new file mode 100644 index 0000000..547d799 --- /dev/null +++ b/PluginSkeletonGenerator/examples/examples.txt @@ -0,0 +1,6 @@ +Abbreviations: +OOP = Out of Process +IP = In Process +JSONRPC = JSONRPC is enabled + +These examples serve as a display to show what your skeleton may look like. \ No newline at end of file diff --git a/PluginGenerator/blueprint_data.py b/PluginSkeletonGenerator/file_data.py similarity index 60% rename from PluginGenerator/blueprint_data.py rename to PluginSkeletonGenerator/file_data.py index 7c49840..f70e4fc 100644 --- a/PluginGenerator/blueprint_data.py +++ b/PluginSkeletonGenerator/file_data.py @@ -1,40 +1,31 @@ #!/usr/bin/env python3 -import helper +from helper import FileUtils -class BlueprintData: - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: +class FileData: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: self.plugin_name = plugin_name self.comrpc_interfaces = comrpc_interfaces if comrpc_interfaces else [] self.jsonrpc_interfaces = jsonrpc_interfaces if jsonrpc_interfaces else [] - self.run_oop = run_oop - self.json_events = json_events - - self.indenter = helper.Helper() + self.out_of_process = out_of_process + self.jsonrpc = jsonrpc self.keywords = self.generate_keywords_map() - def generate_thunder_license(self): - return helper.THUNDER_LICENSE - - def generate_inherited_methods(self): - pass - - def generate_plugin_methods(self): - pass - def generate_keywords_map(self): return { - '{{THUNDER_LICENSE}}' : self.generate_thunder_license(), '{{PLUGIN_NAME}}' : self.plugin_name, - '{{PLUGIN_NAME_CAPS}}' : self.plugin_name.upper(), + '{{PLUGIN_NAME_CAPS}}' : self.plugin_name.upper() } + +class HeaderData(FileData): -class HeaderData(BlueprintData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) - self.keywords = self.generate_keywords_map() + self.keywords = super().generate_keywords_map() + self.keywords.update(self.generate_keywords_map()) + self.keywords.update(self.generate_nested_map()) def generate_jsonrpc_includes(self): includes = [] @@ -52,15 +43,12 @@ def generate_comrpc_includes(self): def generate_inherited_classes(self): - # TODO: Implement differentiation between filetypes - # Implement indent multiplier - - if not self.comrpc_interfaces: - return '' - inheritance = ["PluginHost::IPlugin"] - if not self.run_oop: + if self.jsonrpc: + inheritance.append("public PluginHost::JSONRPC") + + if not self.out_of_process: for inherited_class in self.comrpc_interfaces: inheritance.append(f'public {inherited_class}') @@ -73,7 +61,7 @@ def generate_oop_inherited_classes(self): inheritance = [self.comrpc_interfaces[0]] - if self.run_oop: + if self.out_of_process: for inherited_class in self.comrpc_interfaces[1:]: inheritance.append(f'public {inherited_class}') @@ -82,13 +70,12 @@ def generate_oop_inherited_classes(self): def generate_inherited_methods(self): methods = [] - self.indent_size = 2 - if not self.run_oop: + if not self.out_of_process: for inherited in self.comrpc_interfaces: method1 = f'void {inherited}Method1() override;' method2 = f'void {inherited}Method2() override;' methods.extend([method1,method2]) - return ('\n'+ self.indenter.apply_indent()).join(methods) + return ('\n').join(methods) def generate_plugin_methods(self): method = f'void {self.plugin_name}Method(1);' @@ -99,35 +86,30 @@ def generate_interface_entry(self): for comrpc in self.comrpc_interfaces: entry = f'INTERFACE_ENTRY({comrpc})' entries.append(entry) - return ('\n'+ self.indenter.apply_indent()).join(entries) + return ('\n').join(entries) def generate_interface_aggregate(self): aggregates = [] - if(self.run_oop): + if(self.out_of_process): aggregates = [] for comrpc in self.comrpc_interfaces: aggregate = f'INTERFACE_AGGREGATE({comrpc}, _impl)' aggregates.append(aggregate) - return ('\n'+ self.indenter.apply_indent()).join(aggregates) + return ('\n').join(aggregates) def generate_data_members(self): return 'DATA_MEMBER' def generate_module_plugin_name(self): return f'Plugin_{self.plugin_name}' - - def generate_forward_declarations(self): - return " " - + def generate_comrpc_interface(self): return "Test_COMRPC" - + def generate_keywords_map(self): - return { + return{ '{{JSONRPC_INTERFACE_INCLUDES}}' : self.generate_jsonrpc_includes(), '{{COMRPC_INTERFACE_INCLUDES}}' : self.generate_comrpc_includes(), - '{{PLUGIN_NAME}}' : self.plugin_name, - '{{FORWARD_DECLARATIONS}}' : self.generate_forward_declarations(), '{{INHERITED_CLASS}}' : self.generate_inherited_classes(), '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), @@ -138,37 +120,89 @@ def generate_keywords_map(self): '{{COMRPC_INTERFACE}}' : self.generate_comrpc_interface(), '{{OOP_INHERITED_CLASS}}' : self.generate_oop_inherited_classes() } + + def generate_nested_map(self): + return{ + '{{JSONRPC_EVENT}}' : self.generate_jsonrpc_event(), + '{{CONFIG_CLASS}}' : self.generate_config() + } -class SourceData(BlueprintData): - - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) - self.keywords = self.generate_keywords_map() + def generate_jsonrpc_event(self): + if self.out_of_process: + template_name = 'templates/nested_class/rpc_inotification.txt' + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + return ' ' + + def generate_config(self): + + if not self.out_of_process: + template_name = 'templates/nested_class/config_class.txt' + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + return ' ' + +class SourceData(FileData): + + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + self.keywords = super().generate_keywords_map() + self.keywords.update(self.generate_keywords_map()) + self.keywords.update(self.generate_nested_map()) def generate_include_statements(self): return f'#include "{self.plugin_name}.h"' def generate_plugin_methods(self): - return "test method" + return "Plugin method" def generate_inherited_methods(self): - return "test inherited method" + return "Inherited method" + + def generate_initialize(self): + + if self.out_of_process: + template_name = 'templates/iplugin_methods/initialize_oop.txt' + else: + template_name = 'templates/iplugin_methods/initialize_ip.txt' + + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + + def generate_deinitialize(self): + + if self.out_of_process: + template_name = 'templates/iplugin_methods/deinitialize_oop.txt' + + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + return "" def generate_keywords_map(self): return { '{{INCLUDE}}' : self.generate_include_statements(), - '{{PLUGIN_NAME}}' : self.plugin_name, '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), '{{PRECONDITIONS}}' : "conditions", '{{TERMINATIONS}}' : "terminations", '{{CONTROLS}}' : "controls" - } -class CMakeData(BlueprintData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) + def generate_nested_map(self): + return { + '{{INITIALIZE_IMPLEMENTATION}}' : self.generate_initialize(), + '{{DEINITIALIZE_IMPLEMENTATION}}' : self.generate_deinitialize() + } + +class CMakeData(FileData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + self.keywords = super().generate_keywords_map() + self.keywords.update(self.generate_keywords_map()) def generate_keywords_map(self): return { @@ -176,25 +210,28 @@ def generate_keywords_map(self): } def find_source_files(self): - if(self.run_oop): + if(self.out_of_process): return f'{self.plugin_name}.cpp \n{self.plugin_name}Implementation.cpp' else: return f'{self.plugin_name}.cpp' -class JSONData(BlueprintData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) +class JSONData(FileData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + self.keywords = super().generate_keywords_map() + self.keywords.update(self.generate_keywords_map()) -class ConfData(BlueprintData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, run_oop, json_events) +class ConfData(FileData): + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + self.keywords = super().generate_keywords_map() + self.keywords.update(self.generate_keywords_map()) def generate_keywords_map(self): return { '{{PLUGIN_STARTMODE}}' : f'"@PLUGIN_{self.plugin_name.upper()}_STARTMODE@"' } - # Not in use currently, may use later on to track rather than hardcode class PluginData(): # todo: store data such as class names, filenames etc @@ -203,5 +240,4 @@ def __init__(self) -> None: self.file_names = [] def add_class(self, class_name): - pass - + pass \ No newline at end of file diff --git a/PluginGenerator/generator.py b/PluginSkeletonGenerator/generator.py similarity index 64% rename from PluginGenerator/generator.py rename to PluginSkeletonGenerator/generator.py index ad85749..2698fc1 100755 --- a/PluginGenerator/generator.py +++ b/PluginSkeletonGenerator/generator.py @@ -7,17 +7,20 @@ - json rpc interface (header names required) - Does the plugin require the possibility to run OOP - does the plugin use JSONRPC events ? + +TODO: - does the plugin specific configuration options (is configuration code needed)? - other plugin access required (use new PluginSmartInterfaceType type for this) - compile time implementation differentiation needed (e.g. like DisplayInfo) - special trace categories required (create new category for this plugin) - subsystems support needed (dependend en set) - needs workerpool jobs (scheduled or not), so we can generate an example job - ''' + + import os -from blueprint_data import BlueprintData, HeaderData, SourceData, CMakeData, JSONData, ConfData -from helper import Helper +from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData +from helper import Indenter, FileUtils class PluginGenerator: @@ -25,24 +28,25 @@ def __init__(self, blueprint_data) -> None: self.blueprint_data = blueprint_data self.directory = self.blueprint_data.plugin_name os.makedirs(self.blueprint_data.plugin_name, exist_ok=True) + self.indenter = Indenter() def load_template(self, template_name): - try: - with open(template_name, 'r') as template_file: - return template_file.read() - except FileNotFoundError: - print(f"Could not load template: {template_name}") - return None + return FileUtils.read_file(template_name) + + def replace_code(self,template): + code = FileUtils.replace_keywords(template,self.blueprint_data.keywords) + return code def generate_file(self, template_path, output_path): template = self.load_template(template_path) if template: code = self.replace_code(template) + indented_code = self.indenter.process_indent(code) header_path = os.path.join(self.directory, output_path) with open(header_path, 'w') as f: - f.write(code) + f.write(indented_code) def generate_source(self): @@ -51,7 +55,8 @@ def generate_source(self): def generate_headers(self): - if(self.blueprint_data.run_oop): + # Although this is a .cpp file, it's actually most like a .h + if(self.blueprint_data.out_of_process): self.generate_file("templates/plugin_implementation.txt", f'{self.blueprint_data.plugin_name}Implementation.cpp') self.generate_file("templates/plugin_header.txt", f'{self.blueprint_data.plugin_name}.h') @@ -61,20 +66,15 @@ def generate_cmake(self): self.generate_file("templates/cmake.txt", "CMakeLists.txt") def generate_json(self): + # TODO: # self.generate_file("templates/cmake.txt", "CMakeLists.txt") pass def generate_conf_in(self): self.generate_file("templates/plugin_conf_in.txt", f'{self.blueprint_data.plugin_name}.conf.in') - pass - def replace_code(self,template): - code = template - data = self.blueprint_data.keywords - for keyword, value in data.items(): - code = code.replace(keyword,value) - return code - +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# + def menu(): plugin_name = input("What will your plugin be called: \n") @@ -82,53 +82,63 @@ def menu(): comrpc_interface = [] jsonrpc_interface = [] - print(f"Enter any COM-RPC interfaces used: (Enter ! to quit) \nNote: IPlugin is already defined for you") + print(f"Enter any COM-RPC interfaces used: (Enter to quit) \nNote: IPlugin is already defined for you") while True: comrpc = input("Enter a COM-RPC interface: ") - if comrpc == '!': + if not comrpc: break comrpc_interface.append(comrpc) - print(f"Enter any JSON-RPC interfaces used: (Enter ! to quit)") while True: - jsonrpc = input("Enter a JSONRPC-RPC interface: ") - if jsonrpc == '!': + jsonrpc = input("Does your plugin require JSONRPC functionality: (Enter Y or N)\n") + if(jsonrpc.lower() == 'y'): + jsonrpc= True + break + elif(jsonrpc.lower() == 'n'): + jsonrpc = False break - jsonrpc_interface.append(jsonrpc) + else: + print("Unknown character, try again.") - out_of_process = False + if jsonrpc: + print(f"Enter any JSON-RPC interfaces used: (Enter to quit)") + while True: + jsonrpc_class = input("Enter a JSON-RPC interface: ") + if not jsonrpc_class: + break + jsonrpc_interface.append(jsonrpc_class) while True: - run_oop = input("Is your plugin expected to work out of process: (Enter Y or N)\n") - if(run_oop.lower() == 'y'): + out_of_process = input("Is your plugin expected to work out of process: (Enter Y or N)\n") + if(out_of_process.lower() == 'y'): out_of_process = True break - elif(run_oop.lower() == 'n'): + elif(out_of_process.lower() == 'n'): out_of_process = False break else: print("Unknown character, try again.") - jsonrpc_events = False + data = FileData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) + plugin_generator = PluginGenerator(data) - header_data = HeaderData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) - source_data = SourceData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) - cmake_data = CMakeData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) - conf_data = ConfData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc_events) + header_data = HeaderData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) + source_data = SourceData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) + cmake_data = CMakeData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) + conf_data = ConfData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - plugin_generator = PluginGenerator(header_data) + plugin_generator.blueprint_data = header_data plugin_generator.generate_headers() - plugin_generator.blueprint_data = source_data plugin_generator.generate_source() - plugin_generator.blueprint_data = cmake_data plugin_generator.generate_cmake() - plugin_generator.blueprint_data = conf_data plugin_generator.generate_conf_in() - +def main(): + menu() #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# -menu() +if __name__ == "__main__": + main() diff --git a/PluginSkeletonGenerator/help.txt b/PluginSkeletonGenerator/help.txt new file mode 100644 index 0000000..e3d4be4 --- /dev/null +++ b/PluginSkeletonGenerator/help.txt @@ -0,0 +1,5 @@ +To run this tool: +./generator.py + +And answer the questions accordingly. +To see examples of what the skelton is capable of, see the examples folder. \ No newline at end of file diff --git a/PluginSkeletonGenerator/helper.py b/PluginSkeletonGenerator/helper.py new file mode 100644 index 0000000..d8b058d --- /dev/null +++ b/PluginSkeletonGenerator/helper.py @@ -0,0 +1,47 @@ +class FileUtils(): + def __init__(self) -> None: + pass + + @staticmethod + def replace_keywords(template, keywords): + code = template + data = keywords + for keyword, value in data.items(): + code = code.replace(keyword,value) + return code + + @staticmethod + def read_file(template_name): + try: + with open(template_name, 'r') as template_file: + template = template_file.read() + except FileNotFoundError: + print(f"Could not load template: {template_name}") + return None + return template + +class Indenter(): + def __init__(self) -> None: + self.indent_size = 0 + self.indent = " " + self.indented_code = [] + + def process_indent(self, code): + self.indented_code.clear() + + lines = code.splitlines() + self.indent_size = 0 + for line in lines: + newline = line.strip() + + if('~INDENT_RESET~' in newline): + self.indent_size = 0 + continue + elif('~INDENT_INCREASE~' in newline): + self.indent_size +=1 + continue + elif('~INDENT_DECREASE~' in newline): + self.indent_size -=1 + continue + self.indented_code.append(self.indent * self.indent_size + newline) + return '\n'.join(self.indented_code) \ No newline at end of file diff --git a/PluginGenerator/templates/cmake.txt b/PluginSkeletonGenerator/templates/cmake.txt similarity index 89% rename from PluginGenerator/templates/cmake.txt rename to PluginSkeletonGenerator/templates/cmake.txt index 69a4f48..e26f716 100644 --- a/PluginGenerator/templates/cmake.txt +++ b/PluginSkeletonGenerator/templates/cmake.txt @@ -30,7 +30,9 @@ message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") if(BUILD_REFERENCE) +~INDENT_INCREASE~ add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) +~INDENT_DECREASE~ endif() find_package(${NAMESPACE}Plugins REQUIRED) @@ -38,25 +40,35 @@ find_package(${NAMESPACE}Definitions REQUIRED) find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED +~INDENT_INCREASE~ {{SOURCE_FILES}} +~INDENT_DECREASE~ ) set_target_properties(${MODULE_NAME} PROPERTIES +~INDENT_INCREASE~ CXX_STANDARD 11 CXX_STANDARD_REQUIRED YES) +~INDENT_DECREASE~ target_link_libraries(${MODULE_NAME} +~INDENT_INCREASE~ PRIVATE CompileSettingsDebug::CompileSettingsDebug ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${NAMESPACE}Definitions::${NAMESPACE}Definitions) +~INDENT_DECREASE~ target_include_directories( ${MODULE_NAME} +~INDENT_INCREASE~ PUBLIC $) +~INDENT_DECREASE~ install(TARGETS ${MODULE_NAME} +~INDENT_INCREASE~ DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) +~INDENT_DECREASE~ write_config() diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt new file mode 100644 index 0000000..5162119 --- /dev/null +++ b/PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt @@ -0,0 +1,34 @@ +if (_service != nullptr) { +~INDENT_INCREASE~ +ASSERT(_service == service); + +service->Unregister(&_connectionNotification); + +if (_implementation != nullptr) { +~INDENT_INCREASE~ + // Example if your interface has inotification implemented + //Exchange::JVolumeControl::Unregister(*this); + //_implementation->Unregister(&_volumeNotification); + + RPC::IRemoteConnection* connection(_service->RemoteConnection(_connectionId)); + VARIABLE_IS_NOT_USED uint32_t result = _implementation->Release(); + _implementation = nullptr; + // It should have been the last reference we are releasing, + // so it should endup in a DESTRUCTION_SUCCEEDED, if not we + // are leaking... + ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); + // The process can disappear in the meantime... + if (connection != nullptr) { +~INDENT_INCREASE~ + // But if it did not dissapear in the meantime, forcefully terminate it. Shoot to kill + connection->Terminate(); + connection->Release(); +~INDENT_DECREASE~ + } +~INDENT_DECREASE~ +} +_service->Release(); +_service = nullptr; +_connectionId = 0; +~INDENT_DECREASE~ +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt b/PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt new file mode 100644 index 0000000..bd79b20 --- /dev/null +++ b/PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt @@ -0,0 +1,6 @@ +string message; + +ASSERT (service != nullptr); + +Config config; +config.FromString(service->ConfigLine()); \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt new file mode 100644 index 0000000..e887dd9 --- /dev/null +++ b/PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt @@ -0,0 +1,26 @@ +string message; + +ASSERT (_service == nullptr); +ASSERT (service != nullptr); +ASSERT (_implementation == nullptr); +ASSERT (_connectionId == 0); + +_service = service; +_service->AddRef(); +_service->Register(&_connectionNotification); + +implementation = +service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); +if (_implementation == nullptr) { +~INDENT_INCREASE~ + message = _T("Couldn't create instance"); +~INDENT_DECREASE~ +} else { +~INDENT_INCREASE~ + // Add registration e.g: + //_implementation->Register(&_volumeNotification); + // Exchange::JVolumeControl::Register(*this, _implementation); +~INDENT_DECREASE~ +} + +return (message); \ No newline at end of file diff --git a/PluginGenerator/templates/module/module_header.txt b/PluginSkeletonGenerator/templates/module/module_header.txt similarity index 96% rename from PluginGenerator/templates/module/module_header.txt rename to PluginSkeletonGenerator/templates/module/module_header.txt index 5ddf45a..89bf494 100644 --- a/PluginGenerator/templates/module/module_header.txt +++ b/PluginSkeletonGenerator/templates/module/module_header.txt @@ -2,7 +2,7 @@ * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * - * Copyright 2020 Metrological + * Copyright 2024 Metrological * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/PluginGenerator/templates/module/module_source.txt b/PluginSkeletonGenerator/templates/module/module_source.txt similarity index 100% rename from PluginGenerator/templates/module/module_source.txt rename to PluginSkeletonGenerator/templates/module/module_source.txt diff --git a/PluginSkeletonGenerator/templates/nested_class/config_class.txt b/PluginSkeletonGenerator/templates/nested_class/config_class.txt new file mode 100644 index 0000000..af09759 --- /dev/null +++ b/PluginSkeletonGenerator/templates/nested_class/config_class.txt @@ -0,0 +1,24 @@ +class Config : public Core::JSON::Container { +private: +~INDENT_INCREASE~ + Config(const Config&) = delete; + Config& operator=(const Config&) = delete; +~INDENT_DECREASE~ +public: +~INDENT_INCREASE~ + Config() +~INDENT_INCREASE~ + : Example("Example") +~INDENT_DECREASE~ + { +~INDENT_INCREASE~ + Add(_T("example"), &Example); +~INDENT_DECREASE~ + } + ~Config(){} +~INDENT_DECREASE~ +public: +~INDENT_INCREASE~ +Core::JSON::String Example; +~INDENT_DECREASE~ +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt b/PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt new file mode 100644 index 0000000..0d95a9d --- /dev/null +++ b/PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt @@ -0,0 +1,38 @@ +class ConnectionNotification : public RPC::IRemoteConnection::INotification { +public: +~INDENT_INCREASE~ + explicit ConnectionNotification({{PLUGIN_NAME}}* parent) +~INDENT_INCREASE~ + : _parent(*parent) +~INDENT_DECREASE~ + { +~INDENT_INCREASE~ + ASSERT(parent != nullptr); +~INDENT_DECREASE~ + } + + ~ConnectionNotification() override = default; + ConnectionNotification() = delete; + ConnectionNotification(const ConnectionNotification&) = delete; + ConnectionNotification& operator=(const ConnectionNotification&) = delete; + + void Activated(RPC::IRemoteConnection*) override + { + } + + void Deactivated(RPC::IRemoteConnection* connection) override + { +~INDENT_INCREASE~ + _parent.Deactivated(connection); +~INDENT_DECREASE~ + } + + BEGIN_INTERFACE_MAP(ConnectionNotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP +~INDENT_DECREASE~ +private: +~INDENT_INCREASE~ + {{PLUGIN_NAME}}& _parent; +~INDENT_DECREASE~ +} \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_conf_in.txt b/PluginSkeletonGenerator/templates/plugin_conf_in.txt similarity index 100% rename from PluginGenerator/templates/plugin_conf_in.txt rename to PluginSkeletonGenerator/templates/plugin_conf_in.txt diff --git a/PluginSkeletonGenerator/templates/plugin_header.txt b/PluginSkeletonGenerator/templates/plugin_header.txt new file mode 100644 index 0000000..a6e4086 --- /dev/null +++ b/PluginSkeletonGenerator/templates/plugin_header.txt @@ -0,0 +1,69 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2024 Metrological + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +~INDENT_RESET~ +{{JSONRPC_INTERFACE_INCLUDES}} +{{COMRPC_INTERFACE_INCLUDES}} + +namespace Thunder { +namespace Plugin { +~INDENT_INCREASE~ + + class {{PLUGIN_NAME}} : public {{INHERITED_CLASS}} { + public: +~INDENT_INCREASE~ + {{PLUGIN_NAME}}(const {{PLUGIN_NAME}}&) = delete; + {{PLUGIN_NAME}} &operator=(const {{PLUGIN_NAME}}&) = delete; + {{PLUGIN_NAME}}() {} + ~{{PLUGIN_NAME}} override {} +~INDENT_DECREASE~ + + private: +~INDENT_INCREASE~ + + {{CONFIG_CLASS}} + {{JSONRPC_EVENT}} +~INDENT_DECREASE~ + public: +~INDENT_INCREASE~ + + // Inherited Methods + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + {{INHERITED_METHOD}} + // Plugin Methods + {{PLUGIN_METHOD}} + + BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) + {{INTERFACE_ENTRY}} + {{INTERFACE_AGGREGATE}} + END_INTERFACE_MAP +~INDENT_DECREASE~ + private: +~INDENT_INCREASE~ + // Include the correct member variables for your plugin: + // Note this is only an example, you are responsible for adding the correct members: + uint32_t _connectionId; +~INDENT_DECREASE~ + }; +~INDENT_DECREASE~ +} +} diff --git a/PluginGenerator/templates/plugin_implementation.txt b/PluginSkeletonGenerator/templates/plugin_implementation.txt similarity index 93% rename from PluginGenerator/templates/plugin_implementation.txt rename to PluginSkeletonGenerator/templates/plugin_implementation.txt index 63c58ad..44c4d26 100644 --- a/PluginGenerator/templates/plugin_implementation.txt +++ b/PluginSkeletonGenerator/templates/plugin_implementation.txt @@ -23,12 +23,12 @@ namespace Thunder { namespace Plugin { - +~INDENT_INCREASE~ SERVICE_REGISTRATION({{PLUGIN_NAME}}Implementation, 1, 0) class {{PLUGIN_NAME}}Implementation : public {{OOP_INHERITED_CLASS}} { public: - +~INDENT_INCREASE~ {{PLUGIN_NAME}}Implementation(const {{PLUGIN_NAME}}Implementation&) = delete; {{PLUGIN_NAME}}Implementation& operator=(const {{PLUGIN_NAME}}Implementation&) = delete; @@ -41,9 +41,12 @@ namespace Plugin { // Implement methods from the interface {{INHERITED_METHOD}} - +~INDENT_DECREASE~ private: +~INDENT_INCREASE~ // Add data members, for example: (Core::CriticalSection, std::vector..) -}; +~INDENT_DECREASE~ + }; +~INDENT_DECREASE~ } // Plugin } // Thunder \ No newline at end of file diff --git a/PluginGenerator/templates/plugin_source.txt b/PluginSkeletonGenerator/templates/plugin_source.txt similarity index 61% rename from PluginGenerator/templates/plugin_source.txt rename to PluginSkeletonGenerator/templates/plugin_source.txt index 86b87d4..7803070 100644 --- a/PluginGenerator/templates/plugin_source.txt +++ b/PluginSkeletonGenerator/templates/plugin_source.txt @@ -21,22 +21,43 @@ namespace Thunder{ namespace Plugin{ - +~INDENT_INCREASE~ namespace { - - static Metadata<{{PLUGIN_NAME}}>metadata( +~INDENT_INCREASE~ + static Metadata<{{PLUGIN_NAME}}>metadata( +~INDENT_INCREASE~ // Version 1, 0, 0, // Preconditions - {{{PRECONDITIONS}}} + {}, // Terminations - {{{TERMINATIONS}}} + {}, // Controls - {{{CONTROLS}}} + {} +~INDENT_DECREASE~ ) +~INDENT_DECREASE~ } // Implement all methods from {{PLUGIN_NAME}}.h +const string {{PLUGIN_NAME}}::Initialize(PluginHost::IShell* service) { +~INDENT_INCREASE~ + {{INITIALIZE_IMPLEMENTATION}} +~INDENT_DECREASE~ +} + +void {{PLUGIN_NAME}}::Deinitialize(PluginHost::IShell* service) { +~INDENT_INCREASE~ + {{DEINITIALIZE_IMPLEMENTATION}} +~INDENT_DECREASE~ +} + +string {{PLUGIN_NAME}}::Information(PluginHost::IShell* service) { +~INDENT_INCREASE~ + return string() +~INDENT_DECREASE~ +} +~INDENT_DECREASE~ } // Plugin } // Thunder \ No newline at end of file From dd63f81538a784428636cd54f927bb562fd008eb Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Wed, 4 Sep 2024 06:53:03 -0700 Subject: [PATCH 05/12] global paths created --- PluginSkeletonGenerator/file_data.py | 11 ++++---- PluginSkeletonGenerator/generator.py | 19 +++++++------ PluginSkeletonGenerator/global_variables.py | 31 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 14 deletions(-) create mode 100644 PluginSkeletonGenerator/global_variables.py diff --git a/PluginSkeletonGenerator/file_data.py b/PluginSkeletonGenerator/file_data.py index f70e4fc..7254bf8 100644 --- a/PluginSkeletonGenerator/file_data.py +++ b/PluginSkeletonGenerator/file_data.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from helper import FileUtils +import global_variables class FileData: def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: @@ -129,7 +130,7 @@ def generate_nested_map(self): def generate_jsonrpc_event(self): if self.out_of_process: - template_name = 'templates/nested_class/rpc_inotification.txt' + template_name = global_variables.RPC_NOTIFICATION_CLASS_PATH template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template,self.keywords) return code @@ -138,7 +139,7 @@ def generate_jsonrpc_event(self): def generate_config(self): if not self.out_of_process: - template_name = 'templates/nested_class/config_class.txt' + template_name = global_variables.CONFIG_CLASS_PATH template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template,self.keywords) return code @@ -164,9 +165,9 @@ def generate_inherited_methods(self): def generate_initialize(self): if self.out_of_process: - template_name = 'templates/iplugin_methods/initialize_oop.txt' + template_name = global_variables.INITIALIZE_OOP_PATH else: - template_name = 'templates/iplugin_methods/initialize_ip.txt' + template_name = global_variables.INITIALIZE_IP_PATH template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template,self.keywords) @@ -175,7 +176,7 @@ def generate_initialize(self): def generate_deinitialize(self): if self.out_of_process: - template_name = 'templates/iplugin_methods/deinitialize_oop.txt' + template_name = global_variables.DENINITIALIZE_OOP_PATH template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template,self.keywords) diff --git a/PluginSkeletonGenerator/generator.py b/PluginSkeletonGenerator/generator.py index 2698fc1..632cc5d 100755 --- a/PluginSkeletonGenerator/generator.py +++ b/PluginSkeletonGenerator/generator.py @@ -22,6 +22,8 @@ from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData from helper import Indenter, FileUtils +import global_variables + class PluginGenerator: def __init__(self, blueprint_data) -> None: @@ -49,21 +51,20 @@ def generate_file(self, template_path, output_path): f.write(indented_code) def generate_source(self): - - self.generate_file("templates/plugin_source.txt", f'{self.blueprint_data.plugin_name}.cpp') - self.generate_file("templates/module/module_source.txt", "Module.cpp") + self.generate_file(global_variables.PLUGIN_SOURCE_PATH, f'{self.blueprint_data.plugin_name}.cpp') + self.generate_file(global_variables.MODULE_SOURCE_PATH, "Module.cpp") def generate_headers(self): # Although this is a .cpp file, it's actually most like a .h if(self.blueprint_data.out_of_process): - self.generate_file("templates/plugin_implementation.txt", f'{self.blueprint_data.plugin_name}Implementation.cpp') + self.generate_file(global_variables.PLUGIN_IMPLEMENTATION_PATH, f'{self.blueprint_data.plugin_name}Implementation.cpp') - self.generate_file("templates/plugin_header.txt", f'{self.blueprint_data.plugin_name}.h') - self.generate_file("templates/module/module_header.txt", "Module.h") + self.generate_file(global_variables.PLUGIN_HEADER_PATH, f'{self.blueprint_data.plugin_name}.h') + self.generate_file(global_variables.MODULE_HEADER_PATH, "Module.h") def generate_cmake(self): - self.generate_file("templates/cmake.txt", "CMakeLists.txt") + self.generate_file(global_variables.CMAKE_PATH, "CMakeLists.txt") def generate_json(self): # TODO: @@ -71,7 +72,7 @@ def generate_json(self): pass def generate_conf_in(self): - self.generate_file("templates/plugin_conf_in.txt", f'{self.blueprint_data.plugin_name}.conf.in') + self.generate_file(global_variables.PLUGIN_CONF_PATH, f'{self.blueprint_data.plugin_name}.conf.in') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# @@ -141,4 +142,4 @@ def main(): #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/PluginSkeletonGenerator/global_variables.py b/PluginSkeletonGenerator/global_variables.py new file mode 100644 index 0000000..15928cd --- /dev/null +++ b/PluginSkeletonGenerator/global_variables.py @@ -0,0 +1,31 @@ +import os + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + +# Nested Directories: +TEMPLATE_DIR = os.path.join(BASE_DIR,'templates') + +IPLUGIN_DIR = os.path.join(TEMPLATE_DIR,'iplugin_methods') +MODULE_DIR = os.path.join(TEMPLATE_DIR, 'module') +NESTED_CLASS_DIR = os.path.join(TEMPLATE_DIR, 'nested_class') + +# Nested File Paths: +# /templates +CMAKE_PATH = os.path.join(TEMPLATE_DIR,'cmake.txt') +PLUGIN_CONF_PATH = os.path.join(TEMPLATE_DIR,'plugin_conf_in.txt') +PLUGIN_HEADER_PATH = os.path.join(TEMPLATE_DIR,'plugin_header.txt') +PLUGIN_IMPLEMENTATION_PATH = os.path.join(TEMPLATE_DIR,'plugin_implementation.txt') +PLUGIN_SOURCE_PATH = os.path.join(TEMPLATE_DIR,'plugin_source.txt') + +# /templates/iplugin_methods +DENINITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'deinitialize_oop.txt') +INITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'initialize_oop.txt') +INITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR,'initialize_ip.txt') + +# /templates/module +MODULE_HEADER_PATH = os.path.join(MODULE_DIR,'module_header.txt') +MODULE_SOURCE_PATH = os.path.join(MODULE_DIR,'module_source.txt') + +# /templates/nested_class +CONFIG_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'config_class.txt') +RPC_NOTIFICATION_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'rpc_inotification.txt') \ No newline at end of file From d84f4ef5d83371c149f3101becfc16fb0b9cf93e Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Thu, 5 Sep 2024 01:49:40 -0700 Subject: [PATCH 06/12] initial wrapper --- ThunderDevTools/ThunderDev.py | 57 +++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 ThunderDevTools/ThunderDev.py diff --git a/ThunderDevTools/ThunderDev.py b/ThunderDevTools/ThunderDev.py new file mode 100644 index 0000000..996fa10 --- /dev/null +++ b/ThunderDevTools/ThunderDev.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import argparse + +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) +THUNDER_TOOLS_DIR = os.path.dirname(CURRENT_DIR) + +def python_distrubution(): + if os.name == "posix": + return "python3" + else: + return "python" + +# add future scripts +scripts = { +"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","generator.py") +} + +def script_menu(): + print("Choose one of the following tools: (To quit, type q) ") + print("1. Plugin Skeleton Generator") + while True: + option = input("You have picked: ") + + if option == '1': + script = "plugin_skeleton" + break + elif option == "q": + return + else: + print("Incorrect input, try again...") + + run_script(script) + +def run_script(script): + try: + script_path = scripts[script] + full_path = os.path.join(THUNDER_TOOLS_DIR, script_path) + subprocess.run([python_distrubution(), full_path], check=True) + print("Success") + except subprocess.CalledProcessError as e: + print("Error running the script") + +def main(): + parser = argparse.ArgumentParser(description="Run any ThunderDevTool script") + parser.add_argument("--s", help="Choose a script to run: ", choices=scripts.keys()) + arg = parser.parse_args() + + if arg.s: + run_script(arg.s) + else: + script_menu() + +if __name__ == "__main__": + main() \ No newline at end of file From b9398a890f15df5397cd3793211c7c6e9a8bb75d Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Thu, 12 Sep 2024 01:35:41 -0700 Subject: [PATCH 07/12] remarks fix 1 --- ...enerator.py => PluginSkeletonGenerator.py} | 70 +++++-- .../examples/IP_JSONRPC/IP_JSONRPC.conf.in | 1 - .../{IP_JSONRPC => InProcess}/CMakeLists.txt | 9 +- .../examples/InProcess/InProcess.conf.in | 4 + .../InProcess.cpp} | 19 +- .../IP_JSONRPC.h => InProcess/InProcess.h} | 61 ++++-- .../examples/InProcess/InProcessPlugin.json | 32 +++ .../{IP_JSONRPC => InProcess}/Module.cpp | 0 .../{IP_JSONRPC => InProcess}/Module.h | 3 +- .../examples/OOP_JSONRPC/OOP_JSONRPC.conf.in | 1 - .../OOP_JSONRPC/OOP_JSONRPCImplementation.cpp | 46 ----- .../CMakeLists.txt | 11 +- .../{OOP_JSONRPC => OutProcess}/Module.cpp | 0 .../{OOP_JSONRPC => OutProcess}/Module.h | 3 +- .../examples/OutProcess/OutProcess.conf.in | 4 + .../OutProcess.cpp} | 22 +- .../OOP_JSONRPC.h => OutProcess/OutProcess.h} | 47 +++-- .../OutProcess/OutProcessImplementation.cpp | 82 ++++++++ .../examples/OutProcess/OutProcessPlugin.json | 32 +++ PluginSkeletonGenerator/file_data.py | 194 ++++++++++++++---- PluginSkeletonGenerator/global_variables.py | 32 +-- PluginSkeletonGenerator/help.txt | 4 +- .../templates/{cmake.txt => .cmake.txt} | 4 +- .../templates/.plugin_conf_in.txt | 4 + .../{plugin_header.txt => .plugin_header.txt} | 22 +- ...ntation.txt => .plugin_implementation.txt} | 16 +- .../{plugin_source.txt => .plugin_source.txt} | 4 +- .../iplugin_methods/.deinitialize_ip.txt | 1 + ...itialize_oop.txt => .deinitialize_oop.txt} | 2 +- .../iplugin_methods/.initialize_ip.txt | 9 + ...initialize_oop.txt => .initialize_oop.txt} | 6 +- .../iplugin_methods/initialize_ip.txt | 6 - .../templates/json/.json_configuration.txt | 25 +++ .../templates/json/.json_info.txt | 12 ++ .../templates/json/.json_interface.txt | 5 + .../templates/json/.plugin_json.txt | 8 + .../{module_header.txt => .module_header.txt} | 1 + .../{module_source.txt => .module_source.txt} | 0 .../{config_class.txt => .config_class.txt} | 6 +- ...otification.txt => .rpc_inotification.txt} | 2 + .../templates/plugin_conf_in.txt | 1 - .../{helper.py => utils.py} | 21 +- .../{ThunderDev.py => ThunderDevTools.py} | 3 +- 43 files changed, 612 insertions(+), 223 deletions(-) rename PluginSkeletonGenerator/{generator.py => PluginSkeletonGenerator.py} (73%) delete mode 100644 PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in rename PluginSkeletonGenerator/examples/{IP_JSONRPC => InProcess}/CMakeLists.txt (91%) create mode 100644 PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in rename PluginSkeletonGenerator/examples/{IP_JSONRPC/IP_JSONRPC.cpp => InProcess/InProcess.cpp} (69%) rename PluginSkeletonGenerator/examples/{IP_JSONRPC/IP_JSONRPC.h => InProcess/InProcess.h} (55%) create mode 100644 PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json rename PluginSkeletonGenerator/examples/{IP_JSONRPC => InProcess}/Module.cpp (100%) rename PluginSkeletonGenerator/examples/{IP_JSONRPC => InProcess}/Module.h (93%) delete mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in delete mode 100644 PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp rename PluginSkeletonGenerator/examples/{OOP_JSONRPC => OutProcess}/CMakeLists.txt (89%) rename PluginSkeletonGenerator/examples/{OOP_JSONRPC => OutProcess}/Module.cpp (100%) rename PluginSkeletonGenerator/examples/{OOP_JSONRPC => OutProcess}/Module.h (92%) create mode 100644 PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in rename PluginSkeletonGenerator/examples/{OOP_JSONRPC/OOP_JSONRPC.cpp => OutProcess/OutProcess.cpp} (81%) rename PluginSkeletonGenerator/examples/{OOP_JSONRPC/OOP_JSONRPC.h => OutProcess/OutProcess.h} (66%) create mode 100644 PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp create mode 100644 PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json rename PluginSkeletonGenerator/templates/{cmake.txt => .cmake.txt} (98%) create mode 100644 PluginSkeletonGenerator/templates/.plugin_conf_in.txt rename PluginSkeletonGenerator/templates/{plugin_header.txt => .plugin_header.txt} (86%) rename PluginSkeletonGenerator/templates/{plugin_implementation.txt => .plugin_implementation.txt} (86%) rename PluginSkeletonGenerator/templates/{plugin_source.txt => .plugin_source.txt} (91%) create mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_ip.txt rename PluginSkeletonGenerator/templates/iplugin_methods/{deinitialize_oop.txt => .deinitialize_oop.txt} (95%) create mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt rename PluginSkeletonGenerator/templates/iplugin_methods/{initialize_oop.txt => .initialize_oop.txt} (73%) delete mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt create mode 100644 PluginSkeletonGenerator/templates/json/.json_configuration.txt create mode 100644 PluginSkeletonGenerator/templates/json/.json_info.txt create mode 100644 PluginSkeletonGenerator/templates/json/.json_interface.txt create mode 100644 PluginSkeletonGenerator/templates/json/.plugin_json.txt rename PluginSkeletonGenerator/templates/module/{module_header.txt => .module_header.txt} (97%) rename PluginSkeletonGenerator/templates/module/{module_source.txt => .module_source.txt} (100%) rename PluginSkeletonGenerator/templates/nested_class/{config_class.txt => .config_class.txt} (75%) rename PluginSkeletonGenerator/templates/nested_class/{rpc_inotification.txt => .rpc_inotification.txt} (87%) delete mode 100644 PluginSkeletonGenerator/templates/plugin_conf_in.txt rename PluginSkeletonGenerator/{helper.py => utils.py} (68%) rename ThunderDevTools/{ThunderDev.py => ThunderDevTools.py} (91%) diff --git a/PluginSkeletonGenerator/generator.py b/PluginSkeletonGenerator/PluginSkeletonGenerator.py similarity index 73% rename from PluginSkeletonGenerator/generator.py rename to PluginSkeletonGenerator/PluginSkeletonGenerator.py index 632cc5d..ec2acde 100755 --- a/PluginSkeletonGenerator/generator.py +++ b/PluginSkeletonGenerator/PluginSkeletonGenerator.py @@ -20,7 +20,7 @@ import os from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData -from helper import Indenter, FileUtils +from utils import Indenter, FileUtils import global_variables @@ -44,11 +44,11 @@ def generate_file(self, template_path, output_path): template = self.load_template(template_path) if template: code = self.replace_code(template) - indented_code = self.indenter.process_indent(code) - header_path = os.path.join(self.directory, output_path) + indented_code = self.indenter.process_indent(code, output_path) + header_path = os.path.join(self.directory, output_path) with open(header_path, 'w') as f: - f.write(indented_code) + f.write(indented_code) def generate_source(self): self.generate_file(global_variables.PLUGIN_SOURCE_PATH, f'{self.blueprint_data.plugin_name}.cpp') @@ -56,20 +56,21 @@ def generate_source(self): def generate_headers(self): + self.generate_file(global_variables.PLUGIN_HEADER_PATH, f'{self.blueprint_data.plugin_name}.h') + self.generate_file(global_variables.MODULE_HEADER_PATH, "Module.h") + # Although this is a .cpp file, it's actually most like a .h if(self.blueprint_data.out_of_process): + self.blueprint_data.type = HeaderData.HeaderType.HEADER_IMPLEMENTATION + self.blueprint_data.populate_keywords() self.generate_file(global_variables.PLUGIN_IMPLEMENTATION_PATH, f'{self.blueprint_data.plugin_name}Implementation.cpp') - self.generate_file(global_variables.PLUGIN_HEADER_PATH, f'{self.blueprint_data.plugin_name}.h') - self.generate_file(global_variables.MODULE_HEADER_PATH, "Module.h") def generate_cmake(self): self.generate_file(global_variables.CMAKE_PATH, "CMakeLists.txt") def generate_json(self): - # TODO: - # self.generate_file("templates/cmake.txt", "CMakeLists.txt") - pass + self.generate_file(global_variables.PLUGIN_JSON, f'{self.blueprint_data.plugin_name}Plugin.json') def generate_conf_in(self): self.generate_file(global_variables.PLUGIN_CONF_PATH, f'{self.blueprint_data.plugin_name}.conf.in') @@ -120,22 +121,47 @@ def menu(): else: print("Unknown character, try again.") + ''' + TODO: Incomplete + # subsystems support needed (dependend en set) + while True: + sub_systems = input("Is your plugin expected to work out of process: (Enter Y or N)\n") + if(sub_systems.lower() == 'y'): + sub_systems = True + break + elif(sub_systems.lower() == 'n'): + sub_systems = False + break + else: + print("Unknown character, try again.") + + if sub_systems: + preconditions= [] + while True: + precondition = input("Enter subsystem precondition: ") + if not precondition: + break + preconditions.append(precondition) + + # pluginsmartinterface + ''' + data = FileData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) plugin_generator = PluginGenerator(data) - header_data = HeaderData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - source_data = SourceData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - cmake_data = CMakeData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - conf_data = ConfData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - - plugin_generator.blueprint_data = header_data - plugin_generator.generate_headers() - plugin_generator.blueprint_data = source_data - plugin_generator.generate_source() - plugin_generator.blueprint_data = cmake_data - plugin_generator.generate_cmake() - plugin_generator.blueprint_data = conf_data - plugin_generator.generate_conf_in() + file_map = { + HeaderData: plugin_generator.generate_headers, + SourceData: plugin_generator.generate_source, + CMakeData: plugin_generator.generate_cmake, + ConfData: plugin_generator.generate_conf_in, + JSONData: plugin_generator.generate_json + } + + for file_data, generate in file_map.items(): + instance = file_data(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) + instance.populate_keywords() + plugin_generator.blueprint_data = instance + generate() def main(): menu() diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in b/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in deleted file mode 100644 index c367fab..0000000 --- a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.conf.in +++ /dev/null @@ -1 +0,0 @@ -startmode = "@PLUGIN_IP_JSONRPC_STARTMODE@" \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/CMakeLists.txt b/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt similarity index 91% rename from PluginSkeletonGenerator/examples/IP_JSONRPC/CMakeLists.txt rename to PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt index bd69409..4520584 100644 --- a/PluginSkeletonGenerator/examples/IP_JSONRPC/CMakeLists.txt +++ b/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -project(IP_JSONRPC) +project(InProcess) cmake_minimum_required(VERSION 3.15) @@ -27,7 +27,7 @@ set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") -set(PLUGIN_IP_JSONRPC_STARTMODE "Activated" CACHE STRING "Automatically start IP_JSONRPC plugin") +set(PLUGIN_INPROCESS_STARTMODE "Activated" CACHE STRING "Automatically start InProcess plugin") if(BUILD_REFERENCE) add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) @@ -38,7 +38,7 @@ find_package(${NAMESPACE}Definitions REQUIRED) find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED - IP_JSONRPC.cpp + InProcess.cpp ) set_target_properties(${MODULE_NAME} PROPERTIES @@ -58,5 +58,4 @@ target_include_directories( ${MODULE_NAME} install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) -write_config() - +write_config() \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in b/PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in new file mode 100644 index 0000000..29d9838 --- /dev/null +++ b/PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in @@ -0,0 +1,4 @@ +startmode = "@PLUGIN_INPROCESS_STARTMODE@" + +configuration = JSON() +configuration.add("example,"mystring") \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp b/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp similarity index 69% rename from PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp rename to PluginSkeletonGenerator/examples/InProcess/InProcess.cpp index 88d386e..74040db 100644 --- a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.cpp +++ b/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp @@ -17,12 +17,12 @@ * limitations under the License. */ -#include "IP_JSONRPC.h" +#include "InProcess.h" namespace Thunder{ namespace Plugin{ namespace { - static Metadatametadata( + static Metadatametadata( // Version 1, 0, 0, // Preconditions @@ -34,22 +34,27 @@ namespace Plugin{ ) } - // Implement all methods from IP_JSONRPC.h + // Implement all methods from InProcess.h - const string IP_JSONRPC::Initialize(PluginHost::IShell* service) { + const string InProcess::Initialize(PluginHost::IShell* service) { string message; ASSERT (service != nullptr); Config config; config.FromString(service->ConfigLine()); + + Exchange::JHello::Register(*this, this); + Exchange::JWorld::Register(*this, this); + return (message); } - void IP_JSONRPC::Deinitialize(PluginHost::IShell* service) { - + void InProcess::Deinitialize(PluginHost::IShell* service VARIABLE_IS_NOT_USED) { + Exchange::JHello::Unregister(*this); + Exchange::JWorld::Unregister(*this); } - string IP_JSONRPC::Information(PluginHost::IShell* service) { + string InProcess::Information() { return string() } } // Plugin diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h b/PluginSkeletonGenerator/examples/InProcess/InProcess.h similarity index 55% rename from PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h rename to PluginSkeletonGenerator/examples/InProcess/InProcess.h index 4c01b8e..f0005b6 100644 --- a/PluginSkeletonGenerator/examples/IP_JSONRPC/IP_JSONRPC.h +++ b/PluginSkeletonGenerator/examples/InProcess/InProcess.h @@ -18,55 +18,74 @@ */ #pragma once -#include -#include +#include +#include +#include +#include namespace Thunder { namespace Plugin { - class IP_JSONRPC : public PluginHost::IPlugin, public PluginHost::JSONRPC, public COM1 { + class InProcess : public PluginHost::IPlugin, public PluginHost::JSONRPC, public Exchange::IHello, public Exchange::IWorld { public: - IP_JSONRPC(const IP_JSONRPC&) = delete; - IP_JSONRPC &operator=(const IP_JSONRPC&) = delete; - IP_JSONRPC() {} - ~IP_JSONRPC override {} - - private: + InProcess(const InProcess&) = delete; + InProcess &operator=(const InProcess&) = delete; + InProcess(InProcess&&) = delete; + InProcess &operator=(InProcess&&) = delete; + + InProcess() + : IHello() + , IWorld() + , _example(0) + { + } + ~InProcess() override = default; + private: class Config : public Core::JSON::Container { private: Config(const Config&) = delete; Config& operator=(const Config&) = delete; + Config(Config&&) = delete; + Config& operator=(Config&&) = delete; public: Config() - : Example("Example") + : Core::JSON::Container() { Add(_T("example"), &Example); } - ~Config(){} + ~Config() override = default; public: Core::JSON::String Example; } - public: - - // Inherited Methods + // IPlugin Methods const string Initialize(PluginHost::IShell* service) override; void Deinitialize(PluginHost::IShell* service) override; string Information() const override; - void COM1Method1() override; - void COM1Method2() override; - // Plugin Methods - void IP_JSONRPCMethod(1); - BEGIN_INTERFACE_MAP(IP_JSONRPC) - INTERFACE_ENTRY(COM1) + // IHello methods + void IHelloMethod1() override; + void IHelloMethod2() override; + + // IWorld methods + void IWorldMethod1() override; + void IWorldMethod2() override; + // Plugin Methods + void InProcessMethod(1); + + BEGIN_INTERFACE_MAP(InProcess) + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_ENTRY(Exchange::IHello) + INTERFACE_ENTRY(Exchange::IWorld) END_INTERFACE_MAP + private: // Include the correct member variables for your plugin: // Note this is only an example, you are responsible for adding the correct members: - uint32_t _connectionId; + uint32_t _example; }; } } \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json b/PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json new file mode 100644 index 0000000..5eace07 --- /dev/null +++ b/PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json @@ -0,0 +1,32 @@ +{ + "$schema": "plugin.schema.json", + "info": { + "title": "InProcess Plugin", + "callsign": "InProcess", + "locator": "libThunderInProcess.so", + "status": "production", + "description": [ + "" + ], + "version": "1.0" + }, + "configuration": { + "type": "object", + "properties": { + "configuration": { + "type": "object", + "required": [], + "properties": { + "example": { + "type": "string", + "description": "Note: This is an example!" + } + } + } + } + }, + "interface": { + "$cppref": "{cppinterfacedir}/IHello.h", + "$cppref": "{cppinterfacedir}/IWorld.h" + } +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.cpp b/PluginSkeletonGenerator/examples/InProcess/Module.cpp similarity index 100% rename from PluginSkeletonGenerator/examples/IP_JSONRPC/Module.cpp rename to PluginSkeletonGenerator/examples/InProcess/Module.cpp diff --git a/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h b/PluginSkeletonGenerator/examples/InProcess/Module.h similarity index 93% rename from PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h rename to PluginSkeletonGenerator/examples/InProcess/Module.h index f2e0f0b..307a6a2 100644 --- a/PluginSkeletonGenerator/examples/IP_JSONRPC/Module.h +++ b/PluginSkeletonGenerator/examples/InProcess/Module.h @@ -20,9 +20,10 @@ #pragma once #ifndef MODULE_NAME -#define MODULE_NAME Plugin_IP_JSONRPC +#define MODULE_NAME Plugin_InProcess #endif +#include #include #undef EXTERNAL diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in deleted file mode 100644 index c1d52d5..0000000 --- a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.conf.in +++ /dev/null @@ -1 +0,0 @@ -startmode = "@PLUGIN_OOP_JSONRPC_STARTMODE@" \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp b/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp deleted file mode 100644 index d3bf03a..0000000 --- a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPCImplementation.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include - -namespace Thunder { -namespace Plugin { - SERVICE_REGISTRATION(OOP_JSONRPCImplementation, 1, 0) - - class OOP_JSONRPCImplementation : public COM1 { - public: - OOP_JSONRPCImplementation(const OOP_JSONRPCImplementation&) = delete; - OOP_JSONRPCImplementation& operator=(const OOP_JSONRPCImplementation&) = delete; - - OOP_JSONRPCImplementation(); - ~OOP_JSONRPCImplementation() override = default; - - BEGIN_INTERFACE_MAP(OOP_JSONRPCImplementation) - INTERFACE_ENTRY(COM1) - END_INTERFACE_MAP - - // Implement methods from the interface - - private: - // Add data members, for example: (Core::CriticalSection, std::vector..) - }; -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/CMakeLists.txt b/PluginSkeletonGenerator/examples/OutProcess/CMakeLists.txt similarity index 89% rename from PluginSkeletonGenerator/examples/OOP_JSONRPC/CMakeLists.txt rename to PluginSkeletonGenerator/examples/OutProcess/CMakeLists.txt index 365a3d9..448cc98 100644 --- a/PluginSkeletonGenerator/examples/OOP_JSONRPC/CMakeLists.txt +++ b/PluginSkeletonGenerator/examples/OutProcess/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -project(OOP_JSONRPC) +project(OutProcess) cmake_minimum_required(VERSION 3.15) @@ -27,7 +27,7 @@ set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") -set(PLUGIN_OOP_JSONRPC_STARTMODE "Activated" CACHE STRING "Automatically start OOP_JSONRPC plugin") +set(PLUGIN_OUTPROCESS_STARTMODE "Activated" CACHE STRING "Automatically start OutProcess plugin") if(BUILD_REFERENCE) add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) @@ -38,8 +38,8 @@ find_package(${NAMESPACE}Definitions REQUIRED) find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED - OOP_JSONRPC.cpp - OOP_JSONRPCImplementation.cpp + OutProcess.cpp + OutProcessImplementation.cpp ) set_target_properties(${MODULE_NAME} PROPERTIES @@ -59,5 +59,4 @@ target_include_directories( ${MODULE_NAME} install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) -write_config() - +write_config() \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.cpp b/PluginSkeletonGenerator/examples/OutProcess/Module.cpp similarity index 100% rename from PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.cpp rename to PluginSkeletonGenerator/examples/OutProcess/Module.cpp diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h b/PluginSkeletonGenerator/examples/OutProcess/Module.h similarity index 92% rename from PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h rename to PluginSkeletonGenerator/examples/OutProcess/Module.h index 5262400..84622b3 100644 --- a/PluginSkeletonGenerator/examples/OOP_JSONRPC/Module.h +++ b/PluginSkeletonGenerator/examples/OutProcess/Module.h @@ -20,9 +20,10 @@ #pragma once #ifndef MODULE_NAME -#define MODULE_NAME Plugin_OOP_JSONRPC +#define MODULE_NAME Plugin_OutProcess #endif +#include #include #undef EXTERNAL diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in b/PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in new file mode 100644 index 0000000..e502d7f --- /dev/null +++ b/PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in @@ -0,0 +1,4 @@ +startmode = "@PLUGIN_OUTPROCESS_STARTMODE@" + +configuration = JSON() +configuration.add("example,"mystring") \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp b/PluginSkeletonGenerator/examples/OutProcess/OutProcess.cpp similarity index 81% rename from PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp rename to PluginSkeletonGenerator/examples/OutProcess/OutProcess.cpp index 5cd1e6d..7ad6bf8 100644 --- a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.cpp +++ b/PluginSkeletonGenerator/examples/OutProcess/OutProcess.cpp @@ -17,12 +17,12 @@ * limitations under the License. */ -#include "OOP_JSONRPC.h" +#include "OutProcess.h" namespace Thunder{ namespace Plugin{ namespace { - static Metadatametadata( + static Metadatametadata( // Version 1, 0, 0, // Preconditions @@ -34,9 +34,9 @@ namespace Plugin{ ) } - // Implement all methods from OOP_JSONRPC.h + // Implement all methods from OutProcess.h - const string OOP_JSONRPC::Initialize(PluginHost::IShell* service) { + const string OutProcess::Initialize(PluginHost::IShell* service) { string message; ASSERT (_service == nullptr); @@ -48,20 +48,21 @@ namespace Plugin{ _service->AddRef(); _service->Register(&_connectionNotification); - implementation = - service->Root(_connectionId, 2000, _T("OOP_JSONRPCImplementation")); + // Example + _implementation = service->Root(_connectionId, 2000, _T("OutProcessImplementation")); if (_implementation == nullptr) { message = _T("Couldn't create instance"); } else { // Add registration e.g: //_implementation->Register(&_volumeNotification); - // Exchange::JVolumeControl::Register(*this, _implementation); + Exchange::JHello::Register(*this, implJHello); + Exchange::JWorld::Register(*this, implJWorld); } return (message); } - void OOP_JSONRPC::Deinitialize(PluginHost::IShell* service) { + void OutProcess::Deinitialize(PluginHost::IShell* service) { if (_service != nullptr) { ASSERT(_service == service); @@ -69,7 +70,8 @@ namespace Plugin{ if (_implementation != nullptr) { // Example if your interface has inotification implemented - //Exchange::JVolumeControl::Unregister(*this); + Exchange::JHello::Unregister(*this); + Exchange::JWorld::Unregister(*this); //_implementation->Unregister(&_volumeNotification); RPC::IRemoteConnection* connection(_service->RemoteConnection(_connectionId)); @@ -92,7 +94,7 @@ namespace Plugin{ } } - string OOP_JSONRPC::Information(PluginHost::IShell* service) { + string OutProcess::Information() { return string() } } // Plugin diff --git a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h b/PluginSkeletonGenerator/examples/OutProcess/OutProcess.h similarity index 66% rename from PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h rename to PluginSkeletonGenerator/examples/OutProcess/OutProcess.h index eb71bbc..52ad6ac 100644 --- a/PluginSkeletonGenerator/examples/OOP_JSONRPC/OOP_JSONRPC.h +++ b/PluginSkeletonGenerator/examples/OutProcess/OutProcess.h @@ -18,25 +18,31 @@ */ #pragma once -#include -#include +#include +#include +#include +#include namespace Thunder { namespace Plugin { - class OOP_JSONRPC : public PluginHost::IPlugin, public PluginHost::JSONRPC { + class OutProcess : public PluginHost::IPlugin, public PluginHost::JSONRPC { public: - OOP_JSONRPC(const OOP_JSONRPC&) = delete; - OOP_JSONRPC &operator=(const OOP_JSONRPC&) = delete; - OOP_JSONRPC() {} - ~OOP_JSONRPC override {} - - private: + OutProcess(const OutProcess&) = delete; + OutProcess &operator=(const OutProcess&) = delete; + OutProcess(OutProcess&&) = delete; + OutProcess &operator=(OutProcess&&) = delete; + OutProcess() + : _example(0) + { + } + ~OutProcess() override = default; + private: class ConnectionNotification : public RPC::IRemoteConnection::INotification { public: - explicit ConnectionNotification(OOP_JSONRPC* parent) + explicit ConnectionNotification(OutProcess* parent) : _parent(*parent) { ASSERT(parent != nullptr); @@ -46,6 +52,8 @@ namespace Plugin { ConnectionNotification() = delete; ConnectionNotification(const ConnectionNotification&) = delete; ConnectionNotification& operator=(const ConnectionNotification&) = delete; + ConnectionNotification(ConnectionNotification&&) = delete; + ConnectionNotification& operator=(ConnectionNotification&&) = delete; void Activated(RPC::IRemoteConnection*) override { @@ -60,26 +68,29 @@ namespace Plugin { INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) END_INTERFACE_MAP private: - OOP_JSONRPC& _parent; + OutProcess& _parent; } public: - - // Inherited Methods + // IPlugin Methods const string Initialize(PluginHost::IShell* service) override; void Deinitialize(PluginHost::IShell* service) override; string Information() const override; + // Plugin Methods - void OOP_JSONRPCMethod(1); + void OutProcessMethod(1); - BEGIN_INTERFACE_MAP(OOP_JSONRPC) - INTERFACE_ENTRY(COM1) - INTERFACE_AGGREGATE(COM1, _impl) + BEGIN_INTERFACE_MAP(OutProcess) + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_AGGREGATE(Exchange::IHello, _implIHello) + INTERFACE_AGGREGATE(Exchange::IWorld, _implIWorld) END_INTERFACE_MAP + private: // Include the correct member variables for your plugin: // Note this is only an example, you are responsible for adding the correct members: - uint32_t _connectionId; + uint32_t _example; }; } } \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp b/PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp new file mode 100644 index 0000000..e42c2b4 --- /dev/null +++ b/PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp @@ -0,0 +1,82 @@ +/* +* If not stated otherwise in this file or this component's LICENSE file the +* following copyright and licenses apply: +* +* Copyright 2024 Metrological +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include +#include + +namespace Thunder { +namespace Plugin { + SERVICE_REGISTRATION(OutProcessImplementation, 1, 0) + + class OutProcessImplementation : public IHello, public IWorld { + public: + OutProcessImplementation(const OutProcessImplementation&) = delete; + OutProcessImplementation& operator=(const OutProcessImplementation&) = delete; + + OutProcessImplementation() + : IHello() + , IWorld() + , _test(0) + { + } + ~OutProcessImplementation() override = default; + + private: + + class Config : public Core::JSON::Container { + private: + Config(const Config&) = delete; + Config& operator=(const Config&) = delete; + Config(Config&&) = delete; + Config& operator=(Config&&) = delete; + public: + Config() + : Core::JSON::Container() + { + Add(_T("example"), &Example); + } + ~Config() override = default; + public: + Core::JSON::String Example; + } + + public: + + BEGIN_INTERFACE_MAP(OutProcessImplementation) + INTERFACE_ENTRY(Exchange::IHello) + INTERFACE_ENTRY(Exchange::IWorld) + END_INTERFACE_MAP + + // Implement methods from the interface + // IHello methods + void IHelloMethod1() override; + void IHelloMethod2() override; + + // IWorld methods + void IWorldMethod1() override; + void IWorldMethod2() override; + + private: + // Add data members, for example: (Core::CriticalSection, std::vector..) + uint32_t _test; + }; +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json b/PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json new file mode 100644 index 0000000..732e85c --- /dev/null +++ b/PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json @@ -0,0 +1,32 @@ +{ + "$schema": "plugin.schema.json", + "info": { + "title": "OutProcess Plugin", + "callsign": "OutProcess", + "locator": "libThunderOutProcess.so", + "status": "production", + "description": [ + "" + ], + "version": "1.0" + }, + "configuration": { + "type": "object", + "properties": { + "configuration": { + "type": "object", + "required": [], + "properties": { + "example": { + "type": "string", + "description": "Note: This is an example!" + } + } + } + } + }, + "interface": { + "$cppref": "{cppinterfacedir}/IHello.h", + "$cppref": "{cppinterfacedir}/IWorld.h" + } +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/file_data.py b/PluginSkeletonGenerator/file_data.py index 7254bf8..d6f722f 100644 --- a/PluginSkeletonGenerator/file_data.py +++ b/PluginSkeletonGenerator/file_data.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -from helper import FileUtils +from utils import FileUtils +from enum import Enum import global_variables class FileData: @@ -21,11 +22,18 @@ def generate_keywords_map(self): class HeaderData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + class HeaderType(Enum): + HEADER = 1 + HEADER_IMPLEMENTATION = 2 + + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, type=None) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - self.keywords = super().generate_keywords_map() - self.keywords.update(self.generate_keywords_map()) + self.type = type if type else HeaderData.HeaderType.HEADER + self.keywords = self.keywords.copy() + + def populate_keywords(self): + self.keywords.update(self.generate_keyword_map()) self.keywords.update(self.generate_nested_map()) def generate_jsonrpc_includes(self): @@ -51,9 +59,9 @@ def generate_inherited_classes(self): if not self.out_of_process: for inherited_class in self.comrpc_interfaces: - inheritance.append(f'public {inherited_class}') + inheritance.append(f'public Exchange::{inherited_class}') - all_inheritance = ', '.join(inheritance) + all_inheritance = f', '.join(inheritance) return all_inheritance def generate_oop_inherited_classes(self): @@ -71,32 +79,45 @@ def generate_oop_inherited_classes(self): def generate_inherited_methods(self): methods = [] - if not self.out_of_process: + + if (not self.out_of_process) or \ + ((self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION)): for inherited in self.comrpc_interfaces: + comment = f'// {inherited} methods' method1 = f'void {inherited}Method1() override;' - method2 = f'void {inherited}Method2() override;' - methods.extend([method1,method2]) + method2 = f'void {inherited}Method2() override;\n' + methods.extend([comment,method1,method2]) return ('\n').join(methods) def generate_plugin_methods(self): + method = f'void {self.plugin_name}Method(1);' return method def generate_interface_entry(self): entries = [] - for comrpc in self.comrpc_interfaces: - entry = f'INTERFACE_ENTRY({comrpc})' - entries.append(entry) - return ('\n').join(entries) - + if self.type == HeaderData.HeaderType.HEADER: + entries.append(f'INTERFACE_ENTRY(PluginHost::IPlugin)') + + if self.jsonrpc: + entries.append(f'INTERFACE_ENTRY(PluginHost::IDispatcher)') + + if (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ + ((not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER)): + for comrpc in self.comrpc_interfaces: + entry = f'INTERFACE_ENTRY(Exchange::{comrpc})' + entries.append(entry) + entries = ('\n').join(entries) + return entries if entries else 'rm\*n' + def generate_interface_aggregate(self): aggregates = [] if(self.out_of_process): - aggregates = [] for comrpc in self.comrpc_interfaces: - aggregate = f'INTERFACE_AGGREGATE({comrpc}, _impl)' + aggregate = f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc})' aggregates.append(aggregate) - return ('\n').join(aggregates) + test = ('\n').join(aggregates) + return test if aggregates else 'rm\*n' def generate_data_members(self): return 'DATA_MEMBER' @@ -107,7 +128,18 @@ def generate_module_plugin_name(self): def generate_comrpc_interface(self): return "Test_COMRPC" - def generate_keywords_map(self): + def generate_interface_constructor(self): + constructor = [] + if (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ + ((not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER)): + + constructor.append(f' {self.comrpc_interfaces[0]}()\n,') + for comrpc in self.comrpc_interfaces[1:]: + constructor.append(f' {comrpc}()\n,') + return ''.join(constructor) + + + def generate_keyword_map(self): return{ '{{JSONRPC_INTERFACE_INCLUDES}}' : self.generate_jsonrpc_includes(), '{{COMRPC_INTERFACE_INCLUDES}}' : self.generate_comrpc_includes(), @@ -119,7 +151,8 @@ def generate_keywords_map(self): '{{DATA_MEMBERS}}' : self.generate_data_members(), '{{MODULE_PLUGIN_NAME}}' : self.generate_module_plugin_name(), '{{COMRPC_INTERFACE}}' : self.generate_comrpc_interface(), - '{{OOP_INHERITED_CLASS}}' : self.generate_oop_inherited_classes() + '{{OOP_INHERITED_CLASS}}' : self.generate_oop_inherited_classes(), + '{{INTERFACE_CONSTRUCTOR}}' : self.generate_interface_constructor() } def generate_nested_map(self): @@ -134,23 +167,25 @@ def generate_jsonrpc_event(self): template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template,self.keywords) return code - return ' ' + return 'rm\*n' def generate_config(self): - if not self.out_of_process: + if (not self.out_of_process) or (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION): template_name = global_variables.CONFIG_CLASS_PATH template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template,self.keywords) return code - return ' ' + return 'rm\*n' class SourceData(FileData): def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - self.keywords = super().generate_keywords_map() - self.keywords.update(self.generate_keywords_map()) + self.keywords = self.keywords.copy() + + def populate_keywords(self): + self.keywords.update(self.generate_keyword_map()) self.keywords.update(self.generate_nested_map()) def generate_include_statements(self): @@ -177,20 +212,57 @@ def generate_deinitialize(self): if self.out_of_process: template_name = global_variables.DENINITIALIZE_OOP_PATH + else: + template_name = global_variables.DENINITIALIZE_IP_PATH - template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) - return code - return "" + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + + def generate_variable_used(self): + + if self.out_of_process: + return '' + return " VARIABLE_IS_NOT_USED" + + def generate_jsonrpc_register(self): - def generate_keywords_map(self): + registers = [] + if not self.out_of_process: + for jsonrpc in self.jsonrpc_interfaces: + registers.append(f'Exchange::{jsonrpc}::Register(*this, this);') + else: + for jsonrpc in self.jsonrpc_interfaces: + registers.append(f'Exchange::{jsonrpc}::Register(*this, impl{jsonrpc});') + + registers = ('\n').join(registers) + return registers if registers else 'rm\*n' + + def generate_jsonrpc_unregister(self): + + registers = [] + if not self.out_of_process: + for jsonrpc in self.jsonrpc_interfaces: + registers.append(f'Exchange::{jsonrpc}::Unregister(*this);') + else: + for jsonrpc in self.jsonrpc_interfaces: + registers.append(f'Exchange::{jsonrpc}::Unregister(*this);') + + registers = ('\n').join(registers) + return registers if registers else 'rm\*n' + + def generate_keyword_map(self): return { '{{INCLUDE}}' : self.generate_include_statements(), '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), '{{PRECONDITIONS}}' : "conditions", '{{TERMINATIONS}}' : "terminations", - '{{CONTROLS}}' : "controls" + '{{CONTROLS}}' : "controls", + '{{VARIABLE_NOT_USED}}' : self.generate_variable_used(), + '{{JSONRPC_REGISTER}}' : self.generate_jsonrpc_register(), + '{{JSONRPC_UNREGISTER}}' : self.generate_jsonrpc_unregister(), + '{{COMRPC}}' : f'{self.comrpc_interfaces[0]}' } def generate_nested_map(self): @@ -202,10 +274,13 @@ def generate_nested_map(self): class CMakeData(FileData): def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - self.keywords = super().generate_keywords_map() - self.keywords.update(self.generate_keywords_map()) + self.keywords = self.keywords.copy() - def generate_keywords_map(self): + def populate_keywords(self): + self.keywords.update(self.generate_keyword_map()) + #self.keywords.update(self.generate_nested_map()) + + def generate_keyword_map(self): return { '{{SOURCE_FILES}}' : self.find_source_files() } @@ -219,16 +294,59 @@ def find_source_files(self): class JSONData(FileData): def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - self.keywords = super().generate_keywords_map() - self.keywords.update(self.generate_keywords_map()) + self.keywords = self.keywords.copy() + + def populate_keywords(self): + self.keywords.update(self.generate_keyword_map()) + self.keywords.update(self.generate_nested_map()) + + def generate_cppref(self): + cpprefs = [] + for comrpc in self.comrpc_interfaces: + cpprefs.append(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"') + + return ",\n".join(cpprefs) if cpprefs else 'rm\*n' + + def generate_json_info(self): + template_name = global_variables.JSON_INFO + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + + def generate_json_configuration(self): + template_name = global_variables.JSON_CONFIGURATION + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + + def generate_json_interface(self): + template_name = global_variables.JSON_INTERFACE + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template,self.keywords) + return code + + def generate_keyword_map(self): + return { + '{{cppref}}' : self.generate_cppref(), + } + + def generate_nested_map(self): + return { + '{{JSON_INFO}}' : self.generate_json_info(), + '{{JSON_CONFIGURATION}}' : self.generate_json_configuration(), + '{{JSON_INTERFACE}}' : self.generate_json_interface() + } class ConfData(FileData): def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - self.keywords = super().generate_keywords_map() - self.keywords.update(self.generate_keywords_map()) + self.keywords = self.keywords.copy() - def generate_keywords_map(self): + def populate_keywords(self): + self.keywords.update(self.generate_keyword_map()) + #self.keywords.update(self.generate_nested_map()) + + def generate_keyword_map(self): return { '{{PLUGIN_STARTMODE}}' : f'"@PLUGIN_{self.plugin_name.upper()}_STARTMODE@"' } diff --git a/PluginSkeletonGenerator/global_variables.py b/PluginSkeletonGenerator/global_variables.py index 15928cd..2f82e8f 100644 --- a/PluginSkeletonGenerator/global_variables.py +++ b/PluginSkeletonGenerator/global_variables.py @@ -8,24 +8,32 @@ IPLUGIN_DIR = os.path.join(TEMPLATE_DIR,'iplugin_methods') MODULE_DIR = os.path.join(TEMPLATE_DIR, 'module') NESTED_CLASS_DIR = os.path.join(TEMPLATE_DIR, 'nested_class') +JSON_DIR = os.path.join(TEMPLATE_DIR,'json') # Nested File Paths: # /templates -CMAKE_PATH = os.path.join(TEMPLATE_DIR,'cmake.txt') -PLUGIN_CONF_PATH = os.path.join(TEMPLATE_DIR,'plugin_conf_in.txt') -PLUGIN_HEADER_PATH = os.path.join(TEMPLATE_DIR,'plugin_header.txt') -PLUGIN_IMPLEMENTATION_PATH = os.path.join(TEMPLATE_DIR,'plugin_implementation.txt') -PLUGIN_SOURCE_PATH = os.path.join(TEMPLATE_DIR,'plugin_source.txt') +CMAKE_PATH = os.path.join(TEMPLATE_DIR,'.cmake.txt') +PLUGIN_CONF_PATH = os.path.join(TEMPLATE_DIR,'.plugin_conf_in.txt') +PLUGIN_HEADER_PATH = os.path.join(TEMPLATE_DIR,'.plugin_header.txt') +PLUGIN_IMPLEMENTATION_PATH = os.path.join(TEMPLATE_DIR,'.plugin_implementation.txt') +PLUGIN_SOURCE_PATH = os.path.join(TEMPLATE_DIR,'.plugin_source.txt') # /templates/iplugin_methods -DENINITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'deinitialize_oop.txt') -INITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'initialize_oop.txt') -INITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR,'initialize_ip.txt') +DENINITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'.deinitialize_oop.txt') +DENINITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR, '.deinitialize_ip.txt') +INITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'.initialize_oop.txt') +INITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR,'.initialize_ip.txt') # /templates/module -MODULE_HEADER_PATH = os.path.join(MODULE_DIR,'module_header.txt') -MODULE_SOURCE_PATH = os.path.join(MODULE_DIR,'module_source.txt') +MODULE_HEADER_PATH = os.path.join(MODULE_DIR,'.module_header.txt') +MODULE_SOURCE_PATH = os.path.join(MODULE_DIR,'.module_source.txt') # /templates/nested_class -CONFIG_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'config_class.txt') -RPC_NOTIFICATION_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'rpc_inotification.txt') \ No newline at end of file +CONFIG_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'.config_class.txt') +RPC_NOTIFICATION_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'.rpc_inotification.txt') + +# /templates/.json +PLUGIN_JSON = os.path.join(JSON_DIR, '.plugin_json.txt') +JSON_INFO = os.path.join(JSON_DIR, '.json_info.txt') +JSON_CONFIGURATION = os.path.join(JSON_DIR, '.json_configuration.txt') +JSON_INTERFACE = os.path.join(JSON_DIR, '.json_interface.txt') \ No newline at end of file diff --git a/PluginSkeletonGenerator/help.txt b/PluginSkeletonGenerator/help.txt index e3d4be4..f535040 100644 --- a/PluginSkeletonGenerator/help.txt +++ b/PluginSkeletonGenerator/help.txt @@ -1,5 +1,5 @@ To run this tool: -./generator.py +./PluginSkeletonGenerator.py or python3 PluginSkeletonGenerator.py -And answer the questions accordingly. +Answer the questions accordingly. To see examples of what the skelton is capable of, see the examples folder. \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/cmake.txt b/PluginSkeletonGenerator/templates/.cmake.txt similarity index 98% rename from PluginSkeletonGenerator/templates/cmake.txt rename to PluginSkeletonGenerator/templates/.cmake.txt index e26f716..f04ef46 100644 --- a/PluginSkeletonGenerator/templates/cmake.txt +++ b/PluginSkeletonGenerator/templates/.cmake.txt @@ -70,6 +70,4 @@ install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) ~INDENT_DECREASE~ -write_config() - - +write_config() \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/.plugin_conf_in.txt b/PluginSkeletonGenerator/templates/.plugin_conf_in.txt new file mode 100644 index 0000000..efbec70 --- /dev/null +++ b/PluginSkeletonGenerator/templates/.plugin_conf_in.txt @@ -0,0 +1,4 @@ +startmode = {{PLUGIN_STARTMODE}} + +configuration = JSON() +configuration.add("example,"mystring") \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/plugin_header.txt b/PluginSkeletonGenerator/templates/.plugin_header.txt similarity index 86% rename from PluginSkeletonGenerator/templates/plugin_header.txt rename to PluginSkeletonGenerator/templates/.plugin_header.txt index a6e4086..f3f5ad1 100644 --- a/PluginSkeletonGenerator/templates/plugin_header.txt +++ b/PluginSkeletonGenerator/templates/.plugin_header.txt @@ -31,23 +31,28 @@ namespace Plugin { ~INDENT_INCREASE~ {{PLUGIN_NAME}}(const {{PLUGIN_NAME}}&) = delete; {{PLUGIN_NAME}} &operator=(const {{PLUGIN_NAME}}&) = delete; - {{PLUGIN_NAME}}() {} - ~{{PLUGIN_NAME}} override {} -~INDENT_DECREASE~ + {{PLUGIN_NAME}}({{PLUGIN_NAME}}&&) = delete; + {{PLUGIN_NAME}} &operator=({{PLUGIN_NAME}}&&) = delete; + {{PLUGIN_NAME}}() + :{{INTERFACE_CONSTRUCTOR}} _example(0) + { + } + + ~{{PLUGIN_NAME}}() override = default; +~INDENT_DECREASE~ private: ~INDENT_INCREASE~ - {{CONFIG_CLASS}} {{JSONRPC_EVENT}} ~INDENT_DECREASE~ public: ~INDENT_INCREASE~ - - // Inherited Methods + // IPlugin Methods const string Initialize(PluginHost::IShell* service) override; void Deinitialize(PluginHost::IShell* service) override; string Information() const override; + {{INHERITED_METHOD}} // Plugin Methods {{PLUGIN_METHOD}} @@ -56,14 +61,15 @@ namespace Plugin { {{INTERFACE_ENTRY}} {{INTERFACE_AGGREGATE}} END_INTERFACE_MAP + ~INDENT_DECREASE~ private: ~INDENT_INCREASE~ // Include the correct member variables for your plugin: // Note this is only an example, you are responsible for adding the correct members: - uint32_t _connectionId; + uint32_t _example; ~INDENT_DECREASE~ }; ~INDENT_DECREASE~ } -} +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/plugin_implementation.txt b/PluginSkeletonGenerator/templates/.plugin_implementation.txt similarity index 86% rename from PluginSkeletonGenerator/templates/plugin_implementation.txt rename to PluginSkeletonGenerator/templates/.plugin_implementation.txt index 44c4d26..dd3c241 100644 --- a/PluginSkeletonGenerator/templates/plugin_implementation.txt +++ b/PluginSkeletonGenerator/templates/.plugin_implementation.txt @@ -32,9 +32,22 @@ namespace Plugin { {{PLUGIN_NAME}}Implementation(const {{PLUGIN_NAME}}Implementation&) = delete; {{PLUGIN_NAME}}Implementation& operator=(const {{PLUGIN_NAME}}Implementation&) = delete; - {{PLUGIN_NAME}}Implementation(); + {{PLUGIN_NAME}}Implementation() + :{{INTERFACE_CONSTRUCTOR}} _test(0) + { + } ~{{PLUGIN_NAME}}Implementation() override = default; +~INDENT_DECREASE~ + private: + +~INDENT_INCREASE~ + {{CONFIG_CLASS}} +~INDENT_DECREASE~ + + public: +~INDENT_INCREASE~ + BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}Implementation) {{INTERFACE_ENTRY}} END_INTERFACE_MAP @@ -45,6 +58,7 @@ namespace Plugin { private: ~INDENT_INCREASE~ // Add data members, for example: (Core::CriticalSection, std::vector..) + uint32_t _test; ~INDENT_DECREASE~ }; ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/plugin_source.txt b/PluginSkeletonGenerator/templates/.plugin_source.txt similarity index 91% rename from PluginSkeletonGenerator/templates/plugin_source.txt rename to PluginSkeletonGenerator/templates/.plugin_source.txt index 7803070..cebeb58 100644 --- a/PluginSkeletonGenerator/templates/plugin_source.txt +++ b/PluginSkeletonGenerator/templates/.plugin_source.txt @@ -47,13 +47,13 @@ const string {{PLUGIN_NAME}}::Initialize(PluginHost::IShell* service) { ~INDENT_DECREASE~ } -void {{PLUGIN_NAME}}::Deinitialize(PluginHost::IShell* service) { +void {{PLUGIN_NAME}}::Deinitialize(PluginHost::IShell* service{{VARIABLE_NOT_USED}}) { ~INDENT_INCREASE~ {{DEINITIALIZE_IMPLEMENTATION}} ~INDENT_DECREASE~ } -string {{PLUGIN_NAME}}::Information(PluginHost::IShell* service) { +string {{PLUGIN_NAME}}::Information() { ~INDENT_INCREASE~ return string() ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_ip.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_ip.txt new file mode 100644 index 0000000..699c17b --- /dev/null +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_ip.txt @@ -0,0 +1 @@ +{{JSONRPC_UNREGISTER}} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt similarity index 95% rename from PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt rename to PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt index 5162119..dff337a 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/deinitialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt @@ -7,7 +7,7 @@ service->Unregister(&_connectionNotification); if (_implementation != nullptr) { ~INDENT_INCREASE~ // Example if your interface has inotification implemented - //Exchange::JVolumeControl::Unregister(*this); + {{JSONRPC_UNREGISTER}} //_implementation->Unregister(&_volumeNotification); RPC::IRemoteConnection* connection(_service->RemoteConnection(_connectionId)); diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt new file mode 100644 index 0000000..74ed009 --- /dev/null +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt @@ -0,0 +1,9 @@ +string message; + +ASSERT (service != nullptr); + +Config config; +config.FromString(service->ConfigLine()); + +{{JSONRPC_REGISTER}} +return (message); \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt similarity index 73% rename from PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt rename to PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt index e887dd9..0a31d22 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/initialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt @@ -9,8 +9,8 @@ _service = service; _service->AddRef(); _service->Register(&_connectionNotification); -implementation = -service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); +// Example +_implementation = service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); if (_implementation == nullptr) { ~INDENT_INCREASE~ message = _T("Couldn't create instance"); @@ -19,7 +19,7 @@ if (_implementation == nullptr) { ~INDENT_INCREASE~ // Add registration e.g: //_implementation->Register(&_volumeNotification); - // Exchange::JVolumeControl::Register(*this, _implementation); + {{JSONRPC_REGISTER}} ~INDENT_DECREASE~ } diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt b/PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt deleted file mode 100644 index bd79b20..0000000 --- a/PluginSkeletonGenerator/templates/iplugin_methods/initialize_ip.txt +++ /dev/null @@ -1,6 +0,0 @@ -string message; - -ASSERT (service != nullptr); - -Config config; -config.FromString(service->ConfigLine()); \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/json/.json_configuration.txt b/PluginSkeletonGenerator/templates/json/.json_configuration.txt new file mode 100644 index 0000000..1996272 --- /dev/null +++ b/PluginSkeletonGenerator/templates/json/.json_configuration.txt @@ -0,0 +1,25 @@ +"configuration": { + ~INDENT_INCREASE~ + "type": "object", + "properties": { + ~INDENT_INCREASE~ + "configuration": { + ~INDENT_INCREASE~ + "type": "object", + "required": [], + "properties": { + ~INDENT_INCREASE~ + "example": { + ~INDENT_INCREASE~ + "type": "string", + "description": "Note: This is an example!" + ~INDENT_DECREASE~ + } + ~INDENT_DECREASE~ + } + ~INDENT_DECREASE~ + } + ~INDENT_DECREASE~ + } + ~INDENT_DECREASE~ +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/json/.json_info.txt b/PluginSkeletonGenerator/templates/json/.json_info.txt new file mode 100644 index 0000000..8a66b06 --- /dev/null +++ b/PluginSkeletonGenerator/templates/json/.json_info.txt @@ -0,0 +1,12 @@ +"info": { + ~INDENT_INCREASE~ + "title": "{{PLUGIN_NAME}} Plugin", + "callsign": "{{PLUGIN_NAME}}", + "locator": "libThunder{{PLUGIN_NAME}}.so", + "status": "production", + "description": [ + "" + ], + "version": "1.0" + ~INDENT_DECREASE~ + } \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/json/.json_interface.txt b/PluginSkeletonGenerator/templates/json/.json_interface.txt new file mode 100644 index 0000000..6385984 --- /dev/null +++ b/PluginSkeletonGenerator/templates/json/.json_interface.txt @@ -0,0 +1,5 @@ +"interface": { + ~INDENT_INCREASE~ + {{cppref}} + ~INDENT_DECREASE~ + } \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/json/.plugin_json.txt b/PluginSkeletonGenerator/templates/json/.plugin_json.txt new file mode 100644 index 0000000..a0ba934 --- /dev/null +++ b/PluginSkeletonGenerator/templates/json/.plugin_json.txt @@ -0,0 +1,8 @@ +{ +~INDENT_INCREASE~ + "$schema": "plugin.schema.json", + {{JSON_INFO}}, + {{JSON_CONFIGURATION}}, + {{JSON_INTERFACE}} +~INDENT_DECREASE~ +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/module/module_header.txt b/PluginSkeletonGenerator/templates/module/.module_header.txt similarity index 97% rename from PluginSkeletonGenerator/templates/module/module_header.txt rename to PluginSkeletonGenerator/templates/module/.module_header.txt index 89bf494..26f37f0 100644 --- a/PluginSkeletonGenerator/templates/module/module_header.txt +++ b/PluginSkeletonGenerator/templates/module/.module_header.txt @@ -23,6 +23,7 @@ #define MODULE_NAME {{MODULE_PLUGIN_NAME}} #endif +#include #include #undef EXTERNAL diff --git a/PluginSkeletonGenerator/templates/module/module_source.txt b/PluginSkeletonGenerator/templates/module/.module_source.txt similarity index 100% rename from PluginSkeletonGenerator/templates/module/module_source.txt rename to PluginSkeletonGenerator/templates/module/.module_source.txt diff --git a/PluginSkeletonGenerator/templates/nested_class/config_class.txt b/PluginSkeletonGenerator/templates/nested_class/.config_class.txt similarity index 75% rename from PluginSkeletonGenerator/templates/nested_class/config_class.txt rename to PluginSkeletonGenerator/templates/nested_class/.config_class.txt index af09759..f2865f5 100644 --- a/PluginSkeletonGenerator/templates/nested_class/config_class.txt +++ b/PluginSkeletonGenerator/templates/nested_class/.config_class.txt @@ -3,19 +3,21 @@ private: ~INDENT_INCREASE~ Config(const Config&) = delete; Config& operator=(const Config&) = delete; + Config(Config&&) = delete; + Config& operator=(Config&&) = delete; ~INDENT_DECREASE~ public: ~INDENT_INCREASE~ Config() ~INDENT_INCREASE~ - : Example("Example") + : Core::JSON::Container() ~INDENT_DECREASE~ { ~INDENT_INCREASE~ Add(_T("example"), &Example); ~INDENT_DECREASE~ } - ~Config(){} + ~Config() override = default; ~INDENT_DECREASE~ public: ~INDENT_INCREASE~ diff --git a/PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt b/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt similarity index 87% rename from PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt rename to PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt index 0d95a9d..ebd4892 100644 --- a/PluginSkeletonGenerator/templates/nested_class/rpc_inotification.txt +++ b/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt @@ -15,6 +15,8 @@ public: ConnectionNotification() = delete; ConnectionNotification(const ConnectionNotification&) = delete; ConnectionNotification& operator=(const ConnectionNotification&) = delete; + ConnectionNotification(ConnectionNotification&&) = delete; + ConnectionNotification& operator=(ConnectionNotification&&) = delete; void Activated(RPC::IRemoteConnection*) override { diff --git a/PluginSkeletonGenerator/templates/plugin_conf_in.txt b/PluginSkeletonGenerator/templates/plugin_conf_in.txt deleted file mode 100644 index 155bbd8..0000000 --- a/PluginSkeletonGenerator/templates/plugin_conf_in.txt +++ /dev/null @@ -1 +0,0 @@ -startmode = {{PLUGIN_STARTMODE}} \ No newline at end of file diff --git a/PluginSkeletonGenerator/helper.py b/PluginSkeletonGenerator/utils.py similarity index 68% rename from PluginSkeletonGenerator/helper.py rename to PluginSkeletonGenerator/utils.py index d8b058d..dd54f93 100644 --- a/PluginSkeletonGenerator/helper.py +++ b/PluginSkeletonGenerator/utils.py @@ -1,3 +1,4 @@ +import os class FileUtils(): def __init__(self) -> None: pass @@ -23,12 +24,20 @@ def read_file(template_name): class Indenter(): def __init__(self) -> None: self.indent_size = 0 - self.indent = " " + self.indent = "" self.indented_code = [] - def process_indent(self, code): - self.indented_code.clear() + def indent_type(self, path): + + extension = os.path.splitext(path)[1] + if extension == '.json': + self.indent = ' ' * 2 + else: + self.indent = ' ' * 4 + def process_indent(self, code, path): + self.indented_code.clear() + self.indent_type(path) lines = code.splitlines() self.indent_size = 0 for line in lines: @@ -43,5 +52,9 @@ def process_indent(self, code): elif('~INDENT_DECREASE~' in newline): self.indent_size -=1 continue - self.indented_code.append(self.indent * self.indent_size + newline) + # rm\*n refers to remove line, therefore return this to delete line + elif('rm\*n' in newline): + continue + indented_line = self.indent * self.indent_size + newline + self.indented_code.append(indented_line) return '\n'.join(self.indented_code) \ No newline at end of file diff --git a/ThunderDevTools/ThunderDev.py b/ThunderDevTools/ThunderDevTools.py similarity index 91% rename from ThunderDevTools/ThunderDev.py rename to ThunderDevTools/ThunderDevTools.py index 996fa10..3747c0e 100644 --- a/ThunderDevTools/ThunderDev.py +++ b/ThunderDevTools/ThunderDevTools.py @@ -15,10 +15,11 @@ def python_distrubution(): # add future scripts scripts = { -"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","generator.py") +"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","PluginSkeletonGenerator.py") } def script_menu(): + print("== Thunder Development Tools ==") print("Choose one of the following tools: (To quit, type q) ") print("1. Plugin Skeleton Generator") while True: From 26212758c28d15b9cc3bb0117ce6a47c3747fd74 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Mon, 16 Sep 2024 02:32:20 -0700 Subject: [PATCH 08/12] remarks 2 - Mateusz --- .../PluginSkeletonGenerator.py | 93 +----------- .../examples/InProcess/CMakeLists.txt | 2 +- .../examples/InProcess/InProcess.cpp | 8 +- .../examples/InProcess/InProcess.h | 12 +- .../CMakeLists.txt | 10 +- .../{OutProcess => OutOfProcess}/Module.cpp | 0 .../{OutProcess => OutOfProcess}/Module.h | 2 +- .../OutOfProcess.conf.in} | 2 +- .../OutOfProcess.cpp} | 32 ++-- .../OutOfProcess.h} | 28 ++-- .../OutOfProcessImplementation.cpp} | 20 +-- .../OutOfProcessPlugin.json} | 6 +- PluginSkeletonGenerator/examples/examples.txt | 5 - PluginSkeletonGenerator/file_data.py | 143 +++++++----------- PluginSkeletonGenerator/menu.py | 117 ++++++++++++++ PluginSkeletonGenerator/templates/.cmake.txt | 2 +- .../templates/.plugin_header.txt | 6 +- .../templates/.plugin_implementation.txt | 2 + .../templates/.plugin_source.txt | 10 +- .../iplugin_methods/.initialize_ip.txt | 2 +- .../iplugin_methods/.initialize_oop.txt | 8 +- PluginSkeletonGenerator/utils.py | 69 +++++---- ThunderDevTools/ThunderDevTools.py | 8 +- 23 files changed, 301 insertions(+), 286 deletions(-) rename PluginSkeletonGenerator/examples/{OutProcess => OutOfProcess}/CMakeLists.txt (88%) rename PluginSkeletonGenerator/examples/{OutProcess => OutOfProcess}/Module.cpp (100%) rename PluginSkeletonGenerator/examples/{OutProcess => OutOfProcess}/Module.h (95%) rename PluginSkeletonGenerator/examples/{OutProcess/OutProcess.conf.in => OutOfProcess/OutOfProcess.conf.in} (57%) rename PluginSkeletonGenerator/examples/{OutProcess/OutProcess.cpp => OutOfProcess/OutOfProcess.cpp} (82%) rename PluginSkeletonGenerator/examples/{OutProcess/OutProcess.h => OutOfProcess/OutOfProcess.h} (82%) rename PluginSkeletonGenerator/examples/{OutProcess/OutProcessImplementation.cpp => OutOfProcess/OutOfProcessImplementation.cpp} (79%) rename PluginSkeletonGenerator/examples/{OutProcess/OutProcessPlugin.json => OutOfProcess/OutOfProcessPlugin.json} (83%) create mode 100644 PluginSkeletonGenerator/menu.py diff --git a/PluginSkeletonGenerator/PluginSkeletonGenerator.py b/PluginSkeletonGenerator/PluginSkeletonGenerator.py index ec2acde..b754dc4 100755 --- a/PluginSkeletonGenerator/PluginSkeletonGenerator.py +++ b/PluginSkeletonGenerator/PluginSkeletonGenerator.py @@ -17,10 +17,11 @@ - needs workerpool jobs (scheduled or not), so we can generate an example job ''' - import os + from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData from utils import Indenter, FileUtils +import menu import global_variables @@ -76,96 +77,8 @@ def generate_conf_in(self): self.generate_file(global_variables.PLUGIN_CONF_PATH, f'{self.blueprint_data.plugin_name}.conf.in') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# - -def menu(): - - plugin_name = input("What will your plugin be called: \n") - - comrpc_interface = [] - jsonrpc_interface = [] - - print(f"Enter any COM-RPC interfaces used: (Enter to quit) \nNote: IPlugin is already defined for you") - while True: - comrpc = input("Enter a COM-RPC interface: ") - if not comrpc: - break - comrpc_interface.append(comrpc) - - while True: - jsonrpc = input("Does your plugin require JSONRPC functionality: (Enter Y or N)\n") - if(jsonrpc.lower() == 'y'): - jsonrpc= True - break - elif(jsonrpc.lower() == 'n'): - jsonrpc = False - break - else: - print("Unknown character, try again.") - - if jsonrpc: - print(f"Enter any JSON-RPC interfaces used: (Enter to quit)") - while True: - jsonrpc_class = input("Enter a JSON-RPC interface: ") - if not jsonrpc_class: - break - jsonrpc_interface.append(jsonrpc_class) - - while True: - out_of_process = input("Is your plugin expected to work out of process: (Enter Y or N)\n") - if(out_of_process.lower() == 'y'): - out_of_process = True - break - elif(out_of_process.lower() == 'n'): - out_of_process = False - break - else: - print("Unknown character, try again.") - - ''' - TODO: Incomplete - # subsystems support needed (dependend en set) - while True: - sub_systems = input("Is your plugin expected to work out of process: (Enter Y or N)\n") - if(sub_systems.lower() == 'y'): - sub_systems = True - break - elif(sub_systems.lower() == 'n'): - sub_systems = False - break - else: - print("Unknown character, try again.") - - if sub_systems: - preconditions= [] - while True: - precondition = input("Enter subsystem precondition: ") - if not precondition: - break - preconditions.append(precondition) - - # pluginsmartinterface - ''' - - data = FileData(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - plugin_generator = PluginGenerator(data) - - file_map = { - HeaderData: plugin_generator.generate_headers, - SourceData: plugin_generator.generate_source, - CMakeData: plugin_generator.generate_cmake, - ConfData: plugin_generator.generate_conf_in, - JSONData: plugin_generator.generate_json - } - - for file_data, generate in file_map.items(): - instance = file_data(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc) - instance.populate_keywords() - plugin_generator.blueprint_data = instance - generate() - def main(): - menu() + menu.menu() #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# - if __name__ == "__main__": main() \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt b/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt index 4520584..52a7d13 100644 --- a/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt +++ b/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt @@ -51,7 +51,7 @@ target_link_libraries(${MODULE_NAME} ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${NAMESPACE}Definitions::${NAMESPACE}Definitions) -target_include_directories( ${MODULE_NAME} +target_include_directories(${MODULE_NAME} PUBLIC $) diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp b/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp index 74040db..8ab62ed 100644 --- a/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp +++ b/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp @@ -19,14 +19,14 @@ #include "InProcess.h" -namespace Thunder{ -namespace Plugin{ +namespace Thunder { +namespace Plugin { namespace { static Metadatametadata( // Version 1, 0, 0, // Preconditions - {}, + {subsystem::PRE1, subsystem::PRE2}, // Terminations {}, // Controls @@ -39,7 +39,7 @@ namespace Plugin{ const string InProcess::Initialize(PluginHost::IShell* service) { string message; - ASSERT (service != nullptr); + ASSERT(service != nullptr); Config config; config.FromString(service->ConfigLine()); diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcess.h b/PluginSkeletonGenerator/examples/InProcess/InProcess.h index f0005b6..4559306 100644 --- a/PluginSkeletonGenerator/examples/InProcess/InProcess.h +++ b/PluginSkeletonGenerator/examples/InProcess/InProcess.h @@ -34,9 +34,9 @@ namespace Plugin { InProcess &operator=(InProcess&&) = delete; InProcess() - : IHello() - , IWorld() - , _example(0) + : IHello() + , IWorld() + , _example(0) { } @@ -73,7 +73,7 @@ namespace Plugin { void IWorldMethod2() override; // Plugin Methods - void InProcessMethod(1); + void InProcessMethod(); BEGIN_INTERFACE_MAP(InProcess) INTERFACE_ENTRY(PluginHost::IPlugin) @@ -87,5 +87,5 @@ namespace Plugin { // Note this is only an example, you are responsible for adding the correct members: uint32_t _example; }; -} -} \ No newline at end of file +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutProcess/CMakeLists.txt b/PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt similarity index 88% rename from PluginSkeletonGenerator/examples/OutProcess/CMakeLists.txt rename to PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt index 448cc98..ca35745 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/CMakeLists.txt +++ b/PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -project(OutProcess) +project(OutOfProcess) cmake_minimum_required(VERSION 3.15) @@ -27,7 +27,7 @@ set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") -set(PLUGIN_OUTPROCESS_STARTMODE "Activated" CACHE STRING "Automatically start OutProcess plugin") +set(PLUGIN_OUTOFPROCESS_STARTMODE "Activated" CACHE STRING "Automatically start OutOfProcess plugin") if(BUILD_REFERENCE) add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) @@ -38,8 +38,8 @@ find_package(${NAMESPACE}Definitions REQUIRED) find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED - OutProcess.cpp - OutProcessImplementation.cpp + OutOfProcess.cpp + OutOfProcessImplementation.cpp ) set_target_properties(${MODULE_NAME} PROPERTIES @@ -52,7 +52,7 @@ target_link_libraries(${MODULE_NAME} ${NAMESPACE}Plugins::${NAMESPACE}Plugins ${NAMESPACE}Definitions::${NAMESPACE}Definitions) -target_include_directories( ${MODULE_NAME} +target_include_directories(${MODULE_NAME} PUBLIC $) diff --git a/PluginSkeletonGenerator/examples/OutProcess/Module.cpp b/PluginSkeletonGenerator/examples/OutOfProcess/Module.cpp similarity index 100% rename from PluginSkeletonGenerator/examples/OutProcess/Module.cpp rename to PluginSkeletonGenerator/examples/OutOfProcess/Module.cpp diff --git a/PluginSkeletonGenerator/examples/OutProcess/Module.h b/PluginSkeletonGenerator/examples/OutOfProcess/Module.h similarity index 95% rename from PluginSkeletonGenerator/examples/OutProcess/Module.h rename to PluginSkeletonGenerator/examples/OutOfProcess/Module.h index 84622b3..8661274 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/Module.h +++ b/PluginSkeletonGenerator/examples/OutOfProcess/Module.h @@ -20,7 +20,7 @@ #pragma once #ifndef MODULE_NAME -#define MODULE_NAME Plugin_OutProcess +#define MODULE_NAME Plugin_OutOfProcess #endif #include diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in similarity index 57% rename from PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in rename to PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in index e502d7f..1535cf0 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.conf.in +++ b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in @@ -1,4 +1,4 @@ -startmode = "@PLUGIN_OUTPROCESS_STARTMODE@" +startmode = "@PLUGIN_OUTOFPROCESS_STARTMODE@" configuration = JSON() configuration.add("example,"mystring") \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.cpp b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp similarity index 82% rename from PluginSkeletonGenerator/examples/OutProcess/OutProcess.cpp rename to PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp index 7ad6bf8..abdedcf 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.cpp +++ b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp @@ -17,39 +17,39 @@ * limitations under the License. */ -#include "OutProcess.h" +#include "OutOfProcess.h" -namespace Thunder{ -namespace Plugin{ +namespace Thunder { +namespace Plugin { namespace { - static Metadatametadata( + static Metadatametadata( // Version 1, 0, 0, // Preconditions - {}, + {subsystem::PRE}, // Terminations - {}, + {subsystem::TERM}, // Controls - {} + {subsystem::CONT} ) } - // Implement all methods from OutProcess.h + // Implement all methods from OutOfProcess.h - const string OutProcess::Initialize(PluginHost::IShell* service) { + const string OutOfProcess::Initialize(PluginHost::IShell* service) { string message; - ASSERT (_service == nullptr); - ASSERT (service != nullptr); - ASSERT (_implementation == nullptr); - ASSERT (_connectionId == 0); + ASSERT(_service == nullptr); + ASSERT(service != nullptr); + ASSERT(_implementation == nullptr); + ASSERT(_connectionId == 0); _service = service; _service->AddRef(); _service->Register(&_connectionNotification); // Example - _implementation = service->Root(_connectionId, 2000, _T("OutProcessImplementation")); + _implementation = service->Root(_connectionId, 2000, _T("OutOfProcessImplementation")); if (_implementation == nullptr) { message = _T("Couldn't create instance"); } else { @@ -62,7 +62,7 @@ namespace Plugin{ return (message); } - void OutProcess::Deinitialize(PluginHost::IShell* service) { + void OutOfProcess::Deinitialize(PluginHost::IShell* service) { if (_service != nullptr) { ASSERT(_service == service); @@ -94,7 +94,7 @@ namespace Plugin{ } } - string OutProcess::Information() { + string OutOfProcess::Information() { return string() } } // Plugin diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.h b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h similarity index 82% rename from PluginSkeletonGenerator/examples/OutProcess/OutProcess.h rename to PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h index 52ad6ac..f0facfc 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/OutProcess.h +++ b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h @@ -26,23 +26,23 @@ namespace Thunder { namespace Plugin { - class OutProcess : public PluginHost::IPlugin, public PluginHost::JSONRPC { + class OutOfProcess : public PluginHost::IPlugin, public PluginHost::JSONRPC { public: - OutProcess(const OutProcess&) = delete; - OutProcess &operator=(const OutProcess&) = delete; - OutProcess(OutProcess&&) = delete; - OutProcess &operator=(OutProcess&&) = delete; + OutOfProcess(const OutOfProcess&) = delete; + OutOfProcess &operator=(const OutOfProcess&) = delete; + OutOfProcess(OutOfProcess&&) = delete; + OutOfProcess &operator=(OutOfProcess&&) = delete; - OutProcess() - : _example(0) + OutOfProcess() + : _example(0) { } - ~OutProcess() override = default; + ~OutOfProcess() override = default; private: class ConnectionNotification : public RPC::IRemoteConnection::INotification { public: - explicit ConnectionNotification(OutProcess* parent) + explicit ConnectionNotification(OutOfProcess* parent) : _parent(*parent) { ASSERT(parent != nullptr); @@ -68,7 +68,7 @@ namespace Plugin { INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) END_INTERFACE_MAP private: - OutProcess& _parent; + OutOfProcess& _parent; } public: // IPlugin Methods @@ -78,9 +78,9 @@ namespace Plugin { // Plugin Methods - void OutProcessMethod(1); + void OutOfProcessMethod(); - BEGIN_INTERFACE_MAP(OutProcess) + BEGIN_INTERFACE_MAP(OutOfProcess) INTERFACE_ENTRY(PluginHost::IPlugin) INTERFACE_ENTRY(PluginHost::IDispatcher) INTERFACE_AGGREGATE(Exchange::IHello, _implIHello) @@ -92,5 +92,5 @@ namespace Plugin { // Note this is only an example, you are responsible for adding the correct members: uint32_t _example; }; -} -} \ No newline at end of file +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp similarity index 79% rename from PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp rename to PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp index e42c2b4..a6ab7f3 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/OutProcessImplementation.cpp +++ b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp @@ -24,20 +24,20 @@ namespace Thunder { namespace Plugin { - SERVICE_REGISTRATION(OutProcessImplementation, 1, 0) + SERVICE_REGISTRATION(OutOfProcessImplementation, 1, 0) - class OutProcessImplementation : public IHello, public IWorld { + class OutOfProcessImplementation : public IHello, public IWorld { public: - OutProcessImplementation(const OutProcessImplementation&) = delete; - OutProcessImplementation& operator=(const OutProcessImplementation&) = delete; + OutOfProcessImplementation(const OutOfProcessImplementation&) = delete; + OutOfProcessImplementation& operator=(const OutOfProcessImplementation&) = delete; - OutProcessImplementation() - : IHello() - , IWorld() - , _test(0) + OutOfProcessImplementation() + : IHello() + , IWorld() + , _test(0) { } - ~OutProcessImplementation() override = default; + ~OutOfProcessImplementation() override = default; private: @@ -60,7 +60,7 @@ namespace Plugin { public: - BEGIN_INTERFACE_MAP(OutProcessImplementation) + BEGIN_INTERFACE_MAP(OutOfProcessImplementation) INTERFACE_ENTRY(Exchange::IHello) INTERFACE_ENTRY(Exchange::IWorld) END_INTERFACE_MAP diff --git a/PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json similarity index 83% rename from PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json rename to PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json index 732e85c..0cfc87f 100644 --- a/PluginSkeletonGenerator/examples/OutProcess/OutProcessPlugin.json +++ b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json @@ -1,9 +1,9 @@ { "$schema": "plugin.schema.json", "info": { - "title": "OutProcess Plugin", - "callsign": "OutProcess", - "locator": "libThunderOutProcess.so", + "title": "OutOfProcess Plugin", + "callsign": "OutOfProcess", + "locator": "libThunderOutOfProcess.so", "status": "production", "description": [ "" diff --git a/PluginSkeletonGenerator/examples/examples.txt b/PluginSkeletonGenerator/examples/examples.txt index 547d799..6aadad5 100644 --- a/PluginSkeletonGenerator/examples/examples.txt +++ b/PluginSkeletonGenerator/examples/examples.txt @@ -1,6 +1 @@ -Abbreviations: -OOP = Out of Process -IP = In Process -JSONRPC = JSONRPC is enabled - These examples serve as a display to show what your skeleton may look like. \ No newline at end of file diff --git a/PluginSkeletonGenerator/file_data.py b/PluginSkeletonGenerator/file_data.py index d6f722f..00d55d8 100644 --- a/PluginSkeletonGenerator/file_data.py +++ b/PluginSkeletonGenerator/file_data.py @@ -26,7 +26,8 @@ class HeaderType(Enum): HEADER = 1 HEADER_IMPLEMENTATION = 2 - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, type=None) -> None: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions, terminations, controls, type=None) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) self.type = type if type else HeaderData.HeaderType.HEADER @@ -37,107 +38,74 @@ def populate_keywords(self): self.keywords.update(self.generate_nested_map()) def generate_jsonrpc_includes(self): - includes = [] - for jsonrpc in self.jsonrpc_interfaces: - includes.append(f'#include ') + return '\n'.join([f'#include ' for jsonrpc in self.jsonrpc_interfaces]) - return '\n'.join(includes) - def generate_comrpc_includes(self): - includes = [] - for comrpc in self.comrpc_interfaces: - includes.append(f'#include ') - - return '\n'.join(includes) + return '\n'.join([f'#include ' for comrpc in self.comrpc_interfaces]) def generate_inherited_classes(self): - inheritance = ["PluginHost::IPlugin"] - if self.jsonrpc: inheritance.append("public PluginHost::JSONRPC") - if not self.out_of_process: - for inherited_class in self.comrpc_interfaces: - inheritance.append(f'public Exchange::{inherited_class}') - - all_inheritance = f', '.join(inheritance) - return all_inheritance + inheritance.extend(f'public Exchange::{cls}' for cls in self.comrpc_interfaces) + return ', '.join(inheritance) def generate_oop_inherited_classes(self): if not self.comrpc_interfaces: return '' - inheritance = [self.comrpc_interfaces[0]] - if self.out_of_process: - for inherited_class in self.comrpc_interfaces[1:]: - inheritance.append(f'public {inherited_class}') - - all_inheritance = ', '.join(inheritance) - return all_inheritance + inheritance.extend(f'public {cls}' for cls in self.comrpc_interfaces[1:]) + return ', '.join(inheritance) def generate_inherited_methods(self): - methods = [] - - if (not self.out_of_process) or \ - ((self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION)): - for inherited in self.comrpc_interfaces: - comment = f'// {inherited} methods' - method1 = f'void {inherited}Method1() override;' - method2 = f'void {inherited}Method2() override;\n' - methods.extend([comment,method1,method2]) + if (not self.out_of_process and self.type != HeaderData.HeaderType.HEADER) or \ + (self.out_of_process and self.type != HeaderData.HeaderType.HEADER_IMPLEMENTATION): + return '' + + methods = [ + f'// {inherited} methods\n' + f'void {inherited}Method1() override;\n' + f'void {inherited}Method2() override;\n' + for inherited in self.comrpc_interfaces] return ('\n').join(methods) def generate_plugin_methods(self): - - method = f'void {self.plugin_name}Method(1);' + method = f'void {self.plugin_name}Method();' return method def generate_interface_entry(self): entries = [] if self.type == HeaderData.HeaderType.HEADER: entries.append(f'INTERFACE_ENTRY(PluginHost::IPlugin)') - if self.jsonrpc: entries.append(f'INTERFACE_ENTRY(PluginHost::IDispatcher)') if (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ ((not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER)): - for comrpc in self.comrpc_interfaces: - entry = f'INTERFACE_ENTRY(Exchange::{comrpc})' - entries.append(entry) - entries = ('\n').join(entries) - return entries if entries else 'rm\*n' + entries.extend(f'INTERFACE_ENTRY(Exchange::{comrpc})' for comrpc in self.comrpc_interfaces) + return '\n'.join(entries) if entries else 'rm\*n' def generate_interface_aggregate(self): - aggregates = [] if(self.out_of_process): - for comrpc in self.comrpc_interfaces: - aggregate = f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc})' - aggregates.append(aggregate) - test = ('\n').join(aggregates) - return test if aggregates else 'rm\*n' - - def generate_data_members(self): - return 'DATA_MEMBER' + aggregates = [f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc})' for comrpc in self.comrpc_interfaces] + return ('\n').join(aggregates) + return 'rm\*n' def generate_module_plugin_name(self): return f'Plugin_{self.plugin_name}' - - def generate_comrpc_interface(self): - return "Test_COMRPC" def generate_interface_constructor(self): - constructor = [] + if not self.comrpc_interfaces: + return '' + if (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ ((not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER)): - - constructor.append(f' {self.comrpc_interfaces[0]}()\n,') - for comrpc in self.comrpc_interfaces[1:]: - constructor.append(f' {comrpc}()\n,') - return ''.join(constructor) - + constructor = [f' {self.comrpc_interfaces[0]}()\n,'] + \ + [f' {comrpc}()\n,' for comrpc in self.comrpc_interfaces[1:]] + return ''.join(constructor) + return '' def generate_keyword_map(self): return{ @@ -148,9 +116,7 @@ def generate_keyword_map(self): '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), '{{INTERFACE_ENTRY}}' : self.generate_interface_entry(), '{{INTERFACE_AGGREGATE}}' : self.generate_interface_aggregate(), - '{{DATA_MEMBERS}}' : self.generate_data_members(), '{{MODULE_PLUGIN_NAME}}' : self.generate_module_plugin_name(), - '{{COMRPC_INTERFACE}}' : self.generate_comrpc_interface(), '{{OOP_INHERITED_CLASS}}' : self.generate_oop_inherited_classes(), '{{INTERFACE_CONSTRUCTOR}}' : self.generate_interface_constructor() } @@ -180,9 +146,13 @@ def generate_config(self): class SourceData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions, terminations, controls) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) self.keywords = self.keywords.copy() + self.preconditions = preconditions if preconditions else [] + self.terminations = terminations if terminations else [] + self.controls = controls if controls else [] def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) @@ -191,12 +161,6 @@ def populate_keywords(self): def generate_include_statements(self): return f'#include "{self.plugin_name}.h"' - def generate_plugin_methods(self): - return "Plugin method" - - def generate_inherited_methods(self): - return "Inherited method" - def generate_initialize(self): if self.out_of_process: @@ -250,19 +214,26 @@ def generate_jsonrpc_unregister(self): registers = ('\n').join(registers) return registers if registers else 'rm\*n' + + def generate_preconditions(self): + return ', '.join([f'subsystem::{condition}'for condition in self.preconditions]) + + def generate_terminations(self): + return ', '.join([f'subsystem::{termination}'for termination in self.terminations]) + + def generate_controls(self): + return ', '.join([f'subsystem::{control}'for control in self.controls]) def generate_keyword_map(self): return { '{{INCLUDE}}' : self.generate_include_statements(), - '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), - '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), - '{{PRECONDITIONS}}' : "conditions", - '{{TERMINATIONS}}' : "terminations", - '{{CONTROLS}}' : "controls", + '{{PRECONDITIONS}}' : self.generate_preconditions(), + '{{TERMINATIONS}}' : self.generate_terminations(), + '{{CONTROLS}}' : self.generate_controls(), '{{VARIABLE_NOT_USED}}' : self.generate_variable_used(), '{{JSONRPC_REGISTER}}' : self.generate_jsonrpc_register(), '{{JSONRPC_UNREGISTER}}' : self.generate_jsonrpc_unregister(), - '{{COMRPC}}' : f'{self.comrpc_interfaces[0]}' + '{{COMRPC}}' : f'{self.comrpc_interfaces[0] if self.comrpc_interfaces else "INTERFACE_NEEDED"}' } def generate_nested_map(self): @@ -272,7 +243,8 @@ def generate_nested_map(self): } class CMakeData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions=None, terminations=None, controls=None) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) self.keywords = self.keywords.copy() @@ -292,7 +264,8 @@ def find_source_files(self): return f'{self.plugin_name}.cpp' class JSONData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions=None, terminations=None, controls=None) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) self.keywords = self.keywords.copy() @@ -300,12 +273,9 @@ def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) self.keywords.update(self.generate_nested_map()) - def generate_cppref(self): - cpprefs = [] - for comrpc in self.comrpc_interfaces: - cpprefs.append(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"') - - return ",\n".join(cpprefs) if cpprefs else 'rm\*n' + def generate_cppref(self): + return ",\n".join(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"' for comrpc in self.comrpc_interfaces) \ + if self.comrpc_interfaces else 'rm\*n' def generate_json_info(self): template_name = global_variables.JSON_INFO @@ -338,7 +308,8 @@ def generate_nested_map(self): } class ConfData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions=None, terminations=None, controls=None) -> None: super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) self.keywords = self.keywords.copy() diff --git a/PluginSkeletonGenerator/menu.py b/PluginSkeletonGenerator/menu.py new file mode 100644 index 0000000..dcec32b --- /dev/null +++ b/PluginSkeletonGenerator/menu.py @@ -0,0 +1,117 @@ +from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData +from PluginSkeletonGenerator import PluginGenerator + +# Helper for menu options +def get_boolean_input(option): + while True: + user_input = input(f"{option}") + if(user_input.lower() == 'y'): + user_input = True + break + elif(user_input.lower() == 'n'): + user_input = False + break + else: + print("Unknown character, try again.") + return user_input + +def display_settings(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc, + subsystems, preconditions, terminations, controls): + print("=======================================") + print("You have chosen the following settings:") + print(f"Plugin Name: {plugin_name}") + print(f"COMRPC Interfaces: {comrpc_interface if comrpc_interface else 'None'}") + print(f"JSONRPC Functionality: {jsonrpc}") + print(f"JSONRPC Interfaces: {jsonrpc_interface if jsonrpc else 'N/A'} ") + print(f"Out Of Process: {out_of_process}") + print(f"Subsystem Support: {subsystems}") + print(f"Subsystem Preconditions: {preconditions if subsystems else 'N/A'} ") + print(f"Subsystem Terminations: {terminations if subsystems else 'N/A'}") + print(f"Subsystem Controls: {controls if subsystems else 'N/A'}") + +# Menu options + +def menu(): + comrpc_interfaces = [] + jsonrpc_interfaces = [] + preconditions = [] + terminations = [] + controls = [] + + plugin_name = str(user_plugin_name()) + print(plugin_name) + user_comrpc(comrpc_interfaces) + jsonrpc = user_jsonrpc(jsonrpc_interfaces) + out_of_process = user_out_of_process() + subsystems = user_subsystems(preconditions, terminations, controls) + display_settings(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + subsystems, preconditions, terminations, controls) + + data = FileData(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + plugin_generator = PluginGenerator(data) + + file_map = { + HeaderData: plugin_generator.generate_headers, + SourceData: plugin_generator.generate_source, + CMakeData: plugin_generator.generate_cmake, + ConfData: plugin_generator.generate_conf_in, + JSONData: plugin_generator.generate_json + } + + for file_data, generate in file_map.items(): + instance = file_data(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions, terminations, controls) + instance.populate_keywords() + plugin_generator.blueprint_data = instance + generate() + + +def user_plugin_name(): + name = input("What will your plugin be called: ") + return name + +def user_comrpc(comrpc_interfaces): + print(f"Enter any COM-RPC interfaces used: (Enter to quit) \nNote: IPlugin is already defined for you") + while True: + comrpc = input("Enter a COM-RPC interface: ") + if not comrpc: + break + comrpc_interfaces.append(comrpc) + +def user_jsonrpc(jsonrpc_interfaces): + jsonrpc = get_boolean_input("Does your plugin require JSON-RPC functionality: (Enter Y or N)\n") + if jsonrpc: + print(f"Enter any JSON-RPC interfaces used: (Enter to quit)") + while True: + jsonrpc_class = input("Enter a JSON-RPC interface: ") + if not jsonrpc_class: + break + jsonrpc_interfaces.append(jsonrpc_class) + return jsonrpc + +def user_out_of_process(): + out_of_process = get_boolean_input("Is your plugin expected to work out of process: (Enter Y or N)\n") + return out_of_process + +def user_subsystems(preconditions, terminations, controls): + sub_systems = get_boolean_input("Does your plugin need subsystem support: (Enter Y or N)\n") + + if sub_systems: + while True: + precondition = input("Enter subsystem precondition: (Enter to quit) ") + if not precondition: + break + preconditions.append(precondition) + + while True: + termination = input("Enter subsystem termination: (Enter to quit) ") + if not termination: + break + terminations.append(termination) + + while True: + control = input("Enter subsystem control: (Enter to quit) ") + if not control: + break + controls.append(control) + return sub_systems \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/.cmake.txt b/PluginSkeletonGenerator/templates/.cmake.txt index f04ef46..f9c7e1c 100644 --- a/PluginSkeletonGenerator/templates/.cmake.txt +++ b/PluginSkeletonGenerator/templates/.cmake.txt @@ -59,7 +59,7 @@ target_link_libraries(${MODULE_NAME} ${NAMESPACE}Definitions::${NAMESPACE}Definitions) ~INDENT_DECREASE~ -target_include_directories( ${MODULE_NAME} +target_include_directories(${MODULE_NAME} ~INDENT_INCREASE~ PUBLIC $) diff --git a/PluginSkeletonGenerator/templates/.plugin_header.txt b/PluginSkeletonGenerator/templates/.plugin_header.txt index f3f5ad1..b23bbc3 100644 --- a/PluginSkeletonGenerator/templates/.plugin_header.txt +++ b/PluginSkeletonGenerator/templates/.plugin_header.txt @@ -35,7 +35,9 @@ namespace Plugin { {{PLUGIN_NAME}} &operator=({{PLUGIN_NAME}}&&) = delete; {{PLUGIN_NAME}}() + ~INDENT_INCREASE~ :{{INTERFACE_CONSTRUCTOR}} _example(0) + ~INDENT_DECREASE~ { } @@ -71,5 +73,5 @@ namespace Plugin { ~INDENT_DECREASE~ }; ~INDENT_DECREASE~ -} -} \ No newline at end of file +} // Plugin +} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/.plugin_implementation.txt b/PluginSkeletonGenerator/templates/.plugin_implementation.txt index dd3c241..1c21564 100644 --- a/PluginSkeletonGenerator/templates/.plugin_implementation.txt +++ b/PluginSkeletonGenerator/templates/.plugin_implementation.txt @@ -33,7 +33,9 @@ namespace Plugin { {{PLUGIN_NAME}}Implementation& operator=(const {{PLUGIN_NAME}}Implementation&) = delete; {{PLUGIN_NAME}}Implementation() + ~INDENT_INCREASE~ :{{INTERFACE_CONSTRUCTOR}} _test(0) + ~INDENT_DECREASE~ { } ~{{PLUGIN_NAME}}Implementation() override = default; diff --git a/PluginSkeletonGenerator/templates/.plugin_source.txt b/PluginSkeletonGenerator/templates/.plugin_source.txt index cebeb58..b650922 100644 --- a/PluginSkeletonGenerator/templates/.plugin_source.txt +++ b/PluginSkeletonGenerator/templates/.plugin_source.txt @@ -19,8 +19,8 @@ {{INCLUDE}} -namespace Thunder{ -namespace Plugin{ +namespace Thunder { +namespace Plugin { ~INDENT_INCREASE~ namespace { ~INDENT_INCREASE~ @@ -29,11 +29,11 @@ namespace Plugin{ // Version 1, 0, 0, // Preconditions - {}, + {{{PRECONDITIONS}}}, // Terminations - {}, + {{{TERMINATIONS}}}, // Controls - {} + {{{CONTROLS}}} ~INDENT_DECREASE~ ) ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt index 74ed009..694a39e 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt @@ -1,6 +1,6 @@ string message; -ASSERT (service != nullptr); +ASSERT(service != nullptr); Config config; config.FromString(service->ConfigLine()); diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt index 0a31d22..168a8c1 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt @@ -1,9 +1,9 @@ string message; -ASSERT (_service == nullptr); -ASSERT (service != nullptr); -ASSERT (_implementation == nullptr); -ASSERT (_connectionId == 0); +ASSERT(_service == nullptr); +ASSERT(service != nullptr); +ASSERT(_implementation == nullptr); +ASSERT(_connectionId == 0); _service = service; _service->AddRef(); diff --git a/PluginSkeletonGenerator/utils.py b/PluginSkeletonGenerator/utils.py index dd54f93..e779032 100644 --- a/PluginSkeletonGenerator/utils.py +++ b/PluginSkeletonGenerator/utils.py @@ -1,60 +1,75 @@ import os +import re + class FileUtils(): def __init__(self) -> None: pass @staticmethod def replace_keywords(template, keywords): - code = template - data = keywords - for keyword, value in data.items(): - code = code.replace(keyword,value) - return code - + pattern = re.compile('|'.join(re.escape(k) for k in keywords.keys())) + return pattern.sub(lambda m: keywords[m.group(0)], template) + @staticmethod def read_file(template_name): try: with open(template_name, 'r') as template_file: - template = template_file.read() - except FileNotFoundError: - print(f"Could not load template: {template_name}") - return None - return template + return template_file.read() + except FileNotFoundError as e: + raise(f'Could not load template: {template_name}') from e + except PermissionError as e: + raise(f'Permissions denied: {template_name}') from e + except OSError as e: + raise OSError(f'OS error occurred trying to open: {template_name}, Error details: {e.strerror}') class Indenter(): def __init__(self) -> None: self.indent_size = 0 self.indent = "" self.indented_code = [] + self.indent_map = self.create_indent_map() - def indent_type(self, path): + self.INDENT_RESET = '~INDENT_RESET~' + self.INDENT_INCREASE = '~INDENT_INCREASE~' + self.INDENT_DECREASE = '~INDENT_DECREASE~' + self.REMOVE_LINE = 'rm\*n' + def create_indent_map(self): + return { + '.json': ' ' * 2, + '.py' : ' ' * 4, + '.h' : ' ' * 4, + '.cpp' : ' ' * 4 + } + + def indent_type(self, path): extension = os.path.splitext(path)[1] - if extension == '.json': - self.indent = ' ' * 2 - else: - self.indent = ' ' * 4 + self.indent = self.indent_map.get(extension, ' ' * 4) # Default case: 4 spaces def process_indent(self, code, path): + if not code: + return '' + self.indented_code.clear() self.indent_type(path) lines = code.splitlines() self.indent_size = 0 + + actions = { + self.INDENT_RESET: lambda: setattr(self, 'indent_size', 0), + self.INDENT_INCREASE: lambda: setattr(self, 'indent_size', self.indent_size + 1), + self.INDENT_DECREASE: lambda: setattr(self, 'indent_size', self.indent_size - 1), + self.REMOVE_LINE: lambda: None + } + for line in lines: newline = line.strip() - if('~INDENT_RESET~' in newline): - self.indent_size = 0 - continue - elif('~INDENT_INCREASE~' in newline): - self.indent_size +=1 - continue - elif('~INDENT_DECREASE~' in newline): - self.indent_size -=1 - continue - # rm\*n refers to remove line, therefore return this to delete line - elif('rm\*n' in newline): + action = actions.get(newline, None) + if action: + action() continue + indented_line = self.indent * self.indent_size + newline self.indented_code.append(indented_line) return '\n'.join(self.indented_code) \ No newline at end of file diff --git a/ThunderDevTools/ThunderDevTools.py b/ThunderDevTools/ThunderDevTools.py index 3747c0e..de6c3d9 100644 --- a/ThunderDevTools/ThunderDevTools.py +++ b/ThunderDevTools/ThunderDevTools.py @@ -7,7 +7,7 @@ CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) THUNDER_TOOLS_DIR = os.path.dirname(CURRENT_DIR) -def python_distrubution(): +def python_distribution(): if os.name == "posix": return "python3" else: @@ -15,7 +15,7 @@ def python_distrubution(): # add future scripts scripts = { -"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","PluginSkeletonGenerator.py") +"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","PluginSkeletonGeneratror.py") } def script_menu(): @@ -39,10 +39,10 @@ def run_script(script): try: script_path = scripts[script] full_path = os.path.join(THUNDER_TOOLS_DIR, script_path) - subprocess.run([python_distrubution(), full_path], check=True) + subprocess.run([python_distribution(), full_path], check=True, text=True, stderr=subprocess.PIPE) print("Success") except subprocess.CalledProcessError as e: - print("Error running the script") + print(f"Error running the script: {e.stderr}") def main(): parser = argparse.ArgumentParser(description="Run any ThunderDevTool script") From 3f16ad48c3f8baab0a97a319683eb6d6c87d34f4 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Wed, 18 Sep 2024 00:26:07 -0700 Subject: [PATCH 09/12] addedConfigSettings --- PluginSkeletonGenerator/menu.py | 72 ++++++----- PluginSkeletonGenerator/tests/test.py | 171 ++++++++++++++++++++++++++ 2 files changed, 211 insertions(+), 32 deletions(-) create mode 100644 PluginSkeletonGenerator/tests/test.py diff --git a/PluginSkeletonGenerator/menu.py b/PluginSkeletonGenerator/menu.py index dcec32b..d63c46e 100644 --- a/PluginSkeletonGenerator/menu.py +++ b/PluginSkeletonGenerator/menu.py @@ -1,20 +1,30 @@ from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData from PluginSkeletonGenerator import PluginGenerator -# Helper for menu options -def get_boolean_input(option): - while True: - user_input = input(f"{option}") - if(user_input.lower() == 'y'): - user_input = True - break - elif(user_input.lower() == 'n'): - user_input = False - break - else: - print("Unknown character, try again.") - return user_input +# Helpers for menu options + +def generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + subsystems, preconditions, terminations, controls): + + data = FileData(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + plugin_generator = PluginGenerator(data) + file_map = { + HeaderData: plugin_generator.generate_headers, + SourceData: plugin_generator.generate_source, + CMakeData: plugin_generator.generate_cmake, + ConfData: plugin_generator.generate_conf_in, + JSONData: plugin_generator.generate_json + } + + for file_data, generate in file_map.items(): + instance = file_data(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + preconditions, terminations, controls) + instance.populate_keywords() + plugin_generator.blueprint_data = instance + generate() + return True + def display_settings(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc, subsystems, preconditions, terminations, controls): print("=======================================") @@ -44,27 +54,25 @@ def menu(): jsonrpc = user_jsonrpc(jsonrpc_interfaces) out_of_process = user_out_of_process() subsystems = user_subsystems(preconditions, terminations, controls) + display_settings(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, subsystems, preconditions, terminations, controls) - - data = FileData(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - plugin_generator = PluginGenerator(data) - - file_map = { - HeaderData: plugin_generator.generate_headers, - SourceData: plugin_generator.generate_source, - CMakeData: plugin_generator.generate_cmake, - ConfData: plugin_generator.generate_conf_in, - JSONData: plugin_generator.generate_json - } - - for file_data, generate in file_map.items(): - instance = file_data(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions, terminations, controls) - instance.populate_keywords() - plugin_generator.blueprint_data = instance - generate() - + + generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, + subsystems, preconditions, terminations, controls) + +def get_boolean_input(option): + while True: + user_input = input(f"{option}") + if(user_input.lower() == 'y'): + user_input = True + break + elif(user_input.lower() == 'n'): + user_input = False + break + else: + print("Unknown character, try again.") + return user_input def user_plugin_name(): name = input("What will your plugin be called: ") diff --git a/PluginSkeletonGenerator/tests/test.py b/PluginSkeletonGenerator/tests/test.py new file mode 100644 index 0000000..bb0aa85 --- /dev/null +++ b/PluginSkeletonGenerator/tests/test.py @@ -0,0 +1,171 @@ +#!/usr/bin/env python3 + +import unittest +import sys +import os + +sys.path.insert(1, os.path.join(sys.path[0], '..')) +from menu import generate_files + +def test_plugin_name(): + return 'TestPluginName' + +def test_comrpc_interfaces(): + return ['IHello', 'IWorld'] + +def test_no_comrpc_interfaces(): + return [] + +def test_jsonrpc_functionality(): + return True + +def test_no_jsonrpc_functionality(): + return False + +def test_jsonrpc_interfaces(): + return ['JHello', 'JWorld'] + +def test_no_jsonrpc_interfaces(): + return [] + +def test_out_of_process(): + return True + +def test_no_out_of_process(): + return False + +def test_subsystems(): + return True + +def test_no_subsystems(): + return False + +def test_preconditions(): + return ["PRE1", "PRE2"] + +def test_no_preconditions(): + return [] + +def test_terminations(): + return ["PRE1", "PRE2"] + +def test_no_terminations(): + return [] + +def test_controls(): + return ["PRE1", "PRE2"] + +def test_no_controls(): + return [] + + +test_cases = { + 'InProcessComrpcJsonrpc': { + 'test_plugin_name' : 'InProcessComrpcJsonrpc', + 'test_comrpc_interfaces' : test_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_jsonrpc_interfaces(), + 'test_out_of_process' : test_no_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'InProcessComrpc': { + 'test_plugin_name' : 'InProcessComrpc', + 'test_comrpc_interfaces' : test_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_no_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_no_jsonrpc_interfaces(), + 'test_out_of_process' : test_no_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'InProcessJsonrpc': { + 'test_plugin_name' : 'InProcessJsonrpc', + 'test_comrpc_interfaces' : test_no_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_jsonrpc_interfaces(), + 'test_out_of_process' : test_no_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'InProcess': { + 'test_plugin_name' : 'InProcess', + 'test_comrpc_interfaces' : test_no_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_no_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_no_jsonrpc_interfaces(), + 'test_out_of_process' : test_no_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'OutProcessComrpcJsonrpc': { + 'test_plugin_name' : 'OutProcessComrpcJsonrpc', + 'test_comrpc_interfaces' : test_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_jsonrpc_interfaces(), + 'test_out_of_process' : test_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'OutProcessComrpc': { + 'test_plugin_name' : 'OutProcessComrpc', + 'test_comrpc_interfaces' : test_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_no_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_no_jsonrpc_interfaces(), + 'test_out_of_process' : test_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'OutProcessJsonrpc': { + 'test_plugin_name' : 'OutProcessJsonrpc', + 'test_comrpc_interfaces' : test_no_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_jsonrpc_interfaces(), + 'test_out_of_process' : test_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, + 'OutProcess': { + 'test_plugin_name' : 'OutProcess', + 'test_comrpc_interfaces' : test_no_comrpc_interfaces(), + 'test_jsonrpc_functionality' : test_no_jsonrpc_functionality(), + 'test_jsonrpc_interfaces' : test_no_jsonrpc_interfaces(), + 'test_out_of_process' : test_out_of_process(), + 'test_subsystems' : test_no_subsystems(), + 'test_preconditions' : test_no_preconditions(), + 'test_terminations' : test_no_terminations(), + 'test_controls' : test_no_controls() + }, +} + +class TestSkeletonGenerator(unittest.TestCase): + def test(self): + for key,value in test_cases.items(): + result = generate_files( + value['test_plugin_name'], + value['test_comrpc_interfaces'], + value['test_jsonrpc_interfaces'], + value['test_out_of_process'], + value['test_jsonrpc_functionality'], + value['test_subsystems'], + value['test_preconditions'], + value['test_terminations'], + value['test_controls'] + ) + self.assertEqual(result, True) + print(f'Success for case: {value["test_plugin_name"]}') + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 41eaef411ea776f44ff05adf43658a4ce7c6c931 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Thu, 17 Oct 2024 01:49:22 -0700 Subject: [PATCH 10/12] New updates notification,events --- .../PluginSkeletonGenerator.py | 49 +- .../examples/InProcess/CMakeLists.txt | 61 -- .../examples/InProcess/InProcess.conf.in | 4 - .../examples/InProcess/InProcess.cpp | 61 -- .../examples/InProcess/InProcess.h | 91 --- .../examples/InProcess/InProcessPlugin.json | 32 - .../examples/InProcess/Module.cpp | 22 - .../examples/InProcess/Module.h | 30 - .../examples/OutOfProcess/CMakeLists.txt | 62 -- .../examples/OutOfProcess/Module.cpp | 22 - .../examples/OutOfProcess/Module.h | 30 - .../OutOfProcess/OutOfProcess.conf.in | 4 - .../examples/OutOfProcess/OutOfProcess.cpp | 101 --- .../examples/OutOfProcess/OutOfProcess.h | 96 --- .../OutOfProcessImplementation.cpp | 82 -- .../OutOfProcess/OutOfProcessPlugin.json | 32 - PluginSkeletonGenerator/examples/examples.txt | 1 - PluginSkeletonGenerator/file_data.py | 714 ++++++++++++++---- PluginSkeletonGenerator/global_variables.py | 37 +- PluginSkeletonGenerator/menu.py | 181 +++-- PluginSkeletonGenerator/templates/.cmake.txt | 3 +- .../templates/.plugin_conf_in.txt | 5 +- .../templates/.plugin_header.txt | 13 +- .../templates/.plugin_implementation.txt | 20 +- .../templates/.plugin_source.txt | 17 +- .../iplugin_methods/.deinitialize_oop.txt | 22 +- .../iplugin_methods/.initialize_ip.txt | 7 +- .../iplugin_methods/.initialize_oop.txt | 13 +- .../.nested_initialize_oop.txt | 15 + .../templates/json/.json_configuration.txt | 2 +- .../templates/json/.json_info.txt | 2 +- .../templates/json/.plugin_json.txt | 2 +- .../templates/nested_class/.config_class.txt | 7 +- .../nested_class/.rpc_inotification.txt | 29 +- .../templates/nested_methods/.configure.txt | 11 + .../nested_methods/.notification_register.txt | 15 + .../.notification_unregister.txt | 15 + PluginSkeletonGenerator/tests/test.py | 8 +- PluginSkeletonGenerator/utils.py | 47 +- ThunderDevTools/ThunderDevTools.py | 2 +- 40 files changed, 901 insertions(+), 1066 deletions(-) delete mode 100644 PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt delete mode 100644 PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in delete mode 100644 PluginSkeletonGenerator/examples/InProcess/InProcess.cpp delete mode 100644 PluginSkeletonGenerator/examples/InProcess/InProcess.h delete mode 100644 PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json delete mode 100644 PluginSkeletonGenerator/examples/InProcess/Module.cpp delete mode 100644 PluginSkeletonGenerator/examples/InProcess/Module.h delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/Module.cpp delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/Module.h delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp delete mode 100644 PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json delete mode 100644 PluginSkeletonGenerator/examples/examples.txt create mode 100644 PluginSkeletonGenerator/templates/iplugin_methods/.nested_initialize_oop.txt create mode 100644 PluginSkeletonGenerator/templates/nested_methods/.configure.txt create mode 100644 PluginSkeletonGenerator/templates/nested_methods/.notification_register.txt create mode 100644 PluginSkeletonGenerator/templates/nested_methods/.notification_unregister.txt mode change 100644 => 100755 ThunderDevTools/ThunderDevTools.py diff --git a/PluginSkeletonGenerator/PluginSkeletonGenerator.py b/PluginSkeletonGenerator/PluginSkeletonGenerator.py index b754dc4..66e1174 100755 --- a/PluginSkeletonGenerator/PluginSkeletonGenerator.py +++ b/PluginSkeletonGenerator/PluginSkeletonGenerator.py @@ -1,32 +1,12 @@ #!/usr/bin/env python3 - -''' -- thunder version (not in the first version as it will only support Thunder R5.0). But we also need to take into account generated skeleton the code could be slightly different for future Thunder versions. -- plugin name -- COMRPC interface (if any) -- json rpc interface (header names required) -- Does the plugin require the possibility to run OOP -- does the plugin use JSONRPC events ? - -TODO: -- does the plugin specific configuration options (is configuration code needed)? -- other plugin access required (use new PluginSmartInterfaceType type for this) -- compile time implementation differentiation needed (e.g. like DisplayInfo) -- special trace categories required (create new category for this plugin) -- subsystems support needed (dependend en set) -- needs workerpool jobs (scheduled or not), so we can generate an example job -''' - import os - from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData from utils import Indenter, FileUtils import menu - import global_variables + class PluginGenerator: - def __init__(self, blueprint_data) -> None: self.blueprint_data = blueprint_data self.directory = self.blueprint_data.plugin_name @@ -35,40 +15,37 @@ def __init__(self, blueprint_data) -> None: def load_template(self, template_name): return FileUtils.read_file(template_name) - - def replace_code(self,template): - code = FileUtils.replace_keywords(template,self.blueprint_data.keywords) + + def replace_code(self, template): + code = FileUtils.replace_keywords(template, self.blueprint_data.keywords) return code - - def generate_file(self, template_path, output_path): + def generate_file(self, template_path, output_path): template = self.load_template(template_path) if template: code = self.replace_code(template) indented_code = self.indenter.process_indent(code, output_path) header_path = os.path.join(self.directory, output_path) - with open(header_path, 'w') as f: - f.write(indented_code) + with open(header_path, "w") as f: + f.write(indented_code) def generate_source(self): self.generate_file(global_variables.PLUGIN_SOURCE_PATH, f'{self.blueprint_data.plugin_name}.cpp') - self.generate_file(global_variables.MODULE_SOURCE_PATH, "Module.cpp") + self.generate_file(global_variables.MODULE_SOURCE_PATH, 'Module.cpp') def generate_headers(self): - self.generate_file(global_variables.PLUGIN_HEADER_PATH, f'{self.blueprint_data.plugin_name}.h') - self.generate_file(global_variables.MODULE_HEADER_PATH, "Module.h") + self.generate_file(global_variables.MODULE_HEADER_PATH, 'Module.h') # Although this is a .cpp file, it's actually most like a .h - if(self.blueprint_data.out_of_process): + if self.blueprint_data.out_of_process: self.blueprint_data.type = HeaderData.HeaderType.HEADER_IMPLEMENTATION self.blueprint_data.populate_keywords() self.generate_file(global_variables.PLUGIN_IMPLEMENTATION_PATH, f'{self.blueprint_data.plugin_name}Implementation.cpp') - def generate_cmake(self): - self.generate_file(global_variables.CMAKE_PATH, "CMakeLists.txt") + self.generate_file(global_variables.CMAKE_PATH, 'CMakeLists.txt') def generate_json(self): self.generate_file(global_variables.PLUGIN_JSON, f'{self.blueprint_data.plugin_name}Plugin.json') @@ -76,9 +53,9 @@ def generate_json(self): def generate_conf_in(self): self.generate_file(global_variables.PLUGIN_CONF_PATH, f'{self.blueprint_data.plugin_name}.conf.in') -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# def main(): menu.menu() -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# if __name__ == "__main__": main() \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt b/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt deleted file mode 100644 index 52a7d13..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt +++ /dev/null @@ -1,61 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2024 Metrological -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(InProcess) - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) - -project_version(1.0.0) - -set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) - -message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") - -set(PLUGIN_INPROCESS_STARTMODE "Activated" CACHE STRING "Automatically start InProcess plugin") - -if(BUILD_REFERENCE) - add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) -endif() - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - InProcess.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -target_include_directories(${MODULE_NAME} - PUBLIC - $) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) - -write_config() \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in b/PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in deleted file mode 100644 index 29d9838..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -startmode = "@PLUGIN_INPROCESS_STARTMODE@" - -configuration = JSON() -configuration.add("example,"mystring") \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp b/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp deleted file mode 100644 index 8ab62ed..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/InProcess.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "InProcess.h" - -namespace Thunder { -namespace Plugin { - namespace { - static Metadatametadata( - // Version - 1, 0, 0, - // Preconditions - {subsystem::PRE1, subsystem::PRE2}, - // Terminations - {}, - // Controls - {} - ) - } - - // Implement all methods from InProcess.h - - const string InProcess::Initialize(PluginHost::IShell* service) { - string message; - - ASSERT(service != nullptr); - - Config config; - config.FromString(service->ConfigLine()); - - Exchange::JHello::Register(*this, this); - Exchange::JWorld::Register(*this, this); - return (message); - } - - void InProcess::Deinitialize(PluginHost::IShell* service VARIABLE_IS_NOT_USED) { - Exchange::JHello::Unregister(*this); - Exchange::JWorld::Unregister(*this); - } - - string InProcess::Information() { - return string() - } -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcess.h b/PluginSkeletonGenerator/examples/InProcess/InProcess.h deleted file mode 100644 index 4559306..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/InProcess.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#include -#include -#include -#include - -namespace Thunder { -namespace Plugin { - - class InProcess : public PluginHost::IPlugin, public PluginHost::JSONRPC, public Exchange::IHello, public Exchange::IWorld { - public: - InProcess(const InProcess&) = delete; - InProcess &operator=(const InProcess&) = delete; - InProcess(InProcess&&) = delete; - InProcess &operator=(InProcess&&) = delete; - - InProcess() - : IHello() - , IWorld() - , _example(0) - { - } - - ~InProcess() override = default; - private: - class Config : public Core::JSON::Container { - private: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - Config(Config&&) = delete; - Config& operator=(Config&&) = delete; - public: - Config() - : Core::JSON::Container() - { - Add(_T("example"), &Example); - } - ~Config() override = default; - public: - Core::JSON::String Example; - } - public: - // IPlugin Methods - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - // IHello methods - void IHelloMethod1() override; - void IHelloMethod2() override; - - // IWorld methods - void IWorldMethod1() override; - void IWorldMethod2() override; - - // Plugin Methods - void InProcessMethod(); - - BEGIN_INTERFACE_MAP(InProcess) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_ENTRY(Exchange::IHello) - INTERFACE_ENTRY(Exchange::IWorld) - END_INTERFACE_MAP - - private: - // Include the correct member variables for your plugin: - // Note this is only an example, you are responsible for adding the correct members: - uint32_t _example; - }; -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json b/PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json deleted file mode 100644 index 5eace07..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/InProcessPlugin.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "plugin.schema.json", - "info": { - "title": "InProcess Plugin", - "callsign": "InProcess", - "locator": "libThunderInProcess.so", - "status": "production", - "description": [ - "" - ], - "version": "1.0" - }, - "configuration": { - "type": "object", - "properties": { - "configuration": { - "type": "object", - "required": [], - "properties": { - "example": { - "type": "string", - "description": "Note: This is an example!" - } - } - } - } - }, - "interface": { - "$cppref": "{cppinterfacedir}/IHello.h", - "$cppref": "{cppinterfacedir}/IWorld.h" - } -} \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/Module.cpp b/PluginSkeletonGenerator/examples/InProcess/Module.cpp deleted file mode 100644 index c3a1a78..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/InProcess/Module.h b/PluginSkeletonGenerator/examples/InProcess/Module.h deleted file mode 100644 index 307a6a2..0000000 --- a/PluginSkeletonGenerator/examples/InProcess/Module.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_InProcess -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt b/PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt deleted file mode 100644 index ca35745..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/CMakeLists.txt +++ /dev/null @@ -1,62 +0,0 @@ -# If not stated otherwise in this file or this component's license file the -# following copyright and licenses apply: -# -# Copyright 2024 Metrological -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(OutOfProcess) - -cmake_minimum_required(VERSION 3.15) - -find_package(Thunder) - -project_version(1.0.0) - -set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) - -message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") - -set(PLUGIN_OUTOFPROCESS_STARTMODE "Activated" CACHE STRING "Automatically start OutOfProcess plugin") - -if(BUILD_REFERENCE) - add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE}) -endif() - -find_package(${NAMESPACE}Plugins REQUIRED) -find_package(${NAMESPACE}Definitions REQUIRED) -find_package(CompileSettingsDebug CONFIG REQUIRED) - -add_library(${MODULE_NAME} SHARED - OutOfProcess.cpp - OutOfProcessImplementation.cpp -) - -set_target_properties(${MODULE_NAME} PROPERTIES - CXX_STANDARD 11 - CXX_STANDARD_REQUIRED YES) - -target_link_libraries(${MODULE_NAME} - PRIVATE - CompileSettingsDebug::CompileSettingsDebug - ${NAMESPACE}Plugins::${NAMESPACE}Plugins - ${NAMESPACE}Definitions::${NAMESPACE}Definitions) - -target_include_directories(${MODULE_NAME} - PUBLIC - $) - -install(TARGETS ${MODULE_NAME} - DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime) - -write_config() \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/Module.cpp b/PluginSkeletonGenerator/examples/OutOfProcess/Module.cpp deleted file mode 100644 index c3a1a78..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/Module.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "Module.h" - -MODULE_NAME_DECLARATION(BUILD_REFERENCE) \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/Module.h b/PluginSkeletonGenerator/examples/OutOfProcess/Module.h deleted file mode 100644 index 8661274..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/Module.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#ifndef MODULE_NAME -#define MODULE_NAME Plugin_OutOfProcess -#endif - -#include -#include - -#undef EXTERNAL -#define EXTERNAL \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in deleted file mode 100644 index 1535cf0..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.conf.in +++ /dev/null @@ -1,4 +0,0 @@ -startmode = "@PLUGIN_OUTOFPROCESS_STARTMODE@" - -configuration = JSON() -configuration.add("example,"mystring") \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp deleted file mode 100644 index abdedcf..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "OutOfProcess.h" - -namespace Thunder { -namespace Plugin { - namespace { - static Metadatametadata( - // Version - 1, 0, 0, - // Preconditions - {subsystem::PRE}, - // Terminations - {subsystem::TERM}, - // Controls - {subsystem::CONT} - ) - } - - // Implement all methods from OutOfProcess.h - - const string OutOfProcess::Initialize(PluginHost::IShell* service) { - string message; - - ASSERT(_service == nullptr); - ASSERT(service != nullptr); - ASSERT(_implementation == nullptr); - ASSERT(_connectionId == 0); - - _service = service; - _service->AddRef(); - _service->Register(&_connectionNotification); - - // Example - _implementation = service->Root(_connectionId, 2000, _T("OutOfProcessImplementation")); - if (_implementation == nullptr) { - message = _T("Couldn't create instance"); - } else { - // Add registration e.g: - //_implementation->Register(&_volumeNotification); - Exchange::JHello::Register(*this, implJHello); - Exchange::JWorld::Register(*this, implJWorld); - } - - return (message); - } - - void OutOfProcess::Deinitialize(PluginHost::IShell* service) { - if (_service != nullptr) { - ASSERT(_service == service); - - service->Unregister(&_connectionNotification); - - if (_implementation != nullptr) { - // Example if your interface has inotification implemented - Exchange::JHello::Unregister(*this); - Exchange::JWorld::Unregister(*this); - //_implementation->Unregister(&_volumeNotification); - - RPC::IRemoteConnection* connection(_service->RemoteConnection(_connectionId)); - VARIABLE_IS_NOT_USED uint32_t result = _implementation->Release(); - _implementation = nullptr; - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... - ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); - // The process can disappear in the meantime... - if (connection != nullptr) { - // But if it did not dissapear in the meantime, forcefully terminate it. Shoot to kill - connection->Terminate(); - connection->Release(); - } - } - _service->Release(); - _service = nullptr; - _connectionId = 0; - } - } - - string OutOfProcess::Information() { - return string() - } -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h deleted file mode 100644 index f0facfc..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcess.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once -#include -#include -#include -#include - -namespace Thunder { -namespace Plugin { - - class OutOfProcess : public PluginHost::IPlugin, public PluginHost::JSONRPC { - public: - OutOfProcess(const OutOfProcess&) = delete; - OutOfProcess &operator=(const OutOfProcess&) = delete; - OutOfProcess(OutOfProcess&&) = delete; - OutOfProcess &operator=(OutOfProcess&&) = delete; - - OutOfProcess() - : _example(0) - { - } - - ~OutOfProcess() override = default; - private: - class ConnectionNotification : public RPC::IRemoteConnection::INotification { - public: - explicit ConnectionNotification(OutOfProcess* parent) - : _parent(*parent) - { - ASSERT(parent != nullptr); - } - - ~ConnectionNotification() override = default; - ConnectionNotification() = delete; - ConnectionNotification(const ConnectionNotification&) = delete; - ConnectionNotification& operator=(const ConnectionNotification&) = delete; - ConnectionNotification(ConnectionNotification&&) = delete; - ConnectionNotification& operator=(ConnectionNotification&&) = delete; - - void Activated(RPC::IRemoteConnection*) override - { - } - - void Deactivated(RPC::IRemoteConnection* connection) override - { - _parent.Deactivated(connection); - } - - BEGIN_INTERFACE_MAP(ConnectionNotification) - INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) - END_INTERFACE_MAP - private: - OutOfProcess& _parent; - } - public: - // IPlugin Methods - const string Initialize(PluginHost::IShell* service) override; - void Deinitialize(PluginHost::IShell* service) override; - string Information() const override; - - - // Plugin Methods - void OutOfProcessMethod(); - - BEGIN_INTERFACE_MAP(OutOfProcess) - INTERFACE_ENTRY(PluginHost::IPlugin) - INTERFACE_ENTRY(PluginHost::IDispatcher) - INTERFACE_AGGREGATE(Exchange::IHello, _implIHello) - INTERFACE_AGGREGATE(Exchange::IWorld, _implIWorld) - END_INTERFACE_MAP - - private: - // Include the correct member variables for your plugin: - // Note this is only an example, you are responsible for adding the correct members: - uint32_t _example; - }; -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp deleted file mode 100644 index a6ab7f3..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessImplementation.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* -* If not stated otherwise in this file or this component's LICENSE file the -* following copyright and licenses apply: -* -* Copyright 2024 Metrological -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#pragma once - -#include -#include - -namespace Thunder { -namespace Plugin { - SERVICE_REGISTRATION(OutOfProcessImplementation, 1, 0) - - class OutOfProcessImplementation : public IHello, public IWorld { - public: - OutOfProcessImplementation(const OutOfProcessImplementation&) = delete; - OutOfProcessImplementation& operator=(const OutOfProcessImplementation&) = delete; - - OutOfProcessImplementation() - : IHello() - , IWorld() - , _test(0) - { - } - ~OutOfProcessImplementation() override = default; - - private: - - class Config : public Core::JSON::Container { - private: - Config(const Config&) = delete; - Config& operator=(const Config&) = delete; - Config(Config&&) = delete; - Config& operator=(Config&&) = delete; - public: - Config() - : Core::JSON::Container() - { - Add(_T("example"), &Example); - } - ~Config() override = default; - public: - Core::JSON::String Example; - } - - public: - - BEGIN_INTERFACE_MAP(OutOfProcessImplementation) - INTERFACE_ENTRY(Exchange::IHello) - INTERFACE_ENTRY(Exchange::IWorld) - END_INTERFACE_MAP - - // Implement methods from the interface - // IHello methods - void IHelloMethod1() override; - void IHelloMethod2() override; - - // IWorld methods - void IWorldMethod1() override; - void IWorldMethod2() override; - - private: - // Add data members, for example: (Core::CriticalSection, std::vector..) - uint32_t _test; - }; -} // Plugin -} // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json b/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json deleted file mode 100644 index 0cfc87f..0000000 --- a/PluginSkeletonGenerator/examples/OutOfProcess/OutOfProcessPlugin.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "plugin.schema.json", - "info": { - "title": "OutOfProcess Plugin", - "callsign": "OutOfProcess", - "locator": "libThunderOutOfProcess.so", - "status": "production", - "description": [ - "" - ], - "version": "1.0" - }, - "configuration": { - "type": "object", - "properties": { - "configuration": { - "type": "object", - "required": [], - "properties": { - "example": { - "type": "string", - "description": "Note: This is an example!" - } - } - } - } - }, - "interface": { - "$cppref": "{cppinterfacedir}/IHello.h", - "$cppref": "{cppinterfacedir}/IWorld.h" - } -} \ No newline at end of file diff --git a/PluginSkeletonGenerator/examples/examples.txt b/PluginSkeletonGenerator/examples/examples.txt deleted file mode 100644 index 6aadad5..0000000 --- a/PluginSkeletonGenerator/examples/examples.txt +++ /dev/null @@ -1 +0,0 @@ -These examples serve as a display to show what your skeleton may look like. \ No newline at end of file diff --git a/PluginSkeletonGenerator/file_data.py b/PluginSkeletonGenerator/file_data.py index 00d55d8..ea73af1 100644 --- a/PluginSkeletonGenerator/file_data.py +++ b/PluginSkeletonGenerator/file_data.py @@ -1,220 +1,437 @@ #!/usr/bin/env python3 -from utils import FileUtils +from utils import FileUtils, Utils from enum import Enum import global_variables class FileData: - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) -> None: + def __init__(self,plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, plugin_config, notification_interfaces) -> None: self.plugin_name = plugin_name self.comrpc_interfaces = comrpc_interfaces if comrpc_interfaces else [] self.jsonrpc_interfaces = jsonrpc_interfaces if jsonrpc_interfaces else [] self.out_of_process = out_of_process self.jsonrpc = jsonrpc + self.plugin_config = plugin_config + self.notification_interfaces = notification_interfaces self.keywords = self.generate_keywords_map() def generate_keywords_map(self): return { - '{{PLUGIN_NAME}}' : self.plugin_name, - '{{PLUGIN_NAME_CAPS}}' : self.plugin_name.upper() + "{{PLUGIN_NAME}}": self.plugin_name, + "{{PLUGIN_NAME_CAPS}}": self.plugin_name.upper() } - -class HeaderData(FileData): +class HeaderData(FileData): class HeaderType(Enum): HEADER = 1 HEADER_IMPLEMENTATION = 2 - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions, terminations, controls, type=None) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) - - self.type = type if type else HeaderData.HeaderType.HEADER + def __init__( + self, + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) -> None: + super().__init__( + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) + self.type = HeaderData.HeaderType.HEADER self.keywords = self.keywords.copy() def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) self.keywords.update(self.generate_nested_map()) - - def generate_jsonrpc_includes(self): - return '\n'.join([f'#include ' for jsonrpc in self.jsonrpc_interfaces]) def generate_comrpc_includes(self): - return '\n'.join([f'#include ' for comrpc in self.comrpc_interfaces]) - + includes = [] + for comrpc in self.comrpc_interfaces: + if comrpc == 'IConfiguration': + break + includes.append(f'#include ') + for interface in self.jsonrpc_interfaces: + if 'I' + interface[1:] in self.notification_interfaces: + includes.append(f'#include ') + return '\n'.join(includes) if includes else 'rm\*n' + def generate_inherited_classes(self): - inheritance = ["PluginHost::IPlugin"] + inheritance = ['PluginHost::IPlugin'] if self.jsonrpc: - inheritance.append("public PluginHost::JSONRPC") + inheritance.append('public PluginHost::JSONRPC') if not self.out_of_process: inheritance.extend(f'public Exchange::{cls}' for cls in self.comrpc_interfaces) return ', '.join(inheritance) - + def generate_oop_inherited_classes(self): if not self.comrpc_interfaces: - return '' - inheritance = [self.comrpc_interfaces[0]] + return "" + inheritance = [f': public Exchange::{self.comrpc_interfaces[0]}'] if self.out_of_process: - inheritance.extend(f'public {cls}' for cls in self.comrpc_interfaces[1:]) - return ', '.join(inheritance) - + inheritance.extend(f', public Exchange::{cls}' for cls in self.comrpc_interfaces[1:]) + return "".join(inheritance) + + def notification_registers(self, interface): + text = [] + text.append('\n~INDENT_INCREASE~') + text.append('\nASSERT(notification);') + text.append('\n_adminLock.Lock();') + text.append(f'''\nauto item = std::find(_notifications{interface}.begin(), _notifications{interface}.end(), notification); + ASSERT(item == _notifications{interface}.end()); + if (item == _notifications{interface}.end()) {{ + ~INDENT_INCREASE~ + notification->AddRef(); + notifications{interface}.push_back(notification); + ~INDENT_DECREASE~ + }} + + _adminLock.Unlock(); ''') + text.append('\n~INDENT_DECREASE~') + return ''.join(text) + + def notification_unregisters(self,interface): + text = [] + text.append(f'''\n~INDENT_INCREASE~ + ASSERT(notification); + + _adminLock.Lock(); + auto item = std::find(_notifications{interface}.begin(), _notifications{interface}.end(), notification); + ASSERT(item != _notifications{interface}.end()); + + if (item != _notifications{interface}.end()) {{ + ~INDENT_INCREASE~ + _notifications{interface}.erase(item); + (*item)->Release(); + ~INDENT_DECREASE~ + }} + _adminLock.Unlock(); + ~INDENT_DECREASE~''') + return ''.join(text) + def generate_inherited_methods(self): if (not self.out_of_process and self.type != HeaderData.HeaderType.HEADER) or \ - (self.out_of_process and self.type != HeaderData.HeaderType.HEADER_IMPLEMENTATION): - return '' + (self.out_of_process and self.type != HeaderData.HeaderType.HEADER_IMPLEMENTATION): + return "rm\*n" - methods = [ - f'// {inherited} methods\n' - f'void {inherited}Method1() override;\n' - f'void {inherited}Method2() override;\n' - for inherited in self.comrpc_interfaces] - return ('\n').join(methods) + if not self.comrpc_interfaces: + return 'rm\*n' + + methods = [] + for inherited in self.comrpc_interfaces: + if (inherited == 'IConfiguration'): + continue + if self.type == HeaderData.HeaderType.HEADER: + methods.append(f"// {inherited} methods\n" f"void {inherited}Method1() override;\n") + if inherited in self.notification_interfaces: + methods.append(f'void Register(Exchange::{inherited}::INotification* notification) override;') + methods.append(f'void Unregister(Exchange::{inherited}::INotification* notification) override;') + else: + methods.append(f'// {inherited} methods') + + methods.append(f'void {inherited}Method1() override {{\n\n}}\n') + if inherited in self.notification_interfaces: + methods.append(f'void Register(Exchange::{inherited}::INotification* notification) override {{') + methods.append(self.notification_registers(inherited)) + methods.append('}') + methods.append(f'void Unregister(Exchange::{inherited}::INotification* notification) override {{') + methods.append(self.notification_unregisters(inherited)) + methods.append('}') + + if self.comrpc_interfaces: + if self.comrpc_interfaces[-1] == "IConfiguration": + template_name = global_variables.CONFIGURE_METHOD + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template, self.keywords) + methods.append(code) + return ("\n").join(methods) def generate_plugin_methods(self): - method = f'void {self.plugin_name}Method();' - return method - + method = [] + if self.type == HeaderData.HeaderType.HEADER: + method = [f'void {self.plugin_name}Method();'] + if self.notification_interfaces: + method.append(f'void Deactivated(RPC::IRemoteConnection* connection);') + return '\n'.join(method) + def generate_interface_entry(self): entries = [] if self.type == HeaderData.HeaderType.HEADER: - entries.append(f'INTERFACE_ENTRY(PluginHost::IPlugin)') + entries.append(f"INTERFACE_ENTRY(PluginHost::IPlugin)") if self.jsonrpc: - entries.append(f'INTERFACE_ENTRY(PluginHost::IDispatcher)') + entries.append(f"INTERFACE_ENTRY(PluginHost::IDispatcher)") if (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ - ((not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER)): + (not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER): entries.extend(f'INTERFACE_ENTRY(Exchange::{comrpc})' for comrpc in self.comrpc_interfaces) return '\n'.join(entries) if entries else 'rm\*n' - + def generate_interface_aggregate(self): - if(self.out_of_process): - aggregates = [f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc})' for comrpc in self.comrpc_interfaces] - return ('\n').join(aggregates) - return 'rm\*n' - + aggregates = [] + if self.out_of_process: + for comrpc in self.comrpc_interfaces: + if comrpc == "IConfiguration": + break + aggregates.append(f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc})') + return ('\n').join(aggregates) if aggregates else 'rm\*n' + def generate_module_plugin_name(self): return f'Plugin_{self.plugin_name}' - + + def generate_base_constructor(self): + constructor = [f' PluginHost::IPlugin()'] + if self.jsonrpc: + constructor.append(f'\n, PluginHost::JSONRPC()') + return ''.join(constructor) + def generate_interface_constructor(self): + constructor = [] if not self.comrpc_interfaces: return '' - if (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ - ((not self.out_of_process) and (self.type == HeaderData.HeaderType.HEADER)): - constructor = [f' {self.comrpc_interfaces[0]}()\n,'] + \ - [f' {comrpc}()\n,' for comrpc in self.comrpc_interfaces[1:]] - return ''.join(constructor) - return '' + if self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION: + constructor = [f": Exchange::{self.comrpc_interfaces[0]}()"] + [f", Exchange::{comrpc}()" for comrpc in self.comrpc_interfaces[1:]] + constructor.append(', test(0)') + if self.notification_interfaces: + constructor.append(', _adminLock()') + for interface in self.notification_interfaces: + constructor.append(f', _notifications{interface}()') + + if (not self.out_of_process and self.type == HeaderData.HeaderType.HEADER): + if self.comrpc_interfaces: + constructor.append(f", Exchange::{self.comrpc_interfaces[0]}()") + for comrpc in self.comrpc_interfaces[1:]: + if comrpc == 'IConfiguration': + continue + constructor.append(f", Exchange::{comrpc}()") + return "\n".join(constructor) if constructor else "rm\*n" + + def generate_member_impl(self): + members = [] + if self.out_of_process: + for comrpc in self.comrpc_interfaces: + if comrpc == 'IConfiguration': + break + members.append(f"Exchange::{comrpc}* _impl{comrpc};") + if self.jsonrpc: + members.append("Core::SinkType _notification;") + return "\n".join(members) if members else 'rm\*n' + def generate_member_constructor(self): + members = [] + if self.out_of_process: + for comrpc in self.comrpc_interfaces: + if comrpc == "IConfiguration": + break + members.append(f", _impl{comrpc}(nullptr)") + return "\n".join(members) if members else 'rm\*n' + + def generate_notification_class(self): + + classes = [] + classes.append(f"public RPC::IRemoteConnection::INotification") + for interface in self.notification_interfaces: + classes.append(f", public Exchange::{interface}::INotification") + return "".join(classes) + + def generate_notification_constructor(self): + members = [] + for notif in self.notification_interfaces: + members.append(f', Exchange::{notif}::INotification()') + return '\n'.join(members) if members else 'rm\*n' + + def generate_notification_entry(self): + entries = [] + for entry in self.notification_interfaces: + entries.append(f'INTERFACE_ENTRY(Exchange::{entry}::INotification)') + return '\n'.join(entries) if entries else 'rm\*n' + + def generate_notification_function(self): + methods = [] + for inherited in self.notification_interfaces: + if Utils.replace_comrpc_to_jsonrpc(inherited) in self.jsonrpc_interfaces: + methods.append(f'''void {inherited}Notification() override {{\n~INDENT_INCREASE~\nExchange::J{inherited[1:]}::Event::{inherited}Notification();\n~INDENT_DECREASE~\n}}\n''') + else: + methods.append(f'void {inherited}Notification() override {{\n\n}}') + return ("\n").join(methods) if methods else 'rm\*n' + + def generate_oop_members(self): + members = [] + if self.notification_interfaces: + members.append('Core::CriticalSection _adminLock;') + for interface in self.notification_interfaces: + members.append(f'std::vector _notifications{interface};') + return '\n'.join(members) if members else 'rm\*n' + + def generate_notify_method(self): + methods = [] + + for interface in self.notification_interfaces: + methods.append(f'void Notify{interface}() override {{') + methods.append('\n~INDENT_INCREASE~') + methods.append('\n_adminLock.Lock();') + methods.append(f'''\nfor (auto* notification : _notifications{interface}) {{ + ~INDENT_INCREASE~ + notification->{interface}Notification(); + ~INDENT_DECREASE~ + }} + _adminLock.Unlock(); + ~INDENT_DECREASE~ + }}\n''') + + return ''.join(methods) if methods else 'rm\*n' + def generate_keyword_map(self): - return{ - '{{JSONRPC_INTERFACE_INCLUDES}}' : self.generate_jsonrpc_includes(), - '{{COMRPC_INTERFACE_INCLUDES}}' : self.generate_comrpc_includes(), - '{{INHERITED_CLASS}}' : self.generate_inherited_classes(), - '{{INHERITED_METHOD}}' : self.generate_inherited_methods(), - '{{PLUGIN_METHOD}}' : self.generate_plugin_methods(), - '{{INTERFACE_ENTRY}}' : self.generate_interface_entry(), - '{{INTERFACE_AGGREGATE}}' : self.generate_interface_aggregate(), - '{{MODULE_PLUGIN_NAME}}' : self.generate_module_plugin_name(), - '{{OOP_INHERITED_CLASS}}' : self.generate_oop_inherited_classes(), - '{{INTERFACE_CONSTRUCTOR}}' : self.generate_interface_constructor() + return { + "{{COMRPC_INTERFACE_INCLUDES}}": self.generate_comrpc_includes(), + "{{INHERITED_CLASS}}": self.generate_inherited_classes(), + "{{INHERITED_METHOD}}": self.generate_inherited_methods(), + "{{PLUGIN_METHOD}}": self.generate_plugin_methods(), + "{{INTERFACE_ENTRY}}": self.generate_interface_entry(), + "{{INTERFACE_AGGREGATE}}": self.generate_interface_aggregate(), + "{{MODULE_PLUGIN_NAME}}": self.generate_module_plugin_name(), + "{{OOP_INHERITED_CLASS}}": self.generate_oop_inherited_classes(), + "{{BASE_CONSTRUCTOR}}": self.generate_base_constructor(), + "{{INTERFACE_CONSTRUCTOR}}": self.generate_interface_constructor(), + "{{MEMBER_IMPL}}": self.generate_member_impl(), + "{{MEMBER_CONSTRUCTOR}}": self.generate_member_constructor(), + "{{NOTIFICATION_CLASS}}": self.generate_notification_class(), + "{{NOTIFICATION_CONSTRUCTOR}}" : self.generate_notification_constructor(), + "{{NOTIFICATION_ENTRY}}" : self.generate_notification_entry(), + "{{NOTIFICATION_FUNCTION}}" : self.generate_notification_function(), + "{{OOP_MEMBERS}}" : self.generate_oop_members(), + "{{NOTIFY_METHOD}}" : self.generate_notify_method() } - + def generate_nested_map(self): - return{ - '{{JSONRPC_EVENT}}' : self.generate_jsonrpc_event(), - '{{CONFIG_CLASS}}' : self.generate_config() + return { + "{{JSONRPC_EVENT}}": self.generate_jsonrpc_event(), + "{{CONFIG_CLASS}}": self.generate_config(), } def generate_jsonrpc_event(self): - if self.out_of_process: + if self.jsonrpc or self.notification_interfaces: template_name = global_variables.RPC_NOTIFICATION_CLASS_PATH template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) + code = FileUtils.replace_keywords(template, self.keywords) return code - return 'rm\*n' - + def generate_config(self): + if self.plugin_config: + if (not self.out_of_process) or (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION): + template_name = global_variables.CONFIG_CLASS_PATH + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template, self.keywords) + return code + return "rm\*n" - if (not self.out_of_process) or (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION): - template_name = global_variables.CONFIG_CLASS_PATH - template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) - return code - return 'rm\*n' - -class SourceData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions, terminations, controls) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) +class SourceData(FileData): + def __init__( + self, + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) -> None: + super().__init__( + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) self.keywords = self.keywords.copy() - self.preconditions = preconditions if preconditions else [] - self.terminations = terminations if terminations else [] - self.controls = controls if controls else [] + # self.preconditions = preconditions if preconditions else [] + # self.terminations = terminations if terminations else [] + # self.controls = controls if controls else [] def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) self.keywords.update(self.generate_nested_map()) def generate_include_statements(self): - return f'#include "{self.plugin_name}.h"' + return_string = f'#include "{self.plugin_name}.h"' + if self.plugin_config and self.out_of_process: + return_string += f'\n#include ' + return return_string def generate_initialize(self): - if self.out_of_process: template_name = global_variables.INITIALIZE_OOP_PATH else: template_name = global_variables.INITIALIZE_IP_PATH template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) + code = FileUtils.replace_keywords(template, self.keywords) return code def generate_deinitialize(self): - if self.out_of_process: template_name = global_variables.DENINITIALIZE_OOP_PATH else: template_name = global_variables.DENINITIALIZE_IP_PATH template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) + code = FileUtils.replace_keywords(template, self.keywords) return code - + def generate_variable_used(self): - if self.out_of_process: - return '' - return " VARIABLE_IS_NOT_USED" - + return "" + return "VARIABLE_IS_NOT_USED " + def generate_jsonrpc_register(self): + if not self.jsonrpc_interfaces: + return 'rm\*n' + registers = [] - if not self.out_of_process: - for jsonrpc in self.jsonrpc_interfaces: - registers.append(f'Exchange::{jsonrpc}::Register(*this, this);') - else: - for jsonrpc in self.jsonrpc_interfaces: - registers.append(f'Exchange::{jsonrpc}::Register(*this, impl{jsonrpc});') + ''' + _implementation->Register(&_volumeNotification); + Exchange::JVolumeControl::Register(*this, _implementation); + ''' + for jsonrpc in self.jsonrpc_interfaces: + registers.append(f"Exchange::{jsonrpc}::Register(*this, this);") - registers = ('\n').join(registers) - return registers if registers else 'rm\*n' - - def generate_jsonrpc_unregister(self): + registers = ("\n").join(registers) + return registers if registers else "rm\*n" + def generate_jsonrpc_unregister(self): registers = [] if not self.out_of_process: for jsonrpc in self.jsonrpc_interfaces: - registers.append(f'Exchange::{jsonrpc}::Unregister(*this);') + registers.append(f"Exchange::{jsonrpc}::Unregister(*this);") else: for jsonrpc in self.jsonrpc_interfaces: - registers.append(f'Exchange::{jsonrpc}::Unregister(*this);') + registers.append(f"Exchange::{jsonrpc}::Unregister(*this);") - registers = ('\n').join(registers) - return registers if registers else 'rm\*n' - + registers = ("\n").join(registers) + return registers if registers else "rm\*n" + + def generate_jsonrpc_includes(self): + includes = [] + for jsonrpc in self.jsonrpc_interfaces: + if 'I' + jsonrpc[1:] in self.notification_interfaces: + continue + else: + includes.append(f"#include ") + return "\n".join(includes) if includes else 'rm\*n' + + """ def generate_preconditions(self): return ', '.join([f'subsystem::{condition}'for condition in self.preconditions]) @@ -223,107 +440,298 @@ def generate_terminations(self): def generate_controls(self): return ', '.join([f'subsystem::{control}'for control in self.controls]) + """ + + def generate_plugin_method_impl(self): + if self.out_of_process: + method = [f"void {self.plugin_name}::Deactivated(RPC::IRemoteConnection* connection) {{\n\n}}\n"] + return "".join(method) + return "rm\*n" + def generate_inherited_method_impl(self): + if not self.out_of_process: + methods = [f"void {self.plugin_name}::{inherited}Method1() {{\n\n}}\n" for inherited in self.comrpc_interfaces] + return ("\n").join(methods) + return 'rm\*n' + + def generate_nested_query(self): + nested_query = [] + closing_brackets = len(self.comrpc_interfaces) - 1 + if self.plugin_config: + closing_brackets -= 1 + iteration = 0 + + for comrpc in self.comrpc_interfaces[1:]: + if comrpc == 'IConfiguration': + break + nested_query.append("\nrm\*n \n~INDENT_INCREASE~\n") + if self.comrpc_interfaces[iteration] in self.notification_interfaces: + nested_query.append(f"_impl{self.comrpc_interfaces[iteration]}->Register(¬ification);\n") + if any(Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration]) in notif for notif in self.jsonrpc_interfaces): + nested_query.append(f'Exchange::{Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration])}::Register(*this, impl{self.comrpc_interfaces[iteration]});\n') + nested_query.append(f"_impl{comrpc} = _impl{comrpc}->QueryInterface();") + nested_query.append(f'''\nif (_impl{comrpc} == nullptr) {{ + ~INDENT_INCREASE~ + message = _T("Couldn't create instance of _impl{comrpc}") + ~INDENT_DECREASE~ + }} else {{\n''') + iteration += 1 + + nested_query.append(self.generate_nested_initialize(iteration)) + + for i in range(closing_brackets): + nested_query.append("\n~INDENT_DECREASE~") + nested_query.append("\n}") + + return ''.join(nested_query) + + def generate_nested_initialize(self, iteration): + + text = [] + rootCOMRPC = self.comrpc_interfaces[0] if self.comrpc_interfaces else 'IPlugin' + + if self.comrpc_interfaces: + text.append("\n~INDENT_INCREASE~\n") + text.append(f'_impl{self.comrpc_interfaces[iteration]}->Register(&_notification);\n') + if self.jsonrpc_interfaces: + if self.jsonrpc_interfaces[-1] == Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration]): + text.append(f'Exchange::{self.jsonrpc_interfaces[-1]}::Register(*this, impl{self.comrpc_interfaces[iteration]});\n') + if self.plugin_config: + #text.append("\n~INDENT_INCREASE~\n") + text.append(f'''\nExchange::IConfiguration* configuration = _impl{rootCOMRPC}->QueryInterface(); + ASSERT(configuration != nullptr); + if (configuration != nullptr) {{ + ~INDENT_INCREASE~ + if (configuration->configure(service) != Core::ERROR_NONE) {{ + ~INDENT_INCREASE~ + message = _T("{self.plugin_name} could not be configured."); + ~INDENT_DECREASE~ + }} + ~INDENT_DECREASE~ + configuration->Release(); + }}''') + + return ''.join(text) if text else 'rm\*n' + + def generate_configure_implementation(self): + return 'Config config;\nconfig.FromString(service->ConfigLine());' if self.plugin_config else 'rm\*n' + + def generate_nested_deinitialize(self): + text = [] + if not self.comrpc_interfaces: + return '' + text.append(f'if (_impl{self.comrpc_interfaces[0]} != nullptr) {{') + text.append(f'\n~INDENT_INCREASE~') + if self.notification_interfaces: + if self.notification_interfaces[0] == self.comrpc_interfaces[0]: + text.append(f'\n_impl{self.comrpc_interfaces[0]}->Unregister(&_notification);') + if Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[0]) in self.jsonrpc_interfaces: + text.append(f'\nExchange::{Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[0])}::Unregister(*this);') + + for comrpc in self.comrpc_interfaces[1:]: + if comrpc == 'IConfiguration': + break + text.append(f'''\nif (_impl{comrpc} != nullptr) {{ + \n~INDENT_INCREASE~ + _impl{comrpc}->Release();''') + if Utils.replace_comrpc_to_jsonrpc(comrpc) in self.jsonrpc_interfaces: + text.append(f'\nExchange::{Utils.replace_comrpc_to_jsonrpc(comrpc)}::Unregister(*this);') + if comrpc in self.notification_interfaces: + text.append(f'\n_impl{comrpc}->Unregister(&_notification);') + text.append(f'\n_impl{comrpc} = nullptr;') + text.append('\n~INDENT_DECREASE~') + text.append('\n}') + + text.append(f'''\nRPC::IRemoteConnection* connection(service->RemoteConnection(_connectionId)); + \nVARIABLE_IS_NOT_USED uint32_t result = _impl{self.comrpc_interfaces[0]}->Release(); + \n_impl{self.comrpc_interfaces[0]} = nullptr;''') + return ''.join(text) + + def generate_keyword_map(self): return { - '{{INCLUDE}}' : self.generate_include_statements(), + "{{INCLUDE}}": self.generate_include_statements(), + """ '{{PRECONDITIONS}}' : self.generate_preconditions(), '{{TERMINATIONS}}' : self.generate_terminations(), '{{CONTROLS}}' : self.generate_controls(), - '{{VARIABLE_NOT_USED}}' : self.generate_variable_used(), - '{{JSONRPC_REGISTER}}' : self.generate_jsonrpc_register(), - '{{JSONRPC_UNREGISTER}}' : self.generate_jsonrpc_unregister(), - '{{COMRPC}}' : f'{self.comrpc_interfaces[0] if self.comrpc_interfaces else "INTERFACE_NEEDED"}' + """ + "{{VARIABLE_NOT_USED}}": self.generate_variable_used(), + "{{REGISTER}}": self.generate_jsonrpc_register(), + "{{JSONRPC_UNREGISTER}}": self.generate_jsonrpc_unregister(), + "{{COMRPC}}": f'{self.comrpc_interfaces[0] if self.comrpc_interfaces else "Exchange::IPlugin"}', + "{{JSONRPC_INTERFACE_INCLUDES}}": self.generate_jsonrpc_includes(), + "{{PLUGIN_METHOD_IMPL}}": self.generate_plugin_method_impl(), + "{{INHERITED_METHOD_IMPL}}": self.generate_inherited_method_impl(), + "{{VARIABLE_NOT_USED}}" : self.generate_variable_used(), + "{{NESTED_QUERY}}" : self.generate_nested_query(), + "{{CONFIGURE_IP}}" : self.generate_configure_implementation(), + "{{DEINITIALIZE}}" : self.generate_nested_deinitialize(), } - + def generate_nested_map(self): return { - '{{INITIALIZE_IMPLEMENTATION}}' : self.generate_initialize(), - '{{DEINITIALIZE_IMPLEMENTATION}}' : self.generate_deinitialize() + "{{INITIALIZE_IMPLEMENTATION}}": self.generate_initialize(), + "{{DEINITIALIZE_IMPLEMENTATION}}": self.generate_deinitialize(), } - + + class CMakeData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions=None, terminations=None, controls=None) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + + def __init__( + self, + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) -> None: + super().__init__( + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) self.keywords = self.keywords.copy() def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) - #self.keywords.update(self.generate_nested_map()) + # self.keywords.update(self.generate_nested_map()) + + def generate_set_mode(self): + s = '' + if self.out_of_process: + s = (f'set(PLUGIN_{self.plugin_name.upper()}_MODE "Local" CACHE STRING "Controls if the plugin should run in its own process, in process or remote.")') + return s if s else 'rm\*n' def generate_keyword_map(self): return { - '{{SOURCE_FILES}}' : self.find_source_files() - } - + "{{SOURCE_FILES}}": self.find_source_files(), + '{{SET_MODE}}' : self.generate_set_mode() + } + def find_source_files(self): - if(self.out_of_process): - return f'{self.plugin_name}.cpp \n{self.plugin_name}Implementation.cpp' + if self.out_of_process: + return f"{self.plugin_name}.cpp \n{self.plugin_name}Implementation.cpp" else: - return f'{self.plugin_name}.cpp' + return f"{self.plugin_name}.cpp" + class JSONData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions=None, terminations=None, controls=None) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + + def __init__( + self, + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) -> None: + super().__init__( + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) self.keywords = self.keywords.copy() def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) self.keywords.update(self.generate_nested_map()) - def generate_cppref(self): - return ",\n".join(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"' for comrpc in self.comrpc_interfaces) \ - if self.comrpc_interfaces else 'rm\*n' + def generate_cppref(self): + return (",\n".join(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"' for comrpc in self.comrpc_interfaces) if self.comrpc_interfaces else "rm\*n") def generate_json_info(self): template_name = global_variables.JSON_INFO template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) + code = FileUtils.replace_keywords(template, self.keywords) return code - + def generate_json_configuration(self): - template_name = global_variables.JSON_CONFIGURATION - template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) - return code - + code = [] + if self.plugin_config: + template_name = global_variables.JSON_CONFIGURATION + template = FileUtils.read_file(template_name) + code = FileUtils.replace_keywords(template, self.keywords) + return code if code else "rm\*n" + def generate_json_interface(self): template_name = global_variables.JSON_INTERFACE template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template,self.keywords) + code = FileUtils.replace_keywords(template, self.keywords) return code def generate_keyword_map(self): return { - '{{cppref}}' : self.generate_cppref(), + "{{cppref}}": self.generate_cppref(), } - + def generate_nested_map(self): return { - '{{JSON_INFO}}' : self.generate_json_info(), - '{{JSON_CONFIGURATION}}' : self.generate_json_configuration(), - '{{JSON_INTERFACE}}' : self.generate_json_interface() + "{{JSON_INFO}}": self.generate_json_info(), + "{{JSON_CONFIGURATION}}": self.generate_json_configuration(), + "{{JSON_INTERFACE}}": self.generate_json_interface(), } class ConfData(FileData): - def __init__(self, plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions=None, terminations=None, controls=None) -> None: - super().__init__(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + + def __init__( + self, + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) -> None: + super().__init__( + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) self.keywords = self.keywords.copy() def populate_keywords(self): self.keywords.update(self.generate_keyword_map()) - #self.keywords.update(self.generate_nested_map()) + # self.keywords.update(self.generate_nested_map()) + + def generate_config(self): + if self.plugin_config: + return f'configuration = JSON() \nconfiguration.add("example,"mystring")' + return 'rm\*n' + + def generate_root(self): + root = [] + if self.out_of_process: + root.append(f'root = JSON() \n root.add("mode", "@PLUGIN_{self.plugin_name.upper()}_MODE@)') + return ''.join(root) if root else 'rm\*n' def generate_keyword_map(self): return { - '{{PLUGIN_STARTMODE}}' : f'"@PLUGIN_{self.plugin_name.upper()}_STARTMODE@"' + "{{PLUGIN_STARTMODE}}": f'"@PLUGIN_{self.plugin_name.upper()}_STARTMODE@"', + "{{OOP_ROOT}}" : self.generate_root(), + '{{CONFIG}}' : self.generate_config() } + # Not in use currently, may use later on to track rather than hardcode -class PluginData(): +class PluginData: # todo: store data such as class names, filenames etc def __init__(self) -> None: self.classes = [] diff --git a/PluginSkeletonGenerator/global_variables.py b/PluginSkeletonGenerator/global_variables.py index 2f82e8f..3fa8dd8 100644 --- a/PluginSkeletonGenerator/global_variables.py +++ b/PluginSkeletonGenerator/global_variables.py @@ -1,36 +1,41 @@ -import os +import os BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Nested Directories: -TEMPLATE_DIR = os.path.join(BASE_DIR,'templates') +TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates') -IPLUGIN_DIR = os.path.join(TEMPLATE_DIR,'iplugin_methods') +IPLUGIN_DIR = os.path.join(TEMPLATE_DIR, 'iplugin_methods') MODULE_DIR = os.path.join(TEMPLATE_DIR, 'module') NESTED_CLASS_DIR = os.path.join(TEMPLATE_DIR, 'nested_class') -JSON_DIR = os.path.join(TEMPLATE_DIR,'json') +NESTED_METHOD_DIR = os.path.join(TEMPLATE_DIR, 'nested_methods') +JSON_DIR = os.path.join(TEMPLATE_DIR, 'json') # Nested File Paths: # /templates -CMAKE_PATH = os.path.join(TEMPLATE_DIR,'.cmake.txt') -PLUGIN_CONF_PATH = os.path.join(TEMPLATE_DIR,'.plugin_conf_in.txt') -PLUGIN_HEADER_PATH = os.path.join(TEMPLATE_DIR,'.plugin_header.txt') -PLUGIN_IMPLEMENTATION_PATH = os.path.join(TEMPLATE_DIR,'.plugin_implementation.txt') -PLUGIN_SOURCE_PATH = os.path.join(TEMPLATE_DIR,'.plugin_source.txt') +CMAKE_PATH = os.path.join(TEMPLATE_DIR, '.cmake.txt') +PLUGIN_CONF_PATH = os.path.join(TEMPLATE_DIR, '.plugin_conf_in.txt') +PLUGIN_HEADER_PATH = os.path.join(TEMPLATE_DIR, '.plugin_header.txt') +PLUGIN_IMPLEMENTATION_PATH = os.path.join(TEMPLATE_DIR, '.plugin_implementation.txt') +PLUGIN_SOURCE_PATH = os.path.join(TEMPLATE_DIR, '.plugin_source.txt') # /templates/iplugin_methods -DENINITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'.deinitialize_oop.txt') +DENINITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR, '.deinitialize_oop.txt') DENINITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR, '.deinitialize_ip.txt') -INITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR,'.initialize_oop.txt') -INITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR,'.initialize_ip.txt') +INITIALIZE_OOP_PATH = os.path.join(IPLUGIN_DIR, '.initialize_oop.txt') +INITIALIZE_IP_PATH = os.path.join(IPLUGIN_DIR, '.initialize_ip.txt') +NESTED_OOP_PATH = os.path.join(IPLUGIN_DIR, '.nested_initialize_oop.txt') # /templates/module -MODULE_HEADER_PATH = os.path.join(MODULE_DIR,'.module_header.txt') -MODULE_SOURCE_PATH = os.path.join(MODULE_DIR,'.module_source.txt') +MODULE_HEADER_PATH = os.path.join(MODULE_DIR, '.module_header.txt') +MODULE_SOURCE_PATH = os.path.join(MODULE_DIR, '.module_source.txt') # /templates/nested_class -CONFIG_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'.config_class.txt') -RPC_NOTIFICATION_CLASS_PATH = os.path.join(NESTED_CLASS_DIR,'.rpc_inotification.txt') +CONFIG_CLASS_PATH = os.path.join(NESTED_CLASS_DIR, '.config_class.txt') +RPC_NOTIFICATION_CLASS_PATH = os.path.join(NESTED_CLASS_DIR, '.rpc_inotification.txt') + +# /templates/nested_methods +CONFIGURE_METHOD = os.path.join(NESTED_METHOD_DIR, '.configure.txt') # /templates/.json PLUGIN_JSON = os.path.join(JSON_DIR, '.plugin_json.txt') diff --git a/PluginSkeletonGenerator/menu.py b/PluginSkeletonGenerator/menu.py index d63c46e..6607a04 100644 --- a/PluginSkeletonGenerator/menu.py +++ b/PluginSkeletonGenerator/menu.py @@ -1,12 +1,16 @@ +import json +from os import wait from file_data import FileData, HeaderData, SourceData, CMakeData, JSONData, ConfData from PluginSkeletonGenerator import PluginGenerator +from utils import Utils +import time # Helpers for menu options -def generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - subsystems, preconditions, terminations, controls): - - data = FileData(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc) + +def generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, plugin_config, notification_interfaces): + + data = FileData(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, plugin_config, notification_interfaces) plugin_generator = PluginGenerator(data) file_map = { @@ -14,93 +18,176 @@ def generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_pr SourceData: plugin_generator.generate_source, CMakeData: plugin_generator.generate_cmake, ConfData: plugin_generator.generate_conf_in, - JSONData: plugin_generator.generate_json + JSONData: plugin_generator.generate_json, } for file_data, generate in file_map.items(): - instance = file_data(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - preconditions, terminations, controls) + instance = file_data(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, plugin_config, notification_interfaces) instance.populate_keywords() plugin_generator.blueprint_data = instance generate() return True - -def display_settings(plugin_name, comrpc_interface, jsonrpc_interface, out_of_process, jsonrpc, - subsystems, preconditions, terminations, controls): + + +def display_settings( + plugin_name, + comrpc_interface, + jsonrpc_interface, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces +): print("=======================================") print("You have chosen the following settings:") print(f"Plugin Name: {plugin_name}") print(f"COMRPC Interfaces: {comrpc_interface if comrpc_interface else 'None'}") + print(f"COMRPC Interfaces with events: {notification_interfaces if notification_interfaces else 'None'}") print(f"JSONRPC Functionality: {jsonrpc}") print(f"JSONRPC Interfaces: {jsonrpc_interface if jsonrpc else 'N/A'} ") print(f"Out Of Process: {out_of_process}") + """ print(f"Subsystem Support: {subsystems}") print(f"Subsystem Preconditions: {preconditions if subsystems else 'N/A'} ") print(f"Subsystem Terminations: {terminations if subsystems else 'N/A'}") print(f"Subsystem Controls: {controls if subsystems else 'N/A'}") + """ # Menu options def menu(): + print("=======================================") comrpc_interfaces = [] jsonrpc_interfaces = [] - preconditions = [] - terminations = [] - controls = [] + notification_interfaces = [] plugin_name = str(user_plugin_name()) - print(plugin_name) - user_comrpc(comrpc_interfaces) - jsonrpc = user_jsonrpc(jsonrpc_interfaces) out_of_process = user_out_of_process() - subsystems = user_subsystems(preconditions, terminations, controls) + jsonrpc = user_comrpc(out_of_process, comrpc_interfaces, jsonrpc_interfaces, notification_interfaces) + plugin_config = user_plugin_configuration(comrpc_interfaces, out_of_process) + + display_settings(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, plugin_config, notification_interfaces) + + generate_files( + plugin_name, + comrpc_interfaces, + jsonrpc_interfaces, + out_of_process, + jsonrpc, + plugin_config, + notification_interfaces + ) + - display_settings(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - subsystems, preconditions, terminations, controls) - - generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, - subsystems, preconditions, terminations, controls) - def get_boolean_input(option): while True: user_input = input(f"{option}") - if(user_input.lower() == 'y'): + if user_input.lower() == "y": user_input = True break - elif(user_input.lower() == 'n'): + elif user_input.lower() == "n": user_input = False break else: print("Unknown character, try again.") return user_input + def user_plugin_name(): name = input("What will your plugin be called: ") return name -def user_comrpc(comrpc_interfaces): - print(f"Enter any COM-RPC interfaces used: (Enter to quit) \nNote: IPlugin is already defined for you") - while True: - comrpc = input("Enter a COM-RPC interface: ") - if not comrpc: - break - comrpc_interfaces.append(comrpc) -def user_jsonrpc(jsonrpc_interfaces): - jsonrpc = get_boolean_input("Does your plugin require JSON-RPC functionality: (Enter Y or N)\n") - if jsonrpc: - print(f"Enter any JSON-RPC interfaces used: (Enter to quit)") - while True: - jsonrpc_class = input("Enter a JSON-RPC interface: ") - if not jsonrpc_class: - break - jsonrpc_interfaces.append(jsonrpc_class) - return jsonrpc +def user_comrpc(out_of_process, comrpc_interfaces, jsonrpc_interfaces, notification_interfaces): + + myBool = True + iteration = 0 + jsonrpc = False + + print("\n=======================================") + print("[INFO]: The following section tracks the number of sucessfully defined interfaces!") + print("=======================================") + while myBool: + + print(f"\nNumber of succesfully defined interfaces: {iteration}") + tempName = input( + "What C++ IDL interface header file (COMRPC Interface) is your interface in?" + "\nExample: IHello.h" + "\n[Note]: Do not define: IPlugin, IConfiguration, JSONRPC. They are automatically configured accordingly!" + "\nTo quit defining interfaces, press ENTER \n" + ) + + if tempName: + correctInitial = Utils.check_correct_comrpc(tempName) + correctExtension = Utils.extract_interface(tempName) + if not correctInitial: + print("\n=======================================") + print("[Error]: Interface header file does not begin with 'I'") + print("=======================================") + if not correctExtension: + print("\n=======================================") + print("[Error]: Interface header file does not have the extension '.h'") + print("=======================================\n") + + if not correctInitial or not correctExtension: + time.sleep(2) + continue + correctName = correctExtension + # CorrectName at this point will always return the correct interface name without the '.h' + while True: + comrpc_confirm = input(f"The name of the interface in {tempName} is (enter to confirm or type the correct interface name) {correctName}: ") + if comrpc_confirm: + correctInitial = Utils.check_correct_comrpc(comrpc_confirm) + if not correctInitial: + print("\n=======================================") + print("[Error]: Interface header file does not begin with 'I'") + print("=======================================") + else: + correctName = comrpc_confirm + break + else: + break + + comrpc_interfaces.append(correctName) + notification = get_boolean_input("\nDoes your interface contain a notification: (Enter Y or N)\n") + if notification: + notification_interfaces.append(correctName) + + json_tag = user_jsonrpc(correctName, jsonrpc_interfaces) + if json_tag: + jsonrpc = True + iteration += 1 + else: + if out_of_process and not comrpc_interfaces: + print("An out of process plugin requires a COMRPC interface.") + else: + myBool = False + return jsonrpc + + +def user_jsonrpc(comrpc_interface, jsonrpc_interfaces): + + json_tag = get_boolean_input("Does your plugin require JSON-RPC functionality (@JSON tag): (Enter Y or N)\n") + if json_tag: + jsonrpc_interface = Utils.replace_comrpc_to_jsonrpc(comrpc_interface) + jsonrpc_interfaces.append(jsonrpc_interface) + return True + return False + def user_out_of_process(): - out_of_process = get_boolean_input("Is your plugin expected to work out of process: (Enter Y or N)\n") + out_of_process = get_boolean_input("\nIs your plugin expected to work out of process: (Enter Y or N)\n") return out_of_process +def user_plugin_configuration(comrpc_interfaces, out_of_process): + plugin_config = get_boolean_input("\nDoes the plugin require plugin specific configuration: (Enter Y or N) \n") + if plugin_config and out_of_process: + comrpc_interfaces.append("IConfiguration") + return plugin_config + + +# Future Thunder Versions.. +""" def user_subsystems(preconditions, terminations, controls): sub_systems = get_boolean_input("Does your plugin need subsystem support: (Enter Y or N)\n") @@ -122,4 +209,10 @@ def user_subsystems(preconditions, terminations, controls): if not control: break controls.append(control) - return sub_systems \ No newline at end of file + return sub_systems + +def user_smart_interface(): + + smart_interface = get_boolean_input("Does your plugin require smart interface") + return smart_interface +""" diff --git a/PluginSkeletonGenerator/templates/.cmake.txt b/PluginSkeletonGenerator/templates/.cmake.txt index f9c7e1c..10f4573 100644 --- a/PluginSkeletonGenerator/templates/.cmake.txt +++ b/PluginSkeletonGenerator/templates/.cmake.txt @@ -28,6 +28,7 @@ set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME}) message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") +{{SET_MODE}} if(BUILD_REFERENCE) ~INDENT_INCREASE~ @@ -61,7 +62,7 @@ target_link_libraries(${MODULE_NAME} target_include_directories(${MODULE_NAME} ~INDENT_INCREASE~ - PUBLIC + PRIVATE $) ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/.plugin_conf_in.txt b/PluginSkeletonGenerator/templates/.plugin_conf_in.txt index efbec70..3102463 100644 --- a/PluginSkeletonGenerator/templates/.plugin_conf_in.txt +++ b/PluginSkeletonGenerator/templates/.plugin_conf_in.txt @@ -1,4 +1,3 @@ startmode = {{PLUGIN_STARTMODE}} - -configuration = JSON() -configuration.add("example,"mystring") \ No newline at end of file +{{CONFIG}} +{{OOP_ROOT}} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/.plugin_header.txt b/PluginSkeletonGenerator/templates/.plugin_header.txt index b23bbc3..f9cac40 100644 --- a/PluginSkeletonGenerator/templates/.plugin_header.txt +++ b/PluginSkeletonGenerator/templates/.plugin_header.txt @@ -19,7 +19,6 @@ #pragma once ~INDENT_RESET~ -{{JSONRPC_INTERFACE_INCLUDES}} {{COMRPC_INTERFACE_INCLUDES}} namespace Thunder { @@ -36,11 +35,14 @@ namespace Plugin { {{PLUGIN_NAME}}() ~INDENT_INCREASE~ - :{{INTERFACE_CONSTRUCTOR}} _example(0) + :{{BASE_CONSTRUCTOR}} + {{INTERFACE_CONSTRUCTOR}} + , _example(0) + {{MEMBER_CONSTRUCTOR}} ~INDENT_DECREASE~ { } - + ~{{PLUGIN_NAME}}() override = default; ~INDENT_DECREASE~ private: @@ -60,8 +62,10 @@ namespace Plugin { {{PLUGIN_METHOD}} BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}) + ~INDENT_INCREASE~ {{INTERFACE_ENTRY}} {{INTERFACE_AGGREGATE}} + ~INDENT_DECREASE~ END_INTERFACE_MAP ~INDENT_DECREASE~ @@ -70,6 +74,9 @@ namespace Plugin { // Include the correct member variables for your plugin: // Note this is only an example, you are responsible for adding the correct members: uint32_t _example; + + PluginHost::IShell* _service; + {{MEMBER_IMPL}} ~INDENT_DECREASE~ }; ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/.plugin_implementation.txt b/PluginSkeletonGenerator/templates/.plugin_implementation.txt index 1c21564..38ef0b4 100644 --- a/PluginSkeletonGenerator/templates/.plugin_implementation.txt +++ b/PluginSkeletonGenerator/templates/.plugin_implementation.txt @@ -26,32 +26,29 @@ namespace Plugin { ~INDENT_INCREASE~ SERVICE_REGISTRATION({{PLUGIN_NAME}}Implementation, 1, 0) - class {{PLUGIN_NAME}}Implementation : public {{OOP_INHERITED_CLASS}} { + class {{PLUGIN_NAME}}Implementation {{OOP_INHERITED_CLASS}} { public: ~INDENT_INCREASE~ {{PLUGIN_NAME}}Implementation(const {{PLUGIN_NAME}}Implementation&) = delete; {{PLUGIN_NAME}}Implementation& operator=(const {{PLUGIN_NAME}}Implementation&) = delete; + {{PLUGIN_NAME}}({{PLUGIN_NAME}}&&) = delete; + {{PLUGIN_NAME}}& operator=({{PLUGIN_NAME}}&&) = delete; {{PLUGIN_NAME}}Implementation() ~INDENT_INCREASE~ - :{{INTERFACE_CONSTRUCTOR}} _test(0) + {{INTERFACE_CONSTRUCTOR}} ~INDENT_DECREASE~ { } ~{{PLUGIN_NAME}}Implementation() override = default; - -~INDENT_DECREASE~ - private: - -~INDENT_INCREASE~ - {{CONFIG_CLASS}} ~INDENT_DECREASE~ - public: ~INDENT_INCREASE~ BEGIN_INTERFACE_MAP({{PLUGIN_NAME}}Implementation) + ~INDENT_INCREASE~ {{INTERFACE_ENTRY}} + ~INDENT_DECREASE~ END_INTERFACE_MAP // Implement methods from the interface @@ -59,8 +56,11 @@ namespace Plugin { ~INDENT_DECREASE~ private: ~INDENT_INCREASE~ - // Add data members, for example: (Core::CriticalSection, std::vector..) + {{CONFIG_CLASS}} + {{NOTIFY_METHOD}} + // Note: test is just an example... uint32_t _test; + {{OOP_MEMBERS}} ~INDENT_DECREASE~ }; ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/.plugin_source.txt b/PluginSkeletonGenerator/templates/.plugin_source.txt index b650922..d5a3c55 100644 --- a/PluginSkeletonGenerator/templates/.plugin_source.txt +++ b/PluginSkeletonGenerator/templates/.plugin_source.txt @@ -18,6 +18,7 @@ */ {{INCLUDE}} +{{JSONRPC_INTERFACE_INCLUDES}} namespace Thunder { namespace Plugin { @@ -29,11 +30,11 @@ namespace Plugin { // Version 1, 0, 0, // Preconditions - {{{PRECONDITIONS}}}, + {}, // Terminations - {{{TERMINATIONS}}}, + {}, // Controls - {{{CONTROLS}}} + {} ~INDENT_DECREASE~ ) ~INDENT_DECREASE~ @@ -47,7 +48,7 @@ const string {{PLUGIN_NAME}}::Initialize(PluginHost::IShell* service) { ~INDENT_DECREASE~ } -void {{PLUGIN_NAME}}::Deinitialize(PluginHost::IShell* service{{VARIABLE_NOT_USED}}) { +void {{PLUGIN_NAME}}::Deinitialize({{VARIABLE_NOT_USED}}PluginHost::IShell* service) { ~INDENT_INCREASE~ {{DEINITIALIZE_IMPLEMENTATION}} ~INDENT_DECREASE~ @@ -58,6 +59,14 @@ string {{PLUGIN_NAME}}::Information() { return string() ~INDENT_DECREASE~ } + +void {{PLUGIN_NAME}}::{{PLUGIN_NAME}}Method() { + +} + +{{PLUGIN_METHOD_IMPL}} +{{INHERITED_METHOD_IMPL}} + ~INDENT_DECREASE~ } // Plugin } // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt index dff337a..fc0859c 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt @@ -1,21 +1,9 @@ -if (_service != nullptr) { -~INDENT_INCREASE~ + ASSERT(_service == service); -service->Unregister(&_connectionNotification); +service->Unregister(&_notification); -if (_implementation != nullptr) { -~INDENT_INCREASE~ - // Example if your interface has inotification implemented - {{JSONRPC_UNREGISTER}} - //_implementation->Unregister(&_volumeNotification); - - RPC::IRemoteConnection* connection(_service->RemoteConnection(_connectionId)); - VARIABLE_IS_NOT_USED uint32_t result = _implementation->Release(); - _implementation = nullptr; - // It should have been the last reference we are releasing, - // so it should endup in a DESTRUCTION_SUCCEEDED, if not we - // are leaking... +{{DEINITIALIZE}} ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); // The process can disappear in the meantime... if (connection != nullptr) { @@ -29,6 +17,4 @@ if (_implementation != nullptr) { } _service->Release(); _service = nullptr; -_connectionId = 0; -~INDENT_DECREASE~ -} \ No newline at end of file +_connectionId = 0; \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt index 694a39e..8d472da 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_ip.txt @@ -1,9 +1,6 @@ string message; ASSERT(service != nullptr); - -Config config; -config.FromString(service->ConfigLine()); - -{{JSONRPC_REGISTER}} +{{CONFIGURE_IP}} +{{REGISTER}} return (message); \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt index 168a8c1..307910a 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt @@ -7,19 +7,16 @@ ASSERT(_connectionId == 0); _service = service; _service->AddRef(); -_service->Register(&_connectionNotification); +_service->Register(&_notification); // Example -_implementation = service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); -if (_implementation == nullptr) { +_impl{{COMRPC}} = service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); +if (_impl{{COMRPC}} == nullptr) { ~INDENT_INCREASE~ - message = _T("Couldn't create instance"); + message = _T("Couldn't create instance of impl{{COMRPC}}"); ~INDENT_DECREASE~ } else { -~INDENT_INCREASE~ - // Add registration e.g: - //_implementation->Register(&_volumeNotification); - {{JSONRPC_REGISTER}} + {{NESTED_QUERY}} ~INDENT_DECREASE~ } diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.nested_initialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.nested_initialize_oop.txt new file mode 100644 index 0000000..5686044 --- /dev/null +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.nested_initialize_oop.txt @@ -0,0 +1,15 @@ +~INDENT_INCREASE~ +Exchange::IConfiguration* config{{COMRPC}}= _impl{self.comrpc_interfaces[0]}->QueryInterface(); +ASSERT (config{{COMRPC}}!= nullptr); + +if (config{{COMRPC}} != nullptr) { + ~INDENT_INCREASE~ + if (config{{COMRPC}}>Configure(service) != Core::ERROR_NONE) { + ~INDENT_INCREASE~ + message = _T("{{PLUGIN_NAME}} could not be configured."); + ~INDENT_DECREASE~ + } +~INDENT_DECREASE~ +config{{COMRPC}}->Release(); +} +~INDENT_DECREASE~ \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/json/.json_configuration.txt b/PluginSkeletonGenerator/templates/json/.json_configuration.txt index 1996272..8d8a0d7 100644 --- a/PluginSkeletonGenerator/templates/json/.json_configuration.txt +++ b/PluginSkeletonGenerator/templates/json/.json_configuration.txt @@ -22,4 +22,4 @@ ~INDENT_DECREASE~ } ~INDENT_DECREASE~ -} \ No newline at end of file +}, \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/json/.json_info.txt b/PluginSkeletonGenerator/templates/json/.json_info.txt index 8a66b06..4640930 100644 --- a/PluginSkeletonGenerator/templates/json/.json_info.txt +++ b/PluginSkeletonGenerator/templates/json/.json_info.txt @@ -3,7 +3,7 @@ "title": "{{PLUGIN_NAME}} Plugin", "callsign": "{{PLUGIN_NAME}}", "locator": "libThunder{{PLUGIN_NAME}}.so", - "status": "production", + "status": "development", "description": [ "" ], diff --git a/PluginSkeletonGenerator/templates/json/.plugin_json.txt b/PluginSkeletonGenerator/templates/json/.plugin_json.txt index a0ba934..c19341b 100644 --- a/PluginSkeletonGenerator/templates/json/.plugin_json.txt +++ b/PluginSkeletonGenerator/templates/json/.plugin_json.txt @@ -2,7 +2,7 @@ ~INDENT_INCREASE~ "$schema": "plugin.schema.json", {{JSON_INFO}}, - {{JSON_CONFIGURATION}}, + {{JSON_CONFIGURATION}} {{JSON_INTERFACE}} ~INDENT_DECREASE~ } \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_class/.config_class.txt b/PluginSkeletonGenerator/templates/nested_class/.config_class.txt index f2865f5..cff945f 100644 --- a/PluginSkeletonGenerator/templates/nested_class/.config_class.txt +++ b/PluginSkeletonGenerator/templates/nested_class/.config_class.txt @@ -1,16 +1,15 @@ class Config : public Core::JSON::Container { -private: +public: ~INDENT_INCREASE~ Config(const Config&) = delete; Config& operator=(const Config&) = delete; Config(Config&&) = delete; Config& operator=(Config&&) = delete; -~INDENT_DECREASE~ -public: -~INDENT_INCREASE~ + Config() ~INDENT_INCREASE~ : Core::JSON::Container() + , Example() ~INDENT_DECREASE~ { ~INDENT_INCREASE~ diff --git a/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt b/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt index ebd4892..bc62eee 100644 --- a/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt +++ b/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt @@ -1,22 +1,21 @@ -class ConnectionNotification : public RPC::IRemoteConnection::INotification { +class Notification : {{NOTIFICATION_CLASS}} { public: ~INDENT_INCREASE~ - explicit ConnectionNotification({{PLUGIN_NAME}}* parent) + explicit Notification({{PLUGIN_NAME}}& parent) ~INDENT_INCREASE~ - : _parent(*parent) + : RPC::IRemoteConnection::INotification() + {{NOTIFICATION_CONSTRUCTOR}} + , _parent(parent) ~INDENT_DECREASE~ { -~INDENT_INCREASE~ - ASSERT(parent != nullptr); -~INDENT_DECREASE~ } - ~ConnectionNotification() override = default; - ConnectionNotification() = delete; - ConnectionNotification(const ConnectionNotification&) = delete; - ConnectionNotification& operator=(const ConnectionNotification&) = delete; - ConnectionNotification(ConnectionNotification&&) = delete; - ConnectionNotification& operator=(ConnectionNotification&&) = delete; + ~Notification() override = default; + Notification() = delete; + Notification(const Notification&) = delete; + Notification& operator=(const Notification&) = delete; + Notification(Notification&&) = delete; + Notification& operator=(Notification&&) = delete; void Activated(RPC::IRemoteConnection*) override { @@ -29,8 +28,12 @@ public: ~INDENT_DECREASE~ } - BEGIN_INTERFACE_MAP(ConnectionNotification) + {{NOTIFICATION_FUNCTION}} + BEGIN_INTERFACE_MAP(Notification) +~INDENT_INCREASE~ INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + {{NOTIFICATION_ENTRY}} +~INDENT_DECREASE~ END_INTERFACE_MAP ~INDENT_DECREASE~ private: diff --git a/PluginSkeletonGenerator/templates/nested_methods/.configure.txt b/PluginSkeletonGenerator/templates/nested_methods/.configure.txt new file mode 100644 index 0000000..28a408b --- /dev/null +++ b/PluginSkeletonGenerator/templates/nested_methods/.configure.txt @@ -0,0 +1,11 @@ +uint32_t Configure(PluginHost::IShell* service) override { + ~INDENT_INCREASE~ + if (service) { + ~INDENT_INCREASE~ + Config config; + config.FromString(service->ConfigLine()); + ~INDENT_DECREASE~ + } + return Core::ERROR_NONE; + ~INDENT_DECREASE~ +} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_methods/.notification_register.txt b/PluginSkeletonGenerator/templates/nested_methods/.notification_register.txt new file mode 100644 index 0000000..d36e0fb --- /dev/null +++ b/PluginSkeletonGenerator/templates/nested_methods/.notification_register.txt @@ -0,0 +1,15 @@ +~INDENT_INCREASE~ +ASSERT(notification); + +_adminLock.Lock(); +auto item = std::find(_notifications.begin(), _notifications.end(), notification); +ASSERT(item == _notifications.end()); + +if (item == _notifications.end()) { +~INDENT_INCREASE~ +notification->AddRef(); +_notifications.push_back(notification); +~INDENT_DECREASE~ +} +_adminLock.Unlock(); +~INDENT_DECREASE~ \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_methods/.notification_unregister.txt b/PluginSkeletonGenerator/templates/nested_methods/.notification_unregister.txt new file mode 100644 index 0000000..d1d3da2 --- /dev/null +++ b/PluginSkeletonGenerator/templates/nested_methods/.notification_unregister.txt @@ -0,0 +1,15 @@ +~INDENT_INCREASE~ +ASSERT(notification); + +_adminLock.Lock(); +auto item = std::find(_notifications.begin(), _notifications.end(), notification); +ASSERT(item != _notifications.end()); + +if (item != _notifications.end()) { + ~INDENT_INCREASE~ +_notifications.erase(item); +(*item)->Release(); +~INDENT_DECREASE~ +} +_adminLock.Unlock(); +~INDENT_DECREASE~ \ No newline at end of file diff --git a/PluginSkeletonGenerator/tests/test.py b/PluginSkeletonGenerator/tests/test.py index bb0aa85..8a9558b 100644 --- a/PluginSkeletonGenerator/tests/test.py +++ b/PluginSkeletonGenerator/tests/test.py @@ -149,7 +149,7 @@ def test_no_controls(): 'test_controls' : test_no_controls() }, } - +#generate_files(plugin_name, comrpc_interfaces, jsonrpc_interfaces, out_of_process, jsonrpc, plugin_config, notification_interfaces): class TestSkeletonGenerator(unittest.TestCase): def test(self): for key,value in test_cases.items(): @@ -159,10 +159,8 @@ def test(self): value['test_jsonrpc_interfaces'], value['test_out_of_process'], value['test_jsonrpc_functionality'], - value['test_subsystems'], - value['test_preconditions'], - value['test_terminations'], - value['test_controls'] + True, + value['test_comrpc_interfaces'] ) self.assertEqual(result, True) print(f'Success for case: {value["test_plugin_name"]}') diff --git a/PluginSkeletonGenerator/utils.py b/PluginSkeletonGenerator/utils.py index e779032..e7f5c43 100644 --- a/PluginSkeletonGenerator/utils.py +++ b/PluginSkeletonGenerator/utils.py @@ -1,3 +1,4 @@ +from enum import Enum import os import re @@ -16,11 +17,13 @@ def read_file(template_name): with open(template_name, 'r') as template_file: return template_file.read() except FileNotFoundError as e: - raise(f'Could not load template: {template_name}') from e + raise (f'Could not load template: {template_name}') from e except PermissionError as e: - raise(f'Permissions denied: {template_name}') from e + raise (f'Permissions denied: {template_name}') from e except OSError as e: - raise OSError(f'OS error occurred trying to open: {template_name}, Error details: {e.strerror}') + raise OSError( + f'OS error occurred trying to open: {template_name}, Error details: {e.strerror}') + class Indenter(): def __init__(self) -> None: @@ -37,14 +40,14 @@ def __init__(self) -> None: def create_indent_map(self): return { '.json': ' ' * 2, - '.py' : ' ' * 4, - '.h' : ' ' * 4, - '.cpp' : ' ' * 4 + '.py': ' ' * 4, + '.h': ' ' * 4, + '.cpp': ' ' * 4 } def indent_type(self, path): extension = os.path.splitext(path)[1] - self.indent = self.indent_map.get(extension, ' ' * 4) # Default case: 4 spaces + self.indent = self.indent_map.get(extension, ' ' * 4) # Default case: 4 spaces def process_indent(self, code, path): if not code: @@ -72,4 +75,32 @@ def process_indent(self, code, path): indented_line = self.indent * self.indent_size + newline self.indented_code.append(indented_line) - return '\n'.join(self.indented_code) \ No newline at end of file + return '\n'.join(self.indented_code) + + +class Utils(): + def __init__(self) -> None: + pass + + class Error(Enum): + EXTENSION = 1 + INITIAL = 2 + + # Replaces COMRPC interface to JSONRPC interface + # IHello -> JHello + # Under the assumption, an interface is correctly named as I + @staticmethod + def replace_comrpc_to_jsonrpc(comrpc_interface): + return f'J{comrpc_interface[1:]}' + + @staticmethod + def extract_interface(interface): + extension = interface[-2:] + if extension != ".h": + return False + return interface[:-2] + + # Currently check to see if interface name begins with I + @staticmethod + def check_correct_comrpc(interface): + return True if interface[0] == "I" else False diff --git a/ThunderDevTools/ThunderDevTools.py b/ThunderDevTools/ThunderDevTools.py old mode 100644 new mode 100755 index de6c3d9..17d1c82 --- a/ThunderDevTools/ThunderDevTools.py +++ b/ThunderDevTools/ThunderDevTools.py @@ -15,7 +15,7 @@ def python_distribution(): # add future scripts scripts = { -"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","PluginSkeletonGeneratror.py") +"plugin_skeleton" : os.path.join("PluginSkeletonGenerator","PluginSkeletonGenerator.py") } def script_menu(): From ac9e189ab2041a2be2ec70e920eea63aae527612 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Mon, 21 Oct 2024 00:29:43 -0700 Subject: [PATCH 11/12] fix devtools stdout --- ThunderDevTools/ThunderDevTools.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ThunderDevTools/ThunderDevTools.py b/ThunderDevTools/ThunderDevTools.py index 17d1c82..c9384dc 100755 --- a/ThunderDevTools/ThunderDevTools.py +++ b/ThunderDevTools/ThunderDevTools.py @@ -3,6 +3,7 @@ import os import subprocess import argparse +import sys CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) THUNDER_TOOLS_DIR = os.path.dirname(CURRENT_DIR) @@ -39,7 +40,7 @@ def run_script(script): try: script_path = scripts[script] full_path = os.path.join(THUNDER_TOOLS_DIR, script_path) - subprocess.run([python_distribution(), full_path], check=True, text=True, stderr=subprocess.PIPE) + subprocess.run([python_distribution(), full_path], check=True, text=True, stderr=sys.stderr, stdout=sys.stdout) print("Success") except subprocess.CalledProcessError as e: print(f"Error running the script: {e.stderr}") From ebf9b52e71923b35ff4292773760c7d8eae026d0 Mon Sep 17 00:00:00 2001 From: nxtumUbun Date: Fri, 25 Oct 2024 01:00:16 -0700 Subject: [PATCH 12/12] compile with fake interface --- .../PluginSkeletonGenerator.py | 3 +- PluginSkeletonGenerator/file_data.py | 260 ++++++++++++------ PluginSkeletonGenerator/help.txt | 5 - PluginSkeletonGenerator/menu.py | 6 +- PluginSkeletonGenerator/templates/.cmake.txt | 2 + .../templates/.plugin_conf_in.txt | 2 + .../templates/.plugin_header.txt | 2 +- .../templates/.plugin_implementation.txt | 15 +- .../templates/.plugin_source.txt | 6 +- .../iplugin_methods/.deinitialize_oop.txt | 6 +- .../iplugin_methods/.initialize_oop.txt | 10 +- .../templates/module/.module_header.txt | 1 + .../templates/nested_class/.config_class.txt | 2 +- .../nested_class/.rpc_inotification.txt | 2 +- .../templates/nested_methods/.configure.txt | 1 + PluginSkeletonGenerator/tests/IHello.h | 28 ++ 16 files changed, 241 insertions(+), 110 deletions(-) delete mode 100644 PluginSkeletonGenerator/help.txt create mode 100644 PluginSkeletonGenerator/tests/IHello.h diff --git a/PluginSkeletonGenerator/PluginSkeletonGenerator.py b/PluginSkeletonGenerator/PluginSkeletonGenerator.py index 66e1174..792bd41 100755 --- a/PluginSkeletonGenerator/PluginSkeletonGenerator.py +++ b/PluginSkeletonGenerator/PluginSkeletonGenerator.py @@ -10,7 +10,7 @@ class PluginGenerator: def __init__(self, blueprint_data) -> None: self.blueprint_data = blueprint_data self.directory = self.blueprint_data.plugin_name - os.makedirs(self.blueprint_data.plugin_name, exist_ok=True) + os.makedirs(self.blueprint_data.plugin_name, exist_ok=False) self.indenter = Indenter() def load_template(self, template_name): @@ -55,6 +55,7 @@ def generate_conf_in(self): # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# def main(): + print('[NOTE]: The output from this generator is a skeleton, therefore it uses example methods. Please correct the generated methods accordingly!') menu.menu() # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~# if __name__ == "__main__": diff --git a/PluginSkeletonGenerator/file_data.py b/PluginSkeletonGenerator/file_data.py index ea73af1..66caad3 100644 --- a/PluginSkeletonGenerator/file_data.py +++ b/PluginSkeletonGenerator/file_data.py @@ -56,12 +56,14 @@ def populate_keywords(self): def generate_comrpc_includes(self): includes = [] for comrpc in self.comrpc_interfaces: - if comrpc == 'IConfiguration': + if comrpc == 'IConfiguration' and self.type == HeaderData.HeaderType.HEADER: break - includes.append(f'#include ') - for interface in self.jsonrpc_interfaces: - if 'I' + interface[1:] in self.notification_interfaces: - includes.append(f'#include ') + includes.append(f'#include ') + if self.type == HeaderData.HeaderType.HEADER: + includes.append("#include ") + for interface in self.jsonrpc_interfaces: + if 'I' + interface[1:] in self.notification_interfaces: + includes.append(f'#include ') return '\n'.join(includes) if includes else 'rm\*n' def generate_inherited_classes(self): @@ -83,14 +85,14 @@ def generate_oop_inherited_classes(self): def notification_registers(self, interface): text = [] text.append('\n~INDENT_INCREASE~') - text.append('\nASSERT(notification);') + text.append('\nASSERT(notification != nullptr);') text.append('\n_adminLock.Lock();') - text.append(f'''\nauto item = std::find(_notifications{interface}.begin(), _notifications{interface}.end(), notification); - ASSERT(item == _notifications{interface}.end()); - if (item == _notifications{interface}.end()) {{ + text.append(f'''\nauto item = std::find(_{interface[1:].lower()}Notification.begin(), _{interface[1:].lower()}Notification.end(), notification); + ASSERT(item == _{interface[1:].lower()}Notification.end()); + if (item == _{interface[1:].lower()}Notification.end()) {{ ~INDENT_INCREASE~ notification->AddRef(); - notifications{interface}.push_back(notification); + _{interface[1:].lower()}Notification.push_back(notification); ~INDENT_DECREASE~ }} @@ -101,16 +103,16 @@ def notification_registers(self, interface): def notification_unregisters(self,interface): text = [] text.append(f'''\n~INDENT_INCREASE~ - ASSERT(notification); + ASSERT(notification != nullptr); _adminLock.Lock(); - auto item = std::find(_notifications{interface}.begin(), _notifications{interface}.end(), notification); - ASSERT(item != _notifications{interface}.end()); + auto item = std::find(_{interface[1:].lower()}Notification.begin(), _{interface[1:].lower()}Notification.end(), notification); + ASSERT(item != _{interface[1:].lower()}Notification.end()); - if (item != _notifications{interface}.end()) {{ + if (item != _{interface[1:].lower()}Notification.end()) {{ ~INDENT_INCREASE~ - _notifications{interface}.erase(item); (*item)->Release(); + _{interface[1:].lower()}Notification.erase(item); ~INDENT_DECREASE~ }} _adminLock.Unlock(); @@ -130,21 +132,31 @@ def generate_inherited_methods(self): if (inherited == 'IConfiguration'): continue if self.type == HeaderData.HeaderType.HEADER: - methods.append(f"// {inherited} methods\n" f"void {inherited}Method1() override;\n") + methods.append(f"// {inherited} methods\n" f"uint32_t {inherited}Method1() override;") if inherited in self.notification_interfaces: methods.append(f'void Register(Exchange::{inherited}::INotification* notification) override;') - methods.append(f'void Unregister(Exchange::{inherited}::INotification* notification) override;') + methods.append(f'void Unregister(const Exchange::{inherited}::INotification* notification) override;') + if f'J{inherited[1:]}' in self.jsonrpc_interfaces and self.out_of_process: + methods.append(f'void {inherited}NotificationExample();') else: methods.append(f'// {inherited} methods') - - methods.append(f'void {inherited}Method1() override {{\n\n}}\n') - if inherited in self.notification_interfaces: + if inherited in self.notification_interfaces: + methods.append(f'''uint32_t {inherited}Method1() override {{\n + ~INDENT_INCREASE~ + // This function could be used to call a notify method + Notify{inherited}(); + return Core::ERROR_NONE; + ~INDENT_DECREASE~ + }}\n''') + else: + methods.append(f'uint32_t {inherited}Method1() override {{\n~INDENT_INCREASE~\nreturn Core::ERROR_NONE;\n~INDENT_DECREASE~\n}}\n') + if inherited in self.notification_interfaces and self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION: methods.append(f'void Register(Exchange::{inherited}::INotification* notification) override {{') methods.append(self.notification_registers(inherited)) - methods.append('}') - methods.append(f'void Unregister(Exchange::{inherited}::INotification* notification) override {{') + methods.append('}\n') + methods.append(f'void Unregister(const Exchange::{inherited}::INotification* notification) override {{') methods.append(self.notification_unregisters(inherited)) - methods.append('}') + methods.append('}\n') if self.comrpc_interfaces: if self.comrpc_interfaces[-1] == "IConfiguration": @@ -158,7 +170,7 @@ def generate_plugin_methods(self): method = [] if self.type == HeaderData.HeaderType.HEADER: method = [f'void {self.plugin_name}Method();'] - if self.notification_interfaces: + if self.out_of_process: method.append(f'void Deactivated(RPC::IRemoteConnection* connection);') return '\n'.join(method) @@ -180,7 +192,7 @@ def generate_interface_aggregate(self): for comrpc in self.comrpc_interfaces: if comrpc == "IConfiguration": break - aggregates.append(f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc})') + aggregates.append(f'INTERFACE_AGGREGATE(Exchange::{comrpc}, _impl{comrpc[1:]})') return ('\n').join(aggregates) if aggregates else 'rm\*n' def generate_module_plugin_name(self): @@ -195,15 +207,15 @@ def generate_base_constructor(self): def generate_interface_constructor(self): constructor = [] if not self.comrpc_interfaces: - return '' + return 'rm\*n' if self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION: constructor = [f": Exchange::{self.comrpc_interfaces[0]}()"] + [f", Exchange::{comrpc}()" for comrpc in self.comrpc_interfaces[1:]] - constructor.append(', test(0)') + constructor.append(', _test(0)') if self.notification_interfaces: constructor.append(', _adminLock()') for interface in self.notification_interfaces: - constructor.append(f', _notifications{interface}()') + constructor.append(f', _{interface[1:].lower()}Notification()') if (not self.out_of_process and self.type == HeaderData.HeaderType.HEADER): if self.comrpc_interfaces: @@ -216,22 +228,35 @@ def generate_interface_constructor(self): def generate_member_impl(self): members = [] + if self.out_of_process: + members.append("PluginHost::IShell* _service;") + members.append("uint32_t _connectionId;") if self.out_of_process: for comrpc in self.comrpc_interfaces: if comrpc == 'IConfiguration': break - members.append(f"Exchange::{comrpc}* _impl{comrpc};") - if self.jsonrpc: - members.append("Core::SinkType _notification;") + members.append(f"Exchange::{comrpc}* _impl{comrpc[1:]};") + members.append(f"Core::SinkType _notification;") + if self.notification_interfaces and not self.out_of_process: + members.append(f"mutable Core::CriticalSection _adminLock;") + for comrpc in self.notification_interfaces: + members.append(f'{comrpc[1:]}NotificationVector _{comrpc[1:].lower()}Notification;') return "\n".join(members) if members else 'rm\*n' def generate_member_constructor(self): members = [] if self.out_of_process: + members.append(f", _service(nullptr)") + members.append(f", _connectionId(0)") for comrpc in self.comrpc_interfaces: if comrpc == "IConfiguration": break - members.append(f", _impl{comrpc}(nullptr)") + members.append(f", _impl{comrpc[1:]}(nullptr)") + members.append(f", _notification(*this)") + if self.notification_interfaces and not self.out_of_process: + members.append(f", _adminLock()") + for comrpc in self.notification_interfaces: + members.append(f", _{comrpc[1:].lower()}Notification()") return "\n".join(members) if members else 'rm\*n' def generate_notification_class(self): @@ -258,7 +283,7 @@ def generate_notification_function(self): methods = [] for inherited in self.notification_interfaces: if Utils.replace_comrpc_to_jsonrpc(inherited) in self.jsonrpc_interfaces: - methods.append(f'''void {inherited}Notification() override {{\n~INDENT_INCREASE~\nExchange::J{inherited[1:]}::Event::{inherited}Notification();\n~INDENT_DECREASE~\n}}\n''') + methods.append(f'''void {inherited}Notification() override {{\n~INDENT_INCREASE~\nExchange::J{inherited[1:]}::Event::{inherited}Notification(_parent);\n~INDENT_DECREASE~\n}}\n''') else: methods.append(f'void {inherited}Notification() override {{\n\n}}') return ("\n").join(methods) if methods else 'rm\*n' @@ -266,29 +291,37 @@ def generate_notification_function(self): def generate_oop_members(self): members = [] if self.notification_interfaces: - members.append('Core::CriticalSection _adminLock;') + members.append('mutable Core::CriticalSection _adminLock;') for interface in self.notification_interfaces: - members.append(f'std::vector _notifications{interface};') + members.append(f'{interface[1:]}NotificationVector _{interface[1:].lower()}Notification;') return '\n'.join(members) if members else 'rm\*n' def generate_notify_method(self): methods = [] - - for interface in self.notification_interfaces: - methods.append(f'void Notify{interface}() override {{') - methods.append('\n~INDENT_INCREASE~') - methods.append('\n_adminLock.Lock();') - methods.append(f'''\nfor (auto* notification : _notifications{interface}) {{ - ~INDENT_INCREASE~ - notification->{interface}Notification(); - ~INDENT_DECREASE~ - }} - _adminLock.Unlock(); - ~INDENT_DECREASE~ - }}\n''') + if self.out_of_process and self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION or not self.out_of_process and HeaderData.HeaderType.HEADER: + for interface in self.notification_interfaces: + methods.append(f'void Notify{interface}() const {{') + methods.append('\n~INDENT_INCREASE~') + methods.append('\n_adminLock.Lock();') + methods.append(f'''\nfor (auto* notification : _{interface[1:].lower()}Notification) {{ + ~INDENT_INCREASE~ + notification->{interface}Notification(); + ~INDENT_DECREASE~ + }} + _adminLock.Unlock(); + ~INDENT_DECREASE~ + }}\n''') return ''.join(methods) if methods else 'rm\*n' + def generate_using_container(self): + usings = [] + if (self.out_of_process and self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION) or \ + (not self.out_of_process and self.type == HeaderData.HeaderType.HEADER): + for comrpc in self.notification_interfaces: + usings.append(f'using {comrpc[1:]}NotificationVector = std::vector;') + return '\n'.join(usings) if usings else 'rm\*n' + def generate_keyword_map(self): return { "{{COMRPC_INTERFACE_INCLUDES}}": self.generate_comrpc_includes(), @@ -308,7 +341,8 @@ def generate_keyword_map(self): "{{NOTIFICATION_ENTRY}}" : self.generate_notification_entry(), "{{NOTIFICATION_FUNCTION}}" : self.generate_notification_function(), "{{OOP_MEMBERS}}" : self.generate_oop_members(), - "{{NOTIFY_METHOD}}" : self.generate_notify_method() + "{{NOTIFY_METHOD}}" : self.generate_notify_method(), + "{{USING_CONTAINER}}" : self.generate_using_container() } def generate_nested_map(self): @@ -318,21 +352,23 @@ def generate_nested_map(self): } def generate_jsonrpc_event(self): - if self.jsonrpc or self.notification_interfaces: + if (self.jsonrpc or self.notification_interfaces) and self.out_of_process: template_name = global_variables.RPC_NOTIFICATION_CLASS_PATH template = FileUtils.read_file(template_name) code = FileUtils.replace_keywords(template, self.keywords) return code def generate_config(self): + code = [] if self.plugin_config: + if self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION: + code.append('~INDENT_DECREASE~\nprivate:\n~INDENT_INCREASE~\n') + print("Hello)") if (not self.out_of_process) or (self.type == HeaderData.HeaderType.HEADER_IMPLEMENTATION): template_name = global_variables.CONFIG_CLASS_PATH template = FileUtils.read_file(template_name) - code = FileUtils.replace_keywords(template, self.keywords) - return code - return "rm\*n" - + code.append(f'{FileUtils.replace_keywords(template, self.keywords)}') + return ''.join(code) if code else 'rm\*n' class SourceData(FileData): def __init__( @@ -443,14 +479,39 @@ def generate_controls(self): """ def generate_plugin_method_impl(self): - if self.out_of_process: - method = [f"void {self.plugin_name}::Deactivated(RPC::IRemoteConnection* connection) {{\n\n}}\n"] + if self.out_of_process and self.notification_interfaces: + method = [f'''\nvoid {self.plugin_name}::Deactivated(RPC::IRemoteConnection* connection) {{ + ~INDENT_INCREASE~ + if (connection->Id() == _connectionId) {{ + ~INDENT_INCREASE~ + ASSERT(_service != nullptr); + Core::IWorkerPool::Instance().Submit(PluginHost::IShell::Job::Create(_service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); + ~INDENT_DECREASE~ + }} + ~INDENT_DECREASE~ + }}\n'''] return "".join(method) return "rm\*n" def generate_inherited_method_impl(self): + methods = [] if not self.out_of_process: - methods = [f"void {self.plugin_name}::{inherited}Method1() {{\n\n}}\n" for inherited in self.comrpc_interfaces] + for inherited in self.comrpc_interfaces: + methods.append(f'uint32_t {self.plugin_name}::{inherited}Method1() {{') + methods.append(f'~INDENT_INCREASE~') + if Utils.replace_comrpc_to_jsonrpc(inherited) in self.jsonrpc_interfaces: + methods.append(f'''// Note this an example of a notification method that can call the JSONRPC interface equivalent. + Exchange::{Utils.replace_comrpc_to_jsonrpc(inherited)}::Event::{inherited}Notification(*this);''') + methods.append(f'return Core::ERROR_NONE;') + methods.append(f'~INDENT_DECREASE~') + methods.append(f'}}') + if inherited in self.notification_interfaces: + methods.append(f'void {self.plugin_name}::Register(Exchange::{inherited}::INotification* notification) {{') + methods.append(HeaderData.notification_registers(None, inherited)) + methods.append('}\n') + methods.append(f'void {self.plugin_name}::Unregister(const Exchange::{inherited}::INotification* notification) {{') + methods.append(HeaderData.notification_unregisters(None, inherited)) + methods.append('}\n') return ("\n").join(methods) return 'rm\*n' @@ -466,11 +527,11 @@ def generate_nested_query(self): break nested_query.append("\nrm\*n \n~INDENT_INCREASE~\n") if self.comrpc_interfaces[iteration] in self.notification_interfaces: - nested_query.append(f"_impl{self.comrpc_interfaces[iteration]}->Register(¬ification);\n") + nested_query.append(f"_impl{self.comrpc_interfaces[iteration][1:]}->Register(¬ification);\n") if any(Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration]) in notif for notif in self.jsonrpc_interfaces): - nested_query.append(f'Exchange::{Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration])}::Register(*this, impl{self.comrpc_interfaces[iteration]});\n') - nested_query.append(f"_impl{comrpc} = _impl{comrpc}->QueryInterface();") - nested_query.append(f'''\nif (_impl{comrpc} == nullptr) {{ + nested_query.append(f'Exchange::{Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration])}::Register(*this, _impl{self.comrpc_interfaces[iteration][1:]});\n') + nested_query.append(f"_impl{comrpc[1:]} = _impl{comrpc[0][1:]}->QueryInterface();") + nested_query.append(f'''\nif (_impl{comrpc[1:]} == nullptr) {{ ~INDENT_INCREASE~ message = _T("Couldn't create instance of _impl{comrpc}") ~INDENT_DECREASE~ @@ -488,21 +549,22 @@ def generate_nested_query(self): def generate_nested_initialize(self, iteration): text = [] - rootCOMRPC = self.comrpc_interfaces[0] if self.comrpc_interfaces else 'IPlugin' + rootCOMRPC = self.comrpc_interfaces[0][1:] if self.comrpc_interfaces else 'IPlugin' if self.comrpc_interfaces: text.append("\n~INDENT_INCREASE~\n") - text.append(f'_impl{self.comrpc_interfaces[iteration]}->Register(&_notification);\n') + if self.notification_interfaces: + text.append(f'_impl{self.comrpc_interfaces[iteration][1:]}->Register(&_notification);\n') if self.jsonrpc_interfaces: if self.jsonrpc_interfaces[-1] == Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[iteration]): - text.append(f'Exchange::{self.jsonrpc_interfaces[-1]}::Register(*this, impl{self.comrpc_interfaces[iteration]});\n') + text.append(f'Exchange::{self.jsonrpc_interfaces[-1]}::Register(*this, _impl{self.comrpc_interfaces[iteration][1:]});\n') if self.plugin_config: #text.append("\n~INDENT_INCREASE~\n") text.append(f'''\nExchange::IConfiguration* configuration = _impl{rootCOMRPC}->QueryInterface(); ASSERT(configuration != nullptr); if (configuration != nullptr) {{ ~INDENT_INCREASE~ - if (configuration->configure(service) != Core::ERROR_NONE) {{ + if (configuration->Configure(service) != Core::ERROR_NONE) {{ ~INDENT_INCREASE~ message = _T("{self.plugin_name} could not be configured."); ~INDENT_DECREASE~ @@ -514,40 +576,53 @@ def generate_nested_initialize(self, iteration): return ''.join(text) if text else 'rm\*n' def generate_configure_implementation(self): - return 'Config config;\nconfig.FromString(service->ConfigLine());' if self.plugin_config else 'rm\*n' + return 'Config config;\nconfig.FromString(service->ConfigLine());\nTRACE(Trace::Information, (_T("This is just an example: [%s])"), config.Example));' if self.plugin_config else 'rm\*n' def generate_nested_deinitialize(self): text = [] if not self.comrpc_interfaces: return '' - text.append(f'if (_impl{self.comrpc_interfaces[0]} != nullptr) {{') + text.append(f'if (_impl{self.comrpc_interfaces[0][1:]} != nullptr) {{') text.append(f'\n~INDENT_INCREASE~') if self.notification_interfaces: if self.notification_interfaces[0] == self.comrpc_interfaces[0]: - text.append(f'\n_impl{self.comrpc_interfaces[0]}->Unregister(&_notification);') + text.append(f'\n_impl{self.comrpc_interfaces[0][1:]}->Unregister(&_notification);') if Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[0]) in self.jsonrpc_interfaces: text.append(f'\nExchange::{Utils.replace_comrpc_to_jsonrpc(self.comrpc_interfaces[0])}::Unregister(*this);') for comrpc in self.comrpc_interfaces[1:]: if comrpc == 'IConfiguration': break - text.append(f'''\nif (_impl{comrpc} != nullptr) {{ - \n~INDENT_INCREASE~ - _impl{comrpc}->Release();''') + text.append(f'''\nif (_impl{comrpc[1:]} != nullptr) {{ + \n~INDENT_INCREASE~\n''') if Utils.replace_comrpc_to_jsonrpc(comrpc) in self.jsonrpc_interfaces: text.append(f'\nExchange::{Utils.replace_comrpc_to_jsonrpc(comrpc)}::Unregister(*this);') if comrpc in self.notification_interfaces: - text.append(f'\n_impl{comrpc}->Unregister(&_notification);') - text.append(f'\n_impl{comrpc} = nullptr;') + text.append(f'\n_impl{comrpc[1:]}->Unregister(&_notification);') + text.append(f"\n_impl{comrpc[1:]}->Release();") + text.append(f'\n_impl{comrpc[1:]} = nullptr;') text.append('\n~INDENT_DECREASE~') text.append('\n}') text.append(f'''\nRPC::IRemoteConnection* connection(service->RemoteConnection(_connectionId)); - \nVARIABLE_IS_NOT_USED uint32_t result = _impl{self.comrpc_interfaces[0]}->Release(); - \n_impl{self.comrpc_interfaces[0]} = nullptr;''') + \nVARIABLE_IS_NOT_USED uint32_t result = _impl{self.comrpc_interfaces[0][1:]}->Release(); + \n_impl{self.comrpc_interfaces[0][1:]} = nullptr;''') return ''.join(text) - + def generate_assert_implementation(self): + asserts = [] + for comrpc in self.comrpc_interfaces: + if comrpc == 'IConfiguration': + continue + asserts.append(f'ASSERT(_impl{comrpc[1:]} == nullptr);') + return '\n'.join(asserts) + + def generate_register_notification(self): + return "_service->Register(&_notification);" + + def generate_unregister_notification(self): + return "_service->Unregister(&_notification);" + def generate_keyword_map(self): return { "{{INCLUDE}}": self.generate_include_statements(), @@ -560,6 +635,7 @@ def generate_keyword_map(self): "{{REGISTER}}": self.generate_jsonrpc_register(), "{{JSONRPC_UNREGISTER}}": self.generate_jsonrpc_unregister(), "{{COMRPC}}": f'{self.comrpc_interfaces[0] if self.comrpc_interfaces else "Exchange::IPlugin"}', + "{{COMRPC[1:]}}" : f'{self.comrpc_interfaces[0][1:] if self.comrpc_interfaces else "Exchange::IPlugin"}', "{{JSONRPC_INTERFACE_INCLUDES}}": self.generate_jsonrpc_includes(), "{{PLUGIN_METHOD_IMPL}}": self.generate_plugin_method_impl(), "{{INHERITED_METHOD_IMPL}}": self.generate_inherited_method_impl(), @@ -567,6 +643,9 @@ def generate_keyword_map(self): "{{NESTED_QUERY}}" : self.generate_nested_query(), "{{CONFIGURE_IP}}" : self.generate_configure_implementation(), "{{DEINITIALIZE}}" : self.generate_nested_deinitialize(), + "{{ASSERT_IMPL}}" : self.generate_assert_implementation(), + "{{REGISTER_NOTIFICATION}}" : self.generate_register_notification(), + "{{UNREGISTER_NOTIFICATION}}" : self.generate_unregister_notification() } def generate_nested_map(self): @@ -608,11 +687,18 @@ def generate_set_mode(self): if self.out_of_process: s = (f'set(PLUGIN_{self.plugin_name.upper()}_MODE "Local" CACHE STRING "Controls if the plugin should run in its own process, in process or remote.")') return s if s else 'rm\*n' + + def generate_set_config(self): + s = '' + if self.plugin_config: + s = (f'set(PLUGIN_{self.plugin_name.upper()}_EXAMPLE "Example Text" CACHE STRING "Example String")') + return s if s else 'rm\*n' def generate_keyword_map(self): return { "{{SOURCE_FILES}}": self.find_source_files(), - '{{SET_MODE}}' : self.generate_set_mode() + '{{SET_MODE}}' : self.generate_set_mode(), + "{{SET_CONFIG}}" : self.generate_set_config() } def find_source_files(self): @@ -650,7 +736,12 @@ def populate_keywords(self): self.keywords.update(self.generate_nested_map()) def generate_cppref(self): - return (",\n".join(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"' for comrpc in self.comrpc_interfaces) if self.comrpc_interfaces else "rm\*n") + cppref = [] + for comrpc in self.comrpc_interfaces: + if comrpc == 'IConfiguration': + break + cppref.append(f'"$cppref": "{{cppinterfacedir}}/{comrpc}.h"') + return ",\n".join(cppref) if cppref else 'rm\*n' def generate_json_info(self): template_name = global_variables.JSON_INFO @@ -712,15 +803,18 @@ def populate_keywords(self): # self.keywords.update(self.generate_nested_map()) def generate_config(self): + configuration = [] + configuration.append("configuration = JSON()") if self.plugin_config: - return f'configuration = JSON() \nconfiguration.add("example,"mystring")' - return 'rm\*n' - + configuration.append(f'configuration.add("example", "@PLUGIN_{self.plugin_name.upper()}_EXAMPLE@")') + return '\n'.join(configuration) + def generate_root(self): root = [] if self.out_of_process: - root.append(f'root = JSON() \n root.add("mode", "@PLUGIN_{self.plugin_name.upper()}_MODE@)') - return ''.join(root) if root else 'rm\*n' + root.append(f'root = JSON() \n root.add("mode", "@PLUGIN_{self.plugin_name.upper()}_MODE@")') + root.append(f'configuration.add("root", root)') + return '\n'.join(root) if root else 'rm\*n' def generate_keyword_map(self): return { diff --git a/PluginSkeletonGenerator/help.txt b/PluginSkeletonGenerator/help.txt deleted file mode 100644 index f535040..0000000 --- a/PluginSkeletonGenerator/help.txt +++ /dev/null @@ -1,5 +0,0 @@ -To run this tool: -./PluginSkeletonGenerator.py or python3 PluginSkeletonGenerator.py - -Answer the questions accordingly. -To see examples of what the skelton is capable of, see the examples folder. \ No newline at end of file diff --git a/PluginSkeletonGenerator/menu.py b/PluginSkeletonGenerator/menu.py index 6607a04..8ad5920 100644 --- a/PluginSkeletonGenerator/menu.py +++ b/PluginSkeletonGenerator/menu.py @@ -46,6 +46,8 @@ def display_settings( print(f"JSONRPC Functionality: {jsonrpc}") print(f"JSONRPC Interfaces: {jsonrpc_interface if jsonrpc else 'N/A'} ") print(f"Out Of Process: {out_of_process}") + print(f"Plugin specific configuration: {plugin_config}") + """ print(f"Subsystem Support: {subsystems}") print(f"Subsystem Preconditions: {preconditions if subsystems else 'N/A'} ") @@ -135,7 +137,7 @@ def user_comrpc(out_of_process, comrpc_interfaces, jsonrpc_interfaces, notificat correctName = correctExtension # CorrectName at this point will always return the correct interface name without the '.h' while True: - comrpc_confirm = input(f"The name of the interface in {tempName} is (enter to confirm or type the correct interface name) {correctName}: ") + comrpc_confirm = input(f"The name of the interface in {tempName} is {correctName} (enter to confirm or type the correct interface name): ") if comrpc_confirm: correctInitial = Utils.check_correct_comrpc(comrpc_confirm) if not correctInitial: @@ -167,7 +169,7 @@ def user_comrpc(out_of_process, comrpc_interfaces, jsonrpc_interfaces, notificat def user_jsonrpc(comrpc_interface, jsonrpc_interfaces): - json_tag = get_boolean_input("Does your plugin require JSON-RPC functionality (@JSON tag): (Enter Y or N)\n") + json_tag = get_boolean_input("Does your plugin require JSON-RPC functionality (@json tag): (Enter Y or N)\n") if json_tag: jsonrpc_interface = Utils.replace_comrpc_to_jsonrpc(comrpc_interface) jsonrpc_interfaces.append(jsonrpc_interface) diff --git a/PluginSkeletonGenerator/templates/.cmake.txt b/PluginSkeletonGenerator/templates/.cmake.txt index 10f4573..eeb7c89 100644 --- a/PluginSkeletonGenerator/templates/.cmake.txt +++ b/PluginSkeletonGenerator/templates/.cmake.txt @@ -29,6 +29,7 @@ message("Setup ${MODULE_NAME} v${PROJECT_VERSION}") set(PLUGIN_{{PLUGIN_NAME_CAPS}}_STARTMODE "Activated" CACHE STRING "Automatically start {{PLUGIN_NAME}} plugin") {{SET_MODE}} +{{SET_CONFIG}} if(BUILD_REFERENCE) ~INDENT_INCREASE~ @@ -43,6 +44,7 @@ find_package(CompileSettingsDebug CONFIG REQUIRED) add_library(${MODULE_NAME} SHARED ~INDENT_INCREASE~ {{SOURCE_FILES}} + Module.cpp ~INDENT_DECREASE~ ) diff --git a/PluginSkeletonGenerator/templates/.plugin_conf_in.txt b/PluginSkeletonGenerator/templates/.plugin_conf_in.txt index 3102463..f8f1012 100644 --- a/PluginSkeletonGenerator/templates/.plugin_conf_in.txt +++ b/PluginSkeletonGenerator/templates/.plugin_conf_in.txt @@ -1,3 +1,5 @@ startmode = {{PLUGIN_STARTMODE}} + {{CONFIG}} + {{OOP_ROOT}} \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/.plugin_header.txt b/PluginSkeletonGenerator/templates/.plugin_header.txt index f9cac40..0fa0cfa 100644 --- a/PluginSkeletonGenerator/templates/.plugin_header.txt +++ b/PluginSkeletonGenerator/templates/.plugin_header.txt @@ -71,11 +71,11 @@ namespace Plugin { ~INDENT_DECREASE~ private: ~INDENT_INCREASE~ + {{USING_CONTAINER}} // Include the correct member variables for your plugin: // Note this is only an example, you are responsible for adding the correct members: uint32_t _example; - PluginHost::IShell* _service; {{MEMBER_IMPL}} ~INDENT_DECREASE~ }; diff --git a/PluginSkeletonGenerator/templates/.plugin_implementation.txt b/PluginSkeletonGenerator/templates/.plugin_implementation.txt index 38ef0b4..cc7c5b4 100644 --- a/PluginSkeletonGenerator/templates/.plugin_implementation.txt +++ b/PluginSkeletonGenerator/templates/.plugin_implementation.txt @@ -17,22 +17,20 @@ * limitations under the License. */ -#pragma once - +#include "Module.h" {{COMRPC_INTERFACE_INCLUDES}} namespace Thunder { namespace Plugin { ~INDENT_INCREASE~ - SERVICE_REGISTRATION({{PLUGIN_NAME}}Implementation, 1, 0) class {{PLUGIN_NAME}}Implementation {{OOP_INHERITED_CLASS}} { public: ~INDENT_INCREASE~ {{PLUGIN_NAME}}Implementation(const {{PLUGIN_NAME}}Implementation&) = delete; {{PLUGIN_NAME}}Implementation& operator=(const {{PLUGIN_NAME}}Implementation&) = delete; - {{PLUGIN_NAME}}({{PLUGIN_NAME}}&&) = delete; - {{PLUGIN_NAME}}& operator=({{PLUGIN_NAME}}&&) = delete; + {{PLUGIN_NAME}}Implementation({{PLUGIN_NAME}}Implementation&&) = delete; + {{PLUGIN_NAME}}Implementation& operator=({{PLUGIN_NAME}}Implementation&&) = delete; {{PLUGIN_NAME}}Implementation() ~INDENT_INCREASE~ @@ -41,6 +39,8 @@ namespace Plugin { { } ~{{PLUGIN_NAME}}Implementation() override = default; + + {{CONFIG_CLASS}} ~INDENT_DECREASE~ public: ~INDENT_INCREASE~ @@ -56,13 +56,16 @@ namespace Plugin { ~INDENT_DECREASE~ private: ~INDENT_INCREASE~ - {{CONFIG_CLASS}} +{{USING_CONTAINER}} + {{NOTIFY_METHOD}} // Note: test is just an example... uint32_t _test; {{OOP_MEMBERS}} ~INDENT_DECREASE~ }; + + SERVICE_REGISTRATION({{PLUGIN_NAME}}Implementation, 1, 0) ~INDENT_DECREASE~ } // Plugin } // Thunder \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/.plugin_source.txt b/PluginSkeletonGenerator/templates/.plugin_source.txt index d5a3c55..bce04cb 100644 --- a/PluginSkeletonGenerator/templates/.plugin_source.txt +++ b/PluginSkeletonGenerator/templates/.plugin_source.txt @@ -36,7 +36,7 @@ namespace Plugin { // Controls {} ~INDENT_DECREASE~ - ) + ); ~INDENT_DECREASE~ } @@ -54,9 +54,9 @@ void {{PLUGIN_NAME}}::Deinitialize({{VARIABLE_NOT_USED}}PluginHost::IShell* serv ~INDENT_DECREASE~ } -string {{PLUGIN_NAME}}::Information() { +string {{PLUGIN_NAME}}::Information() const { ~INDENT_INCREASE~ - return string() + return string(); ~INDENT_DECREASE~ } diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt index fc0859c..b4ce8e9 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.deinitialize_oop.txt @@ -1,14 +1,16 @@ ASSERT(_service == service); -service->Unregister(&_notification); +{{UNREGISTER_NOTIFICATION}} {{DEINITIALIZE}} + ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); + // The process can disappear in the meantime... if (connection != nullptr) { ~INDENT_INCREASE~ - // But if it did not dissapear in the meantime, forcefully terminate it. Shoot to kill + // But if it did not disappear in the meantime, forcefully terminate it. Shoot to kill connection->Terminate(); connection->Release(); ~INDENT_DECREASE~ diff --git a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt index 307910a..de7d95a 100644 --- a/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt +++ b/PluginSkeletonGenerator/templates/iplugin_methods/.initialize_oop.txt @@ -2,18 +2,18 @@ string message; ASSERT(_service == nullptr); ASSERT(service != nullptr); -ASSERT(_implementation == nullptr); +{{ASSERT_IMPL}} ASSERT(_connectionId == 0); _service = service; _service->AddRef(); -_service->Register(&_notification); +{{REGISTER_NOTIFICATION}} // Example -_impl{{COMRPC}} = service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); -if (_impl{{COMRPC}} == nullptr) { +_impl{{COMRPC[1:]}} = service->Root(_connectionId, 2000, _T("{{PLUGIN_NAME}}Implementation")); +if (_impl{{COMRPC[1:]}} == nullptr) { ~INDENT_INCREASE~ - message = _T("Couldn't create instance of impl{{COMRPC}}"); + message = _T("Couldn't create instance of impl{{COMRPC[1:]}}"); ~INDENT_DECREASE~ } else { {{NESTED_QUERY}} diff --git a/PluginSkeletonGenerator/templates/module/.module_header.txt b/PluginSkeletonGenerator/templates/module/.module_header.txt index 26f37f0..fffe31c 100644 --- a/PluginSkeletonGenerator/templates/module/.module_header.txt +++ b/PluginSkeletonGenerator/templates/module/.module_header.txt @@ -25,6 +25,7 @@ #include #include +#include #undef EXTERNAL #define EXTERNAL \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_class/.config_class.txt b/PluginSkeletonGenerator/templates/nested_class/.config_class.txt index cff945f..a13dd47 100644 --- a/PluginSkeletonGenerator/templates/nested_class/.config_class.txt +++ b/PluginSkeletonGenerator/templates/nested_class/.config_class.txt @@ -22,4 +22,4 @@ public: ~INDENT_INCREASE~ Core::JSON::String Example; ~INDENT_DECREASE~ -} \ No newline at end of file +}; \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt b/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt index bc62eee..8363553 100644 --- a/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt +++ b/PluginSkeletonGenerator/templates/nested_class/.rpc_inotification.txt @@ -40,4 +40,4 @@ private: ~INDENT_INCREASE~ {{PLUGIN_NAME}}& _parent; ~INDENT_DECREASE~ -} \ No newline at end of file +}; \ No newline at end of file diff --git a/PluginSkeletonGenerator/templates/nested_methods/.configure.txt b/PluginSkeletonGenerator/templates/nested_methods/.configure.txt index 28a408b..b478cc3 100644 --- a/PluginSkeletonGenerator/templates/nested_methods/.configure.txt +++ b/PluginSkeletonGenerator/templates/nested_methods/.configure.txt @@ -4,6 +4,7 @@ uint32_t Configure(PluginHost::IShell* service) override { ~INDENT_INCREASE~ Config config; config.FromString(service->ConfigLine()); + TRACE(Trace::Information, (_T("This is just an example: [%s]\n)"), config.Example)); ~INDENT_DECREASE~ } return Core::ERROR_NONE; diff --git a/PluginSkeletonGenerator/tests/IHello.h b/PluginSkeletonGenerator/tests/IHello.h new file mode 100644 index 0000000..fdcfdb6 --- /dev/null +++ b/PluginSkeletonGenerator/tests/IHello.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Module.h" + +namespace Thunder { +namespace Exchange { + + // @json 1.0.0 @uncompliant:extended + struct EXTERNAL IHello: virtual public Core::IUnknown { + enum { ID = ID_VOLUMECONTROL }; + + // @event @uncompliant:extended // NOTE: extended format is deprecated!! Do not just copy this line! + struct EXTERNAL INotification : virtual public Core::IUnknown { + enum { ID = ID_VOLUMECONTROL_NOTIFICATION }; + + ~INotification() override = default; + virtual void IHelloNotification() {}; + }; + + ~IHello() override = default; + + virtual void Register(IHello::INotification* sink) {}; + virtual void Unregister(const IHello::INotification* sink) {}; + + virtual uint32_t IHelloMethod1() = 0; + }; +} +}