ominfra 0.0.0.dev160__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.
@@ -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: DeployAtomicPathSwapping,
35
+ atomics: AtomicPathSwapping,
36
36
  ) -> None:
37
37
  super().__init__(
38
38
  owned_dir='git',
@@ -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(DeployAtomicPathSwapping, to_key=DeployTmpManager),
37
+ inj.bind(AtomicPathSwapping, to_key=DeployTmpManager),
38
38
 
39
39
  inj.bind(DeployVenvManager, singleton=True),
40
40
 
@@ -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
- DeployAtomicPathSwapping,
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) -> DeployAtomicPathSwapping:
31
- return TempDirDeployAtomicPathSwapping(
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: DeployAtomicPathSwapKind,
38
+ kind: AtomicPathSwapKind,
39
39
  dst_path: str,
40
40
  **kwargs: ta.Any,
41
- ) -> DeployAtomicPathSwap:
41
+ ) -> AtomicPathSwap:
42
42
  return self._swapping().begin_atomic_path_swap(
43
43
  kind,
44
44
  dst_path,
@@ -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: DeployAtomicPathSwapping,
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
  """
@@ -6516,6 +6318,201 @@ class JsonLogFormatter(logging.Formatter):
6516
6318
  return self._json_dumps(dct)
6517
6319
 
6518
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
+
6519
6516
  ########################################
6520
6517
  # ../../../omdev/interp/types.py
6521
6518
 
@@ -6752,7 +6749,7 @@ CommandExecutorMap = ta.NewType('CommandExecutorMap', ta.Mapping[ta.Type[Command
6752
6749
 
6753
6750
  class DeployTmpManager(
6754
6751
  SingleDirDeployPathOwner,
6755
- DeployAtomicPathSwapping,
6752
+ AtomicPathSwapping,
6756
6753
  ):
6757
6754
  def __init__(
6758
6755
  self,
@@ -6765,18 +6762,18 @@ class DeployTmpManager(
6765
6762
  )
6766
6763
 
6767
6764
  @cached_nullary
6768
- def _swapping(self) -> DeployAtomicPathSwapping:
6769
- return TempDirDeployAtomicPathSwapping(
6765
+ def _swapping(self) -> AtomicPathSwapping:
6766
+ return TempDirAtomicPathSwapping(
6770
6767
  temp_dir=self._make_dir(),
6771
6768
  root_dir=check.non_empty_str(self._deploy_home),
6772
6769
  )
6773
6770
 
6774
6771
  def begin_atomic_path_swap(
6775
6772
  self,
6776
- kind: DeployAtomicPathSwapKind,
6773
+ kind: AtomicPathSwapKind,
6777
6774
  dst_path: str,
6778
6775
  **kwargs: ta.Any,
6779
- ) -> DeployAtomicPathSwap:
6776
+ ) -> AtomicPathSwap:
6780
6777
  return self._swapping().begin_atomic_path_swap(
6781
6778
  kind,
6782
6779
  dst_path,
@@ -8175,7 +8172,7 @@ class DeployGitManager(SingleDirDeployPathOwner):
8175
8172
  self,
8176
8173
  *,
8177
8174
  deploy_home: ta.Optional[DeployHome] = None,
8178
- atomics: DeployAtomicPathSwapping,
8175
+ atomics: AtomicPathSwapping,
8179
8176
  ) -> None:
8180
8177
  super().__init__(
8181
8178
  owned_dir='git',
@@ -8280,7 +8277,7 @@ class DeployVenvManager(DeployPathOwner):
8280
8277
  self,
8281
8278
  *,
8282
8279
  deploy_home: ta.Optional[DeployHome] = None,
8283
- atomics: DeployAtomicPathSwapping,
8280
+ atomics: AtomicPathSwapping,
8284
8281
  ) -> None:
8285
8282
  super().__init__()
8286
8283
 
@@ -9824,7 +9821,7 @@ class DockerManageTargetConnector(ManageTargetConnector):
9824
9821
  if dmt.image is not None:
9825
9822
  sh_parts.extend(['run', '-i', dmt.image])
9826
9823
  elif dmt.container_id is not None:
9827
- sh_parts.extend(['exec', dmt.container_id])
9824
+ sh_parts.extend(['exec', '-i', dmt.container_id])
9828
9825
  else:
9829
9826
  raise ValueError(dmt)
9830
9827
 
@@ -10044,7 +10041,7 @@ def bind_deploy(
10044
10041
  inj.bind(DeployGitManager, singleton=True),
10045
10042
 
10046
10043
  inj.bind(DeployTmpManager, singleton=True),
10047
- inj.bind(DeployAtomicPathSwapping, to_key=DeployTmpManager),
10044
+ inj.bind(AtomicPathSwapping, to_key=DeployTmpManager),
10048
10045
 
10049
10046
  inj.bind(DeployVenvManager, singleton=True),
10050
10047
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev160
3
+ Version: 0.0.0.dev161
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.dev160
16
- Requires-Dist: omlish==0.0.0.dev160
15
+ Requires-Dist: omdev==0.0.0.dev161
16
+ Requires-Dist: omlish==0.0.0.dev161
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=T-ad5HtavIsZG3Y1lNimYXvrvklWfm2kZBcV1DLlI-A,3750
52
- ominfra/manage/deploy/inject.py,sha256=JBc96rxOL7Q6P78yZP4WHp08i2AHvV0JHbRpUzbFblw,1444
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=Wg29UMsWL_A8anFsE-XyvkTNsMfH26Nr8BvJxgKNxMo,1248
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=A1nqFo1Zhxg-Sw3Uyxe6hck4ZEh3bBq8GIjnJPvNLd8,2232
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,12 +71,12 @@ 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=j2QrVS-QFOZJ47TqwaMt8MSPg0whokysGePagjJg3Jg,4637
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=mrjtcbAYVv3RkhEV_tcdPra5lZTJG27k0qgAZsye9zk,293936
79
+ ominfra/scripts/manage.py,sha256=MQQGcgbIDwUfD31nDGJD2DhWhlazj8GVwQi7kOzi3gc,293788
81
80
  ominfra/scripts/supervisor.py,sha256=npGYEWSZfY7E24mdkJ3HrL_ax6AcqjHfqh-7nZ_sX0U,273987
82
81
  ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
83
82
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
@@ -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.dev160.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
124
- ominfra-0.0.0.dev160.dist-info/METADATA,sha256=eS2Inhifb3u6Dusi7KHOATGGlcALPwhc363rDTOzVz0,731
125
- ominfra-0.0.0.dev160.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
126
- ominfra-0.0.0.dev160.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
127
- ominfra-0.0.0.dev160.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
128
- ominfra-0.0.0.dev160.dist-info/RECORD,,
122
+ ominfra-0.0.0.dev161.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
123
+ ominfra-0.0.0.dev161.dist-info/METADATA,sha256=9BUyOL7-nhzomsloRZDx7T8VL-T0KbCHxyQ74LxzbFY,731
124
+ ominfra-0.0.0.dev161.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
125
+ ominfra-0.0.0.dev161.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
126
+ ominfra-0.0.0.dev161.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
127
+ ominfra-0.0.0.dev161.dist-info/RECORD,,
@@ -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
- )