ominfra 0.0.0.dev142__py3-none-any.whl → 0.0.0.dev143__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/manage/__init__.py +10 -0
- ominfra/manage/__main__.py +4 -0
- ominfra/manage/bootstrap.py +11 -0
- ominfra/manage/bootstrap_.py +18 -0
- ominfra/manage/commands/base.py +133 -1
- ominfra/manage/commands/execution.py +23 -0
- ominfra/manage/commands/inject.py +122 -0
- ominfra/manage/commands/marshal.py +26 -0
- ominfra/manage/config.py +10 -0
- ominfra/manage/inject.py +55 -0
- ominfra/manage/main.py +49 -89
- ominfra/manage/marshal.py +12 -0
- ominfra/manage/remote/__init__.py +0 -0
- ominfra/manage/{protocol.py → remote/channel.py} +9 -2
- ominfra/manage/remote/config.py +12 -0
- ominfra/manage/remote/execution.py +193 -0
- ominfra/manage/remote/inject.py +29 -0
- ominfra/manage/{payload.py → remote/payload.py} +7 -1
- ominfra/manage/{spawning.py → remote/spawning.py} +29 -29
- ominfra/pyremote.py +40 -3
- ominfra/scripts/journald2aws.py +98 -50
- ominfra/scripts/manage.py +1854 -169
- ominfra/scripts/supervisor.py +99 -50
- ominfra/supervisor/inject.py +2 -1
- {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev143.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev143.dist-info}/RECORD +30 -17
- {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev143.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev143.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev143.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev143.dist-info}/top_level.txt +0 -0
ominfra/manage/__init__.py
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
from omlish.lite.inject import Injector
|
2
|
+
from omlish.lite.inject import inj
|
3
|
+
from omlish.lite.logs import configure_standard_logging
|
4
|
+
|
5
|
+
from .bootstrap import MainBootstrap
|
6
|
+
from .inject import bind_main
|
7
|
+
|
8
|
+
|
9
|
+
def main_bootstrap(bs: MainBootstrap) -> Injector:
|
10
|
+
if (log_level := bs.main_config.log_level) is not None:
|
11
|
+
configure_standard_logging(log_level)
|
12
|
+
|
13
|
+
injector = inj.create_injector(bind_main( # noqa
|
14
|
+
main_config=bs.main_config,
|
15
|
+
remote_config=bs.remote_config,
|
16
|
+
))
|
17
|
+
|
18
|
+
return injector
|
ominfra/manage/commands/base.py
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
import abc
|
3
3
|
import dataclasses as dc
|
4
|
+
import logging
|
5
|
+
import traceback
|
4
6
|
import typing as ta
|
5
7
|
|
8
|
+
from omlish.lite.check import check_isinstance
|
9
|
+
from omlish.lite.strings import snake_case
|
10
|
+
|
6
11
|
|
7
12
|
CommandT = ta.TypeVar('CommandT', bound='Command')
|
8
13
|
CommandOutputT = ta.TypeVar('CommandOutputT', bound='Command.Output')
|
@@ -17,11 +22,138 @@ class Command(abc.ABC, ta.Generic[CommandOutputT]):
|
|
17
22
|
class Output(abc.ABC): # noqa
|
18
23
|
pass
|
19
24
|
|
25
|
+
@ta.final
|
26
|
+
def execute(self, executor: 'CommandExecutor') -> CommandOutputT:
|
27
|
+
return check_isinstance(executor.execute(self), self.Output) # type: ignore[return-value]
|
28
|
+
|
20
29
|
|
21
30
|
##
|
22
31
|
|
23
32
|
|
33
|
+
@dc.dataclass(frozen=True)
|
34
|
+
class CommandException:
|
35
|
+
name: str
|
36
|
+
repr: str
|
37
|
+
|
38
|
+
traceback: ta.Optional[str] = None
|
39
|
+
|
40
|
+
exc: ta.Optional[ta.Any] = None # Exception
|
41
|
+
|
42
|
+
cmd: ta.Optional[Command] = None
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def of(
|
46
|
+
cls,
|
47
|
+
exc: Exception,
|
48
|
+
*,
|
49
|
+
omit_exc_object: bool = False,
|
50
|
+
|
51
|
+
cmd: ta.Optional[Command] = None,
|
52
|
+
) -> 'CommandException':
|
53
|
+
return CommandException(
|
54
|
+
name=type(exc).__qualname__,
|
55
|
+
repr=repr(exc),
|
56
|
+
|
57
|
+
traceback=(
|
58
|
+
''.join(traceback.format_tb(exc.__traceback__))
|
59
|
+
if getattr(exc, '__traceback__', None) is not None else None
|
60
|
+
),
|
61
|
+
|
62
|
+
exc=None if omit_exc_object else exc,
|
63
|
+
|
64
|
+
cmd=cmd,
|
65
|
+
)
|
66
|
+
|
67
|
+
|
68
|
+
class CommandOutputOrException(abc.ABC, ta.Generic[CommandOutputT]):
|
69
|
+
@property
|
70
|
+
@abc.abstractmethod
|
71
|
+
def output(self) -> ta.Optional[CommandOutputT]:
|
72
|
+
raise NotImplementedError
|
73
|
+
|
74
|
+
@property
|
75
|
+
@abc.abstractmethod
|
76
|
+
def exception(self) -> ta.Optional[CommandException]:
|
77
|
+
raise NotImplementedError
|
78
|
+
|
79
|
+
|
80
|
+
@dc.dataclass(frozen=True)
|
81
|
+
class CommandOutputOrExceptionData(CommandOutputOrException):
|
82
|
+
output: ta.Optional[Command.Output] = None
|
83
|
+
exception: ta.Optional[CommandException] = None
|
84
|
+
|
85
|
+
|
24
86
|
class CommandExecutor(abc.ABC, ta.Generic[CommandT, CommandOutputT]):
|
25
87
|
@abc.abstractmethod
|
26
|
-
def execute(self,
|
88
|
+
def execute(self, cmd: CommandT) -> CommandOutputT:
|
27
89
|
raise NotImplementedError
|
90
|
+
|
91
|
+
def try_execute(
|
92
|
+
self,
|
93
|
+
cmd: CommandT,
|
94
|
+
*,
|
95
|
+
log: ta.Optional[logging.Logger] = None,
|
96
|
+
omit_exc_object: bool = False,
|
97
|
+
) -> CommandOutputOrException[CommandOutputT]:
|
98
|
+
try:
|
99
|
+
o = self.execute(cmd)
|
100
|
+
|
101
|
+
except Exception as e: # noqa
|
102
|
+
if log is not None:
|
103
|
+
log.exception('Exception executing command: %r', type(cmd))
|
104
|
+
|
105
|
+
return CommandOutputOrExceptionData(exception=CommandException.of(
|
106
|
+
e,
|
107
|
+
omit_exc_object=omit_exc_object,
|
108
|
+
cmd=cmd,
|
109
|
+
))
|
110
|
+
|
111
|
+
else:
|
112
|
+
return CommandOutputOrExceptionData(output=o)
|
113
|
+
|
114
|
+
|
115
|
+
##
|
116
|
+
|
117
|
+
|
118
|
+
@dc.dataclass(frozen=True)
|
119
|
+
class CommandRegistration:
|
120
|
+
command_cls: ta.Type[Command]
|
121
|
+
|
122
|
+
name: ta.Optional[str] = None
|
123
|
+
|
124
|
+
@property
|
125
|
+
def name_or_default(self) -> str:
|
126
|
+
if not (cls_name := self.command_cls.__name__).endswith('Command'):
|
127
|
+
raise NameError(cls_name)
|
128
|
+
return snake_case(cls_name[:-len('Command')])
|
129
|
+
|
130
|
+
|
131
|
+
CommandRegistrations = ta.NewType('CommandRegistrations', ta.Sequence[CommandRegistration])
|
132
|
+
|
133
|
+
|
134
|
+
##
|
135
|
+
|
136
|
+
|
137
|
+
@dc.dataclass(frozen=True)
|
138
|
+
class CommandExecutorRegistration:
|
139
|
+
command_cls: ta.Type[Command]
|
140
|
+
executor_cls: ta.Type[CommandExecutor]
|
141
|
+
|
142
|
+
|
143
|
+
CommandExecutorRegistrations = ta.NewType('CommandExecutorRegistrations', ta.Sequence[CommandExecutorRegistration])
|
144
|
+
|
145
|
+
|
146
|
+
##
|
147
|
+
|
148
|
+
|
149
|
+
CommandNameMap = ta.NewType('CommandNameMap', ta.Mapping[str, ta.Type[Command]])
|
150
|
+
|
151
|
+
|
152
|
+
def build_command_name_map(crs: CommandRegistrations) -> CommandNameMap:
|
153
|
+
dct: ta.Dict[str, ta.Type[Command]] = {}
|
154
|
+
cr: CommandRegistration
|
155
|
+
for cr in crs:
|
156
|
+
if (name := cr.name_or_default) in dct:
|
157
|
+
raise NameError(name)
|
158
|
+
dct[name] = cr.command_cls
|
159
|
+
return CommandNameMap(dct)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from .base import Command
|
5
|
+
from .base import CommandExecutor
|
6
|
+
|
7
|
+
|
8
|
+
CommandExecutorMap = ta.NewType('CommandExecutorMap', ta.Mapping[ta.Type[Command], CommandExecutor])
|
9
|
+
|
10
|
+
|
11
|
+
class CommandExecutionService(CommandExecutor):
|
12
|
+
def __init__(
|
13
|
+
self,
|
14
|
+
*,
|
15
|
+
command_executors: CommandExecutorMap,
|
16
|
+
) -> None:
|
17
|
+
super().__init__()
|
18
|
+
|
19
|
+
self._command_executors = command_executors
|
20
|
+
|
21
|
+
def execute(self, cmd: Command) -> Command.Output:
|
22
|
+
ce: CommandExecutor = self._command_executors[type(cmd)]
|
23
|
+
return ce.execute(cmd)
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import dataclasses as dc
|
3
|
+
import functools
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from omlish.lite.inject import Injector
|
7
|
+
from omlish.lite.inject import InjectorBindingOrBindings
|
8
|
+
from omlish.lite.inject import InjectorBindings
|
9
|
+
from omlish.lite.inject import inj
|
10
|
+
|
11
|
+
from ..config import MainConfig
|
12
|
+
from ..marshal import ObjMarshalerInstaller
|
13
|
+
from .base import Command
|
14
|
+
from .base import CommandExecutor
|
15
|
+
from .base import CommandExecutorRegistration
|
16
|
+
from .base import CommandExecutorRegistrations
|
17
|
+
from .base import CommandNameMap
|
18
|
+
from .base import CommandRegistration
|
19
|
+
from .base import CommandRegistrations
|
20
|
+
from .base import build_command_name_map
|
21
|
+
from .execution import CommandExecutionService
|
22
|
+
from .execution import CommandExecutorMap
|
23
|
+
from .marshal import install_command_marshaling
|
24
|
+
from .subprocess import SubprocessCommand
|
25
|
+
from .subprocess import SubprocessCommandExecutor
|
26
|
+
|
27
|
+
|
28
|
+
##
|
29
|
+
|
30
|
+
|
31
|
+
def bind_command(
|
32
|
+
command_cls: ta.Type[Command],
|
33
|
+
executor_cls: ta.Optional[ta.Type[CommandExecutor]],
|
34
|
+
) -> InjectorBindings:
|
35
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
36
|
+
inj.bind(CommandRegistration(command_cls), array=True),
|
37
|
+
]
|
38
|
+
|
39
|
+
if executor_cls is not None:
|
40
|
+
lst.extend([
|
41
|
+
inj.bind(executor_cls, singleton=True),
|
42
|
+
inj.bind(CommandExecutorRegistration(command_cls, executor_cls), array=True),
|
43
|
+
])
|
44
|
+
|
45
|
+
return inj.as_bindings(*lst)
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
|
50
|
+
|
51
|
+
@dc.dataclass(frozen=True)
|
52
|
+
class _FactoryCommandExecutor(CommandExecutor):
|
53
|
+
factory: ta.Callable[[], CommandExecutor]
|
54
|
+
|
55
|
+
def execute(self, i: Command) -> Command.Output:
|
56
|
+
return self.factory().execute(i)
|
57
|
+
|
58
|
+
|
59
|
+
##
|
60
|
+
|
61
|
+
|
62
|
+
def bind_commands(
|
63
|
+
*,
|
64
|
+
main_config: MainConfig,
|
65
|
+
) -> InjectorBindings:
|
66
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
67
|
+
inj.bind_array(CommandRegistration),
|
68
|
+
inj.bind_array_type(CommandRegistration, CommandRegistrations),
|
69
|
+
|
70
|
+
inj.bind_array(CommandExecutorRegistration),
|
71
|
+
inj.bind_array_type(CommandExecutorRegistration, CommandExecutorRegistrations),
|
72
|
+
|
73
|
+
inj.bind(build_command_name_map, singleton=True),
|
74
|
+
]
|
75
|
+
|
76
|
+
#
|
77
|
+
|
78
|
+
def provide_obj_marshaler_installer(cmds: CommandNameMap) -> ObjMarshalerInstaller:
|
79
|
+
return ObjMarshalerInstaller(functools.partial(install_command_marshaling, cmds))
|
80
|
+
|
81
|
+
lst.append(inj.bind(provide_obj_marshaler_installer, array=True))
|
82
|
+
|
83
|
+
#
|
84
|
+
|
85
|
+
def provide_command_executor_map(
|
86
|
+
injector: Injector,
|
87
|
+
crs: CommandExecutorRegistrations,
|
88
|
+
) -> CommandExecutorMap:
|
89
|
+
dct: ta.Dict[ta.Type[Command], CommandExecutor] = {}
|
90
|
+
|
91
|
+
cr: CommandExecutorRegistration
|
92
|
+
for cr in crs:
|
93
|
+
if cr.command_cls in dct:
|
94
|
+
raise KeyError(cr.command_cls)
|
95
|
+
|
96
|
+
factory = functools.partial(injector.provide, cr.executor_cls)
|
97
|
+
if main_config.debug:
|
98
|
+
ce = factory()
|
99
|
+
else:
|
100
|
+
ce = _FactoryCommandExecutor(factory)
|
101
|
+
|
102
|
+
dct[cr.command_cls] = ce
|
103
|
+
|
104
|
+
return CommandExecutorMap(dct)
|
105
|
+
|
106
|
+
lst.extend([
|
107
|
+
inj.bind(provide_command_executor_map, singleton=True),
|
108
|
+
|
109
|
+
inj.bind(CommandExecutionService, singleton=True, eager=main_config.debug),
|
110
|
+
inj.bind(CommandExecutor, to_key=CommandExecutionService),
|
111
|
+
])
|
112
|
+
|
113
|
+
#
|
114
|
+
|
115
|
+
for command_cls, executor_cls in [
|
116
|
+
(SubprocessCommand, SubprocessCommandExecutor),
|
117
|
+
]:
|
118
|
+
lst.append(bind_command(command_cls, executor_cls))
|
119
|
+
|
120
|
+
#
|
121
|
+
|
122
|
+
return inj.as_bindings(*lst)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
2
|
+
from omlish.lite.marshal import PolymorphicObjMarshaler
|
3
|
+
|
4
|
+
from .base import Command
|
5
|
+
from .base import CommandNameMap
|
6
|
+
|
7
|
+
|
8
|
+
def install_command_marshaling(
|
9
|
+
cmds: CommandNameMap,
|
10
|
+
msh: ObjMarshalerManager,
|
11
|
+
) -> None:
|
12
|
+
for fn in [
|
13
|
+
lambda c: c,
|
14
|
+
lambda c: c.Output,
|
15
|
+
]:
|
16
|
+
msh.register_opj_marshaler(
|
17
|
+
fn(Command),
|
18
|
+
PolymorphicObjMarshaler.of([
|
19
|
+
PolymorphicObjMarshaler.Impl(
|
20
|
+
fn(cmd),
|
21
|
+
name,
|
22
|
+
msh.get_obj_marshaler(fn(cmd)),
|
23
|
+
)
|
24
|
+
for name, cmd in cmds.items()
|
25
|
+
]),
|
26
|
+
)
|
ominfra/manage/config.py
ADDED
ominfra/manage/inject.py
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from omlish.lite.inject import InjectorBindingOrBindings
|
5
|
+
from omlish.lite.inject import InjectorBindings
|
6
|
+
from omlish.lite.inject import inj
|
7
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
8
|
+
|
9
|
+
from .commands.inject import bind_commands
|
10
|
+
from .config import MainConfig
|
11
|
+
from .marshal import ObjMarshalerInstaller
|
12
|
+
from .marshal import ObjMarshalerInstallers
|
13
|
+
from .remote.config import RemoteConfig
|
14
|
+
from .remote.inject import bind_remote
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
|
19
|
+
|
20
|
+
def bind_main(
|
21
|
+
*,
|
22
|
+
main_config: MainConfig,
|
23
|
+
remote_config: RemoteConfig,
|
24
|
+
) -> InjectorBindings:
|
25
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
26
|
+
inj.bind(main_config),
|
27
|
+
|
28
|
+
bind_commands(
|
29
|
+
main_config=main_config,
|
30
|
+
),
|
31
|
+
|
32
|
+
bind_remote(
|
33
|
+
remote_config=remote_config,
|
34
|
+
),
|
35
|
+
]
|
36
|
+
|
37
|
+
#
|
38
|
+
|
39
|
+
def build_obj_marshaler_manager(insts: ObjMarshalerInstallers) -> ObjMarshalerManager:
|
40
|
+
msh = ObjMarshalerManager()
|
41
|
+
inst: ObjMarshalerInstaller
|
42
|
+
for inst in insts:
|
43
|
+
inst.fn(msh)
|
44
|
+
return msh
|
45
|
+
|
46
|
+
lst.extend([
|
47
|
+
inj.bind(build_obj_marshaler_manager, singleton=True),
|
48
|
+
|
49
|
+
inj.bind_array(ObjMarshalerInstaller),
|
50
|
+
inj.bind_array_type(ObjMarshalerInstaller, ObjMarshalerInstallers),
|
51
|
+
])
|
52
|
+
|
53
|
+
#
|
54
|
+
|
55
|
+
return inj.as_bindings(*lst)
|
ominfra/manage/main.py
CHANGED
@@ -5,72 +5,18 @@
|
|
5
5
|
manage.py -s 'docker run -i python:3.12'
|
6
6
|
manage.py -s 'ssh -i /foo/bar.pem foo@bar.baz' -q --python=python3.8
|
7
7
|
"""
|
8
|
-
from omlish.lite.
|
8
|
+
from omlish.lite.logs import log # noqa
|
9
|
+
from omlish.lite.marshal import ObjMarshalOptions
|
9
10
|
from omlish.lite.marshal import ObjMarshalerManager
|
10
|
-
from omlish.lite.
|
11
|
+
from omlish.lite.pycharm import PycharmRemoteDebug
|
11
12
|
|
12
|
-
from
|
13
|
-
from
|
14
|
-
from ..pyremote import pyremote_bootstrap_finalize
|
15
|
-
from ..pyremote import pyremote_build_bootstrap_cmd
|
16
|
-
from .commands.base import Command
|
13
|
+
from .bootstrap import MainBootstrap
|
14
|
+
from .bootstrap_ import main_bootstrap
|
17
15
|
from .commands.subprocess import SubprocessCommand
|
18
|
-
from .
|
19
|
-
from .
|
20
|
-
from .
|
21
|
-
from .spawning import
|
22
|
-
|
23
|
-
|
24
|
-
##
|
25
|
-
|
26
|
-
|
27
|
-
_COMMAND_TYPES = {
|
28
|
-
'subprocess': SubprocessCommand,
|
29
|
-
}
|
30
|
-
|
31
|
-
|
32
|
-
##
|
33
|
-
|
34
|
-
|
35
|
-
def register_command_marshaling(msh: ObjMarshalerManager) -> None:
|
36
|
-
for fn in [
|
37
|
-
lambda c: c,
|
38
|
-
lambda c: c.Output,
|
39
|
-
]:
|
40
|
-
msh.register_opj_marshaler(
|
41
|
-
fn(Command),
|
42
|
-
PolymorphicObjMarshaler.of([
|
43
|
-
PolymorphicObjMarshaler.Impl(
|
44
|
-
fn(cty),
|
45
|
-
k,
|
46
|
-
msh.get_obj_marshaler(fn(cty)),
|
47
|
-
)
|
48
|
-
for k, cty in _COMMAND_TYPES.items()
|
49
|
-
]),
|
50
|
-
)
|
51
|
-
|
52
|
-
|
53
|
-
register_command_marshaling(OBJ_MARSHALER_MANAGER)
|
54
|
-
|
55
|
-
|
56
|
-
##
|
57
|
-
|
58
|
-
|
59
|
-
def _remote_main() -> None:
|
60
|
-
rt = pyremote_bootstrap_finalize() # noqa
|
61
|
-
chan = Channel(rt.input, rt.output)
|
62
|
-
|
63
|
-
while True:
|
64
|
-
i = chan.recv_obj(Command)
|
65
|
-
if i is None:
|
66
|
-
break
|
67
|
-
|
68
|
-
if isinstance(i, SubprocessCommand):
|
69
|
-
o = SubprocessCommandExecutor().execute(i) # noqa
|
70
|
-
else:
|
71
|
-
raise TypeError(i)
|
72
|
-
|
73
|
-
chan.send_obj(o, Command.Output)
|
16
|
+
from .config import MainConfig
|
17
|
+
from .remote.config import RemoteConfig
|
18
|
+
from .remote.execution import RemoteExecution
|
19
|
+
from .remote.spawning import RemoteSpawning
|
74
20
|
|
75
21
|
|
76
22
|
##
|
@@ -87,50 +33,64 @@ def _main() -> None:
|
|
87
33
|
parser.add_argument('-q', '--shell-quote', action='store_true')
|
88
34
|
parser.add_argument('--python', default='python3')
|
89
35
|
|
36
|
+
parser.add_argument('--pycharm-debug-port', type=int)
|
37
|
+
parser.add_argument('--pycharm-debug-host')
|
38
|
+
parser.add_argument('--pycharm-debug-version')
|
39
|
+
|
90
40
|
parser.add_argument('--debug', action='store_true')
|
91
41
|
|
42
|
+
parser.add_argument('command', nargs='+')
|
43
|
+
|
92
44
|
args = parser.parse_args()
|
93
45
|
|
94
46
|
#
|
95
47
|
|
96
|
-
|
48
|
+
bs = MainBootstrap(
|
49
|
+
main_config=MainConfig(
|
50
|
+
log_level='DEBUG' if args.debug else 'INFO',
|
51
|
+
|
52
|
+
debug=bool(args.debug),
|
53
|
+
),
|
54
|
+
|
55
|
+
remote_config=RemoteConfig(
|
56
|
+
payload_file=args._payload_file, # noqa
|
57
|
+
|
58
|
+
pycharm_remote_debug=PycharmRemoteDebug(
|
59
|
+
port=args.pycharm_debug_port,
|
60
|
+
host=args.pycharm_debug_host,
|
61
|
+
install_version=args.pycharm_debug_version,
|
62
|
+
) if args.pycharm_debug_port is not None else None,
|
63
|
+
),
|
64
|
+
)
|
65
|
+
|
66
|
+
injector = main_bootstrap(
|
67
|
+
bs,
|
68
|
+
)
|
69
|
+
|
70
|
+
#
|
97
71
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
])
|
72
|
+
cmds = [
|
73
|
+
SubprocessCommand([c])
|
74
|
+
for c in args.command
|
75
|
+
]
|
103
76
|
|
104
77
|
#
|
105
78
|
|
106
|
-
|
107
|
-
pyremote_build_bootstrap_cmd(__package__ or 'manage'),
|
79
|
+
tgt = RemoteSpawning.Target(
|
108
80
|
shell=args.shell,
|
109
81
|
shell_quote=args.shell_quote,
|
110
82
|
python=args.python,
|
111
83
|
)
|
112
84
|
|
113
|
-
with
|
114
|
-
|
115
|
-
|
116
|
-
PyremoteBootstrapOptions(
|
117
|
-
debug=args.debug,
|
118
|
-
),
|
119
|
-
).run(proc.stdout, proc.stdin)
|
120
|
-
|
121
|
-
chan = Channel(proc.stdout, proc.stdin)
|
85
|
+
with injector[RemoteExecution].connect(tgt, bs) as rce:
|
86
|
+
for cmd in cmds:
|
87
|
+
r = rce.try_execute(cmd)
|
122
88
|
|
123
|
-
|
89
|
+
print(injector[ObjMarshalerManager].marshal_obj(r, opts=ObjMarshalOptions(raw_bytes=True)))
|
124
90
|
|
125
|
-
|
126
|
-
SubprocessCommand(['python3', '-'], input=b'print(1)\n'),
|
127
|
-
SubprocessCommand(['uname']),
|
128
|
-
]:
|
129
|
-
chan.send_obj(ci, Command)
|
130
|
-
|
131
|
-
o = chan.recv_obj(Command.Output)
|
91
|
+
#
|
132
92
|
|
133
|
-
|
93
|
+
print('Success')
|
134
94
|
|
135
95
|
|
136
96
|
if __name__ == '__main__':
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import dataclasses as dc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from omlish.lite.marshal import ObjMarshalerManager
|
5
|
+
|
6
|
+
|
7
|
+
@dc.dataclass(frozen=True)
|
8
|
+
class ObjMarshalerInstaller:
|
9
|
+
fn: ta.Callable[[ObjMarshalerManager], None]
|
10
|
+
|
11
|
+
|
12
|
+
ObjMarshalerInstallers = ta.NewType('ObjMarshalerInstallers', ta.Sequence[ObjMarshalerInstaller])
|
File without changes
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
1
2
|
import json
|
2
3
|
import struct
|
3
4
|
import typing as ta
|
@@ -7,7 +8,10 @@ from omlish.lite.marshal import OBJ_MARSHALER_MANAGER
|
|
7
8
|
from omlish.lite.marshal import ObjMarshalerManager
|
8
9
|
|
9
10
|
|
10
|
-
|
11
|
+
T = ta.TypeVar('T')
|
12
|
+
|
13
|
+
|
14
|
+
class RemoteChannel:
|
11
15
|
def __init__(
|
12
16
|
self,
|
13
17
|
input: ta.IO, # noqa
|
@@ -21,6 +25,9 @@ class Channel:
|
|
21
25
|
self._output = output
|
22
26
|
self._msh = msh
|
23
27
|
|
28
|
+
def set_marshaler(self, msh: ObjMarshalerManager) -> None:
|
29
|
+
self._msh = msh
|
30
|
+
|
24
31
|
def send_obj(self, o: ta.Any, ty: ta.Any = None) -> None:
|
25
32
|
j = json_dumps_compact(self._msh.marshal_obj(o, ty))
|
26
33
|
d = j.encode('utf-8')
|
@@ -29,7 +36,7 @@ class Channel:
|
|
29
36
|
self._output.write(d)
|
30
37
|
self._output.flush()
|
31
38
|
|
32
|
-
def recv_obj(self, ty: ta.
|
39
|
+
def recv_obj(self, ty: ta.Type[T]) -> ta.Optional[T]:
|
33
40
|
d = self._input.read(4)
|
34
41
|
if not d:
|
35
42
|
return None
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import dataclasses as dc
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from omlish.lite.pycharm import PycharmRemoteDebug
|
6
|
+
|
7
|
+
|
8
|
+
@dc.dataclass(frozen=True)
|
9
|
+
class RemoteConfig:
|
10
|
+
payload_file: ta.Optional[str] = None
|
11
|
+
|
12
|
+
pycharm_remote_debug: ta.Optional[PycharmRemoteDebug] = None
|