Skip to content

Commit 74d4870

Browse files
authored
♻️🎨 ooil config init to create first .osparc config layout (#5913)
1 parent 009f1b2 commit 74d4870

File tree

15 files changed

+265
-176
lines changed

15 files changed

+265
-176
lines changed

packages/service-integration/requirements/_base.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
--requirement ../../../packages/models-library/requirements/_base.in
77

88
click
9+
cookiecutter
910
docker # pytest-plugin
11+
jinja2_time
1012
jsonschema # pytest-plugin
1113
pytest # pytest-plugin
1214
pyyaml

packages/service-integration/requirements/_base.txt

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
arrow==1.3.0
2-
# via -r requirements/../../../packages/models-library/requirements/_base.in
2+
# via
3+
# -r requirements/../../../packages/models-library/requirements/_base.in
4+
# cookiecutter
5+
# jinja2-time
36
attrs==23.2.0
47
# via
58
# jsonschema
69
# referencing
10+
binaryornot==0.4.4
11+
# via cookiecutter
712
certifi==2024.2.2
813
# via
914
# -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
1015
# -c requirements/../../../requirements/constraints.txt
1116
# requests
17+
chardet==5.2.0
18+
# via binaryornot
1219
charset-normalizer==3.3.2
1320
# via requests
1421
click==8.1.7
1522
# via
1623
# -r requirements/_base.in
24+
# cookiecutter
1725
# typer
26+
cookiecutter==2.6.0
27+
# via -r requirements/_base.in
1828
dnspython==2.6.1
1929
# via email-validator
2030
docker==7.1.0
@@ -29,6 +39,14 @@ idna==3.7
2939
# requests
3040
iniconfig==2.0.0
3141
# via pytest
42+
jinja2==3.1.4
43+
# via
44+
# -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
45+
# -c requirements/../../../requirements/constraints.txt
46+
# cookiecutter
47+
# jinja2-time
48+
jinja2-time==0.2.0
49+
# via -r requirements/_base.in
3250
jsonschema==4.22.0
3351
# via
3452
# -r requirements/../../../packages/models-library/requirements/_base.in
@@ -37,6 +55,8 @@ jsonschema-specifications==2023.12.1
3755
# via jsonschema
3856
markdown-it-py==3.0.0
3957
# via rich
58+
markupsafe==2.1.5
59+
# via jinja2
4060
mdurl==0.1.2
4161
# via markdown-it-py
4262
orjson==3.10.3
@@ -59,19 +79,26 @@ pytest==8.2.0
5979
# via -r requirements/_base.in
6080
python-dateutil==2.9.0.post0
6181
# via arrow
82+
python-slugify==8.0.4
83+
# via cookiecutter
6284
pyyaml==6.0.1
6385
# via
6486
# -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
6587
# -c requirements/../../../requirements/constraints.txt
6688
# -r requirements/_base.in
89+
# cookiecutter
6790
referencing==0.35.1
6891
# via
6992
# jsonschema
7093
# jsonschema-specifications
7194
requests==2.32.2
72-
# via docker
95+
# via
96+
# cookiecutter
97+
# docker
7398
rich==13.7.1
74-
# via typer
99+
# via
100+
# cookiecutter
101+
# typer
75102
rpds-py==0.18.0
76103
# via
77104
# jsonschema
@@ -80,6 +107,8 @@ shellingham==1.5.4
80107
# via typer
81108
six==1.16.0
82109
# via python-dateutil
110+
text-unidecode==1.3
111+
# via python-slugify
83112
tomli==2.0.1
84113
# via pytest
85114
typer==0.12.3

packages/service-integration/scripts/ooil.bash

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ set -o nounset
66
set -o pipefail
77
IFS=$'\n\t'
88

9-
IMAGE_NAME="${DOCKER_REGISTRY:-itisfoundation}/service-integration:${OOIL_IMAGE_TAG:-master-github-latest}"
9+
IMAGE_NAME="${DOCKER_REGISTRY:-local}/service-integration:${OOIL_IMAGE_TAG:-production}"
1010
WORKDIR="$(pwd)"
1111

1212
#
@@ -20,6 +20,7 @@ WORKDIR="$(pwd)"
2020
run() {
2121
docker run \
2222
--rm \
23+
--tty \
2324
--volume="/etc/group:/etc/group:ro" \
2425
--volume="/etc/passwd:/etc/passwd:ro" \
2526
--user="$(id --user "$USER")":"$(id --group "$USER")" \

packages/service-integration/src/service_integration/cli.py

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Allows entrypoint via python -m as well
2+
3+
from typing import Annotated
4+
5+
import rich
6+
import typer
7+
8+
from .._meta import __version__
9+
from ..settings import AppSettings
10+
from . import _compose_spec, _metadata, _run_creator, _test
11+
from ._config import config_app
12+
13+
app = typer.Typer()
14+
15+
16+
def _version_callback(value: bool): # noqa: FBT002
17+
if value:
18+
rich.print(__version__)
19+
raise typer.Exit
20+
21+
22+
@app.callback()
23+
def main(
24+
ctx: typer.Context,
25+
registry_name: Annotated[
26+
str,
27+
typer.Option(
28+
"--REGISTRY_NAME",
29+
help="image registry name. Full url or prefix used as prefix in an image name",
30+
),
31+
] = None,
32+
compose_version: Annotated[
33+
str,
34+
typer.Option(
35+
"--COMPOSE_VERSION",
36+
help="version used for docker compose specification",
37+
),
38+
] = None,
39+
version: Annotated[ # noqa: FBT002
40+
bool,
41+
typer.Option(
42+
"--version",
43+
callback=_version_callback,
44+
is_eager=True,
45+
),
46+
] = False,
47+
):
48+
"""o2s2parc service Integration Library (OOIL in short)"""
49+
assert isinstance(version, bool | None) # nosec
50+
51+
overrides = {}
52+
if registry_name:
53+
overrides["REGISTRY_NAME"] = registry_name
54+
55+
if compose_version:
56+
overrides["COMPOSE_VERSION"] = compose_version
57+
58+
# save states
59+
ctx.settings = AppSettings.parse_obj(overrides)
60+
61+
62+
#
63+
# REGISTER commands and/or sub-apps
64+
#
65+
66+
app.command("compose")(_compose_spec.create_compose)
67+
app.add_typer(config_app, name="config", help="Manage osparc config files")
68+
app.command("test")(_test.run_tests)
69+
# legacy
70+
app.command("bump-version")(_metadata.bump_version)
71+
app.command("get-version")(_metadata.get_version)
72+
app.command("run-creator")(_run_creator.run_creator)

packages/service-integration/src/service_integration/commands/compose.py renamed to packages/service-integration/src/service_integration/cli/_compose_spec.py

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import subprocess
2-
from datetime import datetime
32
from pathlib import Path
3+
from typing import Annotated
44

5+
import arrow
56
import rich
67
import typer
78
import yaml
89
from models_library.utils.labels_annotations import to_labels
910
from rich.console import Console
1011

1112
from ..compose_spec_model import ComposeSpecification
13+
from ..errors import UndefinedOciImageSpecError
1214
from ..oci_image_spec import LS_LABEL_PREFIX, OCI_LABEL_PREFIX
1315
from ..osparc_config import (
1416
OSPARC_CONFIG_DIRNAME,
@@ -61,10 +63,10 @@ def create_docker_compose_image_spec(
6163

6264
config_basedir = meta_config_path.parent
6365

64-
# required
66+
# REQUIRED
6567
meta_cfg = MetadataConfig.from_yaml(meta_config_path)
6668

67-
# required
69+
# REQUIRED
6870
if docker_compose_overwrite_path:
6971
docker_compose_overwrite_cfg = DockerComposeOverwriteConfig.from_yaml(
7072
docker_compose_overwrite_path
@@ -74,11 +76,10 @@ def create_docker_compose_image_spec(
7476
service_name=meta_cfg.service_name()
7577
)
7678

77-
# optional
79+
# OPTIONAL
7880
runtime_cfg = None
7981
if service_config_path:
8082
try:
81-
# TODO: should include default?
8283
runtime_cfg = RuntimeConfig.from_yaml(service_config_path)
8384
except FileNotFoundError:
8485
rich.print("No runtime config found (optional), using default.")
@@ -90,13 +91,11 @@ def create_docker_compose_image_spec(
9091
(config_basedir / f"{OCI_LABEL_PREFIX}.yml").read_text()
9192
)
9293
if not oci_spec:
93-
msg = "Undefined OCI image spec"
94-
raise ValueError(msg)
94+
raise UndefinedOciImageSpecError
9595

9696
oci_labels = to_labels(oci_spec, prefix_key=OCI_LABEL_PREFIX)
9797
extra_labels.update(oci_labels)
98-
except (FileNotFoundError, ValueError):
99-
98+
except (FileNotFoundError, UndefinedOciImageSpecError):
10099
try:
101100
# if not OCI, try label-schema
102101
ls_spec = yaml.safe_load(
@@ -109,9 +108,11 @@ def create_docker_compose_image_spec(
109108
"No explicit config for OCI/label-schema found (optional), skipping OCI annotations."
110109
)
111110
# add required labels
112-
extra_labels[f"{LS_LABEL_PREFIX}.build-date"] = datetime.utcnow().strftime(
113-
"%Y-%m-%dT%H:%M:%SZ"
114-
)
111+
112+
# SEE https://github.com/opencontainers/image-spec/blob/main/annotations.md#pre-defined-annotation-keys
113+
# Format the datetime object as a string following RFC-3339
114+
rfc3339_format = arrow.now().format("YYYY-MM-DDTHH:mm:ssZ")
115+
extra_labels[f"{LS_LABEL_PREFIX}.build-date"] = rfc3339_format
115116
extra_labels[f"{LS_LABEL_PREFIX}.schema-version"] = "1.0"
116117

117118
extra_labels[f"{LS_LABEL_PREFIX}.vcs-ref"] = _run_git_or_empty_string(
@@ -130,25 +131,28 @@ def create_docker_compose_image_spec(
130131
)
131132

132133

133-
def main(
134+
def create_compose(
134135
ctx: typer.Context,
135-
config_path: Path = typer.Option(
136-
OSPARC_CONFIG_DIRNAME,
137-
"-m",
138-
"--metadata",
139-
help="osparc config file or folder. "
140-
"If the latter, it will scan for configs using the glob pattern 'config_path/**/metadata.yml' ",
141-
),
142-
to_spec_file: Path = typer.Option(
143-
Path("docker-compose.yml"),
144-
"-f",
145-
"--to-spec-file",
146-
help="Output docker-compose image spec",
147-
),
136+
config_path: Annotated[
137+
Path,
138+
typer.Option(
139+
"-m",
140+
"--metadata",
141+
help="osparc config file or folder. "
142+
"If the latter, it will scan for configs using the glob pattern 'config_path/**/metadata.yml' ",
143+
),
144+
] = Path(OSPARC_CONFIG_DIRNAME),
145+
to_spec_file: Annotated[
146+
Path,
147+
typer.Option(
148+
"-f",
149+
"--to-spec-file",
150+
help="Output docker-compose image spec",
151+
),
152+
] = Path("docker-compose.yml"),
148153
):
149-
"""create docker image/runtime compose-specs from an osparc config"""
154+
"""Creates the docker image/runtime compose-spec file from an .osparc config"""
150155

151-
# TODO: all these MUST be replaced by osparc_config.ConfigFilesStructure
152156
if not config_path.exists():
153157
msg = "Invalid path to metadata file or folder"
154158
raise typer.BadParameter(msg)
@@ -168,10 +172,10 @@ def main(
168172
config_name = meta_config.parent.name
169173
configs_kwargs_map[config_name] = {}
170174

171-
# load meta [required]
175+
# load meta REQUIRED
172176
configs_kwargs_map[config_name]["meta_config_path"] = meta_config
173177

174-
# others [optional]
178+
# others OPTIONAL
175179
for file_name, arg_name in (
176180
("docker-compose.overwrite.yml", "docker_compose_overwrite_path"),
177181
("runtime.yml", "service_config_path"),
@@ -194,7 +198,6 @@ def main(
194198
settings, **configs_kwargs_map[config_name]
195199
).dict(exclude_unset=True)
196200

197-
# FIXME: shaky! why first decides ??
198201
if n == 0:
199202
compose_spec_dict = nth_compose_spec
200203
else:

0 commit comments

Comments
 (0)