artefacts-cli 0.6.13__py3-none-any.whl → 0.6.16__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.
- artefacts/cli/app.py +13 -50
- artefacts/cli/app_containers.py +77 -0
- artefacts/cli/constants.py +2 -0
- artefacts/cli/containers/__init__.py +61 -0
- artefacts/cli/containers/docker.py +86 -0
- artefacts/cli/containers/utils.py +54 -0
- artefacts/cli/utils.py +64 -0
- artefacts/cli/version.py +2 -2
- {artefacts_cli-0.6.13.dist-info → artefacts_cli-0.6.16.dist-info}/METADATA +24 -23
- artefacts_cli-0.6.16.dist-info/RECORD +21 -0
- {artefacts_cli-0.6.13.dist-info → artefacts_cli-0.6.16.dist-info}/WHEEL +1 -1
- artefacts_cli-0.6.13.dist-info/RECORD +0 -17
- {artefacts_cli-0.6.13.dist-info → artefacts_cli-0.6.16.dist-info}/entry_points.txt +0 -0
- {artefacts_cli-0.6.13.dist-info → artefacts_cli-0.6.16.dist-info}/top_level.txt +0 -0
artefacts/cli/app.py
CHANGED
@@ -9,7 +9,6 @@ import sys
|
|
9
9
|
import tarfile
|
10
10
|
import tempfile
|
11
11
|
import time
|
12
|
-
from typing import Any, Union
|
13
12
|
from urllib.parse import urlparse
|
14
13
|
import webbrowser
|
15
14
|
|
@@ -20,7 +19,9 @@ from pathlib import Path
|
|
20
19
|
from gitignore_parser import parse_gitignore
|
21
20
|
|
22
21
|
from artefacts.cli import init_job, generate_scenarios, AuthenticationError, __version__
|
22
|
+
from artefacts.cli import app_containers as containers
|
23
23
|
from artefacts.cli.constants import DEPRECATED_FRAMEWORKS, SUPPORTED_FRAMEWORKS
|
24
|
+
from artefacts.cli.utils import read_config, config_validation
|
24
25
|
import artefacts_copava as copava
|
25
26
|
|
26
27
|
HOME = os.path.expanduser("~")
|
@@ -100,55 +101,10 @@ class APIConf:
|
|
100
101
|
click.echo(f"Connecting to {self.api_url} using {auth_type}")
|
101
102
|
|
102
103
|
|
103
|
-
def read_config(filename: str) -> dict:
|
104
|
-
try:
|
105
|
-
with open(filename) as f:
|
106
|
-
return copava.parse(f.read())
|
107
|
-
except FileNotFoundError:
|
108
|
-
raise click.ClickException(f"Project config file {filename} not found.")
|
109
|
-
|
110
|
-
|
111
104
|
def validate_artefacts_config(config_file: str) -> dict:
|
112
105
|
pass
|
113
106
|
|
114
107
|
|
115
|
-
def pretty_print_config_error(
|
116
|
-
errors: Union[str, list, dict], indent: int = 0, prefix: str = "", suffix: str = ""
|
117
|
-
) -> str:
|
118
|
-
if type(errors) is str:
|
119
|
-
header = " " * indent
|
120
|
-
output = header + prefix + errors + suffix
|
121
|
-
elif type(errors) is list:
|
122
|
-
_depth = indent + 1
|
123
|
-
output = []
|
124
|
-
for value in errors:
|
125
|
-
output.append(pretty_print_config_error(value, indent=_depth, prefix="- "))
|
126
|
-
output = os.linesep.join(output)
|
127
|
-
elif type(errors) is dict:
|
128
|
-
_depth = indent + 1
|
129
|
-
output = []
|
130
|
-
for key, value in errors.items():
|
131
|
-
output.append(pretty_print_config_error(key, indent=indent, suffix=":"))
|
132
|
-
output.append(pretty_print_config_error(value, indent=_depth))
|
133
|
-
output = os.linesep.join(output)
|
134
|
-
else:
|
135
|
-
# Must not happen, so broad definition, but we want to know fast.
|
136
|
-
raise Exception(f"Unacceptable data type for config error formatting: {errors}")
|
137
|
-
return output
|
138
|
-
|
139
|
-
|
140
|
-
# Click callback syntax
|
141
|
-
def config_validation(context: dict, param: str, value: str) -> str:
|
142
|
-
if context.params["skip_validation"]:
|
143
|
-
return value
|
144
|
-
config = read_config(value)
|
145
|
-
errors = copava.check(config)
|
146
|
-
if len(errors) == 0:
|
147
|
-
return value
|
148
|
-
else:
|
149
|
-
raise click.BadParameter(pretty_print_config_error(errors))
|
150
|
-
|
151
|
-
|
152
108
|
@click.group()
|
153
109
|
def config():
|
154
110
|
return
|
@@ -334,7 +290,7 @@ def run(
|
|
334
290
|
)
|
335
291
|
except AuthenticationError:
|
336
292
|
raise click.ClickException(
|
337
|
-
"Unable to authenticate, check your
|
293
|
+
"Unable to authenticate (Stage: Job initialisation), please check your project name and API key"
|
338
294
|
)
|
339
295
|
|
340
296
|
job_success = True
|
@@ -346,7 +302,7 @@ def run(
|
|
346
302
|
run = warpjob.new_run(scenario)
|
347
303
|
except AuthenticationError:
|
348
304
|
raise click.ClickException(
|
349
|
-
"Unable to authenticate, check your
|
305
|
+
"Unable to authenticate (Stage: Job run), please check your project name and API key"
|
350
306
|
)
|
351
307
|
if framework is not None and framework.startswith("ros2:"):
|
352
308
|
from artefacts.cli.ros2 import run_ros2_tests
|
@@ -474,7 +430,7 @@ def run_remote(config, description, jobname, skip_validation=False):
|
|
474
430
|
click.echo(f"Packaging source...")
|
475
431
|
|
476
432
|
with tempfile.NamedTemporaryFile(
|
477
|
-
prefix=project_id, suffix=".tgz", delete=True
|
433
|
+
prefix=project_id.split("/")[-1], suffix=".tgz", delete=True
|
478
434
|
) as temp_file:
|
479
435
|
# get list of patterns to be ignored in .artefactsignore
|
480
436
|
ignore_file = Path(project_folder) / Path(".artefactsignore")
|
@@ -512,7 +468,13 @@ def run_remote(config, description, jobname, skip_validation=False):
|
|
512
468
|
)
|
513
469
|
|
514
470
|
if not upload_urls_response.ok:
|
515
|
-
|
471
|
+
try:
|
472
|
+
result = upload_urls_response.json()
|
473
|
+
except requests.exceptions.JSONDecodeError:
|
474
|
+
raise click.ClickException(
|
475
|
+
f"Apologies, problem in interacting with the Artefacts backend: {upload_urls_response.status_code} {upload_urls_response.reason}. Response text: {upload_urls_response.text}."
|
476
|
+
)
|
477
|
+
|
516
478
|
if (
|
517
479
|
upload_urls_response.status_code == 403
|
518
480
|
and result["message"] == "Not allowed"
|
@@ -611,6 +573,7 @@ artefacts.add_command(config)
|
|
611
573
|
artefacts.add_command(hello)
|
612
574
|
artefacts.add_command(run)
|
613
575
|
artefacts.add_command(run_remote)
|
576
|
+
artefacts.add_command(containers.package)
|
614
577
|
|
615
578
|
|
616
579
|
if __name__ == "__main__":
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import click
|
4
|
+
|
5
|
+
from artefacts.cli.constants import DEFAULT_API_URL
|
6
|
+
from artefacts.cli.utils import config_validation, read_config
|
7
|
+
from artefacts.cli.containers.utils import ContainerMgr
|
8
|
+
|
9
|
+
|
10
|
+
@click.group()
|
11
|
+
@click.option("--debug/--no-debug", default=False)
|
12
|
+
@click.pass_context
|
13
|
+
def package(ctx: click.Context, debug: bool):
|
14
|
+
ctx.ensure_object(dict)
|
15
|
+
ctx.obj["debug"] = debug
|
16
|
+
|
17
|
+
|
18
|
+
@package.command()
|
19
|
+
@click.option(
|
20
|
+
"--path",
|
21
|
+
default=".",
|
22
|
+
help="Path to the root of the project, where a Dockerfile is available.",
|
23
|
+
)
|
24
|
+
@click.option(
|
25
|
+
"--dockerfile",
|
26
|
+
default="Dockerfile",
|
27
|
+
help="File name of the container definition file. Defaults to the standard Dockerfile inside the project root (see --path)",
|
28
|
+
)
|
29
|
+
@click.option(
|
30
|
+
"--name",
|
31
|
+
required=False,
|
32
|
+
help="Name for the generated package",
|
33
|
+
)
|
34
|
+
@click.pass_context
|
35
|
+
def build(ctx: click.Context, path: str, dockerfile: str, name: str):
|
36
|
+
if not os.path.exists(os.path.join(path, dockerfile)):
|
37
|
+
raise click.ClickException(
|
38
|
+
f"No {dockerfile} found here. I cannot build the package."
|
39
|
+
)
|
40
|
+
if name is None:
|
41
|
+
name = "artefacts"
|
42
|
+
handler = ContainerMgr()
|
43
|
+
image, _ = handler.build(path=path, name=name)
|
44
|
+
print(f"Package complete in image: {image}")
|
45
|
+
|
46
|
+
|
47
|
+
@package.command()
|
48
|
+
@click.argument("image")
|
49
|
+
@click.argument("jobname")
|
50
|
+
@click.option(
|
51
|
+
"--config",
|
52
|
+
callback=config_validation,
|
53
|
+
default="artefacts.yaml",
|
54
|
+
help="Artefacts config file.",
|
55
|
+
)
|
56
|
+
@click.pass_context
|
57
|
+
def run(ctx: click.Context, image: str, jobname: str, config: str):
|
58
|
+
try:
|
59
|
+
artefacts_config = read_config(config)
|
60
|
+
except FileNotFoundError:
|
61
|
+
raise click.ClickException(f"Project config file not found: {config}")
|
62
|
+
project = artefacts_config["project"]
|
63
|
+
handler = ContainerMgr()
|
64
|
+
params = dict(
|
65
|
+
image=image,
|
66
|
+
project=project,
|
67
|
+
jobname=jobname,
|
68
|
+
# Hidden setting primarily useful to Artefacts developers
|
69
|
+
api_url=os.environ.get("ARTEFACTS_API_URL", DEFAULT_API_URL),
|
70
|
+
)
|
71
|
+
container, logs = handler.run(**params)
|
72
|
+
if container:
|
73
|
+
print(f"Package run complete: Container Id for inspection: {container['Id']}")
|
74
|
+
else:
|
75
|
+
print(f"Package run failed:")
|
76
|
+
for entry in logs:
|
77
|
+
print("\t- " + entry)
|
artefacts/cli/constants.py
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
from collections.abc import Generator
|
2
|
+
import configparser
|
3
|
+
import os
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Any, Tuple, Union
|
6
|
+
|
7
|
+
from artefacts.cli.constants import DEFAULT_API_URL
|
8
|
+
|
9
|
+
|
10
|
+
class CMgr:
|
11
|
+
def build(self, **kwargs) -> Tuple[str, Generator]:
|
12
|
+
"""
|
13
|
+
Returns the build image ID (e.g. sha256:abcdefghi)
|
14
|
+
and an iterator over the build log entries.
|
15
|
+
"""
|
16
|
+
raise NotImplemented()
|
17
|
+
|
18
|
+
def run(
|
19
|
+
self,
|
20
|
+
image: str,
|
21
|
+
project: str,
|
22
|
+
jobname: str = None,
|
23
|
+
artefacts_dir: str = Path("~/.artefacts").expanduser(),
|
24
|
+
api_url: str = DEFAULT_API_URL,
|
25
|
+
) -> Tuple[Any, Generator]:
|
26
|
+
"""
|
27
|
+
Returns a container (Any type as depends on the framework)
|
28
|
+
and an iterator over the container log entries.
|
29
|
+
"""
|
30
|
+
raise NotImplemented()
|
31
|
+
|
32
|
+
def _valid_artefacts_api_key(
|
33
|
+
self, project: str, path: Union[str, Path] = Path("~/.artefacts").expanduser()
|
34
|
+
) -> bool:
|
35
|
+
"""
|
36
|
+
Check if a valid API key is available to embed in containers.
|
37
|
+
|
38
|
+
1. Check overrides with the ARTEFACTS_KEY environment variable.
|
39
|
+
2. If `path` is not given, check the default .artefacts folder for the config file.
|
40
|
+
3. If `path` is given, check the file directly is a file, or check for a `config` file if a folder.
|
41
|
+
|
42
|
+
When a config file is found, we check here if the API key for the `project` is available.
|
43
|
+
|
44
|
+
`path` set to None is an error, and aborts execution.
|
45
|
+
"""
|
46
|
+
if not path:
|
47
|
+
raise Exception(
|
48
|
+
"`path` must be a string, a Path object, or exclusded from the kwargs"
|
49
|
+
)
|
50
|
+
if os.environ.get("ARTEFACTS_KEY", None):
|
51
|
+
return True
|
52
|
+
path = Path(path) # Ensure we have a Path object
|
53
|
+
config = configparser.ConfigParser()
|
54
|
+
if path.is_dir():
|
55
|
+
config.read(path / "config")
|
56
|
+
else:
|
57
|
+
config.read(path)
|
58
|
+
try:
|
59
|
+
return config[project].get("apikey") != None
|
60
|
+
except KeyError:
|
61
|
+
return False
|
@@ -0,0 +1,86 @@
|
|
1
|
+
from collections.abc import Generator
|
2
|
+
import json
|
3
|
+
import os
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Any, Tuple
|
6
|
+
from uuid import uuid4
|
7
|
+
|
8
|
+
from artefacts.cli.constants import DEFAULT_API_URL
|
9
|
+
from artefacts.cli.containers import CMgr
|
10
|
+
from artefacts.cli.utils import ensure_available
|
11
|
+
|
12
|
+
ensure_available("docker")
|
13
|
+
|
14
|
+
import docker
|
15
|
+
from docker import APIClient
|
16
|
+
|
17
|
+
|
18
|
+
class DockerManager(CMgr):
|
19
|
+
def __init__(self):
|
20
|
+
self.client = APIClient()
|
21
|
+
|
22
|
+
def build(self, **kwargs) -> Tuple[str, Generator]:
|
23
|
+
kwargs["tag"] = kwargs.pop("name")
|
24
|
+
logs = []
|
25
|
+
img_id = None
|
26
|
+
for entry in self.client.build(**kwargs):
|
27
|
+
line_data = [
|
28
|
+
json.loads(v) for v in entry.decode("utf-8").split("\r\n") if len(v) > 0
|
29
|
+
]
|
30
|
+
for data in line_data:
|
31
|
+
if "stream" in data:
|
32
|
+
line = data["stream"].strip()
|
33
|
+
if not line.startswith("---") and len(line) > 0:
|
34
|
+
print(line)
|
35
|
+
logs.append(line)
|
36
|
+
elif "aux" in data and "ID" in data["aux"]:
|
37
|
+
img_id = data["aux"]["ID"]
|
38
|
+
if img_id is None:
|
39
|
+
img_id = self.client.inspect_image(kwargs["tag"])["Id"]
|
40
|
+
return img_id, iter(logs)
|
41
|
+
|
42
|
+
def run(
|
43
|
+
self,
|
44
|
+
image: str,
|
45
|
+
project: str,
|
46
|
+
jobname: str = None,
|
47
|
+
artefacts_dir: str = Path("~/.artefacts").expanduser(),
|
48
|
+
api_url: str = DEFAULT_API_URL,
|
49
|
+
) -> Tuple[Any, Generator]:
|
50
|
+
if not self._valid_artefacts_api_key(project, artefacts_dir):
|
51
|
+
return None, iter(
|
52
|
+
[
|
53
|
+
"Missing API key for the project. Does `~/.artefacts/config` exist and contain your key?"
|
54
|
+
]
|
55
|
+
)
|
56
|
+
try:
|
57
|
+
env = {
|
58
|
+
"JOB_ID": str(uuid4()),
|
59
|
+
"ARTEFACTS_JOB_NAME": jobname,
|
60
|
+
"ARTEFACTS_API_URL": api_url,
|
61
|
+
}
|
62
|
+
|
63
|
+
container = self.client.create_container(
|
64
|
+
image,
|
65
|
+
environment=env,
|
66
|
+
detach=False,
|
67
|
+
volumes=["/root/.artefacts"],
|
68
|
+
host_config=self.client.create_host_config(
|
69
|
+
binds={
|
70
|
+
artefacts_dir: {
|
71
|
+
"bind": "/root/.artefacts",
|
72
|
+
"mode": "ro",
|
73
|
+
},
|
74
|
+
},
|
75
|
+
),
|
76
|
+
)
|
77
|
+
self.client.start(container=container.get("Id"))
|
78
|
+
for entry in self.client.logs(container=container.get("Id"), stream=True):
|
79
|
+
print(entry.decode("utf-8").strip())
|
80
|
+
return container, iter([])
|
81
|
+
except docker.errors.ImageNotFound:
|
82
|
+
return None, iter(
|
83
|
+
[f"Image {image} not found by Docker. Perhaps need to build first?"]
|
84
|
+
)
|
85
|
+
except Exception as e:
|
86
|
+
return None, iter([f"Failed to run from {image}. All we know: {e}"])
|
@@ -0,0 +1,54 @@
|
|
1
|
+
from collections.abc import Generator
|
2
|
+
import logging
|
3
|
+
from typing import Any, Tuple
|
4
|
+
|
5
|
+
from artefacts.cli.containers import CMgr
|
6
|
+
|
7
|
+
|
8
|
+
class ContainerMgr:
|
9
|
+
SUPPORTED_PRIORITISED_ENGINES = {
|
10
|
+
1: "docker",
|
11
|
+
# 2: "podman",
|
12
|
+
}
|
13
|
+
|
14
|
+
def __init__(self):
|
15
|
+
self.logger = logging.getLogger(__name__)
|
16
|
+
self.mgr = self._configure()
|
17
|
+
if self.mgr is None:
|
18
|
+
raise Exception(
|
19
|
+
f"Failed to find supported container stack. Please install and start one in {list(self.SUPPORTED_PRIORITISED_ENGINES.values())}, with default settings (custom sockets not supported at this stage)"
|
20
|
+
)
|
21
|
+
|
22
|
+
def _configure(self) -> CMgr:
|
23
|
+
manager = None
|
24
|
+
for idx in sorted(self.SUPPORTED_PRIORITISED_ENGINES):
|
25
|
+
engine = self.SUPPORTED_PRIORITISED_ENGINES[idx]
|
26
|
+
try:
|
27
|
+
handler = getattr(self, f"_configure_{engine}")
|
28
|
+
manager = handler()
|
29
|
+
except AttributeError:
|
30
|
+
self.logger.warning(
|
31
|
+
f"Tried to detect an unsupported engine: {engine}. WIP? Ignore and continue."
|
32
|
+
)
|
33
|
+
except Exception as e:
|
34
|
+
self.logger.warning(
|
35
|
+
f"Problem in detecting {engine} ({e}) Ignore and continue."
|
36
|
+
)
|
37
|
+
if manager is not None:
|
38
|
+
break
|
39
|
+
return manager
|
40
|
+
|
41
|
+
def _configure_docker(self):
|
42
|
+
from artefacts.cli.containers.docker import DockerManager
|
43
|
+
|
44
|
+
return DockerManager()
|
45
|
+
|
46
|
+
# def _configure_podman(self):
|
47
|
+
# from artefacts.cli.containers import podman
|
48
|
+
# return PodmanManager()
|
49
|
+
|
50
|
+
def build(self, **kwargs) -> Tuple[str, Generator]:
|
51
|
+
return self.mgr.build(**kwargs)
|
52
|
+
|
53
|
+
def run(self, **kwargs) -> Tuple[Any, Generator]:
|
54
|
+
return self.mgr.run(**kwargs)
|
artefacts/cli/utils.py
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
import os
|
1
2
|
import subprocess
|
2
3
|
import sys
|
4
|
+
from typing import Any, Union
|
5
|
+
|
6
|
+
import click
|
7
|
+
|
8
|
+
import artefacts_copava as copava
|
3
9
|
|
4
10
|
|
5
11
|
def run_and_save_logs(
|
@@ -33,3 +39,61 @@ def run_and_save_logs(
|
|
33
39
|
output_file.write(line)
|
34
40
|
proc.wait()
|
35
41
|
return proc.returncode
|
42
|
+
|
43
|
+
|
44
|
+
def ensure_available(package: str) -> None:
|
45
|
+
import importlib
|
46
|
+
|
47
|
+
try:
|
48
|
+
importlib.import_module(package)
|
49
|
+
except ImportError:
|
50
|
+
"""
|
51
|
+
Recommended by the Python community
|
52
|
+
https://pip.pypa.io/en/latest/user_guide/#using-pip-from-your-program
|
53
|
+
"""
|
54
|
+
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
55
|
+
|
56
|
+
|
57
|
+
def read_config(filename: str) -> dict:
|
58
|
+
try:
|
59
|
+
with open(filename) as f:
|
60
|
+
return copava.parse(f.read())
|
61
|
+
except FileNotFoundError:
|
62
|
+
raise click.ClickException(f"Project config file {filename} not found.")
|
63
|
+
|
64
|
+
|
65
|
+
# Click callback syntax
|
66
|
+
def config_validation(context: dict, param: str, value: str) -> str:
|
67
|
+
if context.params.get("skip_validation", False):
|
68
|
+
return value
|
69
|
+
config = read_config(value)
|
70
|
+
errors = copava.check(config)
|
71
|
+
if len(errors) == 0:
|
72
|
+
return value
|
73
|
+
else:
|
74
|
+
raise click.BadParameter(pretty_print_config_error(errors))
|
75
|
+
|
76
|
+
|
77
|
+
def pretty_print_config_error(
|
78
|
+
errors: Union[str, list, dict], indent: int = 0, prefix: str = "", suffix: str = ""
|
79
|
+
) -> str:
|
80
|
+
if type(errors) is str:
|
81
|
+
header = " " * indent
|
82
|
+
output = header + prefix + errors + suffix
|
83
|
+
elif type(errors) is list:
|
84
|
+
_depth = indent + 1
|
85
|
+
output = []
|
86
|
+
for value in errors:
|
87
|
+
output.append(pretty_print_config_error(value, indent=_depth, prefix="- "))
|
88
|
+
output = os.linesep.join(output)
|
89
|
+
elif type(errors) is dict:
|
90
|
+
_depth = indent + 1
|
91
|
+
output = []
|
92
|
+
for key, value in errors.items():
|
93
|
+
output.append(pretty_print_config_error(key, indent=indent, suffix=":"))
|
94
|
+
output.append(pretty_print_config_error(value, indent=_depth))
|
95
|
+
output = os.linesep.join(output)
|
96
|
+
else:
|
97
|
+
# Must not happen, so broad definition, but we want to know fast.
|
98
|
+
raise Exception(f"Unacceptable data type for config error formatting: {errors}")
|
99
|
+
return output
|
artefacts/cli/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: artefacts_cli
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.16
|
4
4
|
Author-email: FD <fabian@artefacts.com>, AGC <alejandro@artefacts.com>, TN <tomo@artefacts.com>, EP <eric@artefacts.com>
|
5
5
|
Project-URL: Homepage, https://github.com/art-e-fact/artefacts-client
|
6
6
|
Project-URL: Bug Tracker, https://github.com/art-e-fact/artefacts-client/issues
|
@@ -9,32 +9,33 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
10
10
|
Requires-Python: >=3.8
|
11
11
|
Description-Content-Type: text/markdown
|
12
|
-
Requires-Dist: artefacts-copava
|
13
|
-
Requires-Dist: click
|
14
|
-
Requires-Dist:
|
15
|
-
Requires-Dist: junitparser
|
12
|
+
Requires-Dist: artefacts-copava>=0.1.11
|
13
|
+
Requires-Dist: click>=8.0.4
|
14
|
+
Requires-Dist: gitignore_parser>=0.1.11
|
15
|
+
Requires-Dist: junitparser>=2.5
|
16
16
|
Requires-Dist: mcap
|
17
17
|
Requires-Dist: mcap-ros2-support
|
18
|
-
Requires-Dist: PyYAML
|
19
|
-
Requires-Dist: requests
|
18
|
+
Requires-Dist: PyYAML>=6.0
|
19
|
+
Requires-Dist: requests>=2.27.1
|
20
20
|
Requires-Dist: setuptools-scm
|
21
21
|
Provides-Extra: dev
|
22
|
-
Requires-Dist: awscli
|
23
|
-
Requires-Dist: build
|
24
|
-
Requires-Dist:
|
25
|
-
Requires-Dist:
|
26
|
-
Requires-Dist:
|
27
|
-
Requires-Dist: pytest
|
28
|
-
Requires-Dist: pytest-
|
29
|
-
Requires-Dist: pytest-
|
30
|
-
Requires-Dist:
|
31
|
-
Requires-Dist:
|
32
|
-
Requires-Dist:
|
33
|
-
Requires-Dist: mkdocs-
|
34
|
-
Requires-Dist: mkdocs-
|
35
|
-
Requires-Dist: mkdocs
|
36
|
-
Requires-Dist:
|
37
|
-
Requires-Dist:
|
22
|
+
Requires-Dist: awscli; extra == "dev"
|
23
|
+
Requires-Dist: build; extra == "dev"
|
24
|
+
Requires-Dist: docker; extra == "dev"
|
25
|
+
Requires-Dist: lark; extra == "dev"
|
26
|
+
Requires-Dist: pyre-check; extra == "dev"
|
27
|
+
Requires-Dist: pytest; extra == "dev"
|
28
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
29
|
+
Requires-Dist: pytest-env; extra == "dev"
|
30
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
31
|
+
Requires-Dist: ruff; extra == "dev"
|
32
|
+
Requires-Dist: twine; extra == "dev"
|
33
|
+
Requires-Dist: mkdocs-click==0.8.0; extra == "dev"
|
34
|
+
Requires-Dist: mkdocs-material==8.5.6; extra == "dev"
|
35
|
+
Requires-Dist: mkdocs-mermaid2-plugin==0.6.0; extra == "dev"
|
36
|
+
Requires-Dist: mkdocs==1.4.2; extra == "dev"
|
37
|
+
Requires-Dist: pre-commit; extra == "dev"
|
38
|
+
Requires-Dist: python-markdown-math; extra == "dev"
|
38
39
|
|
39
40
|
# Artefacts CLI
|
40
41
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
artefacts/cli/__init__.py,sha256=9rTAfBoS9ALJxKSqaUo32ThbDshbvNN4-EmoyUsPhRI,11643
|
2
|
+
artefacts/cli/app.py,sha256=597uPtK4A_wujvqhk5h4KkrXV_XVkDLpymedd2lZB5k,20140
|
3
|
+
artefacts/cli/app_containers.py,sha256=7OAtc4n9YeK8ZYUKvteOMbZr7lYjx_YMa6tu8Pnu9Yc,2280
|
4
|
+
artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
|
5
|
+
artefacts/cli/constants.py,sha256=bvsVDwqkAc49IZN7j6k6IL6EG87bECHd_VINtKJqbv8,320
|
6
|
+
artefacts/cli/other.py,sha256=7NvzlspvG0zF7sryR-QznwdLupXLln1BKWxHB9VuEcc,1160
|
7
|
+
artefacts/cli/parameters.py,sha256=MDhrM7ur95wKTLDteqz2f-sLdCPcepi5wk0XjeLo6TU,788
|
8
|
+
artefacts/cli/ros1.py,sha256=RbtirCGarD9a0ikfuGK-pdpWYSXfqJhEt4rpA0uFsyU,9625
|
9
|
+
artefacts/cli/ros2.py,sha256=YaCi3HRuCdvCTjM0Ftnm-SLgMOy1OneIr0aU7KVTiAM,4476
|
10
|
+
artefacts/cli/utils.py,sha256=6yQJRzv-xaLbtcA73Tty9C9QZeV06n5pjXMYl3xsLPE,3156
|
11
|
+
artefacts/cli/utils_ros.py,sha256=pYbhAU9fK2VbnWm3nSLBwUMVBzsZuCn10SFZmVW3-Zo,2090
|
12
|
+
artefacts/cli/version.py,sha256=zbqzBVUYJbK8o4vMJuNyIN5tBM9QXVZa7XiEM2PNdR8,413
|
13
|
+
artefacts/cli/containers/__init__.py,sha256=S3DXLsb0csUdfjOZIngTfhMHrmYAaWBeu5EctLEEXbM,2057
|
14
|
+
artefacts/cli/containers/docker.py,sha256=RtUOMbtWHQumTtDRa0ALjJ29tSaa7Pp497Ah1aJ7nZ4,2964
|
15
|
+
artefacts/cli/containers/utils.py,sha256=5yUoREHM9AxnTkDNCY-DFUPSR5OWtu1rNxIVs6n5zZo,1816
|
16
|
+
artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
|
17
|
+
artefacts_cli-0.6.16.dist-info/METADATA,sha256=OLy7Jmo_RMo9CiktBZSKiZRN1HVILJkuhz-W24YB0RA,3021
|
18
|
+
artefacts_cli-0.6.16.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
19
|
+
artefacts_cli-0.6.16.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
|
20
|
+
artefacts_cli-0.6.16.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
|
21
|
+
artefacts_cli-0.6.16.dist-info/RECORD,,
|
@@ -1,17 +0,0 @@
|
|
1
|
-
artefacts/cli/__init__.py,sha256=9rTAfBoS9ALJxKSqaUo32ThbDshbvNN4-EmoyUsPhRI,11643
|
2
|
-
artefacts/cli/app.py,sha256=ZcSzlO-XZE8fjUHgXNcqe9Qk9GUEsdg0FWwdXE6HVG4,21178
|
3
|
-
artefacts/cli/bagparser.py,sha256=FE_QaztC9pg4hQzTjGSdyve6mzZbHJbyqa3wqvZSbxE,3702
|
4
|
-
artefacts/cli/constants.py,sha256=vZxtUprVqqZx1k4-LFFDU2tI0AnENV2cBt655uR17R8,269
|
5
|
-
artefacts/cli/other.py,sha256=7NvzlspvG0zF7sryR-QznwdLupXLln1BKWxHB9VuEcc,1160
|
6
|
-
artefacts/cli/parameters.py,sha256=MDhrM7ur95wKTLDteqz2f-sLdCPcepi5wk0XjeLo6TU,788
|
7
|
-
artefacts/cli/ros1.py,sha256=RbtirCGarD9a0ikfuGK-pdpWYSXfqJhEt4rpA0uFsyU,9625
|
8
|
-
artefacts/cli/ros2.py,sha256=YaCi3HRuCdvCTjM0Ftnm-SLgMOy1OneIr0aU7KVTiAM,4476
|
9
|
-
artefacts/cli/utils.py,sha256=48c8ZwuKT14R0jVMn6zoR4iVswFUR52VxXjW--693Zk,1110
|
10
|
-
artefacts/cli/utils_ros.py,sha256=pYbhAU9fK2VbnWm3nSLBwUMVBzsZuCn10SFZmVW3-Zo,2090
|
11
|
-
artefacts/cli/version.py,sha256=5DsKYkggDL8ad0hjNNaT4I88zoS7dr10lb9BFO_GI3A,413
|
12
|
-
artefacts/wrappers/artefacts_ros1_meta.launch,sha256=9tN7_0xLH8jW27KYFerhF3NuWDx2dED3ks_qoGVZAPw,1412
|
13
|
-
artefacts_cli-0.6.13.dist-info/METADATA,sha256=Bed5E1pNaXvXbiWn3bT5I6WZUHE279uCMOrhkDrGWLg,3009
|
14
|
-
artefacts_cli-0.6.13.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
15
|
-
artefacts_cli-0.6.13.dist-info/entry_points.txt,sha256=nlTXRzilNjccbi53FgaRWCQPkG-pv61HRkaCkrKjlec,58
|
16
|
-
artefacts_cli-0.6.13.dist-info/top_level.txt,sha256=FdaMV1C9m36MWa-2Stm5xVODv7hss_nRYNwR83j_7ow,10
|
17
|
-
artefacts_cli-0.6.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|