1- # SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
1+ # SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR), 2025 Helmholtz-Zentrum Dresden-Rossendorf (HZDR)
22#
33# SPDX-License-Identifier: Apache-2.0
44
55# SPDX-FileContributor: Michael Meinel
6+ # SPDX-FileContributor: David Pape
67
8+ from abc import abstractmethod
79import argparse
8- import os
9- import shutil
10+ import json
1011import sys
1112
1213from pydantic import BaseModel
1314
14- from hermes .commands .base import HermesCommand
15+ from hermes .commands .base import HermesCommand , HermesPlugin
1516from hermes .model .context import CodeMetaContext
17+ from hermes .model .errors import HermesValidationError
18+ from hermes .model .path import ContextPath
1619
1720
1821class _CurateSettings (BaseModel ):
19- """Generic deposition settings."""
22+ """Generic curation settings."""
2023
21- pass
24+ #: Parameter by which the plugin is selected. By default, the accept plugin is used.
25+ method : str = "accept"
26+
27+
28+ class BaseCuratePlugin (HermesPlugin ):
29+ """Base class for curation plugins."""
30+
31+ def __init__ (self , command , ctx ):
32+ self .command = command
33+ self .ctx = ctx
34+
35+ def __call__ (self , command : HermesCommand ) -> None :
36+ """Entry point of the callable.
37+
38+ This method runs the main logic of the plugin. It calls the other methods of the
39+ object in the correct order. Depending on the result of
40+ ``is_publication_approved`` the corresponding ``process_decision_*()`` method is
41+ called, based on the curation decision.
42+ """
43+ self .prepare ()
44+ self .validate ()
45+ self .create_report ()
46+ if self .is_publication_approved ():
47+ self .process_decision_positive ()
48+ else :
49+ self .process_decision_negative ()
50+
51+ def prepare (self ):
52+ """Prepare the plugin.
53+
54+ This method may be used to perform preparatory tasks such as configuration
55+ checks, token permission checks, loading of resources, etc.
56+ """
57+ pass
58+
59+ def validate (self ):
60+ """Validate the metadata.
61+
62+ This method performs the validation of the metadata from the data model.
63+ """
64+ pass
65+
66+ def create_report (self ):
67+ """Create a curation report.
68+
69+ This method is responsible for creating any number of reports about the curation
70+ process. These reports may be machine-readable, human-readable, or both.
71+ """
72+ pass
73+
74+ @abstractmethod
75+ def is_publication_approved (self ) -> bool :
76+ """Return the publication decision made through the curation process.
77+
78+ If publication is allowed, this method must return ``True``, otherwise
79+ ``False``.
80+ """
81+ pass
82+
83+ def process_decision_positive (self ):
84+ """Process a positive curation decision.
85+
86+ This method is called if a positive publication decision was made in the
87+ curation process.
88+ """
89+ pass
90+
91+ def process_decision_negative (self ):
92+ """Process a negative curation decision.
93+
94+ This method is called if a negative publication decision was made in the
95+ curation process. By default, a ``RuntimeError`` is raised, halting the
96+ execution.
97+ """
98+ raise RuntimeError ("Curation declined further processing" )
2299
23100
24101class HermesCurateCommand (HermesCommand ):
25- """ Curate the unified metadata before deposition. """
102+ """Curate the processed metadata before deposition."""
26103
27104 command_name = "curate"
28105 settings_class = _CurateSettings
@@ -31,17 +108,31 @@ def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:
31108 pass
32109
33110 def __call__ (self , args : argparse .Namespace ) -> None :
34-
35- self .log . info ( "# Metadata curation" )
111+ self . args = args
112+ plugin_name = self .settings . method
36113
37114 ctx = CodeMetaContext ()
38- process_output = ctx .hermes_dir / 'process' / (ctx .hermes_name + ".json" )
39-
40- if not process_output .is_file ():
115+ process_output = ctx .get_cache ("process" , ctx .hermes_name )
116+ if not process_output .exists ():
41117 self .log .error (
42118 "No processed metadata found. Please run `hermes process` before curation."
43119 )
44120 sys .exit (1 )
45121
46- os .makedirs (ctx .hermes_dir / 'curate' , exist_ok = True )
47- shutil .copy (process_output , ctx .hermes_dir / 'curate' / (ctx .hermes_name + '.json' ))
122+ curate_path = ContextPath ("curate" )
123+ with open (process_output ) as process_output_fh :
124+ ctx .update (curate_path , json .load (process_output_fh ))
125+
126+ try :
127+ plugin_func = self .plugins [plugin_name ](self , ctx )
128+
129+ except KeyError as e :
130+ self .log .error ("Plugin '%s' not found." , plugin_name )
131+ self .errors .append (e )
132+
133+ try :
134+ plugin_func (self )
135+
136+ except HermesValidationError as e :
137+ self .log .error ("Error while executing %s: %s" , plugin_name , e )
138+ self .errors .append (e )
0 commit comments