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 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 Project Name and API Key"
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 Project Name and API Key"
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
- result = upload_urls_response.json()
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)
@@ -1,3 +1,5 @@
1
+ DEFAULT_API_URL = "https://app.artefacts.com/api"
2
+
1
3
  SUPPORTED_FRAMEWORKS = [
2
4
  "ros2:iron",
3
5
  "ros2:humble",
@@ -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
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.6.13'
16
- __version_tuple__ = version_tuple = (0, 6, 13)
15
+ __version__ = version = '0.6.16'
16
+ __version_tuple__ = version_tuple = (0, 6, 16)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: artefacts_cli
3
- Version: 0.6.13
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 >=0.1.11
13
- Requires-Dist: click >=8.0.4
14
- Requires-Dist: gitignore-parser >=0.1.11
15
- Requires-Dist: junitparser >=2.5
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 >=6.0
19
- Requires-Dist: requests >=2.27.1
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 ; extra == 'dev'
23
- Requires-Dist: build ; extra == 'dev'
24
- Requires-Dist: lark ; extra == 'dev'
25
- Requires-Dist: pyre-check ; extra == 'dev'
26
- Requires-Dist: pytest ; extra == 'dev'
27
- Requires-Dist: pytest-cov ; extra == 'dev'
28
- Requires-Dist: pytest-env ; extra == 'dev'
29
- Requires-Dist: pytest-mock ; extra == 'dev'
30
- Requires-Dist: ruff ; extra == 'dev'
31
- Requires-Dist: twine ; extra == 'dev'
32
- Requires-Dist: mkdocs-click ==0.8.0 ; extra == 'dev'
33
- Requires-Dist: mkdocs-material ==8.5.6 ; extra == 'dev'
34
- Requires-Dist: mkdocs-mermaid2-plugin ==0.6.0 ; extra == 'dev'
35
- Requires-Dist: mkdocs ==1.4.2 ; extra == 'dev'
36
- Requires-Dist: pre-commit ; extra == 'dev'
37
- Requires-Dist: python-markdown-math ; extra == 'dev'
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,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.1.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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,,