diff --git a/pyproject.toml b/pyproject.toml index cd95f3bf..514908a6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,10 @@ invenio = "hermes.commands.deposit.invenio:map_metadata" [tool.poetry.plugins."hermes.deposit"] invenio = "hermes.commands.deposit.invenio:deposit" +[tool.poetry.plugins."hermes.postprocess"] +config_record_id = "hermes.commands.postprocess.invenio:config_record_id" +cff_doi = "hermes.commands.postprocess.invenio:cff_doi" + [tool.taskipy.tasks] docs-build = "poetry run sphinx-build -M html docs/source docs/build -W" docs-clean = "poetry run sphinx-build -M clean docs/source docs/build" diff --git a/src/hermes/commands/deposit/invenio.py b/src/hermes/commands/deposit/invenio.py index c5b6a1f0..512dd93b 100644 --- a/src/hermes/commands/deposit/invenio.py +++ b/src/hermes/commands/deposit/invenio.py @@ -158,6 +158,8 @@ def deposit(click_ctx: click.Context, ctx: CodeMetaContext): deposit = response.json() _log.debug("Created deposit: %s", deposit["links"]["html"]) + with open(ctx.get_cache('deposit', 'deposit', create=True), 'w') as deposit_file: + json.dump(deposit, deposit_file, indent=4) # Upload the files. We'll use the bucket API rather than the files API as it # supports file sizes above 100MB. diff --git a/src/hermes/commands/postprocess/__init__.py b/src/hermes/commands/postprocess/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/hermes/commands/postprocess/invenio.py b/src/hermes/commands/postprocess/invenio.py new file mode 100644 index 00000000..645269cb --- /dev/null +++ b/src/hermes/commands/postprocess/invenio.py @@ -0,0 +1,51 @@ +# SPDX-FileCopyrightText: 2023 German Aerospace Center (DLR) +# +# SPDX-License-Identifier: Apache-2.0 + +# SPDX-FileContributor: Michael Meinel +# SPDX-FileContributor: Stephan Druskat + +import json +import logging + +import toml +from ruamel import yaml + +from hermes import config + + +_log = logging.getLogger('deposit.invenio') + + +def config_record_id(ctx): + deposition_path = ctx.get_cache('deposit', 'deposit') + with deposition_path.open("r") as deposition_file: + deposition = json.load(deposition_file) + conf = config.get('hermes') + try: + conf['deposit']['invenio']['record_id'] = deposition['record_id'] + toml.dump(conf, open('hermes.toml', 'w')) + except KeyError: + raise RuntimeError("No deposit.invenio configuration available to store record id in") from None + + +def cff_doi(ctx): + deposition_path = ctx.get_cache('deposit', 'deposit') + with deposition_path.open("r") as deposition_file: + deposition = json.load(deposition_file) + try: + cff = yaml.load(open('CITATION.cff', 'r'), yaml.Loader) + new_identifier = { + 'description': f"DOI for the published version {deposition['metadata']['version']} " + f"[generated by hermes]", + 'type': 'doi', + 'value': deposition['doi'] + } + if 'identifiers' in cff: + cff['identifiers'].append(new_identifier) + else: + cff['identifiers'] = [new_identifier] + yaml.dump(cff, open('CITATION.cff', 'w'), + indent=4, default_flow_style=False, block_seq_indent=2, allow_unicode=True) + except Exception as e: + raise RuntimeError("Update of CITATION.cff failed.") from e diff --git a/src/hermes/commands/workflow.py b/src/hermes/commands/workflow.py index 8de3e1e0..6e03dc09 100644 --- a/src/hermes/commands/workflow.py +++ b/src/hermes/commands/workflow.py @@ -224,11 +224,39 @@ def deposit(click_ctx: click.Context, auth_token, file): @click.group(invoke_without_command=True) -def postprocess(): +@click.pass_context +def postprocess(click_ctx: click.Context): """ Postprocess metadata after deposition """ - click.echo("Post-processing") + _log = logging.getLogger('cli.postprocess') + + audit_log = logging.getLogger('audit') + audit_log.info("# Post-processing") + + ctx = CodeMetaContext() + + if not (ctx.hermes_dir / "deposit").exists(): + _log.error("You must run the deposit command before post-process") + click_ctx.exit(1) + + # Get all postprocessors + postprocess_config = config.get("postprocess") + postprocess_names = postprocess_config.get('execute', []) + + for postprocess_name in postprocess_names: + postprocessors = metadata.entry_points(group='hermes.postprocess', name=postprocess_name) + if not postprocessors: + _log.warning("- Post-processor %s selected but not found.", postprocess_name) + continue + + postprocessor_ep, *_ = postprocessors + audit_log.info("## Post-process data with %s", postprocessor_ep.name) + postprocessor = postprocessor_ep.load() + postprocessor(ctx) + + audit_log.info('') + logging.shutdown() @click.group(invoke_without_command=True) diff --git a/src/hermes/config.py b/src/hermes/config.py index c43474ab..02bd9ddf 100644 --- a/src/hermes/config.py +++ b/src/hermes/config.py @@ -106,7 +106,7 @@ def get(name: str) -> dict: _config['hermes'][name] = {} _config[name] = _config['hermes'][name] - elif not _config['hermes'][name] is _config[name]: + elif name != 'hermes' and _config['hermes'][name] is not _config[name]: # If a configuration was loaded, after the defaults were set, update it. _config[name].update(_config['hermes'].get('name', {})) diff --git a/test/hermes_test/test_cli.py b/test/hermes_test/test_cli.py index d4ea3bb4..4e448582 100644 --- a/test/hermes_test/test_cli.py +++ b/test/hermes_test/test_cli.py @@ -134,14 +134,14 @@ def test_hermes_with_deposit_and_path(): runner = CliRunner() result = runner.invoke(cli.main, args=('--deposit', '--path', './')) - assert isinstance(result.exception, DepositionUnauthorizedError) + assert result.exit_code == 2 def test_hermes_with_path_and_postprocess(): runner = CliRunner() result = runner.invoke(cli.main, args=('--path', './', '--postprocess')) - assert not result.exception + assert result.exit_code == 1 @pytest.mark.skip(reason="No clean way at the moment of adding more required options that are parsed by Click, \