poetry-plugin-ivcap 0.5.0__py3-none-any.whl → 0.5.2__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 +4 -3
- poetry_plugin_ivcap/docker.py +20 -9
- poetry_plugin_ivcap/ivcap.py +98 -33
- poetry_plugin_ivcap/plugin.py +5 -2
- poetry_plugin_ivcap/types.py +38 -0
- {poetry_plugin_ivcap-0.5.0.dist-info → poetry_plugin_ivcap-0.5.2.dist-info}/METADATA +1 -1
- poetry_plugin_ivcap-0.5.2.dist-info/RECORD +12 -0
- poetry_plugin_ivcap-0.5.0.dist-info/RECORD +0 -11
- {poetry_plugin_ivcap-0.5.0.dist-info → poetry_plugin_ivcap-0.5.2.dist-info}/AUTHORS.md +0 -0
- {poetry_plugin_ivcap-0.5.0.dist-info → poetry_plugin_ivcap-0.5.2.dist-info}/LICENSE +0 -0
- {poetry_plugin_ivcap-0.5.0.dist-info → poetry_plugin_ivcap-0.5.2.dist-info}/WHEEL +0 -0
- {poetry_plugin_ivcap-0.5.0.dist-info → poetry_plugin_ivcap-0.5.2.dist-info}/entry_points.txt +0 -0
poetry_plugin_ivcap/constants.py
CHANGED
|
@@ -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
|
@@ -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
|
poetry_plugin_ivcap/ivcap.py
CHANGED
|
@@ -16,8 +16,7 @@ import requests
|
|
|
16
16
|
import time
|
|
17
17
|
import json
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
from .constants import DEF_POLICY, PLUGIN_NAME, POLICY_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, DEF_IVCAP_BASE_URL
|
|
19
|
+
from .constants import DEF_POLICY, PLUGIN_NAME, POLICY_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, DEF_IVCAP_URL
|
|
21
20
|
|
|
22
21
|
from .docker import docker_cfg, docker_build, docker_push
|
|
23
22
|
from .util import command_exists, get_name, string_to_number
|
|
@@ -56,7 +55,7 @@ def service_register(data, line):
|
|
|
56
55
|
cmd = ["poetry", "run", "python", service, "--print-service-description"]
|
|
57
56
|
line(f"<debug>Running: {' '.join(cmd)} </debug>")
|
|
58
57
|
env = os.environ.copy()
|
|
59
|
-
env.setdefault("
|
|
58
|
+
env.setdefault("IVCAP_URL", DEF_IVCAP_URL)
|
|
60
59
|
svc = subprocess.check_output(cmd, env=env).decode()
|
|
61
60
|
|
|
62
61
|
svc = svc.replace("#DOCKER_IMG#", pkg.strip())\
|
|
@@ -94,7 +93,7 @@ def tool_register(data, line):
|
|
|
94
93
|
cmd = ["poetry", "run", "python", service, "--print-tool-description"]
|
|
95
94
|
line(f"<debug>Running: {' '.join(cmd)} </debug>")
|
|
96
95
|
env = os.environ.copy()
|
|
97
|
-
env.setdefault("
|
|
96
|
+
env.setdefault("IVCAP_URL", DEF_IVCAP_URL)
|
|
98
97
|
svc = subprocess.check_output(cmd, env=env).decode()
|
|
99
98
|
|
|
100
99
|
service_id = get_service_id(data, False, line)
|
|
@@ -158,13 +157,15 @@ def exec_job(data, args, is_silent, line):
|
|
|
158
157
|
pa = p.parse_args(args)
|
|
159
158
|
timeout = 0 if pa.stream else pa.timeout
|
|
160
159
|
# Get access token using ivcap CLI
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
160
|
+
token = pa.auth_token
|
|
161
|
+
if not token:
|
|
162
|
+
try:
|
|
163
|
+
token = subprocess.check_output(
|
|
164
|
+
["ivcap", "--silent", "context", "get", "access-token", "--refresh-token"],
|
|
165
|
+
text=True
|
|
166
|
+
).strip()
|
|
167
|
+
except Exception as e:
|
|
168
|
+
raise RuntimeError(f"Failed to get IVCAP access token: {e}")
|
|
168
169
|
|
|
169
170
|
# Get IVCAP deployment URL
|
|
170
171
|
try:
|
|
@@ -211,15 +212,14 @@ def exec_job(data, args, is_silent, line):
|
|
|
211
212
|
location = f"{payload.get('location')}"
|
|
212
213
|
job_id = payload.get("job-id")
|
|
213
214
|
retry_later = payload.get("retry-later", 5)
|
|
214
|
-
if not is_silent:
|
|
215
|
-
line(f"<debug>Job '{job_id}' accepted, but no result yet. Polling in {retry_later} seconds.</debug>")
|
|
216
|
-
if pa.stream:
|
|
217
|
-
stream_result(location, token, pa)
|
|
218
|
-
else:
|
|
219
|
-
poll_for_result(location, retry_later, token, is_silent, line)
|
|
220
|
-
|
|
221
215
|
except Exception as e:
|
|
222
216
|
line(f"<error>Failed to handle 202 response: {e}</error>")
|
|
217
|
+
|
|
218
|
+
if pa.stream:
|
|
219
|
+
stream_result(location, job_id, token, pa, is_silent, line)
|
|
220
|
+
else:
|
|
221
|
+
poll_for_result(location, job_id, retry_later, token, is_silent, line)
|
|
222
|
+
|
|
223
223
|
else:
|
|
224
224
|
handle_response(response, line)
|
|
225
225
|
|
|
@@ -248,7 +248,9 @@ def handle_response(resp, line):
|
|
|
248
248
|
line(f"<warning>Headers: {str(resp.headers)}</warning>")
|
|
249
249
|
return "unknown"
|
|
250
250
|
|
|
251
|
-
def poll_for_result(location, retry_later, token, is_silent, line):
|
|
251
|
+
def poll_for_result(location, job_id, retry_later, token, is_silent, line):
|
|
252
|
+
if not is_silent:
|
|
253
|
+
line(f"<debug>Job '{job_id}' accepted, but no result yet. Polling in {retry_later} seconds.</debug>")
|
|
252
254
|
while True:
|
|
253
255
|
time.sleep(retry_later)
|
|
254
256
|
poll_headers = {
|
|
@@ -273,35 +275,97 @@ def poll_for_result(location, retry_later, token, is_silent, line):
|
|
|
273
275
|
else:
|
|
274
276
|
break
|
|
275
277
|
|
|
276
|
-
|
|
278
|
+
CONNECT_TIMEOUT = 5
|
|
279
|
+
READ_TIMEOUT = 120 # ensure server sends heartbeat within this window
|
|
280
|
+
|
|
281
|
+
def stream_result(location, job_id, token, pa, is_silent, line):
|
|
277
282
|
"""
|
|
278
283
|
Stream the result content from the given location using the provided token.
|
|
279
284
|
"""
|
|
285
|
+
if not is_silent:
|
|
286
|
+
line(f"<debug>Job '{job_id}' accepted, Waiting for events now.</debug>")
|
|
280
287
|
headers = {
|
|
281
288
|
"Authorization": f"Bearer {token}",
|
|
282
|
-
"Accept": "text/event-stream"
|
|
289
|
+
"Accept": "text/event-stream",
|
|
290
|
+
"Cache-Control": "no-cache",
|
|
291
|
+
"Connection": "keep-alive",
|
|
283
292
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
url = location + "/events"
|
|
294
|
+
session = requests.Session()
|
|
295
|
+
last_event_id = None
|
|
296
|
+
backoff = 1.0
|
|
297
|
+
while True:
|
|
298
|
+
try:
|
|
299
|
+
if last_event_id:
|
|
300
|
+
headers["Last-Event-ID"] = last_event_id
|
|
301
|
+
with session.get(url, stream=True, headers=headers, timeout=(CONNECT_TIMEOUT, READ_TIMEOUT)) as r:
|
|
302
|
+
r.raise_for_status()
|
|
303
|
+
# Reset backoff on successful connect
|
|
304
|
+
backoff = 1.0
|
|
305
|
+
for row in r.iter_lines(decode_unicode=True, chunk_size=1):
|
|
306
|
+
if row is None:
|
|
307
|
+
continue
|
|
308
|
+
if row.startswith(":"):
|
|
309
|
+
# comment/heartbeat
|
|
310
|
+
continue
|
|
311
|
+
if row.startswith("id:"):
|
|
312
|
+
last_event_id = row[3:].strip()
|
|
313
|
+
continue
|
|
314
|
+
if print_sse_row(row, pa, line): # raw SSE lines (e.g., "data: {...}", "event: message")
|
|
315
|
+
return # done
|
|
316
|
+
|
|
317
|
+
except (requests.exceptions.ChunkedEncodingError,
|
|
318
|
+
requests.exceptions.ConnectionError,
|
|
319
|
+
requests.exceptions.ReadTimeout) as e:
|
|
320
|
+
if not is_silent:
|
|
321
|
+
line(f"<debug>stream error: {e}; reconnecting in {backoff:.1f}s</debug>")
|
|
322
|
+
time.sleep(backoff)
|
|
323
|
+
backoff = min(backoff * 2, 30.0) # cap backoff
|
|
324
|
+
continue
|
|
325
|
+
except requests.HTTPError as e:
|
|
326
|
+
# Non-200 or similar; backoff and retry
|
|
327
|
+
if not is_silent:
|
|
328
|
+
line(f"<debug>http error: {e}; reconnecting in {backoff:.1f}s</debug>")
|
|
329
|
+
time.sleep(backoff)
|
|
330
|
+
backoff = min(backoff * 2, 60.0)
|
|
331
|
+
except Exception:
|
|
332
|
+
line(f"<error>Failed to fetch events: {type(e)} - {e}</error>")
|
|
333
|
+
break
|
|
334
|
+
|
|
335
|
+
# except requests.exceptions.ChunkedEncodingError as ce:
|
|
336
|
+
# line(f"<error>Chunked encoding error: {ce}</error>")
|
|
337
|
+
# except Exception as e:
|
|
338
|
+
# line(f"<error>Failed to fetch events: {type(e)} - {e}</error>")
|
|
339
|
+
|
|
340
|
+
def print_sse_row(row, pa, line) -> bool:
|
|
295
341
|
if pa.raw_events:
|
|
296
342
|
print(row)
|
|
343
|
+
return False # continue streaming
|
|
297
344
|
elif row.startswith("data: "):
|
|
298
345
|
# JSON data
|
|
299
346
|
print("----")
|
|
300
347
|
try:
|
|
301
348
|
data = json.loads(row[6:])
|
|
302
349
|
print(json.dumps(data, indent=2, sort_keys=True))
|
|
350
|
+
return check_if_done(data)
|
|
303
351
|
except json.JSONDecodeError as e:
|
|
304
|
-
|
|
352
|
+
line(f"<error>Failed to decode JSON: {e}</error>")
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def check_if_done(data) -> bool:
|
|
356
|
+
# {
|
|
357
|
+
# "Data": {
|
|
358
|
+
# "job-urn": "urn:ivcap:job:3e466031-ec8b-44eb-aec6-dc2f8212bec3",
|
|
359
|
+
# "status": "succeeded"
|
|
360
|
+
# },
|
|
361
|
+
# "Type": "ivcap.job.status"
|
|
362
|
+
# }
|
|
363
|
+
if "Type" in data and data["Type"] == "ivcap.job.status":
|
|
364
|
+
if "Data" in data and "status" in data["Data"]:
|
|
365
|
+
status = data["Data"]["status"]
|
|
366
|
+
if status in ["succeeded", "failed", "error"]:
|
|
367
|
+
return True
|
|
368
|
+
return False # continue streaming
|
|
305
369
|
|
|
306
370
|
def exec_parser():
|
|
307
371
|
p = argparse.ArgumentParser(prog="poetry ivcap job-exec request_file --")
|
|
@@ -310,6 +374,7 @@ def exec_parser():
|
|
|
310
374
|
help="include result content in the response")
|
|
311
375
|
p.add_argument("--stream", action="store_true", help="stream the result content")
|
|
312
376
|
p.add_argument("--raw-events", action="store_true", help="print raw SSE events")
|
|
377
|
+
p.add_argument("--auth-token", help="alternative auth token to use")
|
|
313
378
|
return p
|
|
314
379
|
|
|
315
380
|
def nonneg_int(s: str) -> int:
|
poetry_plugin_ivcap/plugin.py
CHANGED
|
@@ -10,8 +10,9 @@ from cleo.helpers import argument, option
|
|
|
10
10
|
import subprocess
|
|
11
11
|
from importlib.metadata import version
|
|
12
12
|
|
|
13
|
-
from poetry_plugin_ivcap.constants import
|
|
13
|
+
from poetry_plugin_ivcap.constants import DEF_IVCAP_URL, DOCKER_BUILD_TEMPLATE_OPT, DOCKER_RUN_TEMPLATE_OPT, PLUGIN_CMD, PLUGIN_NAME
|
|
14
14
|
from poetry_plugin_ivcap.constants import PORT_OPT, SERVICE_FILE_OPT, SERVICE_ID_OPT, SERVICE_TYPE_OPT, POLICY_OPT
|
|
15
|
+
from poetry_plugin_ivcap.types import BaseConfig
|
|
15
16
|
from poetry_plugin_ivcap.util import get_version
|
|
16
17
|
|
|
17
18
|
from .ivcap import create_service_id, exec_job, get_service_id, service_register, tool_register
|
|
@@ -127,7 +128,9 @@ Configurable options in pyproject.toml:
|
|
|
127
128
|
|
|
128
129
|
env = os.environ.copy()
|
|
129
130
|
env["VERSION"] = get_version(data, None, line)
|
|
130
|
-
|
|
131
|
+
cfg = BaseConfig(line=line)
|
|
132
|
+
env.setdefault("IVCAP_URL", cfg.ivcap_url)
|
|
133
|
+
env.setdefault("IVCAP_JWT", cfg.ivcap_jwt)
|
|
131
134
|
|
|
132
135
|
cmd = ["poetry", "run", "python", service]
|
|
133
136
|
cmd.extend(args)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2025 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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
poetry_plugin_ivcap/constants.py,sha256=jD8j_kBwo0i-IupEGBJRvI_Uwyfde_IaRghYASxf4tA,1326
|
|
2
|
+
poetry_plugin_ivcap/docker.py,sha256=QR3DJRn6l3RFxCiAvn8Kai_6e_mJ3YVuR_Pmnd1szqY,7714
|
|
3
|
+
poetry_plugin_ivcap/ivcap.py,sha256=yRS_mhS5P8sbIEofE9f7PRfsuZNGeyRrfjSNRg8shFY,15464
|
|
4
|
+
poetry_plugin_ivcap/plugin.py,sha256=hBsJaQzOlYnTjoBcS7AVSpsD2v0MtzcAabP70-cG2cs,5627
|
|
5
|
+
poetry_plugin_ivcap/types.py,sha256=gpoMnKZgO8JV-RFJs67cymuSj3d1RrLDJ8160_7NsKY,1351
|
|
6
|
+
poetry_plugin_ivcap/util.py,sha256=bcjjbKoV_pAgeuC7Ws9XbJa3phFpNVyrRAlFJ1VubRg,3429
|
|
7
|
+
poetry_plugin_ivcap-0.5.2.dist-info/AUTHORS.md,sha256=s9xR4_HAHQgbNlj505LViebt5AtACQmhPf92aJvNYgg,88
|
|
8
|
+
poetry_plugin_ivcap-0.5.2.dist-info/LICENSE,sha256=dsQrDPPwW7iJs9pxahgJKDW8RNPf5FyXG70MFUlxcuk,1587
|
|
9
|
+
poetry_plugin_ivcap-0.5.2.dist-info/METADATA,sha256=wUm9lrn8ZZokYRXBXp603XVEGHvG-B0AXcIsudrhSrY,3032
|
|
10
|
+
poetry_plugin_ivcap-0.5.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
11
|
+
poetry_plugin_ivcap-0.5.2.dist-info/entry_points.txt,sha256=3xagEFBkGgrVe8WyjmhlHLr4JDEWPN_W4DwxnIBWbNY,74
|
|
12
|
+
poetry_plugin_ivcap-0.5.2.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=tXu3vj7FOTrE4Jc9RFoLxOnNdBT5NAkyTB-_lGMgaZI,12804
|
|
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.0.dist-info/AUTHORS.md,sha256=s9xR4_HAHQgbNlj505LViebt5AtACQmhPf92aJvNYgg,88
|
|
7
|
-
poetry_plugin_ivcap-0.5.0.dist-info/LICENSE,sha256=dsQrDPPwW7iJs9pxahgJKDW8RNPf5FyXG70MFUlxcuk,1587
|
|
8
|
-
poetry_plugin_ivcap-0.5.0.dist-info/METADATA,sha256=HMskOhMdt6JyvVzTycjXqm32sOOxJUbTMeEnKPLICnc,3032
|
|
9
|
-
poetry_plugin_ivcap-0.5.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
10
|
-
poetry_plugin_ivcap-0.5.0.dist-info/entry_points.txt,sha256=3xagEFBkGgrVe8WyjmhlHLr4JDEWPN_W4DwxnIBWbNY,74
|
|
11
|
-
poetry_plugin_ivcap-0.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{poetry_plugin_ivcap-0.5.0.dist-info → poetry_plugin_ivcap-0.5.2.dist-info}/entry_points.txt
RENAMED
|
File without changes
|