lumilake-cli 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lumilake_cli/__init__.py +0 -0
- lumilake_cli/cli.py +54 -0
- lumilake_cli/commands/__init__.py +69 -0
- lumilake_cli/commands/base.py +41 -0
- lumilake_cli/commands/deploy.py +562 -0
- lumilake_cli/commands/job.py +661 -0
- lumilake_cli/commands/trace.py +143 -0
- lumilake_cli/commands/worker.py +39 -0
- lumilake_cli/core/__init__.py +0 -0
- lumilake_cli/core/config.py +39 -0
- lumilake_cli/core/http.py +132 -0
- lumilake_cli/core/logging.py +34 -0
- lumilake_cli/core/query.py +16 -0
- lumilake_cli/core/typer.py +12 -0
- lumilake_cli-0.1.0.dist-info/METADATA +28 -0
- lumilake_cli-0.1.0.dist-info/RECORD +20 -0
- lumilake_cli-0.1.0.dist-info/WHEEL +5 -0
- lumilake_cli-0.1.0.dist-info/entry_points.txt +2 -0
- lumilake_cli-0.1.0.dist-info/licenses/LICENSE +201 -0
- lumilake_cli-0.1.0.dist-info/top_level.txt +1 -0
lumilake_cli/__init__.py
ADDED
|
File without changes
|
lumilake_cli/cli.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Lumilake CLI entrypoint.
|
|
2
|
+
|
|
3
|
+
Installs a typer-aware handler on the shared ``Lumilake`` logger root so
|
|
4
|
+
records from every workspace package render with the CLI colour palette.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from lumilake.log import ColorFormatter, get_default_logger
|
|
11
|
+
|
|
12
|
+
from .commands import register
|
|
13
|
+
from .core.typer import get_typer
|
|
14
|
+
|
|
15
|
+
root_app = get_typer(help="Lumilake command line interface.")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class _TyperHandler(logging.Handler):
|
|
19
|
+
"""Routes records through ``typer.echo``: stdout for INFO/DEBUG,
|
|
20
|
+
stderr for WARNING/ERROR/CRITICAL. Honours typer's color detection.
|
|
21
|
+
Coloring is left to ``ColorFormatter``.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
25
|
+
try:
|
|
26
|
+
message = self.format(record)
|
|
27
|
+
except Exception:
|
|
28
|
+
self.handleError(record)
|
|
29
|
+
return
|
|
30
|
+
typer.echo(message, err=record.levelno >= logging.WARNING)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _install_handler() -> None:
|
|
34
|
+
root = get_default_logger()
|
|
35
|
+
if any(isinstance(h, _TyperHandler) for h in root.handlers):
|
|
36
|
+
return
|
|
37
|
+
# Drop get_default_logger's StreamHandler so records aren't doubled.
|
|
38
|
+
for existing in list(root.handlers):
|
|
39
|
+
root.removeHandler(existing)
|
|
40
|
+
handler = _TyperHandler()
|
|
41
|
+
handler.setFormatter(ColorFormatter())
|
|
42
|
+
root.addHandler(handler)
|
|
43
|
+
root.propagate = False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def main() -> None:
|
|
47
|
+
"""Attach command groups and dispatch to Typer."""
|
|
48
|
+
_install_handler()
|
|
49
|
+
register(root_app)
|
|
50
|
+
root_app()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
main()
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Command modules for the Lumilake CLI."""
|
|
2
|
+
|
|
3
|
+
from importlib.util import find_spec
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from .base import app as base_app
|
|
8
|
+
from .job import app as job_app
|
|
9
|
+
from .trace import app as trace_app
|
|
10
|
+
from .worker import app as worker_app
|
|
11
|
+
|
|
12
|
+
# The ``[deploy]`` extra pulls ``lumilake-deploy`` and
|
|
13
|
+
# ``flowmesh-cli-stack``; gate on both up front so real ImportError
|
|
14
|
+
# from inside .deploy still bubbles up loudly.
|
|
15
|
+
_DEPLOY_AVAILABLE = (
|
|
16
|
+
find_spec("lumilake_deploy") is not None
|
|
17
|
+
and find_spec("flowmesh_cli_stack") is not None
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
if _DEPLOY_AVAILABLE:
|
|
21
|
+
from .deploy import app as deploy_app
|
|
22
|
+
else:
|
|
23
|
+
_DEPLOY_INSTALL_HINT = (
|
|
24
|
+
"lumilake deploy requires the `deploy` extra. Install with "
|
|
25
|
+
"`pip install 'lumilake[cli]'` or "
|
|
26
|
+
"`pip install 'lumilake-cli[deploy]'`."
|
|
27
|
+
)
|
|
28
|
+
deploy_app = typer.Typer(
|
|
29
|
+
help=(
|
|
30
|
+
"Deploy and manage the Lumilake stack. Install with "
|
|
31
|
+
"`pip install 'lumilake[cli]'` or "
|
|
32
|
+
"`pip install 'lumilake-cli[deploy]'` to enable."
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
def _deploy_hint() -> None:
|
|
37
|
+
typer.echo(_DEPLOY_INSTALL_HINT, err=True)
|
|
38
|
+
raise typer.Exit(code=2)
|
|
39
|
+
|
|
40
|
+
@deploy_app.callback(invoke_without_command=True)
|
|
41
|
+
def _deploy_no_subcommand(ctx: typer.Context) -> None:
|
|
42
|
+
if ctx.resilient_parsing or ctx.invoked_subcommand is not None:
|
|
43
|
+
return
|
|
44
|
+
_deploy_hint()
|
|
45
|
+
|
|
46
|
+
for _name in (
|
|
47
|
+
"init",
|
|
48
|
+
"doctor",
|
|
49
|
+
"build",
|
|
50
|
+
"pull",
|
|
51
|
+
"up",
|
|
52
|
+
"down",
|
|
53
|
+
"clean",
|
|
54
|
+
"reset",
|
|
55
|
+
"status",
|
|
56
|
+
"restart",
|
|
57
|
+
"logs",
|
|
58
|
+
"update-flowmesh",
|
|
59
|
+
):
|
|
60
|
+
deploy_app.command(_name)(_deploy_hint)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def register(app: typer.Typer) -> None:
|
|
64
|
+
"""Register command groups on the root app."""
|
|
65
|
+
app.add_typer(base_app)
|
|
66
|
+
app.add_typer(deploy_app, name="deploy")
|
|
67
|
+
app.add_typer(job_app, name="job")
|
|
68
|
+
app.add_typer(worker_app, name="worker")
|
|
69
|
+
app.add_typer(trace_app, name="trace")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
|
|
6
|
+
from ..core import logging
|
|
7
|
+
from ..core.config import DEFAULT_CONFIG_PATH
|
|
8
|
+
from ..core.http import HttpError, client_from_config, resolve_base_url
|
|
9
|
+
from ..core.typer import get_typer
|
|
10
|
+
|
|
11
|
+
app = get_typer()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command()
|
|
15
|
+
def config(
|
|
16
|
+
config_path: Path = typer.Option(
|
|
17
|
+
DEFAULT_CONFIG_PATH, "--config", help="Path to configuration file"
|
|
18
|
+
),
|
|
19
|
+
) -> None:
|
|
20
|
+
"""Show the resolved Lumilake CLI configuration."""
|
|
21
|
+
base_url, source = resolve_base_url(config_path)
|
|
22
|
+
payload = {"base_url": base_url, "source": source, "config_path": str(config_path)}
|
|
23
|
+
logging.log(json.dumps(payload, indent=2))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@app.command()
|
|
27
|
+
def info() -> None:
|
|
28
|
+
"""Query server health status."""
|
|
29
|
+
client = client_from_config()
|
|
30
|
+
try:
|
|
31
|
+
response = client.get("/healthz")
|
|
32
|
+
except HttpError as exc:
|
|
33
|
+
logging.error(str(exc))
|
|
34
|
+
raise typer.Exit(code=1)
|
|
35
|
+
logging.log(json.dumps(response.json(), indent=2))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@app.command()
|
|
39
|
+
def health() -> None:
|
|
40
|
+
"""Check if the Lumilake server is reachable and healthy."""
|
|
41
|
+
info()
|