msdev 0.9.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.
- msdev/__init__.py +3 -0
- msdev/cli.py +1460 -0
- msdev/core/__init__.py +1 -0
- msdev/core/config.py +193 -0
- msdev/core/guides.py +100 -0
- msdev/core/inventory.py +1390 -0
- msdev/core/limits.py +44 -0
- msdev/core/resources.py +300 -0
- msdev/core/services/__init__.py +111 -0
- msdev/core/services/context.py +61 -0
- msdev/core/services/environment.py +84 -0
- msdev/core/services/execution.py +136 -0
- msdev/core/services/model.py +1085 -0
- msdev/core/services/node.py +210 -0
- msdev/core/services/npu.py +116 -0
- msdev/core/services/workspace.py +567 -0
- msdev/core/transport.py +1225 -0
- msdev/core/workspace/__init__.py +36 -0
- msdev/core/workspace/access.py +1216 -0
- msdev/core/workspace/client.py +274 -0
- msdev/core/workspace/paths.py +45 -0
- msdev/core/workspace/registry.py +151 -0
- msdev/daemon.py +1322 -0
- msdev/session/__init__.py +13 -0
- msdev/session/export.py +190 -0
- msdev/session/log.py +269 -0
- msdev-0.9.0.dist-info/METADATA +295 -0
- msdev-0.9.0.dist-info/RECORD +31 -0
- msdev-0.9.0.dist-info/WHEEL +5 -0
- msdev-0.9.0.dist-info/entry_points.txt +3 -0
- msdev-0.9.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"""Typed command execution application service."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Any, Callable, Mapping
|
|
7
|
+
|
|
8
|
+
from ..limits import (
|
|
9
|
+
DEFAULT_EXEC_TIMEOUT_SECONDS,
|
|
10
|
+
validate_exec_timeout_seconds,
|
|
11
|
+
)
|
|
12
|
+
from .context import ServiceContext
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class ExecRequest:
|
|
17
|
+
environment: str
|
|
18
|
+
argv: tuple[str, ...]
|
|
19
|
+
cwd: str | None = None
|
|
20
|
+
env: Mapping[str, str] = field(default_factory=dict)
|
|
21
|
+
timeout_seconds: float = DEFAULT_EXEC_TIMEOUT_SECONDS
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class ExecResult:
|
|
26
|
+
environment: str
|
|
27
|
+
returncode: int
|
|
28
|
+
stdout: str
|
|
29
|
+
stderr: str
|
|
30
|
+
stdout_truncated: bool = False
|
|
31
|
+
stderr_truncated: bool = False
|
|
32
|
+
output_drain_truncated: bool = False
|
|
33
|
+
timed_out: bool = False
|
|
34
|
+
cancelled: bool = False
|
|
35
|
+
cwd: str | None = None
|
|
36
|
+
runtime: dict[str, Any] | None = None
|
|
37
|
+
environments: tuple[Any, ...] = ()
|
|
38
|
+
raw: dict[str, Any] = field(default_factory=dict, repr=False)
|
|
39
|
+
|
|
40
|
+
def to_dict(self) -> dict[str, Any]:
|
|
41
|
+
return {"environment": self.environment, **self.raw}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ExecutionService:
|
|
45
|
+
def __init__(self, context: ServiceContext):
|
|
46
|
+
self.context = context
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _validate(request: ExecRequest) -> tuple[str, tuple[str, ...], dict[str, str]]:
|
|
50
|
+
environment = (
|
|
51
|
+
request.environment
|
|
52
|
+
if isinstance(request.environment, str) and request.environment.strip()
|
|
53
|
+
else ""
|
|
54
|
+
)
|
|
55
|
+
if not environment:
|
|
56
|
+
raise ValueError("environment must be a non-empty string")
|
|
57
|
+
argv = tuple(request.argv)
|
|
58
|
+
if not argv or not all(isinstance(item, str) and item for item in argv):
|
|
59
|
+
raise ValueError("exec argv must be a non-empty string array")
|
|
60
|
+
env: dict[str, str] = {}
|
|
61
|
+
for key, value in request.env.items():
|
|
62
|
+
if not isinstance(key, str) or not key:
|
|
63
|
+
raise ValueError("environment names must be non-empty strings")
|
|
64
|
+
if not isinstance(value, str):
|
|
65
|
+
raise ValueError("environment values must be strings")
|
|
66
|
+
env[key] = value
|
|
67
|
+
if request.cwd is not None and not isinstance(request.cwd, str):
|
|
68
|
+
raise ValueError("cwd must be a string")
|
|
69
|
+
validate_exec_timeout_seconds(request.timeout_seconds)
|
|
70
|
+
return environment, argv, env
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def _params(
|
|
74
|
+
request: ExecRequest,
|
|
75
|
+
argv: tuple[str, ...],
|
|
76
|
+
env: dict[str, str],
|
|
77
|
+
) -> dict[str, Any]:
|
|
78
|
+
return {
|
|
79
|
+
"command": list(argv),
|
|
80
|
+
"cwd": request.cwd,
|
|
81
|
+
"env": env,
|
|
82
|
+
"timeout_seconds": validate_exec_timeout_seconds(
|
|
83
|
+
request.timeout_seconds
|
|
84
|
+
),
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def _result(environment: str, result: Any) -> ExecResult:
|
|
89
|
+
if not isinstance(result, dict):
|
|
90
|
+
raise RuntimeError("exec returned a non-object result")
|
|
91
|
+
if "returncode" not in result:
|
|
92
|
+
raise RuntimeError("exec result is missing returncode")
|
|
93
|
+
raw = dict(result)
|
|
94
|
+
runtime = raw.get("runtime")
|
|
95
|
+
if runtime is not None and not isinstance(runtime, dict):
|
|
96
|
+
raise RuntimeError("exec result runtime must be an object")
|
|
97
|
+
environments = raw.get("environments") or ()
|
|
98
|
+
if not isinstance(environments, (list, tuple)):
|
|
99
|
+
raise RuntimeError("exec result environments must be an array")
|
|
100
|
+
return ExecResult(
|
|
101
|
+
environment=environment,
|
|
102
|
+
returncode=int(raw["returncode"]),
|
|
103
|
+
stdout=str(raw.get("stdout") or ""),
|
|
104
|
+
stderr=str(raw.get("stderr") or ""),
|
|
105
|
+
stdout_truncated=bool(raw.get("stdout_truncated", False)),
|
|
106
|
+
stderr_truncated=bool(raw.get("stderr_truncated", False)),
|
|
107
|
+
output_drain_truncated=bool(
|
|
108
|
+
raw.get("output_drain_truncated", False)
|
|
109
|
+
),
|
|
110
|
+
timed_out=bool(raw.get("timed_out", False)),
|
|
111
|
+
cancelled=bool(raw.get("cancelled", False)),
|
|
112
|
+
cwd=raw.get("cwd"),
|
|
113
|
+
runtime=runtime,
|
|
114
|
+
environments=tuple(environments),
|
|
115
|
+
raw=raw,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
def run(self, request: ExecRequest) -> ExecResult:
|
|
119
|
+
environment, argv, env = self._validate(request)
|
|
120
|
+
result = self.context.transport_for_environment(environment).call(
|
|
121
|
+
"exec",
|
|
122
|
+
self._params(request, argv, env),
|
|
123
|
+
)
|
|
124
|
+
return self._result(environment, result)
|
|
125
|
+
|
|
126
|
+
def stream(
|
|
127
|
+
self,
|
|
128
|
+
request: ExecRequest,
|
|
129
|
+
on_output: Callable[[str, bytes], None],
|
|
130
|
+
) -> ExecResult:
|
|
131
|
+
environment, argv, env = self._validate(request)
|
|
132
|
+
result = self.context.transport_for_environment(environment).stream_exec(
|
|
133
|
+
self._params(request, argv, env),
|
|
134
|
+
on_output,
|
|
135
|
+
)
|
|
136
|
+
return self._result(environment, result)
|