1515from pydantic import BaseModel
1616from pydantic_settings import BaseSettings , SettingsConfigDict
1717
18+ from hermes import utils
19+ from hermes .model .prov .ld_prov import ld_prov , ld_prov_node
20+ from hermes .model .types import ld_context
21+
1822
1923class HermesSettings (BaseSettings ):
2024 """Root class for HERMES configuration model."""
@@ -33,15 +37,53 @@ class HermesCommand(abc.ABC):
3337 command_name : str = ""
3438 settings_class : Type = HermesSettings
3539
40+ class prov :
41+ @classmethod
42+ def hermes_software (cls ):
43+ return {
44+ "@type" : "schema:SoftwareApplication" ,
45+ "schema:name" : utils .hermes_name ,
46+ "schema:version" : utils .hermes_version ,
47+ "schema:url" : utils .hermes_homepage ,
48+ }
49+
50+ @classmethod
51+ def hermes_command (cls , cmd , app ):
52+ return {
53+ "@type" : "schema:SoftwareApplication" ,
54+ "schema:name" : cmd .command_name ,
55+ "schema:isPartOf" : app .ref ,
56+ }
57+
58+ @classmethod
59+ def hermes_plugin_run (cls , plugin , command ):
60+ return {
61+ "prov:wasStaredBy" : command .ref ,
62+ }
63+
64+ @classmethod
65+ def hermes_json_data (cls , name , data ):
66+ return {
67+ "@type" : "schema:PropertyValue" ,
68+ "schema:name" : name ,
69+ "schema:value" : {"@type" : "@json" , "@value" : data .compact ()},
70+ }
71+
72+
3673 def __init__ (self , parser : argparse .ArgumentParser ):
3774 """Initialize a new instance of any HERMES command.
3875
3976 :param parser: The command line parser used for reading command line arguments.
4077 """
78+ self .prov_doc = ld_prov (context = ld_context .ALL_CONTEXTS )
79+ self .app_entity = self .prov_doc .make_node ('Entity' , self .prov .hermes_software ())
80+
4181 self .parser = parser
4282 self .plugins = self .init_plugins ()
4383 self .settings = None
4484
85+ self .app_entity .commit ()
86+
4587 self .log = logging .getLogger (f"hermes.{ self .command_name } " )
4688 self .errors = []
4789
@@ -50,17 +92,20 @@ def init_plugins(self):
5092
5193 # Collect all entry points for this group (i.e., all valid plug-ins for the step)
5294 entry_point_group = f"hermes.{ self .command_name } "
53- group_plugins = {
54- entry_point .name : entry_point .load ()
55- for entry_point in metadata .entry_points (group = entry_point_group )
56- }
95+ group_plugins = {}
96+ group_settings = {}
97+
98+ for entry_point in metadata .entry_points (group = entry_point_group ):
99+ plugin_cls = entry_point .load ()
100+ ep_metadata = plugin_cls .get_metadata (entry_point )
101+
102+ plugin_cls .plugin_node = self .app_entity .add_related ("schema:hasPart" , "Entity" , ep_metadata )
57103
58- # Collect the plug-in specific configurations
59- self .derive_settings_class ({
60- plugin_name : plugin_class .settings_class
61- for plugin_name , plugin_class in group_plugins .items ()
62- if hasattr (plugin_class , "settings_class" ) and plugin_class .settings_class is not None
63- })
104+ group_plugins [entry_point .name ] = plugin_cls
105+ if hasattr (plugin_cls , 'settings_class' ) and plugin_cls .settings_class is not None :
106+ group_settings [entry_point .name ] = plugin_cls .settings_class
107+
108+ self .derive_settings_class (group_settings )
64109
65110 return group_plugins
66111
@@ -160,8 +205,22 @@ def __call__(self, args: argparse.Namespace):
160205class HermesPlugin (abc .ABC ):
161206 """Base class for all HERMES plugins."""
162207
208+ pluing_node = None
209+
163210 settings_class : Optional [Type ] = None
164211
212+ @classmethod
213+ def get_metadata (cls , entry_point ):
214+ cls .entry_point = entry_point
215+
216+ return {
217+ "@type" : "schema:EntryPoint" ,
218+ "schema:name" : entry_point .name ,
219+ }
220+
221+ def __init__ (self , plugin_prov ):
222+ self .prov_doc = plugin_prov
223+
165224 @abc .abstractmethod
166225 def __call__ (self , command : HermesCommand ) -> None :
167226 """Execute the plugin.
0 commit comments