Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,6 @@ classifiers = [

[project.scripts]
tro-utils = "tro_utils.cli:cli"

[tool.setuptools.package-data]
tro_utils = ["*.jinja2"]
42 changes: 41 additions & 1 deletion tro_utils/cli.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,43 @@
"""Console script for tro_utils."""
import os
import sys

import click

from . import TRPAttribute
from .tro_utils import TRO

_TEMPLATES = {
"default": {
"description": "Default pretty template by Craig Willis",
"filename": "default.jinja2",
},
}


class StringOrPath(click.ParamType):
"""Custom parameter type to accept either a valid string or a file path."""

name = "string_or_path"

def __init__(self, templates=None):
self.valid_strings = templates.keys()

def convert(self, value, param, ctx):
# Check if the value is in the allowed string set
if value in self.valid_strings:
return value
# Check if the value is a valid path
elif os.path.exists(value) and os.path.isfile(value):
return value
else:
self.fail(
f"'{value}' is neither a valid option ({', '.join(self.valid_strings)}) "
f"nor a valid file path.",
param,
ctx,
)


@click.group()
@click.option(
Expand Down Expand Up @@ -189,12 +221,20 @@ def sign(ctx):

@cli.command(help="Generate a report of the TRO", name="report")
@click.option(
"--template", "-t", type=click.Path(), required=True, help="Template file"
"--template",
"-t",
type=StringOrPath(_TEMPLATES),
required=True,
help=f"Template file or one of the following: {', '.join(_TEMPLATES.keys())}",
)
@click.option("--output", "-o", type=click.Path(), required=True, help="Output file")
@click.pass_context
def generate_report(ctx, template, output):
declaration = ctx.parent.params.get("declaration")
if template in _TEMPLATES:
template = os.path.join(
os.path.dirname(__file__), _TEMPLATES[template]["filename"]
)
tro = TRO(
filepath=declaration,
)
Expand Down
69 changes: 69 additions & 0 deletions tro_utils/default.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# <img src="https://transparency-certified.github.io/trace-specification/_static/logo.png" width=40/> TRO Report


## TRO Information
| Property | Value |
| -------- | ----- |
| Name | {{ tro["name"] }} |
| Description | {{ tro["description"] }} |
| Created by | {{ tro["createdBy"] }} |
| Created date | {{ tro["createdDate"] }} |


## TRACE System Information

This TRO was generated by the following TRACE System:

| Property | Value |
| -------- | ----- |
| Name | {{ tro["trs"]["name"] }} |
| Description | {{ tro["trs"]["description"] }} |
| Owner | {{ tro["trs"]["owner"] }} |
| Contact | {{ tro["trs"]["contact"] }} |
| URL | {{ tro["trs"]["url"] }} |

<details>
<summary>Show Public Key</summary>
{{ tro["trs"]["publicKey"] }}
</details>

### Capabilities
| Capability | Description |
| ----------- | ------------ |
{%- for capability in tro["trs"]["capabilities"] %}
| {{ capability["name"] }} | {{ capability["description"] }} |
{%- endfor %}

## Trusted Research Performances

A Trusted Research Performance (TRP) captures the execution of a process in the context of a TRACE system. Typically, a TRP would take as input one or more sets of files (input arrangements) and produce another set of files (output arrangements).

<img src="workflow.png" width=600>

| Description | Accessed | Contributed |
| ----------- | ------------ | ------------ |
{%- for trp in tro["trps"] %}
| {{ trp["description"] }} | {{ trp["accessed"] }} | {{ trp["contributed"] }} |
{%- endfor %}


## Arrangements

Arrangements define how artifacts, typically files, are organized before and after each TRP. Artifacts are defined by their location and a checksum of their contents. Artifacts may be local or remote, defined by an URI. They may be included or excluded from the associated archive.

{%- for arrangement in tro["arrangements"].keys() %}
### {{ tro["arrangements"][arrangement]["name"] }}
| Artifact | SHA-256 | Status |
| -------- | -------- | ------ |
{%- for location in tro["arrangements"][arrangement]["artifacts"] %}
{%- if tro["arrangements"][arrangement]["artifacts"][location]["excluded"] != "None" %}
| ~~{{ location }}~~ | {{ tro["arrangements"][arrangement]["artifacts"][location]["sha256"] | truncate(32) }} | Excluded due to {{ tro["arrangements"][arrangement]["artifacts"][location]["excluded"] }} |
{%- else %}
| {{ location }} | {{ tro["arrangements"][arrangement]["artifacts"][location]["sha256"] | truncate(32) }} | {{ tro["arrangements"][arrangement]["artifacts"][location]["status"] }} |

{%- endif %}
{%- endfor %}
{%- endfor %}



2 changes: 2 additions & 0 deletions tro_utils/tro_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,8 @@ def generate_report(self, template, report):

dot.attr("node", shape="box3d", style="filled, rounded", fillcolor="#D6FDD0")

if isinstance(graph["trov:hasPerformance"], dict):
graph["trov:hasPerformance"] = [graph["trov:hasPerformance"]]
for trp in graph["trov:hasPerformance"]:
description = trp["rdfs:comment"]
accessed = arrangements[trp["trov:accessedArrangement"]["@id"]]["name"]
Expand Down
Loading