ominfra 0.0.0.dev142__py3-none-any.whl → 0.0.0.dev144__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.
Files changed (33) hide show
  1. ominfra/manage/__init__.py +10 -0
  2. ominfra/manage/__main__.py +4 -0
  3. ominfra/manage/bootstrap.py +11 -0
  4. ominfra/manage/bootstrap_.py +18 -0
  5. ominfra/manage/commands/base.py +133 -1
  6. ominfra/manage/commands/execution.py +23 -0
  7. ominfra/manage/commands/inject.py +122 -0
  8. ominfra/manage/commands/marshal.py +26 -0
  9. ominfra/manage/config.py +10 -0
  10. ominfra/manage/deploy/__init__.py +0 -0
  11. ominfra/manage/deploy/command.py +23 -0
  12. ominfra/manage/deploy/inject.py +19 -0
  13. ominfra/manage/inject.py +58 -0
  14. ominfra/manage/main.py +64 -90
  15. ominfra/manage/marshal.py +12 -0
  16. ominfra/manage/remote/__init__.py +0 -0
  17. ominfra/manage/{protocol.py → remote/channel.py} +9 -2
  18. ominfra/manage/remote/config.py +12 -0
  19. ominfra/manage/remote/execution.py +193 -0
  20. ominfra/manage/remote/inject.py +29 -0
  21. ominfra/manage/{payload.py → remote/payload.py} +7 -1
  22. ominfra/manage/{spawning.py → remote/spawning.py} +29 -29
  23. ominfra/pyremote.py +40 -3
  24. ominfra/scripts/journald2aws.py +98 -50
  25. ominfra/scripts/manage.py +2025 -295
  26. ominfra/scripts/supervisor.py +99 -50
  27. ominfra/supervisor/inject.py +2 -1
  28. {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev144.dist-info}/METADATA +3 -3
  29. {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev144.dist-info}/RECORD +33 -17
  30. {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev144.dist-info}/LICENSE +0 -0
  31. {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev144.dist-info}/WHEEL +0 -0
  32. {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev144.dist-info}/entry_points.txt +0 -0
  33. {ominfra-0.0.0.dev142.dist-info → ominfra-0.0.0.dev144.dist-info}/top_level.txt +0 -0
@@ -10,4 +10,14 @@ Jobs:
10
10
  - system service manager - systemd / supervisor
11
11
  - users
12
12
  - firewall
