hermes 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hermes/__init__.py +3 -0
- hermes/__main__.py +11 -0
- hermes/commands/__init__.py +17 -0
- hermes/commands/base.py +199 -0
- hermes/commands/clean/__init__.py +0 -0
- hermes/commands/clean/base.py +30 -0
- hermes/commands/cli.py +61 -0
- hermes/commands/curate/__init__.py +0 -0
- hermes/commands/curate/base.py +47 -0
- hermes/commands/deposit/__init__.py +3 -0
- hermes/commands/deposit/base.py +145 -0
- hermes/commands/deposit/error.py +8 -0
- hermes/commands/deposit/file.py +32 -0
- hermes/commands/deposit/invenio.py +665 -0
- hermes/commands/deposit/invenio_rdm.py +86 -0
- hermes/commands/harvest/__init__.py +3 -0
- hermes/commands/harvest/base.py +66 -0
- hermes/commands/harvest/cff.py +123 -0
- hermes/commands/harvest/codemeta.py +68 -0
- hermes/commands/harvest/util/__init__.py +7 -0
- hermes/commands/harvest/util/validate_codemeta.py +51 -0
- hermes/commands/postprocess/__init__.py +0 -0
- hermes/commands/postprocess/base.py +31 -0
- hermes/commands/postprocess/invenio.py +49 -0
- hermes/commands/postprocess/invenio_rdm.py +26 -0
- hermes/commands/process/__init__.py +0 -0
- hermes/commands/process/base.py +73 -0
- hermes/error.py +8 -0
- hermes/logger.py +82 -0
- hermes/model/__init__.py +3 -0
- hermes/model/context.py +445 -0
- hermes/model/errors.py +46 -0
- hermes/model/merge.py +179 -0
- hermes/model/path.py +399 -0
- hermes/settings.py +44 -0
- hermes/utils.py +16 -0
- hermes-0.1.0.dist-info/LICENSE.md +22 -0
- hermes-0.1.0.dist-info/LICENSES/Apache-2.0.txt +73 -0
- hermes-0.1.0.dist-info/LICENSES/CC-BY-ND-4.0.txt +154 -0
- hermes-0.1.0.dist-info/LICENSES/CC-BY-SA-4.0.txt +170 -0
- hermes-0.1.0.dist-info/LICENSES/CC0-1.0.txt +121 -0
- hermes-0.1.0.dist-info/LICENSES/LicenseRef-BSD-Caltech.txt +28 -0
- hermes-0.1.0.dist-info/METADATA +113 -0
- hermes-0.1.0.dist-info/RECORD +46 -0
- hermes-0.1.0.dist-info/WHEEL +4 -0
- hermes-0.1.0.dist-info/entry_points.txt +17 -0
hermes/__init__.py
ADDED
hermes/__main__.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: Michael Meinel
|
|
6
|
+
|
|
7
|
+
# This is an interface file that only provides a public interface, hence linter is disabled to avoid
|
|
8
|
+
# "unused import" errors.
|
|
9
|
+
# flake8: noqa
|
|
10
|
+
|
|
11
|
+
from hermes.commands.base import HermesHelpCommand
|
|
12
|
+
from hermes.commands.clean.base import HermesCleanCommand
|
|
13
|
+
from hermes.commands.curate.base import HermesCurateCommand
|
|
14
|
+
from hermes.commands.harvest.base import HermesHarvestCommand
|
|
15
|
+
from hermes.commands.process.base import HermesProcessCommand
|
|
16
|
+
from hermes.commands.deposit.base import HermesDepositCommand
|
|
17
|
+
from hermes.commands.postprocess.base import HermesPostprocessCommand
|
hermes/commands/base.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: Michael Meinel
|
|
6
|
+
|
|
7
|
+
import abc
|
|
8
|
+
import argparse
|
|
9
|
+
import logging
|
|
10
|
+
import pathlib
|
|
11
|
+
from importlib import metadata
|
|
12
|
+
from typing import Dict, Optional, Type
|
|
13
|
+
|
|
14
|
+
import toml
|
|
15
|
+
from pydantic import BaseModel
|
|
16
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class HermesSettings(BaseSettings):
|
|
20
|
+
"""Root class for HERMES configuration model."""
|
|
21
|
+
|
|
22
|
+
model_config = SettingsConfigDict(env_file_encoding='utf-8')
|
|
23
|
+
|
|
24
|
+
logging: Dict = {}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class HermesCommand(abc.ABC):
|
|
28
|
+
"""Base class for a HERMES workflow command.
|
|
29
|
+
|
|
30
|
+
:cvar NAME: The name of the sub-command that is defined here.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
command_name: str = ""
|
|
34
|
+
settings_class: Type = HermesSettings
|
|
35
|
+
|
|
36
|
+
def __init__(self, parser: argparse.ArgumentParser):
|
|
37
|
+
"""Initialize a new instance of any HERMES command.
|
|
38
|
+
|
|
39
|
+
:param parser: The command line parser used for reading command line arguments.
|
|
40
|
+
"""
|
|
41
|
+
self.parser = parser
|
|
42
|
+
self.plugins = self.init_plugins()
|
|
43
|
+
self.settings = None
|
|
44
|
+
|
|
45
|
+
self.log = logging.getLogger(f"hermes.{self.command_name}")
|
|
46
|
+
|
|
47
|
+
def init_plugins(self):
|
|
48
|
+
"""Collect and initialize the plugins available for the HERMES command."""
|
|
49
|
+
|
|
50
|
+
# Collect all entry points for this group (i.e., all valid plug-ins for the step)
|
|
51
|
+
entry_point_group = f"hermes.{self.command_name}"
|
|
52
|
+
group_plugins = {
|
|
53
|
+
entry_point.name: entry_point.load()
|
|
54
|
+
for entry_point in metadata.entry_points(group=entry_point_group)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Collect the plug-in specific configurations
|
|
58
|
+
self.derive_settings_class({
|
|
59
|
+
plugin_name: plugin_class.settings_class
|
|
60
|
+
for plugin_name, plugin_class in group_plugins.items()
|
|
61
|
+
if hasattr(plugin_class, "settings_class") and plugin_class.settings_class is not None
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return group_plugins
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def derive_settings_class(cls, setting_types: Dict[str, Type]) -> None:
|
|
68
|
+
"""Build a new Pydantic data model class for configuration.
|
|
69
|
+
|
|
70
|
+
This will create a new class that includes all settings from the plugins available.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
if cls.settings_class is not None:
|
|
74
|
+
# Derive a new settings model class that contains all the plug-in extensions
|
|
75
|
+
cls.settings_class = type(
|
|
76
|
+
f"{cls.__name__}Settings",
|
|
77
|
+
(cls.settings_class, ),
|
|
78
|
+
{
|
|
79
|
+
**{
|
|
80
|
+
plugin_name: plugin_settings()
|
|
81
|
+
for plugin_name, plugin_settings in setting_types.items()
|
|
82
|
+
if plugin_settings is not None
|
|
83
|
+
},
|
|
84
|
+
"__annotations__": setting_types,
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
elif setting_types:
|
|
88
|
+
raise ValueError(f"Command {cls.command_name} has no settings, hence plugin must not have settings, too.")
|
|
89
|
+
|
|
90
|
+
def init_common_parser(self, parser: argparse.ArgumentParser) -> None:
|
|
91
|
+
"""Initialize the common command line arguments available for all HERMES sub-commands.
|
|
92
|
+
|
|
93
|
+
:param parser: The base command line parser used as entry point when reading command line arguments.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
parser.add_argument(
|
|
97
|
+
"--path", default=pathlib.Path(), type=pathlib.Path, help="Working path"
|
|
98
|
+
)
|
|
99
|
+
parser.add_argument(
|
|
100
|
+
"--config",
|
|
101
|
+
default=pathlib.Path("hermes.toml"),
|
|
102
|
+
type=pathlib.Path,
|
|
103
|
+
help="Configuration file in TOML format",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
plugin_args = parser.add_argument_group("Extra options")
|
|
107
|
+
plugin_args.add_argument(
|
|
108
|
+
"-O",
|
|
109
|
+
nargs=2,
|
|
110
|
+
action="append",
|
|
111
|
+
default=[],
|
|
112
|
+
metavar=("NAME", "VALUE"),
|
|
113
|
+
dest="options",
|
|
114
|
+
help="Configuration values to override hermes.toml options. "
|
|
115
|
+
"NAME is the dotted name / path to the option in the TOML file, "
|
|
116
|
+
"VALUE is the actual value.",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:
|
|
120
|
+
"""Initialize the command line arguments available for this specific HERMES sub-commands.
|
|
121
|
+
|
|
122
|
+
You should override this method to add your custom arguments to the command line parser of
|
|
123
|
+
the respective sub-command.
|
|
124
|
+
|
|
125
|
+
:param command_parser: The command line sub-parser responsible for the HERMES sub-command.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
pass
|
|
129
|
+
|
|
130
|
+
def load_settings(self, args: argparse.Namespace):
|
|
131
|
+
"""Load settings from the configuration file (passed in from command line)."""
|
|
132
|
+
|
|
133
|
+
toml_data = toml.load(args.path / args.config)
|
|
134
|
+
self.root_settings = HermesCommand.settings_class.model_validate(toml_data)
|
|
135
|
+
self.settings = getattr(self.root_settings, self.command_name)
|
|
136
|
+
|
|
137
|
+
def patch_settings(self, args: argparse.Namespace):
|
|
138
|
+
"""Process command line options for the settings."""
|
|
139
|
+
|
|
140
|
+
for key, value in args.options:
|
|
141
|
+
target = self.settings
|
|
142
|
+
sub_keys = key.split('.')
|
|
143
|
+
for sub_key in sub_keys[:-1]:
|
|
144
|
+
target = getattr(target, sub_key)
|
|
145
|
+
|
|
146
|
+
# TODO: Transform the value accordingly before setting it
|
|
147
|
+
setattr(target, sub_keys[-1], value)
|
|
148
|
+
|
|
149
|
+
@abc.abstractmethod
|
|
150
|
+
def __call__(self, args: argparse.Namespace):
|
|
151
|
+
"""Execute the HERMES sub-command.
|
|
152
|
+
|
|
153
|
+
:param args: The namespace that was returned by the command line parser when reading the arguments.
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class HermesPlugin(abc.ABC):
|
|
160
|
+
"""Base class for all HERMES plugins."""
|
|
161
|
+
|
|
162
|
+
settings_class: Optional[Type] = None
|
|
163
|
+
|
|
164
|
+
@abc.abstractmethod
|
|
165
|
+
def __call__(self, command: HermesCommand) -> None:
|
|
166
|
+
"""Execute the plugin.
|
|
167
|
+
|
|
168
|
+
:param command: The command that triggered this plugin to run.
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class HermesHelpSettings(BaseModel):
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class HermesHelpCommand(HermesCommand):
|
|
179
|
+
"""Show help page and exit."""
|
|
180
|
+
|
|
181
|
+
command_name = "help"
|
|
182
|
+
settings_class = HermesHelpSettings
|
|
183
|
+
|
|
184
|
+
def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:
|
|
185
|
+
command_parser.add_argument(
|
|
186
|
+
"subcommand",
|
|
187
|
+
nargs="?",
|
|
188
|
+
metavar="COMMAND",
|
|
189
|
+
help="The HERMES sub-command to get help for.",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def __call__(self, args: argparse.Namespace) -> None:
|
|
193
|
+
if args.subcommand:
|
|
194
|
+
# When a sub-command is given, show its help page (i.e., by "running" the command with "-h" flag).
|
|
195
|
+
self.parser.parse_args([args.subcommand, "-h"])
|
|
196
|
+
else:
|
|
197
|
+
# Otherwise, simply show the general help and exit (cleanly).
|
|
198
|
+
self.parser.print_help()
|
|
199
|
+
self.parser.exit()
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: Michael Meinel
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import shutil
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel
|
|
11
|
+
|
|
12
|
+
from hermes.commands.base import HermesCommand
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class HermesCleanSettings(BaseModel):
|
|
16
|
+
"""Configuration of the ``clean`` command."""
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class HermesCleanCommand(HermesCommand):
|
|
21
|
+
""" Clean up caches from previous HERMES runs. """
|
|
22
|
+
|
|
23
|
+
command_name = "clean"
|
|
24
|
+
settings_class = HermesCleanSettings
|
|
25
|
+
|
|
26
|
+
def __call__(self, args: argparse.Namespace) -> None:
|
|
27
|
+
self.log.info("Removing HERMES caches...")
|
|
28
|
+
|
|
29
|
+
# Naive implementation for now... check errors, validate directory, don't construct the path ourselves, etc.
|
|
30
|
+
shutil.rmtree(args.path / '.hermes')
|
hermes/commands/cli.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: Stephan Druskat
|
|
6
|
+
# SPDX-FileContributor: Michael Meinel
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
This module provides the main entry point for the HERMES command line application.
|
|
10
|
+
"""
|
|
11
|
+
import argparse
|
|
12
|
+
|
|
13
|
+
from hermes.commands import HermesHelpCommand, HermesCleanCommand, HermesHarvestCommand, HermesProcessCommand, \
|
|
14
|
+
HermesCurateCommand, HermesDepositCommand, HermesPostprocessCommand
|
|
15
|
+
from hermes.commands.base import HermesCommand
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> None:
|
|
19
|
+
"""
|
|
20
|
+
HERMES main entry point (i.e., run the CLI).
|
|
21
|
+
|
|
22
|
+
This command runs the selected HERMES sub-command.
|
|
23
|
+
"""
|
|
24
|
+
parser = argparse.ArgumentParser(
|
|
25
|
+
prog="hermes",
|
|
26
|
+
description="This command runs HERMES workflow steps.",
|
|
27
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# Register all sub-commands to a new sub-parser each.
|
|
31
|
+
subparsers = parser.add_subparsers(dest="subcommand", required=True,
|
|
32
|
+
help="Available subcommands")
|
|
33
|
+
setting_types = {}
|
|
34
|
+
|
|
35
|
+
for command in (
|
|
36
|
+
HermesHelpCommand(parser),
|
|
37
|
+
HermesCleanCommand(parser),
|
|
38
|
+
HermesHarvestCommand(parser),
|
|
39
|
+
HermesProcessCommand(parser),
|
|
40
|
+
HermesCurateCommand(parser),
|
|
41
|
+
HermesDepositCommand(parser),
|
|
42
|
+
HermesPostprocessCommand(parser),
|
|
43
|
+
):
|
|
44
|
+
if command.settings_class is not None:
|
|
45
|
+
setting_types[command.command_name] = command.settings_class
|
|
46
|
+
|
|
47
|
+
command_parser = subparsers.add_parser(command.command_name, help=command.__doc__)
|
|
48
|
+
command_parser.set_defaults(command=command)
|
|
49
|
+
|
|
50
|
+
command.init_common_parser(command_parser)
|
|
51
|
+
command.init_command_parser(command_parser)
|
|
52
|
+
|
|
53
|
+
# Construct the Pydantic Settings root model
|
|
54
|
+
HermesCommand.derive_settings_class(setting_types)
|
|
55
|
+
|
|
56
|
+
# Actually parse the command line, configure it and execute the selected sub-command.
|
|
57
|
+
args = parser.parse_args()
|
|
58
|
+
|
|
59
|
+
args.command.load_settings(args)
|
|
60
|
+
args.command.patch_settings(args)
|
|
61
|
+
args.command(args)
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022 German Aerospace Center (DLR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: Michael Meinel
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import os
|
|
9
|
+
import shutil
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
from pydantic import BaseModel
|
|
13
|
+
|
|
14
|
+
from hermes.commands.base import HermesCommand
|
|
15
|
+
from hermes.model.context import CodeMetaContext
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CurateSettings(BaseModel):
|
|
19
|
+
"""Generic deposition settings."""
|
|
20
|
+
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class HermesCurateCommand(HermesCommand):
|
|
25
|
+
""" Curate the unified metadata before deposition. """
|
|
26
|
+
|
|
27
|
+
command_name = "curate"
|
|
28
|
+
settings_class = CurateSettings
|
|
29
|
+
|
|
30
|
+
def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
def __call__(self, args: argparse.Namespace) -> None:
|
|
34
|
+
|
|
35
|
+
self.log.info("# Metadata curation")
|
|
36
|
+
|
|
37
|
+
ctx = CodeMetaContext()
|
|
38
|
+
process_output = ctx.hermes_dir / 'process' / (ctx.hermes_name + ".json")
|
|
39
|
+
|
|
40
|
+
if not process_output.is_file():
|
|
41
|
+
self.log.error(
|
|
42
|
+
"No processed metadata found. Please run `hermes process` before curation."
|
|
43
|
+
)
|
|
44
|
+
sys.exit(1)
|
|
45
|
+
|
|
46
|
+
os.makedirs(ctx.hermes_dir / 'curate', exist_ok=True)
|
|
47
|
+
shutil.copy(process_output, ctx.hermes_dir / 'curate' / (ctx.hermes_name + '.json'))
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023 Helmholtz-Zentrum Dresden-Rossendorf (HZDR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: David Pape
|
|
6
|
+
# SPDX-FileContributor: Michael Meinel
|
|
7
|
+
|
|
8
|
+
import abc
|
|
9
|
+
import argparse
|
|
10
|
+
import json
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel
|
|
14
|
+
|
|
15
|
+
from hermes.commands.base import HermesCommand, HermesPlugin
|
|
16
|
+
from hermes.model.context import CodeMetaContext
|
|
17
|
+
from hermes.model.path import ContextPath
|
|
18
|
+
from hermes.model.errors import HermesValidationError
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class BaseDepositPlugin(HermesPlugin):
|
|
22
|
+
"""Base class that implements the generic deposition workflow.
|
|
23
|
+
|
|
24
|
+
TODO: describe workflow... needs refactoring to be less stateful!
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, command, ctx):
|
|
28
|
+
self.command = command
|
|
29
|
+
self.ctx = ctx
|
|
30
|
+
|
|
31
|
+
def __call__(self, command: HermesCommand) -> None:
|
|
32
|
+
"""Initiate the deposition process.
|
|
33
|
+
|
|
34
|
+
This calls a list of additional methods on the class, none of which need to be implemented.
|
|
35
|
+
"""
|
|
36
|
+
self.command = command
|
|
37
|
+
|
|
38
|
+
self.prepare()
|
|
39
|
+
self.map_metadata()
|
|
40
|
+
|
|
41
|
+
if self.is_initial_publication():
|
|
42
|
+
self.create_initial_version()
|
|
43
|
+
else:
|
|
44
|
+
self.create_new_version()
|
|
45
|
+
|
|
46
|
+
self.update_metadata()
|
|
47
|
+
self.delete_artifacts()
|
|
48
|
+
self.upload_artifacts()
|
|
49
|
+
self.publish()
|
|
50
|
+
|
|
51
|
+
def prepare(self) -> None:
|
|
52
|
+
"""Prepare the deposition.
|
|
53
|
+
|
|
54
|
+
This method may be implemented to check whether config and context match some initial conditions.
|
|
55
|
+
|
|
56
|
+
If no exceptions are raised, execution continues.
|
|
57
|
+
"""
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
@abc.abstractmethod
|
|
61
|
+
def map_metadata(self) -> None:
|
|
62
|
+
"""Map the given metadata to the target schema of the deposition platform."""
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def is_initial_publication(self) -> bool:
|
|
66
|
+
"""Decide whether to do an initial publication or publish a new version.
|
|
67
|
+
|
|
68
|
+
Returning ``True`` indicates that publication of an initial version will be executed, resulting in a call of
|
|
69
|
+
:meth:`create_initial_version`. ``False`` indicates a new version of an existing publication, leading to a call
|
|
70
|
+
of :meth:`create_new_version`.
|
|
71
|
+
|
|
72
|
+
By default, this returns ``True``.
|
|
73
|
+
"""
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
def create_initial_version(self) -> None:
|
|
77
|
+
"""Create an initial version of the publication on the target platform."""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
def create_new_version(self) -> None:
|
|
81
|
+
"""Create a new version of an existing publication on the target platform."""
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
def update_metadata(self) -> None:
|
|
85
|
+
"""Update the metadata of the newly created version."""
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
def delete_artifacts(self) -> None:
|
|
89
|
+
"""Delete any superfluous artifacts taken from the previous version of the publication."""
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
def upload_artifacts(self) -> None:
|
|
93
|
+
"""Upload new artifacts to the target platform."""
|
|
94
|
+
pass
|
|
95
|
+
|
|
96
|
+
@abc.abstractmethod
|
|
97
|
+
def publish(self) -> None:
|
|
98
|
+
"""Publish the newly created deposit on the target platform."""
|
|
99
|
+
pass
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class DepositSettings(BaseModel):
|
|
103
|
+
"""Generic deposition settings."""
|
|
104
|
+
|
|
105
|
+
target: str = ""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class HermesDepositCommand(HermesCommand):
|
|
109
|
+
""" Deposit the curated metadata to repositories. """
|
|
110
|
+
|
|
111
|
+
command_name = "deposit"
|
|
112
|
+
settings_class = DepositSettings
|
|
113
|
+
|
|
114
|
+
def init_command_parser(self, command_parser: argparse.ArgumentParser) -> None:
|
|
115
|
+
command_parser.add_argument('--file', '-f', nargs=1, action='append',
|
|
116
|
+
help="File that should be part of the deposition.")
|
|
117
|
+
command_parser.add_argument('--initial', action='store_true', default=False,
|
|
118
|
+
help="Allow initial deposition (i.e., minting a new PID).")
|
|
119
|
+
|
|
120
|
+
def __call__(self, args: argparse.Namespace) -> None:
|
|
121
|
+
self.args = args
|
|
122
|
+
plugin_name = self.settings.target
|
|
123
|
+
print(self.args)
|
|
124
|
+
|
|
125
|
+
ctx = CodeMetaContext()
|
|
126
|
+
codemeta_file = ctx.get_cache("curate", ctx.hermes_name)
|
|
127
|
+
if not codemeta_file.exists():
|
|
128
|
+
self.log.error("You must run the 'curate' command before deposit")
|
|
129
|
+
sys.exit(1)
|
|
130
|
+
|
|
131
|
+
codemeta_path = ContextPath("codemeta")
|
|
132
|
+
with open(codemeta_file) as codemeta_fh:
|
|
133
|
+
ctx.update(codemeta_path, json.load(codemeta_fh))
|
|
134
|
+
|
|
135
|
+
try:
|
|
136
|
+
plugin_func = self.plugins[plugin_name](self, ctx)
|
|
137
|
+
|
|
138
|
+
except KeyError:
|
|
139
|
+
self.log.error("Plugin '%s' not found.", plugin_name)
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
plugin_func(self)
|
|
143
|
+
|
|
144
|
+
except HermesValidationError as e:
|
|
145
|
+
self.log.error("Error while executing %s: %s", plugin_name, e)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2023 German Aerospace Center (DLR), Helmholtz-Zentrum Dresden-Rossendorf (HZDR)
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
# SPDX-FileContributor: David Pape
|
|
6
|
+
# SPDX-FileContributor: Michael Meinel
|
|
7
|
+
# SPDX-FileContributor: Stephan Druskat
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from hermes.commands.deposit.base import BaseDepositPlugin
|
|
14
|
+
from hermes.model.path import ContextPath
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class FileDepositSettings(BaseModel):
|
|
18
|
+
filename: str = 'hermes.json'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FileDepositPlugin(BaseDepositPlugin):
|
|
22
|
+
settings_class = FileDepositSettings
|
|
23
|
+
|
|
24
|
+
def map_metadata(self) -> None:
|
|
25
|
+
self.ctx.update(ContextPath.parse('deposit.file'), self.ctx['codemeta'])
|
|
26
|
+
|
|
27
|
+
def publish(self) -> None:
|
|
28
|
+
file_config = self.command.settings.file
|
|
29
|
+
output_data = self.ctx['deposit.file']
|
|
30
|
+
|
|
31
|
+
with open(file_config.filename, 'w') as deposition_file:
|
|
32
|
+
json.dump(output_data, deposition_file, indent=2)
|