ominfra 0.0.0.dev159__py3-none-any.whl → 0.0.0.dev161__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/apps.py +3 -4
- ominfra/manage/deploy/commands.py +10 -1
- ominfra/manage/deploy/git.py +15 -8
- ominfra/manage/deploy/inject.py +2 -2
- ominfra/manage/deploy/paths.py +7 -36
- ominfra/manage/deploy/specs.py +16 -2
- ominfra/manage/deploy/tmp.py +9 -9
- ominfra/manage/deploy/venvs.py +2 -2
- ominfra/manage/targets/connection.py +1 -1
- ominfra/scripts/journald2aws.py +21 -9
- ominfra/scripts/manage.py +295 -289
- ominfra/scripts/supervisor.py +21 -9
- {ominfra-0.0.0.dev159.dist-info → ominfra-0.0.0.dev161.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev159.dist-info → ominfra-0.0.0.dev161.dist-info}/RECORD +18 -19
- ominfra/manage/deploy/atomics.py +0 -207
- {ominfra-0.0.0.dev159.dist-info → ominfra-0.0.0.dev161.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev159.dist-info → ominfra-0.0.0.dev161.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev159.dist-info → ominfra-0.0.0.dev161.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev159.dist-info → ominfra-0.0.0.dev161.dist-info}/top_level.txt +0 -0
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
|
|
@@ -2692,6 +2692,10 @@ def is_new_type(spec: ta.Any) -> bool:
|
|
2692
2692
|
return isinstance(spec, types.FunctionType) and spec.__code__ is ta.NewType.__code__.co_consts[1] # type: ignore # noqa
|
2693
2693
|
|
2694
2694
|
|
2695
|
+
def get_new_type_supertype(spec: ta.Any) -> ta.Any:
|
2696
|
+
return spec.__supertype__
|
2697
|
+
|
2698
|
+
|
2695
2699
|
def deep_subclasses(cls: ta.Type[T]) -> ta.Iterator[ta.Type[T]]:
|
2696
2700
|
seen = set()
|
2697
2701
|
todo = list(reversed(cls.__subclasses__()))
|
@@ -4060,242 +4064,15 @@ def build_command_name_map(crs: CommandRegistrations) -> CommandNameMap:
|
|
4060
4064
|
return CommandNameMap(dct)
|
4061
4065
|
|
4062
4066
|
|
4063
|
-
########################################
|
4064
|
-
# ../deploy/atomics.py
|
4065
|
-
|
4066
|
-
|
4067
|
-
##
|
4068
|
-
|
4069
|
-
|
4070
|
-
class DeployAtomicPathSwap(abc.ABC):
|
4071
|
-
def __init__(
|
4072
|
-
self,
|
4073
|
-
kind: DeployAtomicPathSwapKind,
|
4074
|
-
dst_path: str,
|
4075
|
-
*,
|
4076
|
-
auto_commit: bool = False,
|
4077
|
-
) -> None:
|
4078
|
-
super().__init__()
|
4079
|
-
|
4080
|
-
self._kind = kind
|
4081
|
-
self._dst_path = dst_path
|
4082
|
-
self._auto_commit = auto_commit
|
4083
|
-
|
4084
|
-
self._state: DeployAtomicPathSwapState = 'open'
|
4085
|
-
|
4086
|
-
def __repr__(self) -> str:
|
4087
|
-
return attr_repr(self, 'kind', 'dst_path', 'tmp_path')
|
4088
|
-
|
4089
|
-
@property
|
4090
|
-
def kind(self) -> DeployAtomicPathSwapKind:
|
4091
|
-
return self._kind
|
4092
|
-
|
4093
|
-
@property
|
4094
|
-
def dst_path(self) -> str:
|
4095
|
-
return self._dst_path
|
4096
|
-
|
4097
|
-
@property
|
4098
|
-
@abc.abstractmethod
|
4099
|
-
def tmp_path(self) -> str:
|
4100
|
-
raise NotImplementedError
|
4101
|
-
|
4102
|
-
#
|
4103
|
-
|
4104
|
-
@property
|
4105
|
-
def state(self) -> DeployAtomicPathSwapState:
|
4106
|
-
return self._state
|
4107
|
-
|
4108
|
-
def _check_state(self, *states: DeployAtomicPathSwapState) -> None:
|
4109
|
-
if self._state not in states:
|
4110
|
-
raise RuntimeError(f'Atomic path swap not in correct state: {self._state}, {states}')
|
4111
|
-
|
4112
|
-
#
|
4113
|
-
|
4114
|
-
@abc.abstractmethod
|
4115
|
-
def _commit(self) -> None:
|
4116
|
-
raise NotImplementedError
|
4117
|
-
|
4118
|
-
def commit(self) -> None:
|
4119
|
-
if self._state == 'committed':
|
4120
|
-
return
|
4121
|
-
self._check_state('open')
|
4122
|
-
try:
|
4123
|
-
self._commit()
|
4124
|
-
except Exception: # noqa
|
4125
|
-
self._abort()
|
4126
|
-
raise
|
4127
|
-
else:
|
4128
|
-
self._state = 'committed'
|
4129
|
-
|
4130
|
-
#
|
4131
|
-
|
4132
|
-
@abc.abstractmethod
|
4133
|
-
def _abort(self) -> None:
|
4134
|
-
raise NotImplementedError
|
4135
|
-
|
4136
|
-
def abort(self) -> None:
|
4137
|
-
if self._state == 'aborted':
|
4138
|
-
return
|
4139
|
-
self._abort()
|
4140
|
-
self._state = 'aborted'
|
4141
|
-
|
4142
|
-
#
|
4143
|
-
|
4144
|
-
def __enter__(self) -> 'DeployAtomicPathSwap':
|
4145
|
-
return self
|
4146
|
-
|
4147
|
-
def __exit__(self, exc_type, exc_val, exc_tb):
|
4148
|
-
if (
|
4149
|
-
exc_type is None and
|
4150
|
-
self._auto_commit and
|
4151
|
-
self._state == 'open'
|
4152
|
-
):
|
4153
|
-
self.commit()
|
4154
|
-
else:
|
4155
|
-
self.abort()
|
4156
|
-
|
4157
|
-
|
4158
|
-
#
|
4159
|
-
|
4160
|
-
|
4161
|
-
class DeployAtomicPathSwapping(abc.ABC):
|
4162
|
-
@abc.abstractmethod
|
4163
|
-
def begin_atomic_path_swap(
|
4164
|
-
self,
|
4165
|
-
kind: DeployAtomicPathSwapKind,
|
4166
|
-
dst_path: str,
|
4167
|
-
*,
|
4168
|
-
name_hint: ta.Optional[str] = None,
|
4169
|
-
make_dirs: bool = False,
|
4170
|
-
**kwargs: ta.Any,
|
4171
|
-
) -> DeployAtomicPathSwap:
|
4172
|
-
raise NotImplementedError
|
4173
|
-
|
4174
|
-
|
4175
|
-
##
|
4176
|
-
|
4177
|
-
|
4178
|
-
class OsRenameDeployAtomicPathSwap(DeployAtomicPathSwap):
|
4179
|
-
def __init__(
|
4180
|
-
self,
|
4181
|
-
kind: DeployAtomicPathSwapKind,
|
4182
|
-
dst_path: str,
|
4183
|
-
tmp_path: str,
|
4184
|
-
**kwargs: ta.Any,
|
4185
|
-
) -> None:
|
4186
|
-
if kind == 'dir':
|
4187
|
-
check.state(os.path.isdir(tmp_path))
|
4188
|
-
elif kind == 'file':
|
4189
|
-
check.state(os.path.isfile(tmp_path))
|
4190
|
-
else:
|
4191
|
-
raise TypeError(kind)
|
4192
|
-
|
4193
|
-
super().__init__(
|
4194
|
-
kind,
|
4195
|
-
dst_path,
|
4196
|
-
**kwargs,
|
4197
|
-
)
|
4198
|
-
|
4199
|
-
self._tmp_path = tmp_path
|
4200
|
-
|
4201
|
-
@property
|
4202
|
-
def tmp_path(self) -> str:
|
4203
|
-
return self._tmp_path
|
4204
|
-
|
4205
|
-
def _commit(self) -> None:
|
4206
|
-
os.rename(self._tmp_path, self._dst_path)
|
4207
|
-
|
4208
|
-
def _abort(self) -> None:
|
4209
|
-
shutil.rmtree(self._tmp_path, ignore_errors=True)
|
4210
|
-
|
4211
|
-
|
4212
|
-
class TempDirDeployAtomicPathSwapping(DeployAtomicPathSwapping):
|
4213
|
-
def __init__(
|
4214
|
-
self,
|
4215
|
-
*,
|
4216
|
-
temp_dir: ta.Optional[str] = None,
|
4217
|
-
root_dir: ta.Optional[str] = None,
|
4218
|
-
) -> None:
|
4219
|
-
super().__init__()
|
4220
|
-
|
4221
|
-
if root_dir is not None:
|
4222
|
-
root_dir = os.path.abspath(root_dir)
|
4223
|
-
self._root_dir = root_dir
|
4224
|
-
self._temp_dir = temp_dir
|
4225
|
-
|
4226
|
-
def begin_atomic_path_swap(
|
4227
|
-
self,
|
4228
|
-
kind: DeployAtomicPathSwapKind,
|
4229
|
-
dst_path: str,
|
4230
|
-
*,
|
4231
|
-
name_hint: ta.Optional[str] = None,
|
4232
|
-
make_dirs: bool = False,
|
4233
|
-
**kwargs: ta.Any,
|
4234
|
-
) -> DeployAtomicPathSwap:
|
4235
|
-
dst_path = os.path.abspath(dst_path)
|
4236
|
-
if self._root_dir is not None and not dst_path.startswith(check.non_empty_str(self._root_dir)):
|
4237
|
-
raise RuntimeError(f'Atomic path swap dst must be in root dir: {dst_path}, {self._root_dir}')
|
4238
|
-
|
4239
|
-
dst_dir = os.path.dirname(dst_path)
|
4240
|
-
if make_dirs:
|
4241
|
-
os.makedirs(dst_dir, exist_ok=True)
|
4242
|
-
if not os.path.isdir(dst_dir):
|
4243
|
-
raise RuntimeError(f'Atomic path swap dst dir does not exist: {dst_dir}')
|
4244
|
-
|
4245
|
-
if kind == 'dir':
|
4246
|
-
tmp_path = tempfile.mkdtemp(prefix=name_hint, dir=self._temp_dir)
|
4247
|
-
elif kind == 'file':
|
4248
|
-
fd, tmp_path = tempfile.mkstemp(prefix=name_hint, dir=self._temp_dir)
|
4249
|
-
os.close(fd)
|
4250
|
-
else:
|
4251
|
-
raise TypeError(kind)
|
4252
|
-
|
4253
|
-
return OsRenameDeployAtomicPathSwap(
|
4254
|
-
kind,
|
4255
|
-
dst_path,
|
4256
|
-
tmp_path,
|
4257
|
-
**kwargs,
|
4258
|
-
)
|
4259
|
-
|
4260
|
-
|
4261
4067
|
########################################
|
4262
4068
|
# ../deploy/paths.py
|
4263
4069
|
"""
|
4264
|
-
|
4265
|
-
|
4266
|
-
|
4267
|
-
|
4268
|
-
|
4269
|
-
|
4270
|
-
<appplaceholder>.env
|
4271
|
-
/nginx
|
4272
|
-
<appplaceholder>.conf
|
4273
|
-
/supervisor
|
4274
|
-
<appplaceholder>.conf
|
4275
|
-
/venv
|
4276
|
-
/<appplaceholder>
|
4277
|
-
|
4278
|
-
/tmp
|
4279
|
-
|
4280
|
-
?
|
4281
|
-
/logs
|
4282
|
-
/wrmsr--omlish--<placeholder>
|
4283
|
-
|
4284
|
-
placeholder = <name>--<rev>--<when>
|
4285
|
-
|
4286
|
-
==
|
4287
|
-
|
4288
|
-
for dn in [
|
4289
|
-
'app',
|
4290
|
-
'conf',
|
4291
|
-
'conf/env',
|
4292
|
-
'conf/nginx',
|
4293
|
-
'conf/supervisor',
|
4294
|
-
'venv',
|
4295
|
-
]:
|
4296
|
-
|
4297
|
-
==
|
4298
|
-
|
4070
|
+
TODO:
|
4071
|
+
- run/pidfile
|
4072
|
+
- logs/...
|
4073
|
+
- current symlink
|
4074
|
+
- conf/{nginx,supervisor}
|
4075
|
+
- env/?
|
4299
4076
|
"""
|
4300
4077
|
|
4301
4078
|
|
@@ -4307,7 +4084,7 @@ DEPLOY_PATH_PLACEHOLDER_SEPARATORS = '-.'
|
|
4307
4084
|
|
4308
4085
|
DEPLOY_PATH_PLACEHOLDERS: ta.FrozenSet[str] = frozenset([
|
4309
4086
|
'app',
|
4310
|
-
'tag',
|
4087
|
+
'tag',
|
4311
4088
|
])
|
4312
4089
|
|
4313
4090
|
|
@@ -4534,14 +4311,28 @@ class DeployGitRepo:
|
|
4534
4311
|
check.not_in('.', check.non_empty_str(self.path))
|
4535
4312
|
|
4536
4313
|
|
4314
|
+
@dc.dataclass(frozen=True)
|
4315
|
+
class DeployGitCheckout:
|
4316
|
+
repo: DeployGitRepo
|
4317
|
+
rev: DeployRev
|
4318
|
+
|
4319
|
+
subtrees: ta.Optional[ta.Sequence[str]] = None
|
4320
|
+
|
4321
|
+
def __post_init__(self) -> None:
|
4322
|
+
hash(self)
|
4323
|
+
check.non_empty_str(self.rev)
|
4324
|
+
if self.subtrees is not None:
|
4325
|
+
for st in self.subtrees:
|
4326
|
+
check.non_empty_str(st)
|
4327
|
+
|
4328
|
+
|
4537
4329
|
##
|
4538
4330
|
|
4539
4331
|
|
4540
4332
|
@dc.dataclass(frozen=True)
|
4541
4333
|
class DeploySpec:
|
4542
4334
|
app: DeployApp
|
4543
|
-
|
4544
|
-
rev: DeployRev
|
4335
|
+
checkout: DeployGitCheckout
|
4545
4336
|
|
4546
4337
|
def __post_init__(self) -> None:
|
4547
4338
|
hash(self)
|
@@ -6008,9 +5799,7 @@ inj = Injection
|
|
6008
5799
|
"""
|
6009
5800
|
TODO:
|
6010
5801
|
- pickle stdlib objs? have to pin to 3.8 pickle protocol, will be cross-version
|
6011
|
-
- namedtuple
|
6012
5802
|
- literals
|
6013
|
-
- newtypes?
|
6014
5803
|
"""
|
6015
5804
|
|
6016
5805
|
|
@@ -6020,7 +5809,7 @@ TODO:
|
|
6020
5809
|
@dc.dataclass(frozen=True)
|
6021
5810
|
class ObjMarshalOptions:
|
6022
5811
|
raw_bytes: bool = False
|
6023
|
-
|
5812
|
+
non_strict_fields: bool = False
|
6024
5813
|
|
6025
5814
|
|
6026
5815
|
class ObjMarshaler(abc.ABC):
|
@@ -6149,10 +5938,10 @@ class IterableObjMarshaler(ObjMarshaler):
|
|
6149
5938
|
|
6150
5939
|
|
6151
5940
|
@dc.dataclass(frozen=True)
|
6152
|
-
class
|
5941
|
+
class FieldsObjMarshaler(ObjMarshaler):
|
6153
5942
|
ty: type
|
6154
5943
|
fs: ta.Mapping[str, ObjMarshaler]
|
6155
|
-
|
5944
|
+
non_strict: bool = False
|
6156
5945
|
|
6157
5946
|
def marshal(self, o: ta.Any, ctx: 'ObjMarshalContext') -> ta.Any:
|
6158
5947
|
return {
|
@@ -6164,7 +5953,7 @@ class DataclassObjMarshaler(ObjMarshaler):
|
|
6164
5953
|
return self.ty(**{
|
6165
5954
|
k: self.fs[k].unmarshal(v, ctx)
|
6166
5955
|
for k, v in o.items()
|
6167
|
-
if not (self.
|
5956
|
+
if not (self.non_strict or ctx.options.non_strict_fields) or k in self.fs
|
6168
5957
|
})
|
6169
5958
|
|
6170
5959
|
|
@@ -6296,7 +6085,7 @@ class ObjMarshalerManager:
|
|
6296
6085
|
ty: ta.Any,
|
6297
6086
|
rec: ta.Callable[[ta.Any], ObjMarshaler],
|
6298
6087
|
*,
|
6299
|
-
|
6088
|
+
non_strict_fields: bool = False,
|
6300
6089
|
) -> ObjMarshaler:
|
6301
6090
|
if isinstance(ty, type):
|
6302
6091
|
if abc.ABC in ty.__bases__:
|
@@ -6318,12 +6107,22 @@ class ObjMarshalerManager:
|
|
6318
6107
|
return EnumObjMarshaler(ty)
|
6319
6108
|
|
6320
6109
|
if dc.is_dataclass(ty):
|
6321
|
-
return
|
6110
|
+
return FieldsObjMarshaler(
|
6322
6111
|
ty,
|
6323
6112
|
{f.name: rec(f.type) for f in dc.fields(ty)},
|
6324
|
-
|
6113
|
+
non_strict=non_strict_fields,
|
6325
6114
|
)
|
6326
6115
|
|
6116
|
+
if issubclass(ty, tuple) and hasattr(ty, '_fields'):
|
6117
|
+
return FieldsObjMarshaler(
|
6118
|
+
ty,
|
6119
|
+
{p.name: rec(p.annotation) for p in inspect.signature(ty).parameters.values()},
|
6120
|
+
non_strict=non_strict_fields,
|
6121
|
+
)
|
6122
|
+
|
6123
|
+
if is_new_type(ty):
|
6124
|
+
return rec(get_new_type_supertype(ty))
|
6125
|
+
|
6327
6126
|
if is_generic_alias(ty):
|
6328
6127
|
try:
|
6329
6128
|
mt = self._generic_mapping_types[ta.get_origin(ty)]
|
@@ -6519,6 +6318,201 @@ class JsonLogFormatter(logging.Formatter):
|
|
6519
6318
|
return self._json_dumps(dct)
|
6520
6319
|
|
6521
6320
|
|
6321
|
+
########################################
|
6322
|
+
# ../../../omlish/os/atomics.py
|
6323
|
+
|
6324
|
+
|
6325
|
+
##
|
6326
|
+
|
6327
|
+
|
6328
|
+
class AtomicPathSwap(abc.ABC):
|
6329
|
+
def __init__(
|
6330
|
+
self,
|
6331
|
+
kind: AtomicPathSwapKind,
|
6332
|
+
dst_path: str,
|
6333
|
+
*,
|
6334
|
+
auto_commit: bool = False,
|
6335
|
+
) -> None:
|
6336
|
+
super().__init__()
|
6337
|
+
|
6338
|
+
self._kind = kind
|
6339
|
+
self._dst_path = dst_path
|
6340
|
+
self._auto_commit = auto_commit
|
6341
|
+
|
6342
|
+
self._state: AtomicPathSwapState = 'open'
|
6343
|
+
|
6344
|
+
def __repr__(self) -> str:
|
6345
|
+
return attr_repr(self, 'kind', 'dst_path', 'tmp_path')
|
6346
|
+
|
6347
|
+
@property
|
6348
|
+
def kind(self) -> AtomicPathSwapKind:
|
6349
|
+
return self._kind
|
6350
|
+
|
6351
|
+
@property
|
6352
|
+
def dst_path(self) -> str:
|
6353
|
+
return self._dst_path
|
6354
|
+
|
6355
|
+
@property
|
6356
|
+
@abc.abstractmethod
|
6357
|
+
def tmp_path(self) -> str:
|
6358
|
+
raise NotImplementedError
|
6359
|
+
|
6360
|
+
#
|
6361
|
+
|
6362
|
+
@property
|
6363
|
+
def state(self) -> AtomicPathSwapState:
|
6364
|
+
return self._state
|
6365
|
+
|
6366
|
+
def _check_state(self, *states: AtomicPathSwapState) -> None:
|
6367
|
+
if self._state not in states:
|
6368
|
+
raise RuntimeError(f'Atomic path swap not in correct state: {self._state}, {states}')
|
6369
|
+
|
6370
|
+
#
|
6371
|
+
|
6372
|
+
@abc.abstractmethod
|
6373
|
+
def _commit(self) -> None:
|
6374
|
+
raise NotImplementedError
|
6375
|
+
|
6376
|
+
def commit(self) -> None:
|
6377
|
+
if self._state == 'committed':
|
6378
|
+
return
|
6379
|
+
self._check_state('open')
|
6380
|
+
try:
|
6381
|
+
self._commit()
|
6382
|
+
except Exception: # noqa
|
6383
|
+
self._abort()
|
6384
|
+
raise
|
6385
|
+
else:
|
6386
|
+
self._state = 'committed'
|
6387
|
+
|
6388
|
+
#
|
6389
|
+
|
6390
|
+
@abc.abstractmethod
|
6391
|
+
def _abort(self) -> None:
|
6392
|
+
raise NotImplementedError
|
6393
|
+
|
6394
|
+
def abort(self) -> None:
|
6395
|
+
if self._state == 'aborted':
|
6396
|
+
return
|
6397
|
+
self._abort()
|
6398
|
+
self._state = 'aborted'
|
6399
|
+
|
6400
|
+
#
|
6401
|
+
|
6402
|
+
def __enter__(self) -> 'AtomicPathSwap':
|
6403
|
+
return self
|
6404
|
+
|
6405
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
6406
|
+
if (
|
6407
|
+
exc_type is None and
|
6408
|
+
self._auto_commit and
|
6409
|
+
self._state == 'open'
|
6410
|
+
):
|
6411
|
+
self.commit()
|
6412
|
+
else:
|
6413
|
+
self.abort()
|
6414
|
+
|
6415
|
+
|
6416
|
+
class AtomicPathSwapping(abc.ABC):
|
6417
|
+
@abc.abstractmethod
|
6418
|
+
def begin_atomic_path_swap(
|
6419
|
+
self,
|
6420
|
+
kind: AtomicPathSwapKind,
|
6421
|
+
dst_path: str,
|
6422
|
+
*,
|
6423
|
+
name_hint: ta.Optional[str] = None,
|
6424
|
+
make_dirs: bool = False,
|
6425
|
+
**kwargs: ta.Any,
|
6426
|
+
) -> AtomicPathSwap:
|
6427
|
+
raise NotImplementedError
|
6428
|
+
|
6429
|
+
|
6430
|
+
##
|
6431
|
+
|
6432
|
+
|
6433
|
+
class OsRenameAtomicPathSwap(AtomicPathSwap):
|
6434
|
+
def __init__(
|
6435
|
+
self,
|
6436
|
+
kind: AtomicPathSwapKind,
|
6437
|
+
dst_path: str,
|
6438
|
+
tmp_path: str,
|
6439
|
+
**kwargs: ta.Any,
|
6440
|
+
) -> None:
|
6441
|
+
if kind == 'dir':
|
6442
|
+
check.state(os.path.isdir(tmp_path))
|
6443
|
+
elif kind == 'file':
|
6444
|
+
check.state(os.path.isfile(tmp_path))
|
6445
|
+
else:
|
6446
|
+
raise TypeError(kind)
|
6447
|
+
|
6448
|
+
super().__init__(
|
6449
|
+
kind,
|
6450
|
+
dst_path,
|
6451
|
+
**kwargs,
|
6452
|
+
)
|
6453
|
+
|
6454
|
+
self._tmp_path = tmp_path
|
6455
|
+
|
6456
|
+
@property
|
6457
|
+
def tmp_path(self) -> str:
|
6458
|
+
return self._tmp_path
|
6459
|
+
|
6460
|
+
def _commit(self) -> None:
|
6461
|
+
os.rename(self._tmp_path, self._dst_path)
|
6462
|
+
|
6463
|
+
def _abort(self) -> None:
|
6464
|
+
shutil.rmtree(self._tmp_path, ignore_errors=True)
|
6465
|
+
|
6466
|
+
|
6467
|
+
class TempDirAtomicPathSwapping(AtomicPathSwapping):
|
6468
|
+
def __init__(
|
6469
|
+
self,
|
6470
|
+
*,
|
6471
|
+
temp_dir: ta.Optional[str] = None,
|
6472
|
+
root_dir: ta.Optional[str] = None,
|
6473
|
+
) -> None:
|
6474
|
+
super().__init__()
|
6475
|
+
|
6476
|
+
if root_dir is not None:
|
6477
|
+
root_dir = os.path.abspath(root_dir)
|
6478
|
+
self._root_dir = root_dir
|
6479
|
+
self._temp_dir = temp_dir
|
6480
|
+
|
6481
|
+
def begin_atomic_path_swap(
|
6482
|
+
self,
|
6483
|
+
kind: AtomicPathSwapKind,
|
6484
|
+
dst_path: str,
|
6485
|
+
*,
|
6486
|
+
name_hint: ta.Optional[str] = None,
|
6487
|
+
make_dirs: bool = False,
|
6488
|
+
**kwargs: ta.Any,
|
6489
|
+
) -> AtomicPathSwap:
|
6490
|
+
dst_path = os.path.abspath(dst_path)
|
6491
|
+
if self._root_dir is not None and not dst_path.startswith(check.non_empty_str(self._root_dir)):
|
6492
|
+
raise RuntimeError(f'Atomic path swap dst must be in root dir: {dst_path}, {self._root_dir}')
|
6493
|
+
|
6494
|
+
dst_dir = os.path.dirname(dst_path)
|
6495
|
+
if make_dirs:
|
6496
|
+
os.makedirs(dst_dir, exist_ok=True)
|
6497
|
+
if not os.path.isdir(dst_dir):
|
6498
|
+
raise RuntimeError(f'Atomic path swap dst dir does not exist: {dst_dir}')
|
6499
|
+
|
6500
|
+
if kind == 'dir':
|
6501
|
+
tmp_path = tempfile.mkdtemp(prefix=name_hint, dir=self._temp_dir)
|
6502
|
+
elif kind == 'file':
|
6503
|
+
fd, tmp_path = tempfile.mkstemp(prefix=name_hint, dir=self._temp_dir)
|
6504
|
+
os.close(fd)
|
6505
|
+
else:
|
6506
|
+
raise TypeError(kind)
|
6507
|
+
|
6508
|
+
return OsRenameAtomicPathSwap(
|
6509
|
+
kind,
|
6510
|
+
dst_path,
|
6511
|
+
tmp_path,
|
6512
|
+
**kwargs,
|
6513
|
+
)
|
6514
|
+
|
6515
|
+
|
6522
6516
|
########################################
|
6523
6517
|
# ../../../omdev/interp/types.py
|
6524
6518
|
|
@@ -6749,34 +6743,13 @@ class PingCommandExecutor(CommandExecutor[PingCommand, PingCommand.Output]):
|
|
6749
6743
|
CommandExecutorMap = ta.NewType('CommandExecutorMap', ta.Mapping[ta.Type[Command], CommandExecutor])
|
6750
6744
|
|
6751
6745
|
|
6752
|
-
########################################
|
6753
|
-
# ../deploy/commands.py
|
6754
|
-
|
6755
|
-
|
6756
|
-
##
|
6757
|
-
|
6758
|
-
|
6759
|
-
@dc.dataclass(frozen=True)
|
6760
|
-
class DeployCommand(Command['DeployCommand.Output']):
|
6761
|
-
@dc.dataclass(frozen=True)
|
6762
|
-
class Output(Command.Output):
|
6763
|
-
pass
|
6764
|
-
|
6765
|
-
|
6766
|
-
class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
|
6767
|
-
async def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
|
6768
|
-
log.info('Deploying!')
|
6769
|
-
|
6770
|
-
return DeployCommand.Output()
|
6771
|
-
|
6772
|
-
|
6773
6746
|
########################################
|
6774
6747
|
# ../deploy/tmp.py
|
6775
6748
|
|
6776
6749
|
|
6777
6750
|
class DeployTmpManager(
|
6778
6751
|
SingleDirDeployPathOwner,
|
6779
|
-
|
6752
|
+
AtomicPathSwapping,
|
6780
6753
|
):
|
6781
6754
|
def __init__(
|
6782
6755
|
self,
|
@@ -6789,18 +6762,18 @@ class DeployTmpManager(
|
|
6789
6762
|
)
|
6790
6763
|
|
6791
6764
|
@cached_nullary
|
6792
|
-
def _swapping(self) ->
|
6793
|
-
return
|
6765
|
+
def _swapping(self) -> AtomicPathSwapping:
|
6766
|
+
return TempDirAtomicPathSwapping(
|
6794
6767
|
temp_dir=self._make_dir(),
|
6795
6768
|
root_dir=check.non_empty_str(self._deploy_home),
|
6796
6769
|
)
|
6797
6770
|
|
6798
6771
|
def begin_atomic_path_swap(
|
6799
6772
|
self,
|
6800
|
-
kind:
|
6773
|
+
kind: AtomicPathSwapKind,
|
6801
6774
|
dst_path: str,
|
6802
6775
|
**kwargs: ta.Any,
|
6803
|
-
) ->
|
6776
|
+
) -> AtomicPathSwap:
|
6804
6777
|
return self._swapping().begin_atomic_path_swap(
|
6805
6778
|
kind,
|
6806
6779
|
dst_path,
|
@@ -8199,7 +8172,7 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
8199
8172
|
self,
|
8200
8173
|
*,
|
8201
8174
|
deploy_home: ta.Optional[DeployHome] = None,
|
8202
|
-
atomics:
|
8175
|
+
atomics: AtomicPathSwapping,
|
8203
8176
|
) -> None:
|
8204
8177
|
super().__init__(
|
8205
8178
|
owned_dir='git',
|
@@ -8237,12 +8210,16 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
8237
8210
|
else:
|
8238
8211
|
return f'https://{self._repo.host}/{self._repo.path}'
|
8239
8212
|
|
8213
|
+
#
|
8214
|
+
|
8240
8215
|
async def _call(self, *cmd: str) -> None:
|
8241
8216
|
await asyncio_subprocesses.check_call(
|
8242
8217
|
*cmd,
|
8243
8218
|
cwd=self._dir,
|
8244
8219
|
)
|
8245
8220
|
|
8221
|
+
#
|
8222
|
+
|
8246
8223
|
@async_cached_nullary
|
8247
8224
|
async def init(self) -> None:
|
8248
8225
|
os.makedirs(self._dir, exist_ok=True)
|
@@ -8256,7 +8233,9 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
8256
8233
|
await self.init()
|
8257
8234
|
await self._call('git', 'fetch', '--depth=1', 'origin', rev)
|
8258
8235
|
|
8259
|
-
|
8236
|
+
#
|
8237
|
+
|
8238
|
+
async def checkout(self, checkout: DeployGitCheckout, dst_dir: str) -> None:
|
8260
8239
|
check.state(not os.path.exists(dst_dir))
|
8261
8240
|
with self._git._atomics.begin_atomic_path_swap( # noqa
|
8262
8241
|
'dir',
|
@@ -8264,14 +8243,14 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
8264
8243
|
auto_commit=True,
|
8265
8244
|
make_dirs=True,
|
8266
8245
|
) as dst_swap:
|
8267
|
-
await self.fetch(rev)
|
8246
|
+
await self.fetch(checkout.rev)
|
8268
8247
|
|
8269
8248
|
dst_call = functools.partial(asyncio_subprocesses.check_call, cwd=dst_swap.tmp_path)
|
8270
8249
|
await dst_call('git', 'init')
|
8271
8250
|
|
8272
8251
|
await dst_call('git', 'remote', 'add', 'local', self._dir)
|
8273
|
-
await dst_call('git', 'fetch', '--depth=1', 'local', rev)
|
8274
|
-
await dst_call('git', 'checkout', rev)
|
8252
|
+
await dst_call('git', 'fetch', '--depth=1', 'local', checkout.rev)
|
8253
|
+
await dst_call('git', 'checkout', checkout.rev, *(checkout.subtrees or []))
|
8275
8254
|
|
8276
8255
|
def get_repo_dir(self, repo: DeployGitRepo) -> RepoDir:
|
8277
8256
|
try:
|
@@ -8280,8 +8259,8 @@ class DeployGitManager(SingleDirDeployPathOwner):
|
|
8280
8259
|
repo_dir = self._repo_dirs[repo] = DeployGitManager.RepoDir(self, repo)
|
8281
8260
|
return repo_dir
|
8282
8261
|
|
8283
|
-
async def checkout(self,
|
8284
|
-
await self.get_repo_dir(repo).checkout(
|
8262
|
+
async def checkout(self, checkout: DeployGitCheckout, dst_dir: str) -> None:
|
8263
|
+
await self.get_repo_dir(checkout.repo).checkout(checkout, dst_dir)
|
8285
8264
|
|
8286
8265
|
|
8287
8266
|
########################################
|
@@ -8298,7 +8277,7 @@ class DeployVenvManager(DeployPathOwner):
|
|
8298
8277
|
self,
|
8299
8278
|
*,
|
8300
8279
|
deploy_home: ta.Optional[DeployHome] = None,
|
8301
|
-
atomics:
|
8280
|
+
atomics: AtomicPathSwapping,
|
8302
8281
|
) -> None:
|
8303
8282
|
super().__init__()
|
8304
8283
|
|
@@ -8919,15 +8898,14 @@ class DeployAppManager(DeployPathOwner):
|
|
8919
8898
|
async def prepare_app(
|
8920
8899
|
self,
|
8921
8900
|
spec: DeploySpec,
|
8922
|
-
):
|
8923
|
-
app_tag = DeployAppTag(spec.app, make_deploy_tag(spec.rev, spec.key()))
|
8901
|
+
) -> None:
|
8902
|
+
app_tag = DeployAppTag(spec.app, make_deploy_tag(spec.checkout.rev, spec.key()))
|
8924
8903
|
app_dir = os.path.join(self._dir(), spec.app, app_tag.tag)
|
8925
8904
|
|
8926
8905
|
#
|
8927
8906
|
|
8928
8907
|
await self._git.checkout(
|
8929
|
-
spec.
|
8930
|
-
spec.rev,
|
8908
|
+
spec.checkout,
|
8931
8909
|
app_dir,
|
8932
8910
|
)
|
8933
8911
|
|
@@ -9650,6 +9628,34 @@ class SystemInterpProvider(InterpProvider):
|
|
9650
9628
|
raise KeyError(version)
|
9651
9629
|
|
9652
9630
|
|
9631
|
+
########################################
|
9632
|
+
# ../deploy/commands.py
|
9633
|
+
|
9634
|
+
|
9635
|
+
##
|
9636
|
+
|
9637
|
+
|
9638
|
+
@dc.dataclass(frozen=True)
|
9639
|
+
class DeployCommand(Command['DeployCommand.Output']):
|
9640
|
+
spec: DeploySpec
|
9641
|
+
|
9642
|
+
@dc.dataclass(frozen=True)
|
9643
|
+
class Output(Command.Output):
|
9644
|
+
pass
|
9645
|
+
|
9646
|
+
|
9647
|
+
@dc.dataclass(frozen=True)
|
9648
|
+
class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
|
9649
|
+
_apps: DeployAppManager
|
9650
|
+
|
9651
|
+
async def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
|
9652
|
+
log.info('Deploying! %r', cmd.spec)
|
9653
|
+
|
9654
|
+
await self._apps.prepare_app(cmd.spec)
|
9655
|
+
|
9656
|
+
return DeployCommand.Output()
|
9657
|
+
|
9658
|
+
|
9653
9659
|
########################################
|
9654
9660
|
# ../remote/inject.py
|
9655
9661
|
|
@@ -9815,7 +9821,7 @@ class DockerManageTargetConnector(ManageTargetConnector):
|
|
9815
9821
|
if dmt.image is not None:
|
9816
9822
|
sh_parts.extend(['run', '-i', dmt.image])
|
9817
9823
|
elif dmt.container_id is not None:
|
9818
|
-
sh_parts.extend(['exec', dmt.container_id])
|
9824
|
+
sh_parts.extend(['exec', '-i', dmt.container_id])
|
9819
9825
|
else:
|
9820
9826
|
raise ValueError(dmt)
|
9821
9827
|
|
@@ -10035,7 +10041,7 @@ def bind_deploy(
|
|
10035
10041
|
inj.bind(DeployGitManager, singleton=True),
|
10036
10042
|
|
10037
10043
|
inj.bind(DeployTmpManager, singleton=True),
|
10038
|
-
inj.bind(
|
10044
|
+
inj.bind(AtomicPathSwapping, to_key=DeployTmpManager),
|
10039
10045
|
|
10040
10046
|
inj.bind(DeployVenvManager, singleton=True),
|
10041
10047
|
|