poetry-plugin-ivcap 0.5.1__py3-none-any.whl → 0.6.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.
- poetry_plugin_ivcap/constants.py +5 -4
- poetry_plugin_ivcap/docker.py +24 -13
- poetry_plugin_ivcap/ivcap.py +57 -29
- poetry_plugin_ivcap/plugin.py +48 -19
- poetry_plugin_ivcap/types.py +38 -0
- poetry_plugin_ivcap/util.py +1 -1
- {poetry_plugin_ivcap-0.5.1.dist-info → poetry_plugin_ivcap-0.6.0.dist-info}/METADATA +23 -3
- poetry_plugin_ivcap-0.6.0.dist-info/RECORD +12 -0
- poetry_plugin_ivcap-0.5.1.dist-info/RECORD +0 -11
- {poetry_plugin_ivcap-0.5.1.dist-info → poetry_plugin_ivcap-0.6.0.dist-info}/AUTHORS.md +0 -0
- {poetry_plugin_ivcap-0.5.1.dist-info → poetry_plugin_ivcap-0.6.0.dist-info}/LICENSE +0 -0
- {poetry_plugin_ivcap-0.5.1.dist-info → poetry_plugin_ivcap-0.6.0.dist-info}/WHEEL +0 -0
- {poetry_plugin_ivcap-0.5.1.dist-info → poetry_plugin_ivcap-0.6.0.dist-info}/entry_points.txt +0 -0
poetry_plugin_ivcap/constants.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c)
|
|
2
|
+
# Copyright (c) 2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
3
|
# Use of this source code is governed by a BSD-style license that can be
|
|
4
4
|
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
5
|
#
|
|
@@ -19,7 +19,7 @@ DOCKER_BUILD_TEMPLATE_OPT = "docker-build-template"
|
|
|
19
19
|
|
|
20
20
|
DEF_POLICY = "urn:ivcap:policy:ivcap.base.metadata"
|
|
21
21
|
DEF_PORT = 8000
|
|
22
|
-
|
|
22
|
+
DEF_IVCAP_URL = "https://develop.ivcap.net"
|
|
23
23
|
|
|
24
24
|
DOCKER_BUILD_TEMPLATE = """
|
|
25
25
|
docker buildx build
|
|
@@ -34,7 +34,8 @@ docker buildx build
|
|
|
34
34
|
DOCKER_LAMBDA_RUN_TEMPLATE = """
|
|
35
35
|
docker run -it
|
|
36
36
|
-p #PORT#:#PORT#
|
|
37
|
-
-e
|
|
37
|
+
-e IVCAP_URL=#IVCAP_URL#
|
|
38
|
+
-e IVCAP_JWT=#IVCAP_JWT#
|
|
38
39
|
--platform=linux/#ARCH#
|
|
39
40
|
--rm \
|
|
40
41
|
#NAME#_#ARCH#:#TAG#
|
|
@@ -42,7 +43,7 @@ DOCKER_LAMBDA_RUN_TEMPLATE = """
|
|
|
42
43
|
|
|
43
44
|
DOCKER_BATCH_RUN_TEMPLATE = """
|
|
44
45
|
docker run -it
|
|
45
|
-
-e
|
|
46
|
+
-e IVCAP_URL=#IVCAP_URL#
|
|
46
47
|
--platform=linux/#ARCH#
|
|
47
48
|
-v #PROJECT_DIR#:/data
|
|
48
49
|
--rm \
|
poetry_plugin_ivcap/docker.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c)
|
|
2
|
+
# Copyright (c) 2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
3
|
# Use of this source code is governed by a BSD-style license that can be
|
|
4
4
|
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
5
|
#
|
|
@@ -8,20 +8,25 @@ import os
|
|
|
8
8
|
import re
|
|
9
9
|
import sys
|
|
10
10
|
import tempfile
|
|
11
|
-
from typing import Dict, List, Optional
|
|
12
|
-
from pydantic import BaseModel, Field
|
|
11
|
+
from typing import Any, Dict, List, Optional
|
|
12
|
+
from pydantic import BaseModel, Field, SkipValidation
|
|
13
13
|
import subprocess
|
|
14
14
|
|
|
15
|
-
from .constants import
|
|
15
|
+
from .constants import (
|
|
16
|
+
DEF_IVCAP_URL, DEF_PORT, DOCKER_BATCH_RUN_TEMPLATE, DOCKER_BUILD_TEMPLATE, DOCKER_BUILD_TEMPLATE_OPT,
|
|
17
|
+
DOCKER_LAMBDA_RUN_TEMPLATE, DOCKER_RUN_OPT, DOCKER_RUN_TEMPLATE_OPT, PLUGIN_NAME, SERVICE_TYPE_OPT
|
|
18
|
+
)
|
|
16
19
|
from .util import command_exists, get_name, get_version
|
|
20
|
+
from .types import BaseConfig
|
|
17
21
|
|
|
18
|
-
class DockerConfig(
|
|
22
|
+
class DockerConfig(BaseConfig):
|
|
19
23
|
name: Optional[str] = Field(None)
|
|
20
24
|
tag: Optional[str] = Field(None)
|
|
21
25
|
arch: Optional[str] = Field(None)
|
|
22
26
|
version: Optional[str] = Field(None)
|
|
23
27
|
dockerfile: Optional[str] = Field("Dockerfile")
|
|
24
28
|
project_dir: Optional[str] = Field(os.getcwd())
|
|
29
|
+
line: SkipValidation[Any]
|
|
25
30
|
|
|
26
31
|
@property
|
|
27
32
|
def docker_name(self) -> str:
|
|
@@ -66,10 +71,10 @@ class DockerConfig(BaseModel):
|
|
|
66
71
|
port_in_args = False
|
|
67
72
|
port = str(pdata.get("port", DEF_PORT))
|
|
68
73
|
|
|
69
|
-
base_url = os.environ.get("IVCAP_BASE_URL", DEF_IVCAP_BASE_URL)
|
|
70
74
|
t = template.strip()\
|
|
71
75
|
.replace("#DOCKER_NAME#", self.docker_name)\
|
|
72
|
-
.replace("#
|
|
76
|
+
.replace("#IVCAP_URL#", self.ivcap_url)\
|
|
77
|
+
.replace("#IVCAP_JWT#", self.ivcap_jwt)\
|
|
73
78
|
.replace("#NAME#", self.name)\
|
|
74
79
|
.replace("#TAG#", self.tag)\
|
|
75
80
|
.replace("#PORT#", port)\
|
|
@@ -84,7 +89,6 @@ class DockerConfig(BaseModel):
|
|
|
84
89
|
cmd.extend(["--port", port])
|
|
85
90
|
return cmd
|
|
86
91
|
|
|
87
|
-
|
|
88
92
|
def docker_build(data: dict, line, arch = None) -> None:
|
|
89
93
|
check_docker_cmd(line)
|
|
90
94
|
config = docker_cfg(data, line, arch)
|
|
@@ -102,19 +106,26 @@ def docker_run(data: dict, args, line) -> None:
|
|
|
102
106
|
check_docker_cmd(line)
|
|
103
107
|
config = docker_cfg(data, line)
|
|
104
108
|
build_run = config.from_run_template(data, args, line)
|
|
105
|
-
|
|
109
|
+
log_run(build_run, line)
|
|
106
110
|
process = subprocess.Popen(build_run, stdout=sys.stdout, stderr=sys.stderr)
|
|
111
|
+
print(">>>> 2")
|
|
107
112
|
exit_code = process.wait()
|
|
113
|
+
print(">>>> 3")
|
|
108
114
|
if exit_code != 0:
|
|
109
115
|
line(f"<error>ERROR: Docker run failed with exit code {exit_code}</error>")
|
|
110
116
|
else:
|
|
111
117
|
line("<info>INFO: Docker run completed successfully</info>")
|
|
112
118
|
|
|
119
|
+
mask_token = re.compile(r'''(?<!\w)(IVCAP_JWT=)(?:(["'])(.*?)\2|(\S+))''')
|
|
120
|
+
def log_run(cmd, line):
|
|
121
|
+
masked_cmd = mask_token.sub("IVCAP_JWT=***", ' '.join(cmd))
|
|
122
|
+
line(f"<info>INFO: {masked_cmd}</info>")
|
|
123
|
+
|
|
113
124
|
def docker_cfg(data: dict, line, arch = None) -> DockerConfig:
|
|
114
125
|
name = get_name(data)
|
|
115
126
|
|
|
116
127
|
pdata = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
117
|
-
config = DockerConfig(name=name, **pdata.get("docker", {}))
|
|
128
|
+
config = DockerConfig(name=name, line=line, **pdata.get("docker", {}))
|
|
118
129
|
if arch:
|
|
119
130
|
# override architecture if provided
|
|
120
131
|
config.arch = arch
|
|
@@ -134,7 +145,7 @@ def docker_cfg(data: dict, line, arch = None) -> DockerConfig:
|
|
|
134
145
|
config.arch = subprocess.check_output(['uname', '-m']).decode().strip()
|
|
135
146
|
except Exception as e:
|
|
136
147
|
line(f"<error>ERROR: cannot obtain build architecture: {e}</error>")
|
|
137
|
-
|
|
148
|
+
sys.exit(1)
|
|
138
149
|
|
|
139
150
|
return config
|
|
140
151
|
|
|
@@ -162,9 +173,9 @@ def docker_push(docker_img, line):
|
|
|
162
173
|
line(f"<error>ERROR: package push failed with exit code {exit_code}</error>")
|
|
163
174
|
sys.exit(1)
|
|
164
175
|
|
|
165
|
-
#
|
|
176
|
+
# Looking for "45a06508-5c3a-4678-8e6d-e6399bf27538/gene_onology_term_mapper_amd64:9a9a7cc pushed\n"
|
|
166
177
|
pattern = re.compile(
|
|
167
|
-
r'([0-9a-f]{8}
|
|
178
|
+
r'(?:(?:[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})/)?([^\s]+) pushed'
|
|
168
179
|
)
|
|
169
180
|
package_name = None
|
|
170
181
|
with open(tmp_path, 'r') as f:
|
poetry_plugin_ivcap/ivcap.py
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c)
|
|
2
|
+
# Copyright (c) 2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
3
|
# Use of this source code is governed by a BSD-style license that can be
|
|
4
4
|
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
5
|
#
|
|
6
|
+
from typing import Optional
|
|
6
7
|
import argparse
|
|
7
8
|
import os
|
|
8
9
|
import re
|
|
@@ -16,8 +17,7 @@ import requests
|
|
|
16
17
|
import time
|
|
17
18
|
import json
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
from .constants import DEF_POLICY, PLUGIN_NAME, POLICY_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, DEF_IVCAP_BASE_URL
|
|
20
|
+
from .constants import DEF_POLICY, PLUGIN_NAME, POLICY_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, DEF_IVCAP_URL
|
|
21
21
|
|
|
22
22
|
from .docker import docker_cfg, docker_build, docker_push
|
|
23
23
|
from .util import command_exists, get_name, string_to_number
|
|
@@ -36,6 +36,29 @@ def docker_publish(data, line):
|
|
|
36
36
|
pkg_name = docker_push(dname, line)
|
|
37
37
|
|
|
38
38
|
def service_register(data, line):
|
|
39
|
+
svc = service_description(data, line)
|
|
40
|
+
|
|
41
|
+
with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
|
|
42
|
+
tmp.write(svc)
|
|
43
|
+
tmp_path = tmp.name # Save the file name for subprocess
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
policy = get_policy(data, line)
|
|
47
|
+
up_cmd = ["ivcap", "aspect", "update", "--policy", policy, service_id, "-f", tmp_path]
|
|
48
|
+
try:
|
|
49
|
+
line(f"<debug>Running: {' '.join(up_cmd)} </debug>")
|
|
50
|
+
jaid = subprocess.check_output(up_cmd).decode().strip()
|
|
51
|
+
p = re.compile(r'.*(urn:[^"]*)')
|
|
52
|
+
aid = p.search(jaid).group(1)
|
|
53
|
+
line(f"<info>INFO: service definition successfully uploaded - {aid}</info>")
|
|
54
|
+
except Exception as e:
|
|
55
|
+
line(f"<error>ERROR: cannot upload service definitiion: {e}</error>")
|
|
56
|
+
sys.exit(1)
|
|
57
|
+
finally:
|
|
58
|
+
if os.path.exists(tmp_path):
|
|
59
|
+
os.remove(tmp_path)
|
|
60
|
+
|
|
61
|
+
def service_description(data, line):
|
|
39
62
|
check_ivcap_cmd(line)
|
|
40
63
|
config = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
41
64
|
|
|
@@ -56,11 +79,15 @@ def service_register(data, line):
|
|
|
56
79
|
cmd = ["poetry", "run", "python", service, "--print-service-description"]
|
|
57
80
|
line(f"<debug>Running: {' '.join(cmd)} </debug>")
|
|
58
81
|
env = os.environ.copy()
|
|
59
|
-
env.setdefault("
|
|
82
|
+
env.setdefault("IVCAP_URL", DEF_IVCAP_URL)
|
|
60
83
|
svc = subprocess.check_output(cmd, env=env).decode()
|
|
61
84
|
|
|
62
85
|
svc = svc.replace("#DOCKER_IMG#", pkg.strip())\
|
|
63
86
|
.replace("#SERVICE_ID#", service_id)
|
|
87
|
+
return svc
|
|
88
|
+
|
|
89
|
+
def tool_register(data, line):
|
|
90
|
+
svc = tool_description(data, line)
|
|
64
91
|
|
|
65
92
|
with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
|
|
66
93
|
tmp.write(svc)
|
|
@@ -74,15 +101,15 @@ def service_register(data, line):
|
|
|
74
101
|
jaid = subprocess.check_output(up_cmd).decode().strip()
|
|
75
102
|
p = re.compile(r'.*(urn:[^"]*)')
|
|
76
103
|
aid = p.search(jaid).group(1)
|
|
77
|
-
line(f"<info>INFO:
|
|
104
|
+
line(f"<info>INFO: tool description successfully uploaded - {aid}</info>")
|
|
78
105
|
except Exception as e:
|
|
79
|
-
line(f"<error>ERROR: cannot upload
|
|
106
|
+
line(f"<error>ERROR: cannot upload tool description: {e}</error>")
|
|
80
107
|
sys.exit(1)
|
|
81
108
|
finally:
|
|
82
109
|
if os.path.exists(tmp_path):
|
|
83
110
|
os.remove(tmp_path)
|
|
84
111
|
|
|
85
|
-
def
|
|
112
|
+
def tool_description(data, line) -> str:
|
|
86
113
|
check_ivcap_cmd(line)
|
|
87
114
|
config = data.get("tool", {}).get(PLUGIN_NAME, {})
|
|
88
115
|
|
|
@@ -94,31 +121,12 @@ def tool_register(data, line):
|
|
|
94
121
|
cmd = ["poetry", "run", "python", service, "--print-tool-description"]
|
|
95
122
|
line(f"<debug>Running: {' '.join(cmd)} </debug>")
|
|
96
123
|
env = os.environ.copy()
|
|
97
|
-
env.setdefault("
|
|
124
|
+
env.setdefault("IVCAP_URL", DEF_IVCAP_URL)
|
|
98
125
|
svc = subprocess.check_output(cmd, env=env).decode()
|
|
99
126
|
|
|
100
127
|
service_id = get_service_id(data, False, line)
|
|
101
128
|
svc = svc.replace("#SERVICE_ID#", service_id)
|
|
102
|
-
|
|
103
|
-
with tempfile.NamedTemporaryFile(mode='w+', delete=False) as tmp:
|
|
104
|
-
tmp.write(svc)
|
|
105
|
-
tmp_path = tmp.name # Save the file name for subprocess
|
|
106
|
-
|
|
107
|
-
try:
|
|
108
|
-
policy = get_policy(data, line)
|
|
109
|
-
up_cmd = ["ivcap", "aspect", "update", "--policy", policy, service_id, "-f", tmp_path]
|
|
110
|
-
try:
|
|
111
|
-
line(f"<debug>Running: {' '.join(up_cmd)} </debug>")
|
|
112
|
-
jaid = subprocess.check_output(up_cmd).decode().strip()
|
|
113
|
-
p = re.compile(r'.*(urn:[^"]*)')
|
|
114
|
-
aid = p.search(jaid).group(1)
|
|
115
|
-
line(f"<info>INFO: tool description successfully uploaded - {aid}</info>")
|
|
116
|
-
except Exception as e:
|
|
117
|
-
line(f"<error>ERROR: cannot upload tool description: {e}</error>")
|
|
118
|
-
sys.exit(1)
|
|
119
|
-
finally:
|
|
120
|
-
if os.path.exists(tmp_path):
|
|
121
|
-
os.remove(tmp_path)
|
|
129
|
+
return svc
|
|
122
130
|
|
|
123
131
|
def get_service_id(data, is_silent, line):
|
|
124
132
|
service_id = data.get("tool", {}).get(PLUGIN_NAME, {}).get(SERVICE_ID_OPT)
|
|
@@ -400,4 +408,24 @@ def check_ivcap_cmd(line, is_silent=False):
|
|
|
400
408
|
if not command_exists("ivcap"):
|
|
401
409
|
line("<error>'ivcap' command not found. Please install the IVCAP CLI tool.</error>")
|
|
402
410
|
line("<error>... see https://github.com/ivcap-works/ivcap-cli?tab=readme-ov-file#install-released-binaries for instructions</error>")
|
|
403
|
-
|
|
411
|
+
sys.exit(1)
|
|
412
|
+
|
|
413
|
+
def ivcap_cli_version() -> Optional[str]:
|
|
414
|
+
# Best-effort: also report the installed external `ivcap` CLI version.
|
|
415
|
+
# Expected output:
|
|
416
|
+
# ivcap version 0.47.0|a4f9b30|2026-01-30T04:45:00Z
|
|
417
|
+
ivcap_version = None
|
|
418
|
+
try:
|
|
419
|
+
res = subprocess.run(
|
|
420
|
+
["ivcap", "--version"],
|
|
421
|
+
capture_output=True,
|
|
422
|
+
text=True,
|
|
423
|
+
check=False,
|
|
424
|
+
)
|
|
425
|
+
raw = (res.stdout or res.stderr or "").strip()
|
|
426
|
+
m = re.search(r"\bivcap\s+version\s+([0-9]+(?:\.[0-9]+)+)", raw)
|
|
427
|
+
if m:
|
|
428
|
+
return m.group(1)
|
|
429
|
+
except FileNotFoundError:
|
|
430
|
+
# `ivcap` is not installed / not on PATH
|
|
431
|
+
return
|
poetry_plugin_ivcap/plugin.py
CHANGED
|
@@ -1,22 +1,49 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c)
|
|
2
|
+
# Copyright (c) 2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
3
|
# Use of this source code is governed by a BSD-style license that can be
|
|
4
4
|
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
5
|
#
|
|
6
6
|
import os
|
|
7
|
+
import re
|
|
7
8
|
from poetry.plugins.application_plugin import ApplicationPlugin
|
|
8
9
|
from cleo.commands.command import Command
|
|
9
10
|
from cleo.helpers import argument, option
|
|
10
11
|
import subprocess
|
|
11
12
|
from importlib.metadata import version
|
|
12
13
|
|
|
13
|
-
from poetry_plugin_ivcap.constants import
|
|
14
|
+
from poetry_plugin_ivcap.constants import DEF_IVCAP_URL, DOCKER_BUILD_TEMPLATE_OPT, DOCKER_RUN_TEMPLATE_OPT, PLUGIN_CMD, PLUGIN_NAME
|
|
14
15
|
from poetry_plugin_ivcap.constants import PORT_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, SERVICE_TYPE_OPT, POLICY_OPT
|
|
16
|
+
from poetry_plugin_ivcap.types import BaseConfig
|
|
15
17
|
from poetry_plugin_ivcap.util import get_version
|
|
16
18
|
|
|
17
19
|
from .ivcap import create_service_id, exec_job, get_service_id, service_register, tool_register
|
|
18
20
|
from .docker import docker_build, docker_run
|
|
19
|
-
from .ivcap import docker_publish
|
|
21
|
+
from .ivcap import docker_publish, ivcap_cli_version, service_description, tool_description
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_SUBCOMMANDS = [
|
|
25
|
+
("run", "Run the service locally"),
|
|
26
|
+
("docker-build", "Build the docker image for this service"),
|
|
27
|
+
("docker-run", "Run the service's docker image locally for testing"),
|
|
28
|
+
(
|
|
29
|
+
"deploy",
|
|
30
|
+
"Deploy the service to IVCAP (calls docker-publish, service-register and tool-register)",
|
|
31
|
+
),
|
|
32
|
+
("job-exec file_name", "Execute a job defined in 'file_name'"),
|
|
33
|
+
("docker-publish", "Publish the service's docker image to IVCAP"),
|
|
34
|
+
("service-register", "Register the service with IVCAP"),
|
|
35
|
+
("tool-register", "Register the service as an AI Tool with IVCAP"),
|
|
36
|
+
("create-service-id", "Create a unique service ID for the service"),
|
|
37
|
+
("get-service-id", "Return the service ID for the service"),
|
|
38
|
+
("get-service-description", "Return the service description as json"),
|
|
39
|
+
("get-tool-description", "Return the tool description as json"),
|
|
40
|
+
("version", "Print the version of this plugin"),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
_SUBCOMMANDS_COL_WIDTH = max(len(cmd) for cmd, _ in _SUBCOMMANDS)
|
|
44
|
+
_SUBCOMMANDS_HELP = "\n".join(
|
|
45
|
+
f" {cmd.ljust(_SUBCOMMANDS_COL_WIDTH)} {desc}" for cmd, desc in _SUBCOMMANDS
|
|
46
|
+
)
|
|
20
47
|
|
|
21
48
|
class IvcapCommand(Command):
|
|
22
49
|
name = "ivcap"
|
|
@@ -28,21 +55,12 @@ IVCAP plugin
|
|
|
28
55
|
Supporting the development of services and tools for the IVCAP platform
|
|
29
56
|
|
|
30
57
|
Available subcommands:
|
|
31
|
-
|
|
32
|
-
docker-build Build the docker image for this service
|
|
33
|
-
docker-run Run the service's docker image locally for testing
|
|
34
|
-
deploy Deploy the service to IVCAP (calls docker-publish, service-register and tool-register)
|
|
35
|
-
job-exec file_name Execute a job defined in 'file_name'
|
|
36
|
-
docker-publish Publish the service's docker image to IVCAP
|
|
37
|
-
service-register Register the service with IVCAP
|
|
38
|
-
create-service-id Create a unique service ID for the service
|
|
39
|
-
get-service-id Return the service ID for the service
|
|
40
|
-
tool-register Register the service as an AI Tool with IVCAP
|
|
41
|
-
version Print the version of this plugin
|
|
58
|
+
{_SUBCOMMANDS_HELP}
|
|
42
59
|
|
|
43
60
|
Example:
|
|
44
61
|
poetry {PLUGIN_CMD} run -- --port 8080
|
|
45
62
|
poetry {PLUGIN_CMD} job-exec request.json -- --timeout 0 # don't wait for result
|
|
63
|
+
poetry {PLUGIN_CMD} job-exec request.json -- --watch # shows all the events produced by the service
|
|
46
64
|
|
|
47
65
|
Configurable options in pyproject.toml:
|
|
48
66
|
|
|
@@ -70,15 +88,18 @@ Configurable options in pyproject.toml:
|
|
|
70
88
|
def handle(self):
|
|
71
89
|
|
|
72
90
|
sub = self.argument("subcommand")
|
|
91
|
+
poetry = self.application.poetry
|
|
92
|
+
|
|
73
93
|
if sub == "version":
|
|
74
|
-
#v = poetry.get_plugin('ivcap').version
|
|
75
94
|
v = version(PLUGIN_NAME)
|
|
76
|
-
|
|
95
|
+
ivcap_version = ivcap_cli_version()
|
|
96
|
+
if ivcap_version:
|
|
97
|
+
print(f"IVCAP plugin (version {v} - cli {ivcap_version})")
|
|
98
|
+
else:
|
|
99
|
+
print(f"IVCAP plugin (version {v})")
|
|
77
100
|
return
|
|
78
101
|
|
|
79
|
-
poetry = self.application.poetry
|
|
80
102
|
data = poetry.pyproject.data
|
|
81
|
-
|
|
82
103
|
args = self.argument("args")
|
|
83
104
|
is_silent = self.option("silent")
|
|
84
105
|
|
|
@@ -104,6 +125,12 @@ Configurable options in pyproject.toml:
|
|
|
104
125
|
elif sub == "get-service-id":
|
|
105
126
|
sid = get_service_id(data, is_silent, self.line)
|
|
106
127
|
print(sid)
|
|
128
|
+
elif sub == "get-service-description":
|
|
129
|
+
sd = service_description(data, self.line)
|
|
130
|
+
print(sd)
|
|
131
|
+
elif sub == "get-tool-description":
|
|
132
|
+
td = tool_description(data, self.line)
|
|
133
|
+
print(td)
|
|
107
134
|
elif sub == "tool-register":
|
|
108
135
|
tool_register(data, self.line)
|
|
109
136
|
|
|
@@ -127,7 +154,9 @@ Configurable options in pyproject.toml:
|
|
|
127
154
|
|
|
128
155
|
env = os.environ.copy()
|
|
129
156
|
env["VERSION"] = get_version(data, None, line)
|
|
130
|
-
|
|
157
|
+
cfg = BaseConfig(line=line)
|
|
158
|
+
env.setdefault("IVCAP_URL", cfg.ivcap_url)
|
|
159
|
+
env.setdefault("IVCAP_JWT", cfg.ivcap_jwt)
|
|
131
160
|
|
|
132
161
|
cmd = ["poetry", "run", "python", service]
|
|
133
162
|
cmd.extend(args)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
|
+
# Use of this source code is governed by a BSD-style license that can be
|
|
4
|
+
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
|
+
#
|
|
6
|
+
import os
|
|
7
|
+
import sys
|
|
8
|
+
from typing import Any
|
|
9
|
+
from pydantic import BaseModel, SkipValidation
|
|
10
|
+
import subprocess
|
|
11
|
+
|
|
12
|
+
from .constants import DEF_IVCAP_URL
|
|
13
|
+
|
|
14
|
+
class BaseConfig(BaseModel):
|
|
15
|
+
line: SkipValidation[Any]
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def ivcap_url(self) -> str:
|
|
19
|
+
base_url = os.environ.get("IVCAP_URL")
|
|
20
|
+
if not base_url:
|
|
21
|
+
cmd = ["ivcap", "context", "get", "url"]
|
|
22
|
+
self.line(f"<debug>Running: {' '.join(cmd)} </debug>")
|
|
23
|
+
base_url = subprocess.check_output(cmd).decode().strip()
|
|
24
|
+
if not base_url:
|
|
25
|
+
base_url = DEF_IVCAP_URL
|
|
26
|
+
return base_url
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def ivcap_jwt(self) -> str:
|
|
30
|
+
jwt = os.environ.get("IVCAP_JWT")
|
|
31
|
+
if not jwt:
|
|
32
|
+
cmd = ["ivcap", "context", "get", "access-token", "--refresh-token"]
|
|
33
|
+
self.line(f"<debug>Running: {' '.join(cmd)} </debug>")
|
|
34
|
+
jwt = subprocess.check_output(cmd).decode().strip()
|
|
35
|
+
if not jwt:
|
|
36
|
+
self.line("<error>ERROR: IVCAP JWT is not set. Please run 'ivcap login' first.</error>")
|
|
37
|
+
sys.exit(1)
|
|
38
|
+
return jwt
|
poetry_plugin_ivcap/util.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#
|
|
2
|
-
# Copyright (c)
|
|
2
|
+
# Copyright (c) 2026 Commonwealth Scientific and Industrial Research Organisation (CSIRO). All rights reserved.
|
|
3
3
|
# Use of this source code is governed by a BSD-style license that can be
|
|
4
4
|
# found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
5
5
|
#
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: poetry-plugin-ivcap
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A custom Poetry command for IVCAP deployments
|
|
5
5
|
License: MIT
|
|
6
6
|
Author: Max Ott
|
|
7
7
|
Author-email: max.ott@csiro.au
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
@@ -84,6 +83,27 @@ Configurable optiosn in pyproject.toml:
|
|
|
84
83
|
|
|
85
84
|
## Development
|
|
86
85
|
|
|
86
|
+
### Test the plugin as part of the "global" installed poetry
|
|
87
|
+
|
|
88
|
+
```shell
|
|
89
|
+
# 1) remove any existing installed copy first
|
|
90
|
+
poetry self remove poetry-plugin-ivcap
|
|
91
|
+
|
|
92
|
+
# 2) install this checkout as an editable plugin
|
|
93
|
+
poetry self add -e $PWD
|
|
94
|
+
|
|
95
|
+
# 3) verify Poetry sees the plugin
|
|
96
|
+
poetry self show plugins
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
Switch back:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
poetry self remove poetry-plugin-ivcap
|
|
104
|
+
poetry self add poetry-plugin-ivcap@latest
|
|
105
|
+
```
|
|
106
|
+
|
|
87
107
|
### Build the Plugin Package
|
|
88
108
|
|
|
89
109
|
```bash
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
poetry_plugin_ivcap/constants.py,sha256=1p7QAqdSyY5z0RqQUYtyyFEWqGEZy0NOppvJz093HLA,1326
|
|
2
|
+
poetry_plugin_ivcap/docker.py,sha256=WQwCvMYm804eLjZcinQ0ZpB2QFf4xDpME35NSuIDeo8,7706
|
|
3
|
+
poetry_plugin_ivcap/ivcap.py,sha256=5QHhMqVM1kZEL3S4LEwD9q7pI3l7huo2atqexmCDPVk,16339
|
|
4
|
+
poetry_plugin_ivcap/plugin.py,sha256=tMSEXEyP0YkUxkiKo2WRtcNarEBucLX07qy-itywQiw,6562
|
|
5
|
+
poetry_plugin_ivcap/types.py,sha256=LVB5D6LEyehls2BEWm-QVEQ2lQgGrJMKnfHbyTVPt2w,1351
|
|
6
|
+
poetry_plugin_ivcap/util.py,sha256=3DKFkTJkDClfz-j9nVnosWZKse62Les4w7kGKn0xcy4,3429
|
|
7
|
+
poetry_plugin_ivcap-0.6.0.dist-info/AUTHORS.md,sha256=s9xR4_HAHQgbNlj505LViebt5AtACQmhPf92aJvNYgg,88
|
|
8
|
+
poetry_plugin_ivcap-0.6.0.dist-info/LICENSE,sha256=dsQrDPPwW7iJs9pxahgJKDW8RNPf5FyXG70MFUlxcuk,1587
|
|
9
|
+
poetry_plugin_ivcap-0.6.0.dist-info/METADATA,sha256=YPje2ptaqu33nKcHcgsP-oV1bY_PbHpLuDGUeaJ0xl4,3390
|
|
10
|
+
poetry_plugin_ivcap-0.6.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
11
|
+
poetry_plugin_ivcap-0.6.0.dist-info/entry_points.txt,sha256=3xagEFBkGgrVe8WyjmhlHLr4JDEWPN_W4DwxnIBWbNY,74
|
|
12
|
+
poetry_plugin_ivcap-0.6.0.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
poetry_plugin_ivcap/constants.py,sha256=zsUnw-cS3uTqRlkAsWPYBeMpn5Wpz7r4ByjYaFZQFUo,1318
|
|
2
|
-
poetry_plugin_ivcap/docker.py,sha256=Pny5uF7juKy8Jld7D-5euAtgzguDZ8E2SRn-romk-Sg,7409
|
|
3
|
-
poetry_plugin_ivcap/ivcap.py,sha256=K-wZES-7EIViTnUZ4fklVqIr_uV-6KuQXM2ziNAwFHw,15490
|
|
4
|
-
poetry_plugin_ivcap/plugin.py,sha256=NWYdqjvlw3cqg4DVcEcZLGAVuL1aa9o0GmQGNZ6wfbI,5506
|
|
5
|
-
poetry_plugin_ivcap/util.py,sha256=bcjjbKoV_pAgeuC7Ws9XbJa3phFpNVyrRAlFJ1VubRg,3429
|
|
6
|
-
poetry_plugin_ivcap-0.5.1.dist-info/AUTHORS.md,sha256=s9xR4_HAHQgbNlj505LViebt5AtACQmhPf92aJvNYgg,88
|
|
7
|
-
poetry_plugin_ivcap-0.5.1.dist-info/LICENSE,sha256=dsQrDPPwW7iJs9pxahgJKDW8RNPf5FyXG70MFUlxcuk,1587
|
|
8
|
-
poetry_plugin_ivcap-0.5.1.dist-info/METADATA,sha256=_USNLVLTjHMkREPWR3CXnsuYSeWvRZJFT7JAJhtnePg,3032
|
|
9
|
-
poetry_plugin_ivcap-0.5.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
10
|
-
poetry_plugin_ivcap-0.5.1.dist-info/entry_points.txt,sha256=3xagEFBkGgrVe8WyjmhlHLr4JDEWPN_W4DwxnIBWbNY,74
|
|
11
|
-
poetry_plugin_ivcap-0.5.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{poetry_plugin_ivcap-0.5.1.dist-info → poetry_plugin_ivcap-0.6.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|