ominfra 0.0.0.dev160__py3-none-any.whl → 0.0.0.dev162__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.
- ominfra/manage/deploy/git.py +2 -2
- ominfra/manage/deploy/inject.py +2 -2
- ominfra/manage/deploy/tmp.py +9 -9
- ominfra/manage/deploy/venvs.py +2 -2
- ominfra/manage/targets/connection.py +1 -1
- ominfra/scripts/manage.py +224 -240
- ominfra/scripts/supervisor.py +16 -29
- {ominfra-0.0.0.dev160.dist-info → ominfra-0.0.0.dev162.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev160.dist-info → ominfra-0.0.0.dev162.dist-info}/RECORD +13 -14
- ominfra/manage/deploy/atomics.py +0 -207
- {ominfra-0.0.0.dev160.dist-info → ominfra-0.0.0.dev162.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev160.dist-info → ominfra-0.0.0.dev162.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev160.dist-info → ominfra-0.0.0.dev162.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev160.dist-info → ominfra-0.0.0.dev162.dist-info}/top_level.txt +0 -0
ominfra/manage/deploy/git.py
CHANGED
@@ -15,8 +15,8 @@ import typing as ta
|
|
15
15
|
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
|
16
16
|
from omlish.lite.cached import async_cached_nullary
|
17
17
|
from omlish.lite.check import check
|
18
|
+
from omlish.os.atomics import AtomicPathSwapping
|
18
19
|
|
19
|
-
from .atomics import DeployAtomicPathSwapping
|
20
20
|
from .paths import SingleDirDeployPathOwner
|
21
21
|
from .specs import DeployGitCheckout
|
22
22
|
from .specs import DeployGitRepo
|
@@ -32,7 +32,7 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
32
32
|
self,
|
33
33
|
*,
|
34
34
|
deploy_home: ta.Optional[DeployHome] = None,
|
35
|
-
atomics:
|
35
|
+
atomics: AtomicPathSwapping,
|
36
36
|
) -> None:
|
37
37
|
super().__init__(
|
38
38
|
owned_dir='git',
|
ominfra/manage/deploy/inject.py
CHANGED
@@ -5,10 +5,10 @@ import typing as ta
|
|
5
5
|
from omlish.lite.inject import InjectorBindingOrBindings
|
6
6
|
from omlish.lite.inject import InjectorBindings
|
7
7
|
from omlish.lite.inject import inj
|
8
|
+
from omlish.os.atomics import AtomicPathSwapping
|
8
9
|
|
9
10
|
from ..commands.inject import bind_command
|
10
11
|
from .apps import DeployAppManager
|
11
|
-
from .atomics import DeployAtomicPathSwapping
|
12
12
|
from .commands import DeployCommand
|
13
13
|
from .commands import DeployCommandExecutor
|
14
14
|
from .config import DeployConfig
|
@@ -34,7 +34,7 @@ def bind_deploy(
|
|
34
34
|
inj.bind(DeployGitManager, singleton=True),
|
35
35
|
|
36
36
|
inj.bind(DeployTmpManager, singleton=True),
|
37
|
-
inj.bind(
|
37
|
+
inj.bind(AtomicPathSwapping, to_key=DeployTmpManager),
|
38
38
|
|
39
39
|
inj.bind(DeployVenvManager, singleton=True),
|
40
40
|
|
ominfra/manage/deploy/tmp.py
CHANGED
@@ -3,18 +3,18 @@ import typing as ta
|
|
3
3
|
|
4
4
|
from omlish.lite.cached import cached_nullary
|
5
5
|
from omlish.lite.check import check
|
6
|
+
from omlish.os.atomics import AtomicPathSwap
|
7
|
+
from omlish.os.atomics import AtomicPathSwapKind
|
8
|
+
from omlish.os.atomics import AtomicPathSwapping
|
9
|
+
from omlish.os.atomics import TempDirAtomicPathSwapping
|
6
10
|
|
7
|
-
from .atomics import DeployAtomicPathSwap
|
8
|
-
from .atomics import DeployAtomicPathSwapKind
|
9
|
-
from .atomics import DeployAtomicPathSwapping
|
10
|
-
from .atomics import TempDirDeployAtomicPathSwapping
|
11
11
|
from .paths import SingleDirDeployPathOwner
|
12
12
|
from .types import DeployHome
|
13
13
|
|
14
14
|
|
15
15
|
class DeployTmpManager(
|
16
16
|
SingleDirDeployPathOwner,
|
17
|
-
|
17
|
+
AtomicPathSwapping,
|
18
18
|
):
|
19
19
|
def __init__(
|
20
20
|
self,
|
@@ -27,18 +27,18 @@ class DeployTmpManager(
|
|
27
27
|
)
|
28
28
|
|
29
29
|
@cached_nullary
|
30
|
-
def _swapping(self) ->
|
31
|
-
return
|
30
|
+
def _swapping(self) -> AtomicPathSwapping:
|
31
|
+
return TempDirAtomicPathSwapping(
|
32
32
|
temp_dir=self._make_dir(),
|
33
33
|
root_dir=check.non_empty_str(self._deploy_home),
|
34
34
|
)
|
35
35
|
|
36
36
|
def begin_atomic_path_swap(
|
37
37
|
self,
|
38
|
-
kind:
|
38
|
+
kind: AtomicPathSwapKind,
|
39
39
|
dst_path: str,
|
40
40
|
**kwargs: ta.Any,
|
41
|
-
) ->
|
41
|
+
) -> AtomicPathSwap:
|
42
42
|
return self._swapping().begin_atomic_path_swap(
|
43
43
|
kind,
|
44
44
|
dst_path,
|
ominfra/manage/deploy/venvs.py
CHANGED
@@ -10,8 +10,8 @@ import typing as ta
|
|
10
10
|
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
|
11
11
|
from omlish.lite.cached import cached_nullary
|
12
12
|
from omlish.lite.check import check
|
13
|
+
from omlish.os.atomics import AtomicPathSwapping
|
13
14
|
|
14
|
-
from .atomics import DeployAtomicPathSwapping
|
15
15
|
from .paths import DeployPath
|
16
16
|
from .paths import DeployPathOwner
|
17
17
|
from .types import DeployAppTag
|
@@ -23,7 +23,7 @@ class DeployVenvManager(DeployPathOwner):
|
|
23
23
|
self,
|
24
24
|
*,
|
25
25
|
deploy_home: ta.Optional[DeployHome] = None,
|
26
|
-
atomics:
|
26
|
+
atomics: AtomicPathSwapping,
|
27
27
|
) -> None:
|
28
28
|
super().__init__()
|
29
29
|
|
@@ -105,7 +105,7 @@ class DockerManageTargetConnector(ManageTargetConnector):
|
|
105
105
|
if dmt.image is not None:
|
106
106
|
sh_parts.extend(['run', '-i', dmt.image])
|
107
107
|
elif dmt.container_id is not None:
|
108
|
-
sh_parts.extend(['exec', dmt.container_id])
|
108
|
+
sh_parts.extend(['exec', '-i', dmt.container_id])
|
109
109
|
else:
|
110
110
|
raise ValueError(dmt)
|
111
111
|
|
ominfra/scripts/manage.py
CHANGED
@@ -100,10 +100,6 @@ CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
100
100
|
CommandT = ta.TypeVar('CommandT', bound='Command')
|
101
101
|
CommandOutputT = ta.TypeVar('CommandOutputT', bound='Command.Output')
|
102
102
|
|
103
|
-
# deploy/atomics.py
|
104
|
-
DeployAtomicPathSwapKind = ta.Literal['dir', 'file']
|
105
|
-
DeployAtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
|
106
|
-
|
107
103
|
# deploy/paths.py
|
108
104
|
DeployPathKind = ta.Literal['dir', 'file'] # ta.TypeAlias
|
109
105
|
DeployPathPlaceholder = ta.Literal['app', 'tag'] # ta.TypeAlias
|
@@ -121,6 +117,10 @@ InjectorProviderFn = ta.Callable[['Injector'], ta.Any]
|
|
121
117
|
InjectorProviderFnMap = ta.Mapping['InjectorKey', 'InjectorProviderFn']
|
122
118
|
InjectorBindingOrBindings = ta.Union['InjectorBinding', 'InjectorBindings']
|
123
119
|
|
120
|
+
# ../../omlish/os/atomics.py
|
121
|
+
AtomicPathSwapKind = ta.Literal['dir', 'file']
|
122
|
+
AtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
|
123
|
+
|
124
124
|
# ../configs.py
|
125
125
|
ConfigMapping = ta.Mapping[str, ta.Any]
|
126
126
|
|
@@ -4064,204 +4064,6 @@ def build_command_name_map(crs: CommandRegistrations) -> CommandNameMap:
|
|
4064
4064
|
return CommandNameMap(dct)
|
4065
4065
|
|
4066
4066
|
|
4067
|
-
########################################
|
4068
|
-
# ../deploy/atomics.py
|
4069
|
-
|
4070
|
-
|
4071
|
-
##
|
4072
|
-
|
4073
|
-
|
4074
|
-
class DeployAtomicPathSwap(abc.ABC):
|
4075
|
-
def __init__(
|
4076
|
-
self,
|
4077
|
-
kind: DeployAtomicPathSwapKind,
|
4078
|
-
dst_path: str,
|
4079
|
-
*,
|
4080
|
-
auto_commit: bool = False,
|
4081
|
-
) -> None:
|
4082
|
-
super().__init__()
|
4083
|
-
|
4084
|
-
self._kind = kind
|
4085
|
-
self._dst_path = dst_path
|
4086
|
-
self._auto_commit = auto_commit
|
4087
|
-
|
4088
|
-
self._state: DeployAtomicPathSwapState = 'open'
|
4089
|
-
|
4090
|
-
def __repr__(self) -> str:
|
4091
|
-
return attr_repr(self, 'kind', 'dst_path', 'tmp_path')
|
4092
|
-
|
4093
|
-
@property
|
4094
|
-
def kind(self) -> DeployAtomicPathSwapKind:
|
4095
|
-
return self._kind
|
4096
|
-
|
4097
|
-
@property
|
4098
|
-
def dst_path(self) -> str:
|
4099
|
-
return self._dst_path
|
4100
|
-
|
4101
|
-
@property
|
4102
|
-
@abc.abstractmethod
|
4103
|
-
def tmp_path(self) -> str:
|
4104
|
-
raise NotImplementedError
|
4105
|
-
|
4106
|
-
#
|
4107
|
-
|
4108
|
-
@property
|
4109
|
-
def state(self) -> DeployAtomicPathSwapState:
|
4110
|
-
return self._state
|
4111
|
-
|
4112
|
-
def _check_state(self, *states: DeployAtomicPathSwapState) -> None:
|
4113
|
-
if self._state not in states:
|
4114
|
-
raise RuntimeError(f'Atomic path swap not in correct state: {self._state}, {states}')
|
4115
|
-
|
4116
|
-
#
|
4117
|
-
|
4118
|
-
@abc.abstractmethod
|
4119
|
-
def _commit(self) -> None:
|
4120
|
-
raise NotImplementedError
|
4121
|
-
|
4122
|
-
def commit(self) -> None:
|
4123
|
-
if self._state == 'committed':
|
4124
|
-
return
|
4125
|
-
self._check_state('open')
|
4126
|
-
try:
|
4127
|
-
self._commit()
|
4128
|
-
except Exception: # noqa
|
4129
|
-
self._abort()
|
4130
|
-
raise
|
4131
|
-
else:
|
4132
|
-
self._state = 'committed'
|
4133
|
-
|
4134
|
-
#
|
4135
|
-
|
4136
|
-
@abc.abstractmethod
|
4137
|
-
def _abort(self) -> None:
|
4138
|
-
raise NotImplementedError
|
4139
|
-
|
4140
|
-
def abort(self) -> None:
|
4141
|
-
if self._state == 'aborted':
|
4142
|
-
return
|
4143
|
-
self._abort()
|
4144
|
-
self._state = 'aborted'
|
4145
|
-
|
4146
|
-
#
|
4147
|
-
|
4148
|
-
def __enter__(self) -> 'DeployAtomicPathSwap':
|
4149
|
-
return self
|
4150
|
-
|
4151
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
4152
|
-
if (
|
4153
|
-
exc_type is None and
|
4154
|
-
self._auto_commit and
|
4155
|
-
self._state == 'open'
|
4156
|
-
):
|
4157
|
-
self.commit()
|
4158
|
-
else:
|
4159
|
-
self.abort()
|
4160
|
-
|
4161
|
-
|
4162
|
-
#
|
4163
|
-
|
4164
|
-
|
4165
|
-
class DeployAtomicPathSwapping(abc.ABC):
|
4166
|
-
@abc.abstractmethod
|
4167
|
-
def begin_atomic_path_swap(
|
4168
|
-
self,
|
4169
|
-
kind: DeployAtomicPathSwapKind,
|
4170
|
-
dst_path: str,
|
4171
|
-
*,
|
4172
|
-
name_hint: ta.Optional[str] = None,
|
4173
|
-
make_dirs: bool = False,
|
4174
|
-
**kwargs: ta.Any,
|
4175
|
-
) -> DeployAtomicPathSwap:
|
4176
|
-
raise NotImplementedError
|
4177
|
-
|
4178
|
-
|
4179
|
-
##
|
4180
|
-
|
4181
|
-
|
4182
|
-
class OsRenameDeployAtomicPathSwap(DeployAtomicPathSwap):
|
4183
|
-
def __init__(
|
4184
|
-
self,
|
4185
|
-
kind: DeployAtomicPathSwapKind,
|
4186
|
-
dst_path: str,
|
4187
|
-
tmp_path: str,
|
4188
|
-
**kwargs: ta.Any,
|
4189
|
-
) -> None:
|
4190
|
-
if kind == 'dir':
|
4191
|
-
check.state(os.path.isdir(tmp_path))
|
4192
|
-
elif kind == 'file':
|
4193
|
-
check.state(os.path.isfile(tmp_path))
|
4194
|
-
else:
|
4195
|
-
raise TypeError(kind)
|
4196
|
-
|
4197
|
-
super().__init__(
|
4198
|
-
kind,
|
4199
|
-
dst_path,
|
4200
|
-
**kwargs,
|
4201
|
-
)
|
4202
|
-
|
4203
|
-
self._tmp_path = tmp_path
|
4204
|
-
|
4205
|
-
@property
|
4206
|
-
def tmp_path(self) -> str:
|
4207
|
-
return self._tmp_path
|
4208
|
-
|
4209
|
-
def _commit(self) -> None:
|
4210
|
-
os.rename(self._tmp_path, self._dst_path)
|
4211
|
-
|
4212
|
-
def _abort(self) -> None:
|
4213
|
-
shutil.rmtree(self._tmp_path, ignore_errors=True)
|
4214
|
-
|
4215
|
-
|
4216
|
-
class TempDirDeployAtomicPathSwapping(DeployAtomicPathSwapping):
|
4217
|
-
def __init__(
|
4218
|
-
self,
|
4219
|
-
*,
|
4220
|
-
temp_dir: ta.Optional[str] = None,
|
4221
|
-
root_dir: ta.Optional[str] = None,
|
4222
|
-
) -> None:
|
4223
|
-
super().__init__()
|
4224
|
-
|
4225
|
-
if root_dir is not None:
|
4226
|
-
root_dir = os.path.abspath(root_dir)
|
4227
|
-
self._root_dir = root_dir
|
4228
|
-
self._temp_dir = temp_dir
|
4229
|
-
|
4230
|
-
def begin_atomic_path_swap(
|
4231
|
-
self,
|
4232
|
-
kind: DeployAtomicPathSwapKind,
|
4233
|
-
dst_path: str,
|
4234
|
-
*,
|
4235
|
-
name_hint: ta.Optional[str] = None,
|
4236
|
-
make_dirs: bool = False,
|
4237
|
-
**kwargs: ta.Any,
|
4238
|
-
) -> DeployAtomicPathSwap:
|
4239
|
-
dst_path = os.path.abspath(dst_path)
|
4240
|
-
if self._root_dir is not None and not dst_path.startswith(check.non_empty_str(self._root_dir)):
|
4241
|
-
raise RuntimeError(f'Atomic path swap dst must be in root dir: {dst_path}, {self._root_dir}')
|
4242
|
-
|
4243
|
-
dst_dir = os.path.dirname(dst_path)
|
4244
|
-
if make_dirs:
|
4245
|
-
os.makedirs(dst_dir, exist_ok=True)
|
4246
|
-
if not os.path.isdir(dst_dir):
|
4247
|
-
raise RuntimeError(f'Atomic path swap dst dir does not exist: {dst_dir}')
|
4248
|
-
|
4249
|
-
if kind == 'dir':
|
4250
|
-
tmp_path = tempfile.mkdtemp(prefix=name_hint, dir=self._temp_dir)
|
4251
|
-
elif kind == 'file':
|
4252
|
-
fd, tmp_path = tempfile.mkstemp(prefix=name_hint, dir=self._temp_dir)
|
4253
|
-
os.close(fd)
|
4254
|
-
else:
|
4255
|
-
raise TypeError(kind)
|
4256
|
-
|
4257
|
-
return OsRenameDeployAtomicPathSwap(
|
4258
|
-
kind,
|
4259
|
-
dst_path,
|
4260
|
-
tmp_path,
|
4261
|
-
**kwargs,
|
4262
|
-
)
|
4263
|
-
|
4264
|
-
|
4265
4067
|
########################################
|
4266
4068
|
# ../deploy/paths.py
|
4267
4069
|
"""
|
@@ -5687,7 +5489,7 @@ class InjectorBinder:
|
|
5687
5489
|
def __new__(cls, *args, **kwargs): # noqa
|
5688
5490
|
raise TypeError
|
5689
5491
|
|
5690
|
-
_FN_TYPES: ta.Tuple[type, ...] = (
|
5492
|
+
_FN_TYPES: ta.ClassVar[ta.Tuple[type, ...]] = (
|
5691
5493
|
types.FunctionType,
|
5692
5494
|
types.MethodType,
|
5693
5495
|
|
@@ -5709,7 +5511,7 @@ class InjectorBinder:
|
|
5709
5511
|
cls._FN_TYPES = (*cls._FN_TYPES, icls)
|
5710
5512
|
return icls
|
5711
5513
|
|
5712
|
-
_BANNED_BIND_TYPES: ta.Tuple[type, ...] = (
|
5514
|
+
_BANNED_BIND_TYPES: ta.ClassVar[ta.Tuple[type, ...]] = (
|
5713
5515
|
InjectorProvider,
|
5714
5516
|
)
|
5715
5517
|
|
@@ -5888,45 +5690,35 @@ def bind_injector_eager_key(key: ta.Any) -> InjectorBinding:
|
|
5888
5690
|
##
|
5889
5691
|
|
5890
5692
|
|
5891
|
-
class
|
5892
|
-
def __new__(cls, *args, **kwargs): # noqa
|
5893
|
-
raise TypeError
|
5894
|
-
|
5693
|
+
class InjectionApi:
|
5895
5694
|
# keys
|
5896
5695
|
|
5897
|
-
|
5898
|
-
def as_key(cls, o: ta.Any) -> InjectorKey:
|
5696
|
+
def as_key(self, o: ta.Any) -> InjectorKey:
|
5899
5697
|
return as_injector_key(o)
|
5900
5698
|
|
5901
|
-
|
5902
|
-
def array(cls, o: ta.Any) -> InjectorKey:
|
5699
|
+
def array(self, o: ta.Any) -> InjectorKey:
|
5903
5700
|
return dc.replace(as_injector_key(o), array=True)
|
5904
5701
|
|
5905
|
-
|
5906
|
-
def tag(cls, o: ta.Any, t: ta.Any) -> InjectorKey:
|
5702
|
+
def tag(self, o: ta.Any, t: ta.Any) -> InjectorKey:
|
5907
5703
|
return dc.replace(as_injector_key(o), tag=t)
|
5908
5704
|
|
5909
5705
|
# bindings
|
5910
5706
|
|
5911
|
-
|
5912
|
-
def as_bindings(cls, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5707
|
+
def as_bindings(self, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5913
5708
|
return as_injector_bindings(*args)
|
5914
5709
|
|
5915
|
-
|
5916
|
-
def override(cls, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5710
|
+
def override(self, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5917
5711
|
return injector_override(p, *args)
|
5918
5712
|
|
5919
5713
|
# injector
|
5920
5714
|
|
5921
|
-
|
5922
|
-
def create_injector(cls, *args: InjectorBindingOrBindings, parent: ta.Optional[Injector] = None) -> Injector:
|
5715
|
+
def create_injector(self, *args: InjectorBindingOrBindings, parent: ta.Optional[Injector] = None) -> Injector:
|
5923
5716
|
return _Injector(as_injector_bindings(*args), parent)
|
5924
5717
|
|
5925
5718
|
# binder
|
5926
5719
|
|
5927
|
-
@classmethod
|
5928
5720
|
def bind(
|
5929
|
-
|
5721
|
+
self,
|
5930
5722
|
obj: ta.Any,
|
5931
5723
|
*,
|
5932
5724
|
key: ta.Any = None,
|
@@ -5961,35 +5753,32 @@ class Injection:
|
|
5961
5753
|
|
5962
5754
|
# helpers
|
5963
5755
|
|
5964
|
-
@classmethod
|
5965
5756
|
def bind_factory(
|
5966
|
-
|
5757
|
+
self,
|
5967
5758
|
fn: ta.Callable[..., T],
|
5968
5759
|
cls_: U,
|
5969
5760
|
ann: ta.Any = None,
|
5970
5761
|
) -> InjectorBindingOrBindings:
|
5971
|
-
return
|
5762
|
+
return self.bind(make_injector_factory(fn, cls_, ann))
|
5972
5763
|
|
5973
|
-
@classmethod
|
5974
5764
|
def bind_array(
|
5975
|
-
|
5765
|
+
self,
|
5976
5766
|
obj: ta.Any = None,
|
5977
5767
|
*,
|
5978
5768
|
tag: ta.Any = None,
|
5979
5769
|
) -> InjectorBindingOrBindings:
|
5980
5770
|
return bind_injector_array(obj, tag=tag)
|
5981
5771
|
|
5982
|
-
@classmethod
|
5983
5772
|
def bind_array_type(
|
5984
|
-
|
5773
|
+
self,
|
5985
5774
|
ele: ta.Union[InjectorKey, InjectorKeyCls],
|
5986
5775
|
cls_: U,
|
5987
5776
|
ann: ta.Any = None,
|
5988
5777
|
) -> InjectorBindingOrBindings:
|
5989
|
-
return
|
5778
|
+
return self.bind(make_injector_array_type(ele, cls_, ann))
|
5990
5779
|
|
5991
5780
|
|
5992
|
-
inj =
|
5781
|
+
inj = InjectionApi()
|
5993
5782
|
|
5994
5783
|
|
5995
5784
|
########################################
|
@@ -6516,6 +6305,201 @@ class JsonLogFormatter(logging.Formatter):
|
|
6516
6305
|
return self._json_dumps(dct)
|
6517
6306
|
|
6518
6307
|
|
6308
|
+
########################################
|
6309
|
+
# ../../../omlish/os/atomics.py
|
6310
|
+
|
6311
|
+
|
6312
|
+
##
|
6313
|
+
|
6314
|
+
|
6315
|
+
class AtomicPathSwap(abc.ABC):
|
6316
|
+
def __init__(
|
6317
|
+
self,
|
6318
|
+
kind: AtomicPathSwapKind,
|
6319
|
+
dst_path: str,
|
6320
|
+
*,
|
6321
|
+
auto_commit: bool = False,
|
6322
|
+
) -> None:
|
6323
|
+
super().__init__()
|
6324
|
+
|
6325
|
+
self._kind = kind
|
6326
|
+
self._dst_path = dst_path
|
6327
|
+
self._auto_commit = auto_commit
|
6328
|
+
|
6329
|
+
self._state: AtomicPathSwapState = 'open'
|
6330
|
+
|
6331
|
+
def __repr__(self) -> str:
|
6332
|
+
return attr_repr(self, 'kind', 'dst_path', 'tmp_path')
|
6333
|
+
|
6334
|
+
@property
|
6335
|
+
def kind(self) -> AtomicPathSwapKind:
|
6336
|
+
return self._kind
|
6337
|
+
|
6338
|
+
@property
|
6339
|
+
def dst_path(self) -> str:
|
6340
|
+
return self._dst_path
|
6341
|
+
|
6342
|
+
@property
|
6343
|
+
@abc.abstractmethod
|
6344
|
+
def tmp_path(self) -> str:
|
6345
|
+
raise NotImplementedError
|
6346
|
+
|
6347
|
+
#
|
6348
|
+
|
6349
|
+
@property
|
6350
|
+
def state(self) -> AtomicPathSwapState:
|
6351
|
+
return self._state
|
6352
|
+
|
6353
|
+
def _check_state(self, *states: AtomicPathSwapState) -> None:
|
6354
|
+
if self._state not in states:
|
6355
|
+
raise RuntimeError(f'Atomic path swap not in correct state: {self._state}, {states}')
|
6356
|
+
|
6357
|
+
#
|
6358
|
+
|
6359
|
+
@abc.abstractmethod
|
6360
|
+
def _commit(self) -> None:
|
6361
|
+
raise NotImplementedError
|
6362
|
+
|
6363
|
+
def commit(self) -> None:
|
6364
|
+
if self._state == 'committed':
|
6365
|
+
return
|
6366
|
+
self._check_state('open')
|
6367
|
+
try:
|
6368
|
+
self._commit()
|
6369
|
+
except Exception: # noqa
|
6370
|
+
self._abort()
|
6371
|
+
raise
|
6372
|
+
else:
|
6373
|
+
self._state = 'committed'
|
6374
|
+
|
6375
|
+
#
|
6376
|
+
|
6377
|
+
@abc.abstractmethod
|
6378
|
+
def _abort(self) -> None:
|
6379
|
+
raise NotImplementedError
|
6380
|
+
|
6381
|
+
def abort(self) -> None:
|
6382
|
+
if self._state == 'aborted':
|
6383
|
+
return
|
6384
|
+
self._abort()
|
6385
|
+
self._state = 'aborted'
|
6386
|
+
|
6387
|
+
#
|
6388
|
+
|
6389
|
+
def __enter__(self) -> 'AtomicPathSwap':
|
6390
|
+
return self
|
6391
|
+
|
6392
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
6393
|
+
if (
|
6394
|
+
exc_type is None and
|
6395
|
+
self._auto_commit and
|
6396
|
+
self._state == 'open'
|
6397
|
+
):
|
6398
|
+
self.commit()
|
6399
|
+
else:
|
6400
|
+
self.abort()
|
6401
|
+
|
6402
|
+
|
6403
|
+
class AtomicPathSwapping(abc.ABC):
|
6404
|
+
@abc.abstractmethod
|
6405
|
+
def begin_atomic_path_swap(
|
6406
|
+
self,
|
6407
|
+
kind: AtomicPathSwapKind,
|
6408
|
+
dst_path: str,
|
6409
|
+
*,
|
6410
|
+
name_hint: ta.Optional[str] = None,
|
6411
|
+
make_dirs: bool = False,
|
6412
|
+
**kwargs: ta.Any,
|
6413
|
+
) -> AtomicPathSwap:
|
6414
|
+
raise NotImplementedError
|
6415
|
+
|
6416
|
+
|
6417
|
+
##
|
6418
|
+
|
6419
|
+
|
6420
|
+
class OsRenameAtomicPathSwap(AtomicPathSwap):
|
6421
|
+
def __init__(
|
6422
|
+
self,
|
6423
|
+
kind: AtomicPathSwapKind,
|
6424
|
+
dst_path: str,
|
6425
|
+
tmp_path: str,
|
6426
|
+
**kwargs: ta.Any,
|
6427
|
+
) -> None:
|
6428
|
+
if kind == 'dir':
|
6429
|
+
check.state(os.path.isdir(tmp_path))
|
6430
|
+
elif kind == 'file':
|
6431
|
+
check.state(os.path.isfile(tmp_path))
|
6432
|
+
else:
|
6433
|
+
raise TypeError(kind)
|
6434
|
+
|
6435
|
+
super().__init__(
|
6436
|
+
kind,
|
6437
|
+
dst_path,
|
6438
|
+
**kwargs,
|
6439
|
+
)
|
6440
|
+
|
6441
|
+
self._tmp_path = tmp_path
|
6442
|
+
|
6443
|
+
@property
|
6444
|
+
def tmp_path(self) -> str:
|
6445
|
+
return self._tmp_path
|
6446
|
+
|
6447
|
+
def _commit(self) -> None:
|
6448
|
+
os.rename(self._tmp_path, self._dst_path)
|
6449
|
+
|
6450
|
+
def _abort(self) -> None:
|
6451
|
+
shutil.rmtree(self._tmp_path, ignore_errors=True)
|
6452
|
+
|
6453
|
+
|
6454
|
+
class TempDirAtomicPathSwapping(AtomicPathSwapping):
|
6455
|
+
def __init__(
|
6456
|
+
self,
|
6457
|
+
*,
|
6458
|
+
temp_dir: ta.Optional[str] = None,
|
6459
|
+
root_dir: ta.Optional[str] = None,
|
6460
|
+
) -> None:
|
6461
|
+
super().__init__()
|
6462
|
+
|
6463
|
+
if root_dir is not None:
|
6464
|
+
root_dir = os.path.abspath(root_dir)
|
6465
|
+
self._root_dir = root_dir
|
6466
|
+
self._temp_dir = temp_dir
|
6467
|
+
|
6468
|
+
def begin_atomic_path_swap(
|
6469
|
+
self,
|
6470
|
+
kind: AtomicPathSwapKind,
|
6471
|
+
dst_path: str,
|
6472
|
+
*,
|
6473
|
+
name_hint: ta.Optional[str] = None,
|
6474
|
+
make_dirs: bool = False,
|
6475
|
+
**kwargs: ta.Any,
|
6476
|
+
) -> AtomicPathSwap:
|
6477
|
+
dst_path = os.path.abspath(dst_path)
|
6478
|
+
if self._root_dir is not None and not dst_path.startswith(check.non_empty_str(self._root_dir)):
|
6479
|
+
raise RuntimeError(f'Atomic path swap dst must be in root dir: {dst_path}, {self._root_dir}')
|
6480
|
+
|
6481
|
+
dst_dir = os.path.dirname(dst_path)
|
6482
|
+
if make_dirs:
|
6483
|
+
os.makedirs(dst_dir, exist_ok=True)
|
6484
|
+
if not os.path.isdir(dst_dir):
|
6485
|
+
raise RuntimeError(f'Atomic path swap dst dir does not exist: {dst_dir}')
|
6486
|
+
|
6487
|
+
if kind == 'dir':
|
6488
|
+
tmp_path = tempfile.mkdtemp(prefix=name_hint, dir=self._temp_dir)
|
6489
|
+
elif kind == 'file':
|
6490
|
+
fd, tmp_path = tempfile.mkstemp(prefix=name_hint, dir=self._temp_dir)
|
6491
|
+
os.close(fd)
|
6492
|
+
else:
|
6493
|
+
raise TypeError(kind)
|
6494
|
+
|
6495
|
+
return OsRenameAtomicPathSwap(
|
6496
|
+
kind,
|
6497
|
+
dst_path,
|
6498
|
+
tmp_path,
|
6499
|
+
**kwargs,
|
6500
|
+
)
|
6501
|
+
|
6502
|
+
|
6519
6503
|
########################################
|
6520
6504
|
# ../../../omdev/interp/types.py
|
6521
6505
|
|
@@ -6752,7 +6736,7 @@ CommandExecutorMap = ta.NewType('CommandExecutorMap', ta.Mapping[ta.Type[Command
|
|
6752
6736
|
|
6753
6737
|
class DeployTmpManager(
|
6754
6738
|
SingleDirDeployPathOwner,
|
6755
|
-
|
6739
|
+
AtomicPathSwapping,
|
6756
6740
|
):
|
6757
6741
|
def __init__(
|
6758
6742
|
self,
|
@@ -6765,18 +6749,18 @@ class DeployTmpManager(
|
|
6765
6749
|
)
|
6766
6750
|
|
6767
6751
|
@cached_nullary
|
6768
|
-
def _swapping(self) ->
|
6769
|
-
return
|
6752
|
+
def _swapping(self) -> AtomicPathSwapping:
|
6753
|
+
return TempDirAtomicPathSwapping(
|
6770
6754
|
temp_dir=self._make_dir(),
|
6771
6755
|
root_dir=check.non_empty_str(self._deploy_home),
|
6772
6756
|
)
|
6773
6757
|
|
6774
6758
|
def begin_atomic_path_swap(
|
6775
6759
|
self,
|
6776
|
-
kind:
|
6760
|
+
kind: AtomicPathSwapKind,
|
6777
6761
|
dst_path: str,
|
6778
6762
|
**kwargs: ta.Any,
|
6779
|
-
) ->
|
6763
|
+
) -> AtomicPathSwap:
|
6780
6764
|
return self._swapping().begin_atomic_path_swap(
|
6781
6765
|
kind,
|
6782
6766
|
dst_path,
|
@@ -8175,7 +8159,7 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
8175
8159
|
self,
|
8176
8160
|
*,
|
8177
8161
|
deploy_home: ta.Optional[DeployHome] = None,
|
8178
|
-
atomics:
|
8162
|
+
atomics: AtomicPathSwapping,
|
8179
8163
|
) -> None:
|
8180
8164
|
super().__init__(
|
8181
8165
|
owned_dir='git',
|
@@ -8280,7 +8264,7 @@ class DeployVenvManager(DeployPathOwner):
|
|
8280
8264
|
self,
|
8281
8265
|
*,
|
8282
8266
|
deploy_home: ta.Optional[DeployHome] = None,
|
8283
|
-
atomics:
|
8267
|
+
atomics: AtomicPathSwapping,
|
8284
8268
|
) -> None:
|
8285
8269
|
super().__init__()
|
8286
8270
|
|
@@ -9824,7 +9808,7 @@ class DockerManageTargetConnector(ManageTargetConnector):
|
|
9824
9808
|
if dmt.image is not None:
|
9825
9809
|
sh_parts.extend(['run', '-i', dmt.image])
|
9826
9810
|
elif dmt.container_id is not None:
|
9827
|
-
sh_parts.extend(['exec', dmt.container_id])
|
9811
|
+
sh_parts.extend(['exec', '-i', dmt.container_id])
|
9828
9812
|
else:
|
9829
9813
|
raise ValueError(dmt)
|
9830
9814
|
|
@@ -10044,7 +10028,7 @@ def bind_deploy(
|
|
10044
10028
|
inj.bind(DeployGitManager, singleton=True),
|
10045
10029
|
|
10046
10030
|
inj.bind(DeployTmpManager, singleton=True),
|
10047
|
-
inj.bind(
|
10031
|
+
inj.bind(AtomicPathSwapping, to_key=DeployTmpManager),
|
10048
10032
|
|
10049
10033
|
inj.bind(DeployVenvManager, singleton=True),
|
10050
10034
|
|
ominfra/scripts/supervisor.py
CHANGED
@@ -4548,7 +4548,7 @@ class InjectorBinder:
|
|
4548
4548
|
def __new__(cls, *args, **kwargs): # noqa
|
4549
4549
|
raise TypeError
|
4550
4550
|
|
4551
|
-
_FN_TYPES: ta.Tuple[type, ...] = (
|
4551
|
+
_FN_TYPES: ta.ClassVar[ta.Tuple[type, ...]] = (
|
4552
4552
|
types.FunctionType,
|
4553
4553
|
types.MethodType,
|
4554
4554
|
|
@@ -4570,7 +4570,7 @@ class InjectorBinder:
|
|
4570
4570
|
cls._FN_TYPES = (*cls._FN_TYPES, icls)
|
4571
4571
|
return icls
|
4572
4572
|
|
4573
|
-
_BANNED_BIND_TYPES: ta.Tuple[type, ...] = (
|
4573
|
+
_BANNED_BIND_TYPES: ta.ClassVar[ta.Tuple[type, ...]] = (
|
4574
4574
|
InjectorProvider,
|
4575
4575
|
)
|
4576
4576
|
|
@@ -4749,45 +4749,35 @@ def bind_injector_eager_key(key: ta.Any) -> InjectorBinding:
|
|
4749
4749
|
##
|
4750
4750
|
|
4751
4751
|
|
4752
|
-
class
|
4753
|
-
def __new__(cls, *args, **kwargs): # noqa
|
4754
|
-
raise TypeError
|
4755
|
-
|
4752
|
+
class InjectionApi:
|
4756
4753
|
# keys
|
4757
4754
|
|
4758
|
-
|
4759
|
-
def as_key(cls, o: ta.Any) -> InjectorKey:
|
4755
|
+
def as_key(self, o: ta.Any) -> InjectorKey:
|
4760
4756
|
return as_injector_key(o)
|
4761
4757
|
|
4762
|
-
|
4763
|
-
def array(cls, o: ta.Any) -> InjectorKey:
|
4758
|
+
def array(self, o: ta.Any) -> InjectorKey:
|
4764
4759
|
return dc.replace(as_injector_key(o), array=True)
|
4765
4760
|
|
4766
|
-
|
4767
|
-
def tag(cls, o: ta.Any, t: ta.Any) -> InjectorKey:
|
4761
|
+
def tag(self, o: ta.Any, t: ta.Any) -> InjectorKey:
|
4768
4762
|
return dc.replace(as_injector_key(o), tag=t)
|
4769
4763
|
|
4770
4764
|
# bindings
|
4771
4765
|
|
4772
|
-
|
4773
|
-
def as_bindings(cls, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
4766
|
+
def as_bindings(self, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
4774
4767
|
return as_injector_bindings(*args)
|
4775
4768
|
|
4776
|
-
|
4777
|
-
def override(cls, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
4769
|
+
def override(self, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
4778
4770
|
return injector_override(p, *args)
|
4779
4771
|
|
4780
4772
|
# injector
|
4781
4773
|
|
4782
|
-
|
4783
|
-
def create_injector(cls, *args: InjectorBindingOrBindings, parent: ta.Optional[Injector] = None) -> Injector:
|
4774
|
+
def create_injector(self, *args: InjectorBindingOrBindings, parent: ta.Optional[Injector] = None) -> Injector:
|
4784
4775
|
return _Injector(as_injector_bindings(*args), parent)
|
4785
4776
|
|
4786
4777
|
# binder
|
4787
4778
|
|
4788
|
-
@classmethod
|
4789
4779
|
def bind(
|
4790
|
-
|
4780
|
+
self,
|
4791
4781
|
obj: ta.Any,
|
4792
4782
|
*,
|
4793
4783
|
key: ta.Any = None,
|
@@ -4822,35 +4812,32 @@ class Injection:
|
|
4822
4812
|
|
4823
4813
|
# helpers
|
4824
4814
|
|
4825
|
-
@classmethod
|
4826
4815
|
def bind_factory(
|
4827
|
-
|
4816
|
+
self,
|
4828
4817
|
fn: ta.Callable[..., T],
|
4829
4818
|
cls_: U,
|
4830
4819
|
ann: ta.Any = None,
|
4831
4820
|
) -> InjectorBindingOrBindings:
|
4832
|
-
return
|
4821
|
+
return self.bind(make_injector_factory(fn, cls_, ann))
|
4833
4822
|
|
4834
|
-
@classmethod
|
4835
4823
|
def bind_array(
|
4836
|
-
|
4824
|
+
self,
|
4837
4825
|
obj: ta.Any = None,
|
4838
4826
|
*,
|
4839
4827
|
tag: ta.Any = None,
|
4840
4828
|
) -> InjectorBindingOrBindings:
|
4841
4829
|
return bind_injector_array(obj, tag=tag)
|
4842
4830
|
|
4843
|
-
@classmethod
|
4844
4831
|
def bind_array_type(
|
4845
|
-
|
4832
|
+
self,
|
4846
4833
|
ele: ta.Union[InjectorKey, InjectorKeyCls],
|
4847
4834
|
cls_: U,
|
4848
4835
|
ann: ta.Any = None,
|
4849
4836
|
) -> InjectorBindingOrBindings:
|
4850
|
-
return
|
4837
|
+
return self.bind(make_injector_array_type(ele, cls_, ann))
|
4851
4838
|
|
4852
4839
|
|
4853
|
-
inj =
|
4840
|
+
inj = InjectionApi()
|
4854
4841
|
|
4855
4842
|
|
4856
4843
|
########################################
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev162
|
4
4
|
Summary: ominfra
|
5
5
|
Author: wrmsr
|
6
6
|
License: BSD-3-Clause
|
@@ -12,8 +12,8 @@ Classifier: Operating System :: OS Independent
|
|
12
12
|
Classifier: Operating System :: POSIX
|
13
13
|
Requires-Python: >=3.12
|
14
14
|
License-File: LICENSE
|
15
|
-
Requires-Dist: omdev==0.0.0.
|
16
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omdev==0.0.0.dev162
|
16
|
+
Requires-Dist: omlish==0.0.0.dev162
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -45,17 +45,16 @@ ominfra/manage/commands/subprocess.py,sha256=yHGMbAI-xKe_9BUs5IZ3Yav8qRE-I9aGnBt
|
|
45
45
|
ominfra/manage/commands/types.py,sha256=XFZPeqeIBAaIIQF3pdPbGxLlb-LCrz6WtlDWO2q_vz0,210
|
46
46
|
ominfra/manage/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
47
|
ominfra/manage/deploy/apps.py,sha256=lXcbyX8_wrvvwKtIMM9P_Mh7xL8yj6z9_PFTl_0u-0U,1887
|
48
|
-
ominfra/manage/deploy/atomics.py,sha256=j9_L2LXls2dR1I4rQw3msIa2D90JwEO9Mb8KBGOKmyU,5180
|
49
48
|
ominfra/manage/deploy/commands.py,sha256=N9qVntnRgJ_IneI7rEQB2Za0oU7gouPfm-sl2MCwW1E,764
|
50
49
|
ominfra/manage/deploy/config.py,sha256=aR6ubMEWqkTI55XtcG1Cczn6YhCVN6eSL8DT5EHQJN0,166
|
51
|
-
ominfra/manage/deploy/git.py,sha256=
|
52
|
-
ominfra/manage/deploy/inject.py,sha256=
|
50
|
+
ominfra/manage/deploy/git.py,sha256=6CGLvGH8uYkuT8gyZHybJb7sgUPTtFgy7grj1YHkI9g,3747
|
51
|
+
ominfra/manage/deploy/inject.py,sha256=8wuIgdzkDCHbc69nD1meLjwfCOMdWOIfDT5yijL-du8,1441
|
53
52
|
ominfra/manage/deploy/interp.py,sha256=OKkenH8YKEW_mEDR6X7_ZLxK9a1Ox6KHSwFPTHT6OzA,1029
|
54
53
|
ominfra/manage/deploy/paths.py,sha256=tK8zZFWOHDRdTN5AlTe-3MpgZqovhWrljGosQmeEYvo,6839
|
55
54
|
ominfra/manage/deploy/specs.py,sha256=Yq3WiLNJcodUBEsJfP18gPGB3X2ABI1g8YLlsUvJOXg,1230
|
56
|
-
ominfra/manage/deploy/tmp.py,sha256=
|
55
|
+
ominfra/manage/deploy/tmp.py,sha256=L0pIfQuxQ7_6gC_AAv7eubI37_IPzCVR29hkn1MHL2Q,1230
|
57
56
|
ominfra/manage/deploy/types.py,sha256=o95wqvTGNRq8Cxx7VpqeX-9x1tI8k8BpqPFvJZkJYBA,305
|
58
|
-
ominfra/manage/deploy/venvs.py,sha256=
|
57
|
+
ominfra/manage/deploy/venvs.py,sha256=ZG9tXhzg0R173T1IFIc5DE45xEuJK97DjlN1cQPAvXI,2229
|
59
58
|
ominfra/manage/remote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
59
|
ominfra/manage/remote/_main.py,sha256=p5KoiS2WMw6QAqlDl_Zun-JybmCsy8awIfpBMLBjGMY,4356
|
61
60
|
ominfra/manage/remote/channel.py,sha256=36xR9Ti9ZA8TUBtxmY0u7_3Lv7E6wzQTxlZl7gLR5GE,2224
|
@@ -72,13 +71,13 @@ ominfra/manage/system/inject.py,sha256=Ksc7Xw_Yh3lWwkTRxB2JCeOYO-nMyKj-Kssd1RDkR
|
|
72
71
|
ominfra/manage/system/packages.py,sha256=HImCsgzXxcfzAoD2PjrstaSE_qgBWtTFUVb0lTEOxkI,4614
|
73
72
|
ominfra/manage/system/platforms.py,sha256=F0bgYzUzCjZ2LbWVvnEq2ya_X_LfRW406LQYFL7bG44,1202
|
74
73
|
ominfra/manage/targets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
75
|
-
ominfra/manage/targets/connection.py,sha256=
|
74
|
+
ominfra/manage/targets/connection.py,sha256=5e8h9Miej2DKJxZfLyxpGe8y-Y0V_b_AuUW159XVeJM,4643
|
76
75
|
ominfra/manage/targets/inject.py,sha256=P4597xWM-V3I_gCt2O71OLhYQkkXtuJvkYRsIbhhMcE,1561
|
77
76
|
ominfra/manage/targets/targets.py,sha256=CFl8Uirgn3gfowO1Fn-LBK-6qYqEMFJ9snPUl0gCRuM,1753
|
78
77
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
79
78
|
ominfra/scripts/journald2aws.py,sha256=EC8tSKW3hztBV_Kr_ykK72AmcvnWivUxcz6Sfg3M_hI,155085
|
80
|
-
ominfra/scripts/manage.py,sha256=
|
81
|
-
ominfra/scripts/supervisor.py,sha256=
|
79
|
+
ominfra/scripts/manage.py,sha256=mslFxApTHF_954w462BIpZdk9V1oy02fJhcN1N1-Wf4,293592
|
80
|
+
ominfra/scripts/supervisor.py,sha256=uPcw4o8gt8xvQ97jXK-WBAaZj3D81Lq9tqDoKxGvLCU,273791
|
82
81
|
ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
|
83
82
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
84
83
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
@@ -120,9 +119,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
|
120
119
|
ominfra/tailscale/cli.py,sha256=h6akQJMl0KuWLHS7Ur6WcBZ2JwF0DJQhsPTnFBdGyNk,3571
|
121
120
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
122
121
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
123
|
-
ominfra-0.0.0.
|
124
|
-
ominfra-0.0.0.
|
125
|
-
ominfra-0.0.0.
|
126
|
-
ominfra-0.0.0.
|
127
|
-
ominfra-0.0.0.
|
128
|
-
ominfra-0.0.0.
|
122
|
+
ominfra-0.0.0.dev162.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
123
|
+
ominfra-0.0.0.dev162.dist-info/METADATA,sha256=tmh0OqIMABojtwp_fUbGyKMod6s85abgUC2tuyhS30Q,731
|
124
|
+
ominfra-0.0.0.dev162.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
125
|
+
ominfra-0.0.0.dev162.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
126
|
+
ominfra-0.0.0.dev162.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
127
|
+
ominfra-0.0.0.dev162.dist-info/RECORD,,
|
ominfra/manage/deploy/atomics.py
DELETED
@@ -1,207 +0,0 @@
|
|
1
|
-
# ruff: noqa: UP006 UP007
|
2
|
-
import abc
|
3
|
-
import os
|
4
|
-
import shutil
|
5
|
-
import tempfile
|
6
|
-
import typing as ta
|
7
|
-
|
8
|
-
from omlish.lite.check import check
|
9
|
-
from omlish.lite.strings import attr_repr
|
10
|
-
|
11
|
-
|
12
|
-
DeployAtomicPathSwapKind = ta.Literal['dir', 'file']
|
13
|
-
DeployAtomicPathSwapState = ta.Literal['open', 'committed', 'aborted'] # ta.TypeAlias
|
14
|
-
|
15
|
-
|
16
|
-
##
|
17
|
-
|
18
|
-
|
19
|
-
class DeployAtomicPathSwap(abc.ABC):
|
20
|
-
def __init__(
|
21
|
-
self,
|
22
|
-
kind: DeployAtomicPathSwapKind,
|
23
|
-
dst_path: str,
|
24
|
-
*,
|
25
|
-
auto_commit: bool = False,
|
26
|
-
) -> None:
|
27
|
-
super().__init__()
|
28
|
-
|
29
|
-
self._kind = kind
|
30
|
-
self._dst_path = dst_path
|
31
|
-
self._auto_commit = auto_commit
|
32
|
-
|
33
|
-
self._state: DeployAtomicPathSwapState = 'open'
|
34
|
-
|
35
|
-
def __repr__(self) -> str:
|
36
|
-
return attr_repr(self, 'kind', 'dst_path', 'tmp_path')
|
37
|
-
|
38
|
-
@property
|
39
|
-
def kind(self) -> DeployAtomicPathSwapKind:
|
40
|
-
return self._kind
|
41
|
-
|
42
|
-
@property
|
43
|
-
def dst_path(self) -> str:
|
44
|
-
return self._dst_path
|
45
|
-
|
46
|
-
@property
|
47
|
-
@abc.abstractmethod
|
48
|
-
def tmp_path(self) -> str:
|
49
|
-
raise NotImplementedError
|
50
|
-
|
51
|
-
#
|
52
|
-
|
53
|
-
@property
|
54
|
-
def state(self) -> DeployAtomicPathSwapState:
|
55
|
-
return self._state
|
56
|
-
|
57
|
-
def _check_state(self, *states: DeployAtomicPathSwapState) -> None:
|
58
|
-
if self._state not in states:
|
59
|
-
raise RuntimeError(f'Atomic path swap not in correct state: {self._state}, {states}')
|
60
|
-
|
61
|
-
#
|
62
|
-
|
63
|
-
@abc.abstractmethod
|
64
|
-
def _commit(self) -> None:
|
65
|
-
raise NotImplementedError
|
66
|
-
|
67
|
-
def commit(self) -> None:
|
68
|
-
if self._state == 'committed':
|
69
|
-
return
|
70
|
-
self._check_state('open')
|
71
|
-
try:
|
72
|
-
self._commit()
|
73
|
-
except Exception: # noqa
|
74
|
-
self._abort()
|
75
|
-
raise
|
76
|
-
else:
|
77
|
-
self._state = 'committed'
|
78
|
-
|
79
|
-
#
|
80
|
-
|
81
|
-
@abc.abstractmethod
|
82
|
-
def _abort(self) -> None:
|
83
|
-
raise NotImplementedError
|
84
|
-
|
85
|
-
def abort(self) -> None:
|
86
|
-
if self._state == 'aborted':
|
87
|
-
return
|
88
|
-
self._abort()
|
89
|
-
self._state = 'aborted'
|
90
|
-
|
91
|
-
#
|
92
|
-
|
93
|
-
def __enter__(self) -> 'DeployAtomicPathSwap':
|
94
|
-
return self
|
95
|
-
|
96
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
97
|
-
if (
|
98
|
-
exc_type is None and
|
99
|
-
self._auto_commit and
|
100
|
-
self._state == 'open'
|
101
|
-
):
|
102
|
-
self.commit()
|
103
|
-
else:
|
104
|
-
self.abort()
|
105
|
-
|
106
|
-
|
107
|
-
#
|
108
|
-
|
109
|
-
|
110
|
-
class DeployAtomicPathSwapping(abc.ABC):
|
111
|
-
@abc.abstractmethod
|
112
|
-
def begin_atomic_path_swap(
|
113
|
-
self,
|
114
|
-
kind: DeployAtomicPathSwapKind,
|
115
|
-
dst_path: str,
|
116
|
-
*,
|
117
|
-
name_hint: ta.Optional[str] = None,
|
118
|
-
make_dirs: bool = False,
|
119
|
-
**kwargs: ta.Any,
|
120
|
-
) -> DeployAtomicPathSwap:
|
121
|
-
raise NotImplementedError
|
122
|
-
|
123
|
-
|
124
|
-
##
|
125
|
-
|
126
|
-
|
127
|
-
class OsRenameDeployAtomicPathSwap(DeployAtomicPathSwap):
|
128
|
-
def __init__(
|
129
|
-
self,
|
130
|
-
kind: DeployAtomicPathSwapKind,
|
131
|
-
dst_path: str,
|
132
|
-
tmp_path: str,
|
133
|
-
**kwargs: ta.Any,
|
134
|
-
) -> None:
|
135
|
-
if kind == 'dir':
|
136
|
-
check.state(os.path.isdir(tmp_path))
|
137
|
-
elif kind == 'file':
|
138
|
-
check.state(os.path.isfile(tmp_path))
|
139
|
-
else:
|
140
|
-
raise TypeError(kind)
|
141
|
-
|
142
|
-
super().__init__(
|
143
|
-
kind,
|
144
|
-
dst_path,
|
145
|
-
**kwargs,
|
146
|
-
)
|
147
|
-
|
148
|
-
self._tmp_path = tmp_path
|
149
|
-
|
150
|
-
@property
|
151
|
-
def tmp_path(self) -> str:
|
152
|
-
return self._tmp_path
|
153
|
-
|
154
|
-
def _commit(self) -> None:
|
155
|
-
os.rename(self._tmp_path, self._dst_path)
|
156
|
-
|
157
|
-
def _abort(self) -> None:
|
158
|
-
shutil.rmtree(self._tmp_path, ignore_errors=True)
|
159
|
-
|
160
|
-
|
161
|
-
class TempDirDeployAtomicPathSwapping(DeployAtomicPathSwapping):
|
162
|
-
def __init__(
|
163
|
-
self,
|
164
|
-
*,
|
165
|
-
temp_dir: ta.Optional[str] = None,
|
166
|
-
root_dir: ta.Optional[str] = None,
|
167
|
-
) -> None:
|
168
|
-
super().__init__()
|
169
|
-
|
170
|
-
if root_dir is not None:
|
171
|
-
root_dir = os.path.abspath(root_dir)
|
172
|
-
self._root_dir = root_dir
|
173
|
-
self._temp_dir = temp_dir
|
174
|
-
|
175
|
-
def begin_atomic_path_swap(
|
176
|
-
self,
|
177
|
-
kind: DeployAtomicPathSwapKind,
|
178
|
-
dst_path: str,
|
179
|
-
*,
|
180
|
-
name_hint: ta.Optional[str] = None,
|
181
|
-
make_dirs: bool = False,
|
182
|
-
**kwargs: ta.Any,
|
183
|
-
) -> DeployAtomicPathSwap:
|
184
|
-
dst_path = os.path.abspath(dst_path)
|
185
|
-
if self._root_dir is not None and not dst_path.startswith(check.non_empty_str(self._root_dir)):
|
186
|
-
raise RuntimeError(f'Atomic path swap dst must be in root dir: {dst_path}, {self._root_dir}')
|
187
|
-
|
188
|
-
dst_dir = os.path.dirname(dst_path)
|
189
|
-
if make_dirs:
|
190
|
-
os.makedirs(dst_dir, exist_ok=True)
|
191
|
-
if not os.path.isdir(dst_dir):
|
192
|
-
raise RuntimeError(f'Atomic path swap dst dir does not exist: {dst_dir}')
|
193
|
-
|
194
|
-
if kind == 'dir':
|
195
|
-
tmp_path = tempfile.mkdtemp(prefix=name_hint, dir=self._temp_dir)
|
196
|
-
elif kind == 'file':
|
197
|
-
fd, tmp_path = tempfile.mkstemp(prefix=name_hint, dir=self._temp_dir)
|
198
|
-
os.close(fd)
|
199
|
-
else:
|
200
|
-
raise TypeError(kind)
|
201
|
-
|
202
|
-
return OsRenameDeployAtomicPathSwap(
|
203
|
-
kind,
|
204
|
-
dst_path,
|
205
|
-
tmp_path,
|
206
|
-
**kwargs,
|
207
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|