splight-cli 5.4.1__tar.gz → 5.5.0__tar.gz

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.
Files changed (61) hide show
  1. {splight_cli-5.4.1 → splight_cli-5.5.0}/PKG-INFO +1 -8
  2. {splight_cli-5.4.1 → splight_cli-5.5.0}/README.md +0 -7
  3. {splight_cli-5.4.1 → splight_cli-5.5.0}/pyproject.toml +1 -1
  4. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/cli.py +0 -2
  5. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/manager/manager.py +0 -1
  6. splight_cli-5.4.1/splight_cli/hub/__init__.py +0 -14
  7. splight_cli-5.4.1/splight_cli/hub/component/__init__.py +0 -73
  8. splight_cli-5.4.1/splight_cli/hub/component/component_builder.py +0 -109
  9. splight_cli-5.4.1/splight_cli/hub/component/exceptions.py +0 -28
  10. splight_cli-5.4.1/splight_cli/hub/component/hub_manager.py +0 -137
  11. splight_cli-5.4.1/splight_cli/hub/component/resources/Dockerfile +0 -21
  12. splight_cli-5.4.1/splight_cli/hub/component/resources/installer.py +0 -80
  13. splight_cli-5.4.1/splight_cli/hub/component/tests/test_hub_manager.py +0 -135
  14. splight_cli-5.4.1/splight_cli/hub/exceptions.py +0 -21
  15. splight_cli-5.4.1/splight_cli/hub/server/__init__.py +0 -60
  16. splight_cli-5.4.1/splight_cli/hub/server/exceptions.py +0 -28
  17. splight_cli-5.4.1/splight_cli/hub/server/server_builder.py +0 -73
  18. splight_cli-5.4.1/splight_cli/hub/server/server_manager.py +0 -116
  19. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/__init__.py +0 -0
  20. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/__init__.py +0 -0
  21. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/component.py +0 -0
  22. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/exceptions.py +0 -0
  23. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/loaders.py +0 -0
  24. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/.splightignore +0 -0
  25. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/Initialization +0 -0
  26. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/README.md +0 -0
  27. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/auto_readme.md +0 -0
  28. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/main.py +0 -0
  29. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/spec.json +0 -0
  30. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/templates/tests.py +0 -0
  31. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/tests/__init__.py +0 -0
  32. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/tests/test_component_manager.py +0 -0
  33. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/component/utils.py +0 -0
  34. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/config/__init__.py +0 -0
  35. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/constants.py +0 -0
  36. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/__init__.py +0 -0
  37. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/alert/__init__.py +0 -0
  38. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/asset/__init__.py +0 -0
  39. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/attribute/__init__.py +0 -0
  40. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/component/__init__.py +0 -0
  41. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/datalake/__init__.py +0 -0
  42. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/file/__init__.py +0 -0
  43. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/manager/__init__.py +0 -0
  44. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/manager/exceptions.py +0 -0
  45. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/manager/tests/test_datalake_manager.py +0 -0
  46. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/manager/tests/test_resource_manager.py +0 -0
  47. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/engine/secret/__init__.py +0 -0
  48. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/tests/test_component/Initialization +0 -0
  49. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/tests/test_component/README.md +0 -0
  50. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/tests/test_component/main.py +0 -0
  51. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/tests/test_component/spec.json +0 -0
  52. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/tests/test_component/tests.py +0 -0
  53. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/__init__.py +0 -0
  54. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/input.py +0 -0
  55. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/json.py +0 -0
  56. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/loader.py +0 -0
  57. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/pprint.py +0 -0
  58. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/template.py +0 -0
  59. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/utils/yaml.py +0 -0
  60. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/version.py +0 -0
  61. {splight_cli-5.4.1 → splight_cli-5.5.0}/splight_cli/workspace/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: splight-cli
3
- Version: 5.4.1
3
+ Version: 5.5.0
4
4
  Summary: Splight Command Line Interface
5
5
  Author: Splight Dev
6
6
  Author-email: dev@splight-ae.com