13
+
14
+ Deploy:
15
+ - User
16
+ - Dirs
17
+ - GlobalNginx
18
+ - GlobalSupervisor
19
+ - Repo
20
+ - Venv
21
+ - Supervisor
22
+ - Nginx
13
23
  """
@@ -0,0 +1,4 @@
1
+ if __name__ == '__main__':
2
+ from .main import _main # noqa
3
+
4
+ _main()
@@ -0,0 +1,11 @@
1
+ import dataclasses as dc
2
+
3
+ from .config import MainConfig
4
+ from .remote.config import RemoteConfig
5
+
6
+
7
+ @dc.dataclass(frozen=True)
8
+ class MainBootstrap:
9
+ main_config: MainConfig = MainConfig()
10
+
11
+ remote_config: RemoteConfig = RemoteConfig()
@@ -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
@@ -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, i: CommandT) -> CommandOutputT:
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
+ )
@@ -0,0 +1,10 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+ import typing as ta
4
+
5
+
6
+ @dc.dataclass(frozen=True)
7
+ class MainConfig:
8
+ log_level: ta.Optional[str] = 'INFO'
9
+
10
+ debug: bool = False
File without changes
@@ -0,0 +1,23 @@
1
+ # ruff: noqa: UP006 UP007
2
+ import dataclasses as dc
3
+
4
+ from ..commands.base import Command
5
+ from ..commands.base import CommandExecutor
6
+
7
+
8
+ ##
9
+
10
+
11
+ @dc.dataclass(frozen=True)
12
+ class DeployCommand(Command['DeployCommand.Output']):
13
+ @dc.dataclass(frozen=True)
14
+ class Output(Command.Output):
15
+ pass
16
+
17
+
18
+ ##
19
+
20
+
21
+ class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
22
+ def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
23
+ return DeployCommand.Output()
@@ -0,0 +1,19 @@
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
+
8
+ from ..commands.inject import bind_command
9
+ from .command import DeployCommand
10
+ from .command import DeployCommandExecutor
11
+
12
+
13
+ def bind_deploy(
14
+ ) -> InjectorBindings:
15
+ lst: ta.List[InjectorBindingOrBindings] = [
16
+ bind_command(DeployCommand, DeployCommandExecutor),
17
+ ]
18
+
19
+ return inj.as_bindings(*lst)
@@ -0,0 +1,58 @@
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 .deploy.inject import bind_deploy
12
+ from .marshal import ObjMarshalerInstaller
13
+ from .marshal import ObjMarshalerInstallers
14
+ from .remote.config import RemoteConfig
15
+ from .remote.inject import bind_remote
16
+
17
+
18
+ ##
19
+
20
+
21
+ def bind_main(
22
+ *,
23
+ main_config: MainConfig,
24
+ remote_config: RemoteConfig,
25
+ ) -> InjectorBindings:
26
+ lst: ta.List[InjectorBindingOrBindings] = [
27
+ inj.bind(main_config),
28
+
29
+ bind_commands(
30
+ main_config=main_config,
31
+ ),
32
+
33
+ bind_remote(
34
+ remote_config=remote_config,
35
+ ),
36
+
37
+ bind_deploy(),
38
+ ]
39
+
40
+ #
41
+
42
+ def build_obj_marshaler_manager(insts: ObjMarshalerInstallers) -> ObjMarshalerManager:
43
+ msh = ObjMarshalerManager()
44
+ inst: ObjMarshalerInstaller
45
+ for inst in insts:
46
+ inst.fn(msh)
47
+ return msh
48
+
49
+ lst.extend([
50
+ inj.bind(build_obj_marshaler_manager, singleton=True),
51
+
52
+ inj.bind_array(ObjMarshalerInstaller),
53
+ inj.bind_array_type(ObjMarshalerInstaller, ObjMarshalerInstallers),
54
+ ])
55
+
56
+ #
57
+
58
+ return inj.as_bindings(*lst)
ominfra/manage/main.py CHANGED
@@ -5,72 +5,24 @@
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.marshal import OBJ_MARSHALER_MANAGER
8
+ import contextlib
9
+ import typing as ta
10
+
11
+ from omlish.lite.logs import log # noqa
9
12
  from omlish.lite.marshal import ObjMarshalerManager
10
- from omlish.lite.marshal import PolymorphicObjMarshaler
13
+ from omlish.lite.marshal import ObjMarshalOptions
14
+ from omlish.lite.pycharm import PycharmRemoteDebug
11
15
 
12
- from ..pyremote import PyremoteBootstrapDriver
13
- from ..pyremote import PyremoteBootstrapOptions
14
- from ..pyremote import pyremote_bootstrap_finalize
15
- from ..pyremote import pyremote_build_bootstrap_cmd
16
+ from .bootstrap import MainBootstrap
17
+ from .bootstrap_ import main_bootstrap
16
18
  from .commands.base import Command
19
+ from .commands.base import CommandExecutor
17
20
  from .commands.subprocess import SubprocessCommand
18
- from .commands.subprocess import SubprocessCommandExecutor
19
- from .payload import get_payload_src
20
- from .protocol import Channel
21
- from .spawning import PySpawner
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)
21
+ from .config import MainConfig
22
+ from .deploy.command import DeployCommand
23
+ from .remote.config import RemoteConfig
24
+ from .remote.execution import RemoteExecution
25
+ from .remote.spawning import RemoteSpawning
74
26
 
75
27
 
76
28
  ##
@@ -87,50 +39,72 @@ def _main() -> None:
87
39
  parser.add_argument('-q', '--shell-quote', action='store_true')
88
40
  parser.add_argument('--python', default='python3')
89
41
 
42
+ parser.add_argument('--pycharm-debug-port', type=int)
43
+ parser.add_argument('--pycharm-debug-host')
44
+ parser.add_argument('--pycharm-debug-version')
45
+
90
46
  parser.add_argument('--debug', action='store_true')
91
47
 
48
+ parser.add_argument('--local', action='store_true')
49
+
50
+ parser.add_argument('command', nargs='+')
51
+
92
52
  args = parser.parse_args()
93
53
 
94
54
  #
95
55
 
96
- payload_src = get_payload_src(file=args._payload_file) # noqa
56
+ bs = MainBootstrap(
57
+ main_config=MainConfig(
58
+ log_level='DEBUG' if args.debug else 'INFO',
97
59
 
98
- remote_src = '\n\n'.join([
99
- '__name__ = "__remote__"',
100
- payload_src,
101
- '_remote_main()',
102
- ])
60
+ debug=bool(args.debug),
61
+ ),
103
62
 
104
- #
63
+ remote_config=RemoteConfig(
64
+ payload_file=args._payload_file, # noqa
105
65
 
106
- spawner = PySpawner(
107
- pyremote_build_bootstrap_cmd(__package__ or 'manage'),
108
- shell=args.shell,
109
- shell_quote=args.shell_quote,
110
- python=args.python,
66
+ pycharm_remote_debug=PycharmRemoteDebug(
67
+ port=args.pycharm_debug_port,
68
+ host=args.pycharm_debug_host,
69
+ install_version=args.pycharm_debug_version,
70
+ ) if args.pycharm_debug_port is not None else None,
71
+ ),
111
72
  )
112
73
 
113
- with spawner.spawn() as proc:
114
- res = PyremoteBootstrapDriver( # noqa
115
- remote_src,
116
- PyremoteBootstrapOptions(
117
- debug=args.debug,
118
- ),
119
- ).run(proc.stdout, proc.stdin)
74
+ injector = main_bootstrap(
75
+ bs,
76
+ )
120
77
 
121
- chan = Channel(proc.stdout, proc.stdin)
78
+ #
79
+
80
+ cmds: ta.List[Command] = []
81
+ for c in args.command:
82
+ if c == 'deploy':
83
+ cmds.append(DeployCommand())
84
+ else:
85
+ cmds.append(SubprocessCommand([c]))
86
+
87
+ #
88
+
89
+ with contextlib.ExitStack() as es:
90
+ ce: CommandExecutor
122
91
 
123
- #
92
+ if args.local:
93
+ ce = injector[CommandExecutor]
94
+
95
+ else:
96
+ tgt = RemoteSpawning.Target(
97
+ shell=args.shell,
98
+ shell_quote=args.shell_quote,
99
+ python=args.python,
100
+ )
124
101
 
125
- for ci in [
126
- SubprocessCommand(['python3', '-'], input=b'print(1)\n'),
127
- SubprocessCommand(['uname']),
128
- ]:
129
- chan.send_obj(ci, Command)
102
+ ce = es.enter_context(injector[RemoteExecution].connect(tgt, bs)) # noqa
130
103
 
131
- o = chan.recv_obj(Command.Output)
104
+ for cmd in cmds:
105
+ r = ce.try_execute(cmd)
132
106
 
133
- print(o)
107
+ print(injector[ObjMarshalerManager].marshal_obj(r, opts=ObjMarshalOptions(raw_bytes=True)))
134
108
 
135
109
 
136
110
  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