Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin skeleton generator #117

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
171 changes: 171 additions & 0 deletions PluginSkeletonGenerator/PluginSkeletonGenerator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
#!/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
VeithMetro marked this conversation as resolved.
Show resolved Hide resolved
- 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 global_variables

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)
self.indenter = Indenter()

def load_template(self, template_name):
return FileUtils.read_file(template_name)
nxtum marked this conversation as resolved.
Show resolved Hide resolved

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, output_path)
header_path = os.path.join(self.directory, output_path)
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")

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')


def generate_cmake(self):
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')

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")
nxtum marked this conversation as resolved.
Show resolved Hide resolved
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")
nxtum marked this conversation as resolved.
Show resolved Hide resolved
if(jsonrpc.lower() == 'y'):
jsonrpc= True
nxtum marked this conversation as resolved.
Show resolved Hide resolved
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")
nxtum marked this conversation as resolved.
Show resolved Hide resolved
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()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#

if __name__ == "__main__":
main()
61 changes: 61 additions & 0 deletions PluginSkeletonGenerator/examples/InProcess/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# 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}
nxtum marked this conversation as resolved.
Show resolved Hide resolved
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>)

install(TARGETS ${MODULE_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime)

write_config()
4 changes: 4 additions & 0 deletions PluginSkeletonGenerator/examples/InProcess/InProcess.conf.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
startmode = "@PLUGIN_INPROCESS_STARTMODE@"

configuration = JSON()
configuration.add("example,"mystring")
61 changes: 61 additions & 0 deletions PluginSkeletonGenerator/examples/InProcess/InProcess.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* 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{
nxtum marked this conversation as resolved.
Show resolved Hide resolved
namespace Plugin{
namespace {
static Metadata<InProcess>metadata(
// Version
1, 0, 0,
// Preconditions
{},
// Terminations
{},
// Controls
{}
)
}

// Implement all methods from InProcess.h

const string InProcess::Initialize(PluginHost::IShell* service) {
string message;

ASSERT (service != nullptr);
nxtum marked this conversation as resolved.
Show resolved Hide resolved

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
91 changes: 91 additions & 0 deletions PluginSkeletonGenerator/examples/InProcess/InProcess.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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 <interfaces/json/JHello.h>
#include <interfaces/json/JWorld.h>
#include <interfaces/IHello>
#include <interfaces/IWorld>

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)
nxtum marked this conversation as resolved.
Show resolved Hide resolved
{
}

~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(1);
nxtum marked this conversation as resolved.
Show resolved Hide resolved

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;
};
}
}
Loading