@@ -43,8 +43,6 @@ Description-Content-Type: text/markdown
43
43
  - [Commands](#commands)
44
44
  - [Component](#component)
45
45
  - [Configure](#configure)
46
- - [Hub](#hub)
47
- - [Component](#component-1)
48
46
  - [Engine](#engine)
49
47
  - [Workspace](#workspace)
50
48
  - [Developing Components](#developing-components)
@@ -231,11 +229,6 @@ In the same way you can modify one parameter using the `set` command
231
229
  splight configure set <parameter> <value>
232
230
  ```
233
231
 
234
- ### Hub
235
-
236
- This command allows you to interact with the Splight HUB, places where you can find all the
237
- existing components that can be used in the platform.
238
-
239
232
  #### Component
240
233
 
241
234
  - List component
@@ -15,8 +15,6 @@
15
15
  - [Commands](#commands)
16
16
  - [Component](#component)
17
17
  - [Configure](#configure)
18
- - [Hub](#hub)
19
- - [Component](#component-1)
20
18
  - [Engine](#engine)
21
19
  - [Workspace](#workspace)
22
20
  - [Developing Components](#developing-components)
@@ -203,11 +201,6 @@ In the same way you can modify one parameter using the `set` command
203
201
  splight configure set <parameter> <value>
204
202
  ```
205
203
 
206
- ### Hub
207
-
208
- This command allows you to interact with the Splight HUB, places where you can find all the
209
- existing components that can be used in the platform.
210
-
211
204
  #### Component
212
205
 
213
206
  - List component
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "splight-cli"
3
- version = "5.4.1"
3
+ version = "5.5.0"
4
4
  description = "Splight Command Line Interface"
5
5
  authors = [
6
6
  {name = "Splight Dev",email = "dev@splight-ae.com"}
@@ -7,7 +7,6 @@ from splight_lib.settings import workspace_settings
7
7
  from splight_cli.component import component_app
8
8
  from splight_cli.config import config_app
9
9
  from splight_cli.engine import engine_app
10
- from splight_cli.hub import hub_app
11
10
  from splight_cli.version import __version__
12
11
  from splight_cli.workspace import workspace_app
13
12
 
@@ -24,7 +23,6 @@ app = typer.Typer(
24
23
  app.add_typer(config_app, name="configure")
25
24
  app.add_typer(component_app, name="component")
26
25
  app.add_typer(engine_app, name="engine")
27
- app.add_typer(hub_app, name="hub")
28
26
  app.add_typer(workspace_app, name="workspace")
29
27
 
30
28
 
@@ -34,7 +34,6 @@ from splight_cli.engine.manager.exceptions import (
34
34
  UpdateParametersError,
35
35
  VersionUpdateError,
36
36
  )
37
- from splight_cli.hub.component.exceptions import HubComponentNotFound
38
37
  from splight_cli.utils.input import prompt_data_address_value, prompt_param
39
38
 
40
39
  SplightModel = Type[SplightDatabaseBaseModel]
@@ -1,14 +0,0 @@
1
- import typer
2
-
3
- from splight_cli.hub.component import component_app
4
- from splight_cli.hub.server import server_app
5
-
6
- hub_app = typer.Typer(
7
- name="Splight Hub",
8
- add_completion=True,
9
- rich_markup_mode="rich",
10
- no_args_is_help=True,
11
- )
12
-
13
- hub_app.add_typer(component_app, name="component")
14
- hub_app.add_typer(server_app, name="server")
@@ -1,73 +0,0 @@
1
- import typer
2
- from rich.console import Console
3
- from splight_lib.models import Component
4
-
5
- from splight_cli.constants import error_style
6
- from splight_cli.hub.component.hub_manager import HubComponentManager
7
-
8
- component_app = typer.Typer(
9
- name="Splight Hub Component",
10
- add_completion=True,
11
- rich_markup_mode="rich",
12
- no_args_is_help=True,
13
- )
14
-
15
- console = Console()
16
- MODEL = Component
17
-
18
-
19
- @component_app.command()
20
- def push(
21
- ctx: typer.Context,
22
- path: str = typer.Argument(..., help="Path to component source code"),
23
- force: bool = typer.Option(
24
- False,
25
- "--force",
26
- "-f",
27
- help="Overwrite existing component in Splight HUB",
28
- ),
29
- ):
30
- try:
31
- manager = HubComponentManager()
32
- manager.push(path, force=force)
33
- except Exception as exc:
34
- console.print(f"Error pushing component: {exc}", style=error_style)
35
- raise typer.Exit(code=1)
36
-
37
-
38
- @component_app.command()
39
- def pull(
40
- ctx: typer.Context,
41
- name: str = typer.Argument(..., help="The component's name"),
42
- version: str = typer.Argument(..., help="The component's version"),
43
- ):
44
- try:
45
- manager = HubComponentManager()
46
- manager.pull(name=name, version=version)
47
- except Exception as exc:
48
- console.print(f"Error pulling component: {exc}", style=error_style)
49
- raise typer.Exit(code=1)
50
-
51
-
52
- @component_app.command()
53
- def list(ctx: typer.Context):
54
- try:
55
- manager = HubComponentManager()
56
- manager.list_components()
57
- except Exception as exc:
58
- console.print(f"Error listing components: {exc}", style=error_style)
59
- raise typer.Exit(code=1)
60
-
61
-
62
- @component_app.command()
63
- def versions(
64
- ctx: typer.Context, name: str = typer.Argument(..., help="Componet's name")
65
- ):
66
- try:
67
- manager = HubComponentManager()
68
- manager.versions(name=name)
69
- except Exception as exc:
70
- console.print(
71
- f"Error getting component versions: {exc}", style=error_style
72
- )
73
- raise typer.Exit(code=1)
@@ -1,109 +0,0 @@
1
- import gzip
2
- import os
3
- import re
4
- import shutil
5
- import sys
6
-
7
- import docker
8
-
9
- from splight_cli.hub.component.exceptions import BuildError
10
-
11
-
12
- class ComponentBuilder:
13
- _RESOURCES_PATH = "resources"
14
- _RESOURCES = [
15
- "Dockerfile",
16
- "installer.py",
17
- ]
18
-
19
- def __init__(self, component_spec: dict, component_path: str):
20
- self._base_path = os.path.dirname(__file__)
21
- self._component_name = component_spec["name"]
22
- self._component_version = component_spec["version"]
23
- self._spl_pkg = (
24
- "splight-lib"
25
- if component_spec["splight_lib_version"]
26
- else "splight-cli"
27
- )
28
- self._spl_pkg_version = (
29
- component_spec["splight_lib_version"]
30
- if component_spec["splight_lib_version"]
31
- else component_spec["splight_cli_version"]
32
- )
33
- self._component_path = component_path
34
- self._docker_client = docker.from_env()
35
-
36
- def build(self) -> str:
37
- original_path = os.getcwd()
38
- self._copy_resources()
39
- os.chdir(self._component_path)
40
- image_file = self._build_component()
41
- self._clean_up()
42
- os.chdir(original_path)
43
- return image_file
44
-
45
- def _build_component(self) -> str:
46
- full_name = f"{self._component_name}-{self._component_version}"
47
- tag = f"component:{full_name}"
48
- streamer = self._build_component_image(tag)
49
- for chunk in streamer:
50
- try:
51
- log = self._parse_chunk(chunk)
52
- except BuildError as exc:
53
- sys.stdout.write(exc)
54
- sys.stdout.flush()
55
- raise exc
56
- if log:
57
- sys.stdout.write(f"{log}\n")
58
- sys.stdout.flush()
59
-
60
- if "stream" in chunk:
61
- match = re.search(
62
- r"(^Successfully built |sha256:)([0-9a-f]+)$",
63
- chunk["stream"],
64
- )
65
- if match:
66
- image_id = match.group(2)
67
- image = self._docker_client.images.get(image_id)
68
- file_name = f"{full_name}.tgz"
69
- with gzip.open(file_name, "wb") as image_file:
70
- for chunk in image.save(named=True):
71
- image_file.write(chunk)
72
- return file_name
73
-
74
- def _build_component_image(self, tag: str):
75
- client = self._docker_client.api
76
- streamer = client.build(
77
- path=".",
78
- tag=tag,
79
- dockerfile="Dockerfile",
80
- rm=True,
81
- pull=True,
82
- quiet=False,
83
- buildargs={
84
- "COMPONENT_NAME": self._component_name,
85
- "COMPONENT_VERSION": self._component_version,
86
- "SPL_PACKAGE": self._spl_pkg,
87
- "SPL_PACKAGE_VERSION": self._spl_pkg_version,
88
- },
89
- decode=True,
90
- )
91
- return streamer
92
-
93
- def _copy_resources(self):
94
- for resource in self._RESOURCES:
95
- resource_path = os.path.join(
96
- self._base_path, self._RESOURCES_PATH, resource
97
- )
98
- shutil.copy(resource_path, self._component_path)
99
-
100
- def _clean_up(self):
101
- for resource in self._RESOURCES:
102
- os.remove(resource)
103
-
104
- def _parse_chunk(self, chunk: dict) -> str:
105
- if "errorDetail" in chunk:
106
- message = chunk["error"]
107
- raise BuildError(message)
108
- log = "".join([str(item) for item in chunk.values()])
109
- return log.strip("\n") if log != "\n" else ""
@@ -1,28 +0,0 @@
1
- class ComponentAlreadyExists(Exception):
2
- def __init__(self, name: str, version: str):
3
- self._msg = f"Component {name}-{version} already exists in HUB"
4
-
5
- def __str__(self) -> str:
6
- return self._msg
7
-
8
-
9
- class ComponentDirectoryAlreadyExists(Exception):
10
- def __init__(self, directory: str):
11
- self._msg = f"Directory with name {directory} already exists in path"
12
-
13
- def __str__(self) -> str:
14
- return self._msg
15
-
16
-
17
- class HubComponentNotFound(Exception):
18
- """Exception raised when a version is invalid."""
19
-
20
- def __init__(self, name: str, version: str):
21
- self._msg = f"Hub component {name} version {version} not found."
22
-
23
- def __str__(self) -> str:
24
- return self._msg
25
-
26
-
27
- class BuildError(Exception):
28
- pass
@@ -1,137 +0,0 @@
1
- import json
2
- import os
3
- import shutil
4
- from typing import Optional
5
-
6
- import pathspec
7
- import py7zr
8
- from pydantic import ValidationError
9
- from rich.console import Console
10
- from rich.table import Table
11
- from splight_lib.models import HubComponent
12
-
13
- from splight_cli.constants import (
14
- COMPRESSION_TYPE,
15
- SPEC_FILE,
16
- SPLIGHT_IGNORE,
17
- success_style,
18
- )
19
- from splight_cli.hub.component.component_builder import ComponentBuilder
20
- from splight_cli.hub.component.exceptions import (
21
- ComponentAlreadyExists,
22
- ComponentDirectoryAlreadyExists,
23
- HubComponentNotFound,
24
- )
25
- from splight_cli.hub.exceptions import SpecFormatError, SpecValidationError
26
- from splight_cli.utils.loader import Loader
27
-
28
- console = Console()
29
-
30
-
31
- class HubComponentManager:
32
- def push(self, path: str, force: Optional[bool] = False):
33
- try:
34
- with open(os.path.join(path, SPEC_FILE)) as fid:
35
- spec = json.load(fid)
36
- except Exception as exc:
37
- raise SpecFormatError(exc)
38
-
39
- # Validate spec fields before pushing the model
40
- try:
41
- component = HubComponent.model_validate(spec)
42
- except ValidationError as exc:
43
- raise SpecValidationError(exc)
44
-
45
- name = spec["name"]
46
- version = spec["version"]
47
-
48
- if not force and self._exists_in_hub(name, version):
49
- raise ComponentAlreadyExists(name, version)
50
-
51
- builder = ComponentBuilder(spec, path)
52
- image_file = builder.build()
53
-
54
- with Loader("Pushing Component to Splight Hub"):
55
- component = HubComponent.upload(path, image_file)
56
-
57
- console.print(
58
- f"Component {component.id} pushed succesfully", style=success_style
59
- )
60
-
61
- def pull(self, name: str, version: str):
62
- with Loader("Pulling component from Splight Hub"):
63
- self._pull_component(name, version)
64
- console.print(
65
- f"Component {name} pulled succesfully", style=success_style
66
- )
67
-
68
- def _pull_component(self, name: str, version: str):
69
- components = HubComponent.list_mine(name=name, version=version)
70
- if not components:
71
- raise HubComponentNotFound(name, version)
72
-
73
- component_file_wrapper = components[0].download()
74
- component_data = component_file_wrapper.read()
75
-
76
- # TODO: search for a better approach
77
- version_modified = version.replace(".", "_")
78
- component_path = f"{name}/{version_modified}"
79
- versioned_name = f"{name}-{version}"
80
- file_name = f"{versioned_name}.{COMPRESSION_TYPE}"
81
- if os.path.exists(component_path):
82
- raise ComponentDirectoryAlreadyExists(component_path)
83
-
84
- try:
85
- with open(file_name, "wb") as fid:
86
- fid.write(component_data)
87
-
88
- with py7zr.SevenZipFile(file_name, "r") as z:
89
- z.extractall(path=".")
90
- shutil.move(f"{versioned_name}", component_path)
91
-
92
- except Exception as exc:
93
- raise exc
94
- finally:
95
- if os.path.exists(file_name):
96
- os.remove(file_name)
97
-
98
- def list_components(self):
99
- components = HubComponent.list_mine(limit_=10000)
100
- names = set([component.name for component in components])
101
- table = Table("Name")
102
- [table.add_row(name) for name in names]
103
- console.print(table)
104
-
105
- def versions(self, name: str):
106
- components = HubComponent.list_mine(name=name)
107
- table = Table("Name", "Version", "Verification", "Privacy Policy")
108
- for item in components:
109
- table.add_row(
110
- name, item.version, item.verification, item.privacy_policy
111
- )
112
- console.print(table)
113
-
114
- def _get_ignore_pathspec(self, path):
115
- try:
116
- with open(
117
- os.path.join(path, SPLIGHT_IGNORE), "r"
118
- ) as splightignore:
119
- return pathspec.PathSpec.from_lines(
120
- "gitwildmatch", splightignore
121
- )
122
- except FileNotFoundError:
123
- return None
124
-
125
- def _get_component(self, name: str, version: str):
126
- components = HubComponent.list_all(name=name, version=version)
127
- return components
128
-
129
- def _exists_in_hub(self, name: str, version: str) -> bool:
130
- components = self._get_component(name, version)
131
- return len(components) > 0
132
-
133
- def fetch_component_version(self, name: str, version: str):
134
- components = self._get_component(name, version)
135
- if not components:
136
- raise HubComponentNotFound(name, version)
137
- return components[0]
@@ -1,21 +0,0 @@
1
- # syntax=docker/dockerfile:1
2
- FROM --platform=linux/amd64 python:3.11.7-slim
3
-
4
- WORKDIR /whl
5
- RUN pip install --upgrade splight-runner
6
-
7
- ARG SPL_PACKAGE
8
- ARG SPL_PACKAGE_VERSION
9
- RUN pip install ${SPL_PACKAGE}==${SPL_PACKAGE_VERSION}
10
-
11
- ARG COMPONENT_NAME
12
- ARG COMPONENT_VERSION
13
-
14
- WORKDIR /app
15
- COPY . .
16
- RUN python installer.py --name ${COMPONENT_NAME} --version ${COMPONENT_VERSION}
17
-
18
- # Cleaning up files
19
- RUN rm installer.py Dockerfile
20
-
21
- ENTRYPOINT ["splight-runner", "run-component"]
@@ -1,80 +0,0 @@
1
- import argparse
2
- import os
3
- import subprocess
4
- from typing import List
5
-
6
-
7
- class HubComponentInstaller:
8
- _INIT_FILE = "Initialization"
9
-
10
- def __init__(self, name: str, version: str) -> None:
11
- self._name = name
12
- self._version = version
13
- self._component_path = os.getenv("APP_DIR", "/app")
14
-
15
- def _handle_run(self, command: List[str]) -> None:
16
- command: str = " ".join(command)
17
- try:
18
- subprocess.run(
19
- command, check=True, cwd=self._component_path, shell=True
20
- )
21
- except subprocess.CalledProcessError as e:
22
- raise Exception(
23
- f"Failed to run command: {e.cmd}. Output: {e.output}"
24
- )
25
-
26
- def _validate(self):
27
- # VALIDATE INIT FILE EXISTS
28
- if not os.path.isfile(
29
- os.path.join(self._component_path, self._INIT_FILE)
30
- ):
31
- raise Exception(
32
- f"{self._INIT_FILE} file is missing in {self._component_path}"
33
- )
34
-
35
- def _load_commands(self) -> List[List[str]]:
36
- file = os.path.join(self._component_path, self._INIT_FILE)
37
- lines: List[List[str]] = []
38
- lines.append(["RUN", "pip", "cache", "purge"])
39
- with open(file) as f:
40
- for line in f:
41
- line = line.strip()
42
- if line.startswith("#") or line == "":
43
- continue
44
- lines.append(line.split(" "))
45
- return lines
46
-
47
- def install(self):
48
- self._validate()
49
- commands = self._load_commands()
50
- for command in commands:
51
- prefix: str = command[0].lower()
52
- handler = getattr(self, f"_handle_{prefix}", None)
53
- if not handler:
54
- raise Exception(f"Invalid command: {prefix}")
55
- handler(command[1:])
56
-
57
-
58
- if __name__ == "__main__":
59
- parser = argparse.ArgumentParser(description="Install Hub Component")
60
- parser.add_argument(
61
- "-n",
62
- "--name",
63
- type=str,
64
- nargs=1,
65
- help="Hub Component Name",
66
- required=True,
67
- )
68
- parser.add_argument(
69
- "-v",
70
- "--version",
71
- type=str,
72
- nargs=1,
73
- help="Hub Component Version",
74
- required=True,
75
- )
76
-
77
- args = parser.parse_args()
78
-
79
- manager = HubComponentInstaller(name=args.name[0], version=args.version[0])
80
- manager.install()
@@ -1,135 +0,0 @@
1
- import os
2
- from unittest.mock import mock_open, patch
3
- from uuid import uuid4
4
-
5
- import pytest
6
- from splight_lib.models import HubComponent
7
-
8
- from splight_cli.component import ComponentManager
9
- from splight_cli.hub.component.component_builder import ComponentBuilder
10
- from splight_cli.hub.component.exceptions import (
11
- ComponentAlreadyExists,
12
- HubComponentNotFound,
13
- )
14
- from splight_cli.hub.component.hub_manager import HubComponentManager
15
- from splight_cli.hub.exceptions import SpecFormatError, SpecValidationError
16
-
17
- BASE_PATH = os.getcwd()
18
- TEST_COMPONENT_PATH = os.path.join(
19
- BASE_PATH, "splight_cli/tests/test_component/"
20
- )
21
- with open(os.path.join(TEST_COMPONENT_PATH, "spec.json"), "r") as fid:
22
- HUB_COMPONENT = HubComponent.model_validate_json(fid.read())
23
- HUB_COMPONENT.id = str(uuid4())
24
-
25
-
26
- @patch.object(ComponentBuilder, "build", return_value="image_file")
27
- @patch.object(ComponentManager, "test", return_value=None)
28
- @patch.object(HubComponentManager, "_exists_in_hub", return_value=False)
29
- def test_push(mock_exists, mock_component_manager, mock_builder):
30
- manager = HubComponentManager()
31
- test_component_path = os.path.join(
32
- os.getcwd(), "splight_cli/tests/test_component/"
33
- )
34
- with patch.object(
35
- HubComponent, "upload", return_value=HUB_COMPONENT
36
- ) as mock_hub:
37
- manager.push(test_component_path)
38
- mock_builder.assert_called()
39
- mock_hub.assert_called_with(test_component_path, "image_file")
40
-
41
-
42
- @patch.object(ComponentManager, "test", return_value=None)
43
- @patch(
44
- "splight_cli.hub.component.hub_manager.json.load", side_effect=Exception
45
- )
46
- def test_push_spec_format_error(mock_exists, mock_json_load):
47
- manager = HubComponentManager()
48
- test_component_path = os.path.join(
49
- os.getcwd(), "splight_cli/tests/test_component/"
50
- )
51
- with pytest.raises(SpecFormatError):
52
- manager.push(test_component_path, force=False)
53
-
54
-
55
- @patch.object(ComponentManager, "test", return_value=None)
56
- @patch(
57
- "splight_cli.hub.component.hub_manager.json.load",
58
- return_value={"name": "mycomponent", "splight_lib_version": "1.1.0"},
59
- )
60
- def test_push_spec_missing_keys(mock_exists, mock_json_load):
61
- manager = HubComponentManager()
62
- test_component_path = os.path.join(
63
- os.getcwd(), "splight_cli/tests/test_component/"
64
- )
65
- with pytest.raises(SpecValidationError):
66
- manager.push(test_component_path, force=False)
67
-
68
-
69
- @patch.object(ComponentManager, "test", return_value=None)
70
- @patch(
71
- "splight_cli.hub.component.hub_manager.json.load",
72
- return_value={
73
- "name": "mycomponent",
74
- "version": "0.1.0",
75
- "splight_lib_version": "3.0.0",
76
- "input": "wrong_input_type",
77
- },
78
- )
79
- def test_push_spec_wrong_attr_type(mock_exists, mock_json_load):
80
- manager = HubComponentManager()
81
- test_component_path = os.path.join(
82
- os.getcwd(), "splight_cli/tests/test_component/"
83
- )
84
- with pytest.raises(SpecValidationError):
85
- manager.push(test_component_path, force=False)
86
-
87
-
88
- @patch.object(ComponentManager, "test", return_value=None)
89
- @patch.object(HubComponentManager, "_exists_in_hub", return_value=True)
90
- def test_push_already_exists(mock_exists, mock_component_manager):
91
- manager = HubComponentManager()
92
- test_component_path = os.path.join(
93
- os.getcwd(), "splight_cli/tests/test_component/"
94
- )
95
- with pytest.raises(ComponentAlreadyExists):
96
- manager.push(test_component_path, force=False)
97
-
98
-
99
- @patch.object(ComponentBuilder, "build", return_value="image_file")
100
- @patch.object(ComponentManager, "test", return_value=None)
101
- @patch.object(HubComponentManager, "_exists_in_hub", return_value=True)
102
- def test_push_already_exists_with_force(
103
- mock_exists, mock_component_manager, mock_builder
104
- ):
105
- manager = HubComponentManager()
106
- test_component_path = os.path.join(
107
- os.getcwd(), "splight_cli/tests/test_component/"
108
- )
109
- with patch.object(
110
- HubComponent, "upload", return_value=HUB_COMPONENT
111
- ) as mock_hub:
112
- manager.push(test_component_path, force=True)
113
- mock_builder.assert_called()
114
- mock_hub.assert_called_with(test_component_path, "image_file")
115
-
116
-
117
- @patch.object(HubComponent, "list_mine", return_value=[HUB_COMPONENT])
118
- @patch.object(
119
- HubComponent,
120
- "download",
121
- return_value=open(os.path.join(TEST_COMPONENT_PATH, "spec.json"), "r"),
122
- )
123
- @patch("builtins.open", new_callable=mock_open())
124
- @patch("py7zr.SevenZipFile")
125
- @patch("shutil.move", return_value=None)
126
- def test_pull(mock_move, mock_zip, mock_open, mock_download, mock_list):
127
- manager = HubComponentManager()
128
- manager.pull(name="TestComponent", version="1.1.0")
129
-
130
-
131
- @patch.object(HubComponent, "list_mine", return_value=[])
132
- def test_pull_not_found(mock_list):
133
- manager = HubComponentManager()
134
- with pytest.raises(HubComponentNotFound):
135
- manager._pull_component(name="TestComponent", version="1.1.0")
@@ -1,21 +0,0 @@
1
- from json import loads
2
-
3
-
4
- class SpecFormatError(Exception):
5
- def __init__(self, error):
6
- self._msg = f"Error while parsing 'spec.json': {error}"
7
-
8
- def __str__(self) -> str:
9
- return self._msg
10
-
11
-
12
- class SpecValidationError(Exception):
13
- def __init__(self, error):
14
- field = loads(error.json())[0]["loc"][0]
15
- message = loads(error.json())[0]["msg"]
16
- self._msg = (
17
- f"Validation error for field in 'spec.json': '{field}' {message}"
18
- )
19
-
20
- def __str__(self) -> str:
21
- return self._msg
@@ -1,60 +0,0 @@
1
- import typer
2
- from rich.console import Console
3
- from splight_lib.models import Component
4
-
5
- from splight_cli.constants import error_style
6
- from splight_cli.hub.server.server_manager import HubServerManager
7
-
8
- server_app = typer.Typer(
9
- name="Splight Hub Server",
10
- add_completion=True,
11
- rich_markup_mode="rich",
12
- no_args_is_help=True,
13
- )
14
-
15
- console = Console()
16
- MODEL = Component
17
-
18
-
19
- @server_app.command()
20
- def push(
21
- ctx: typer.Context,
22
- path: str = typer.Argument(..., help="Path to server files"),
23
- force: bool = typer.Option(
24
- False,
25
- "--force",
26
- "-f",
27
- help="Overwrite existing server in Splight HUB",
28
- ),
29
- ):
30
- try:
31
- manager = HubServerManager()
32
- manager.push(path, force=force)
33
- except Exception as exc:
34
- console.print(f"Error pushing server: {exc}", style=error_style)
35
- raise
36
- raise typer.Exit(code=1)
37
-
38
-
39
- @server_app.command()
40
- def pull(
41
- ctx: typer.Context,
42
- name: str = typer.Argument(..., help="The servers's name"),
43
- version: str = typer.Argument(..., help="The servers's version"),
44
- ):
45
- try:
46
- manager = HubServerManager()
47
- manager.pull(name=name, version=version)
48
- except Exception as exc:
49
- console.print(f"Error pulling server: {exc}", style=error_style)
50
- raise typer.Exit(code=1)
51
-
52
-
53
- @server_app.command()
54
- def list(ctx: typer.Context):
55
- try:
56
- manager = HubServerManager()
57
- manager.list_servers()
58
- except Exception as exc:
59
- console.print(f"Error listing servers: {exc}", style=error_style)
60
- raise typer.Exit(code=1)
@@ -1,28 +0,0 @@
1
- class ServerAlreadyExists(Exception):
2
- def __init__(self, name: str, version: str):
3
- self._msg = f"Server {name}-{version} already exists in HUB"
4
-
5
- def __str__(self) -> str:
6
- return self._msg
7
-
8
-
9
- class ServerDirectoryAlreadyExists(Exception):
10
- def __init__(self, directory: str):
11
- self._msg = f"Directory with name {directory} already exists in path"
12
-
13
- def __str__(self) -> str:
14
- return self._msg
15
-
16
-
17
- class HubServerNotFound(Exception):
18
- """Exception raised when a version is invalid."""
19
-
20
- def __init__(self, name: str, version: str):
21
- self._msg = f"Hub server {name} version {version} not found."
22
-
23
- def __str__(self) -> str:
24
- return self._msg
25
-
26
-
27
- class BuildError(Exception):
28
- pass
@@ -1,73 +0,0 @@
1
- import gzip
2
- import os
3
- import re
4
- import sys
5
-
6
- import docker
7
-
8
- from splight_cli.hub.server.exceptions import BuildError
9
-
10
-
11
- class ServerBuilder:
12
- def __init__(self, server_spec: dict, server_path: str):
13
- self._base_path = os.path.dirname(__file__)
14
- self._server_name = server_spec["name"]
15
- self._server_version = server_spec["version"]
16
- self._server_path = server_path
17
- self._docker_client = docker.from_env()
18
-
19
- def build(self) -> str:
20
- original_path = os.getcwd()
21
- os.chdir(self._server_path)
22
- image_file = self._build_server()
23
- os.chdir(original_path)
24
- return image_file
25
-
26
- def _build_server(self) -> str:
27
- full_name = f"{self._server_name}-{self._server_version}"
28
- tag = f"server:{full_name}"
29
- streamer = self._build_server_image(tag)
30
- for chunk in streamer:
31
- try:
32
- log = self._parse_chunk(chunk)
33
- except BuildError as exc:
34
- sys.stdout.write(exc)
35
- sys.stdout.flush()
36
- raise exc
37
- if log:
38
- sys.stdout.write(f"{log}\n")
39
- sys.stdout.flush()
40
-
41
- if "stream" in chunk:
42
- match = re.search(
43
- r"(^Successfully built |sha256:)([0-9a-f]+)$",
44
- chunk["stream"],
45
- )
46
- if match:
47
- image_id = match.group(2)
48
- image = self._docker_client.images.get(image_id)
49
- file_name = f"{full_name}.tgz"
50
- with gzip.open(file_name, "wb") as image_file:
51
- for chunk in image.save(named=True):
52
- image_file.write(chunk)
53
- return file_name
54
-
55
- def _build_server_image(self, tag: str):
56
- client = self._docker_client.api
57
- streamer = client.build(
58
- path=".",
59
- tag=tag,
60
- dockerfile="Dockerfile",
61
- rm=True,
62
- pull=True,
63
- quiet=False,
64
- decode=True,
65
- )
66
- return streamer
67
-
68
- def _parse_chunk(self, chunk: dict) -> str:
69
- if "errorDetail" in chunk:
70
- message = chunk["error"]
71
- raise BuildError(message)
72
- log = "".join([str(item) for item in chunk.values()])
73
- return log.strip("\n") if log != "\n" else ""
@@ -1,116 +0,0 @@
1
- import json
2
- import os
3
- import shutil
4
- from collections import namedtuple
5
- from typing import Optional
6
-
7
- import py7zr
8
- from pydantic import ValidationError
9
- from rich.console import Console
10
- from rich.table import Table
11
- from splight_lib.models import HubServer
12
-
13
- from splight_cli.constants import COMPRESSION_TYPE, SPEC_FILE, success_style
14
- from splight_cli.hub.exceptions import SpecFormatError, SpecValidationError
15
- from splight_cli.hub.server.exceptions import (
16
- HubServerNotFound,
17
- ServerAlreadyExists,
18
- ServerDirectoryAlreadyExists,
19
- )
20
- from splight_cli.hub.server.server_builder import ServerBuilder
21
- from splight_cli.utils.loader import Loader
22
-
23
- console = Console()
24
-
25
-
26
- class HubServerManager:
27
- def push(self, path: str, force: Optional[bool] = False):
28
- try:
29
- with open(os.path.join(path, SPEC_FILE)) as fid:
30
- spec = json.load(fid)
31
- except Exception as exc:
32
- raise SpecFormatError(exc)
33
-
34
- # Validate spec fields before pushing the model
35
- try:
36
- server = HubServer.model_validate(spec)
37
- except ValidationError as exc:
38
- raise SpecValidationError(exc)
39
-
40
- name = spec["name"]
41
- version = spec["version"]
42
-
43
- if not force and self._exists_in_hub(name, version):
44
- raise ServerAlreadyExists(name, version)
45
-
46
- builder = ServerBuilder(spec, path)
47
- image_file = builder.build()
48
-
49
- with Loader("Pushing Server to Splight Hub"):
50
- server = HubServer.upload(path, image_file)
51
-
52
- if image_file:
53
- os.remove(image_file)
54
-
55
- console.print(
56
- f"Server {server.id} pushed succesfully", style=success_style
57
- )
58
-
59
- def pull(self, name: str, version: str):
60
- with Loader("Pulling server from Splight Hub"):
61
- self._pull_server(name, version)
62
- console.print(f"Server {name} pulled succesfully", style=success_style)
63
-
64
- def _pull_server(self, name: str, version: str):
65
- server = self._get_hub_server(name, version)
66
- name, version = server.name, server.version
67
-
68
- file_wrapper = server.download()
69
- file_data = file_wrapper.read()
70
-
71
- version_modified = version.replace(".", "_")
72
- server_path = f"{name}/{version_modified}"
73
- versioned_name = f"{name}-{version}"
74
- file_name = f"{versioned_name}.{COMPRESSION_TYPE}"
75
- if os.path.exists(server_path):
76
- raise ServerDirectoryAlreadyExists(server_path)
77
-
78
- try:
79
- with open(file_name, "wb") as fid:
80
- fid.write(file_data)
81
-
82
- with py7zr.SevenZipFile(file_name, "r") as z:
83
- z.extractall(path=".")
84
- shutil.move(f"{versioned_name}", server_path)
85
-
86
- except Exception as exc:
87
- raise exc
88
- finally:
89
- if os.path.exists(file_name):
90
- os.remove(file_name)
91
-
92
- def _get_hub_server(self, name: str, version: str) -> HubServer:
93
- servers = HubServer.list(name=name, version=version)
94
- if not servers:
95
- raise HubServerNotFound(name, version)
96
- return servers[0]
97
-
98
- def list_servers(self):
99
- servers_tuple = namedtuple("Server", ["name", "version"])
100
- all_servers = HubServer.list()
101
- servers = set(
102
- [
103
- servers_tuple(server.name, server.version)
104
- for server in all_servers
105
- ]
106
- )
107
- table = Table("Name", "Version", title="Hub Server List")
108
- [table.add_row(server.name, server.version) for server in servers]
109
- console.print(table)
110
-
111
- def _exists_in_hub(self, name: str, version: str) -> bool:
112
- try:
113
- self._get_hub_server(name, version)
114
- return True
115
- except HubServerNotFound:
116
- return False