ominfra 0.0.0.dev242__py3-none-any.whl → 0.0.0.dev244__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/main.py CHANGED
@@ -11,7 +11,7 @@ import os.path
11
11
  import sys
12
12
  import typing as ta
13
13
 
14
- from omdev.home.paths import get_config_dir
14
+ from omdev.home.paths import get_home_paths
15
15
  from omlish.argparse.cli import ArgparseCli
16
16
  from omlish.argparse.cli import argparse_arg
17
17
  from omlish.argparse.cli import argparse_cmd
@@ -44,7 +44,7 @@ class MainCli(ArgparseCli):
44
44
  @cached_nullary
45
45
  def config(self) -> ManageConfig:
46
46
  if (cf := self.config_file) is None:
47
- cf = os.path.join(get_config_dir(), 'manage', 'manage.yml')
47
+ cf = os.path.join(get_home_paths().config_dir, 'manage', 'manage.yml')
48
48
  if not os.path.isfile(cf):
49
49
  cf = None
50
50
 
@@ -3025,20 +3025,64 @@ class IncrementalWriteBuffer:
3025
3025
 
3026
3026
 
3027
3027
  class ExitStacked:
3028
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
3029
+ super().__init_subclass__(**kwargs)
3030
+
3031
+ for a in ('__enter__', '__exit__'):
3032
+ for b in cls.__bases__:
3033
+ if b is ExitStacked:
3034
+ continue
3035
+ try:
3036
+ fn = getattr(b, a)
3037
+ except AttributeError:
3038
+ pass
3039
+ else:
3040
+ if fn is not getattr(ExitStacked, a):
3041
+ raise TypeError(f'ExitStacked subclass {cls} must not not override {a} via {b}')
3042
+
3028
3043
  _exit_stack: ta.Optional[contextlib.ExitStack] = None
3029
3044
 
3045
+ @contextlib.contextmanager
3046
+ def _exit_stacked_init_wrapper(self) -> ta.Iterator[None]:
3047
+ """
3048
+ Overridable wrapper around __enter__ which deliberately does not have access to an _exit_stack yet. Intended for
3049
+ things like wrapping __enter__ in a lock.
3050
+ """
3051
+
3052
+ yield
3053
+
3054
+ @ta.final
3030
3055
  def __enter__(self: ExitStackedT) -> ExitStackedT:
3031
- check.state(self._exit_stack is None)
3032
- es = self._exit_stack = contextlib.ExitStack()
3033
- es.__enter__()
3034
- return self
3056
+ """
3057
+ Final because any contexts entered during this init must be exited if any exception is thrown, and user
3058
+ overriding would likely interfere with that. Override `_enter_contexts` for such init.
3059
+ """
3060
+
3061
+ with self._exit_stacked_init_wrapper():
3062
+ check.state(self._exit_stack is None)
3063
+ es = self._exit_stack = contextlib.ExitStack()
3064
+ es.__enter__()
3065
+ try:
3066
+ self._enter_contexts()
3067
+ except Exception: # noqa
3068
+ es.__exit__(*sys.exc_info())
3069
+ raise
3070
+ return self
3035
3071
 
3072
+ @ta.final
3036
3073
  def __exit__(self, exc_type, exc_val, exc_tb):
3037
3074
  if (es := self._exit_stack) is None:
3038
3075
  return None
3039
- self._exit_contexts()
3076
+ try:
3077
+ self._exit_contexts()
3078
+ except Exception: # noqa
3079
+ es.__exit__(*sys.exc_info())
3080
+ raise
3040
3081
  return es.__exit__(exc_type, exc_val, exc_tb)
3041
3082
 
3083
+ def _enter_contexts(self) -> None:
3084
+ pass
3085
+
3042
3086
  def _exit_contexts(self) -> None:
3043
3087
  pass
3044
3088
 
@@ -3048,20 +3092,54 @@ class ExitStacked:
3048
3092
 
3049
3093
 
3050
3094
  class AsyncExitStacked:
3095
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
3096
+ super().__init_subclass__(**kwargs)
3097
+
3098
+ for a in ('__aenter__', '__aexit__'):
3099
+ for b in cls.__bases__:
3100
+ if b is AsyncExitStacked:
3101
+ continue
3102
+ try:
3103
+ fn = getattr(b, a)
3104
+ except AttributeError:
3105
+ pass
3106
+ else:
3107
+ if fn is not getattr(AsyncExitStacked, a):
3108
+ raise TypeError(f'AsyncExitStacked subclass {cls} must not not override {a} via {b}')
3109
+
3051
3110
  _exit_stack: ta.Optional[contextlib.AsyncExitStack] = None
3052
3111
 
3112
+ @contextlib.asynccontextmanager
3113
+ async def _async_exit_stacked_init_wrapper(self) -> ta.AsyncGenerator[None, None]:
3114
+ yield
3115
+
3116
+ @ta.final
3053
3117
  async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
3054
- check.state(self._exit_stack is None)
3055
- es = self._exit_stack = contextlib.AsyncExitStack()
3056
- await es.__aenter__()
3057
- return self
3118
+ async with self._async_exit_stacked_init_wrapper():
3119
+ check.state(self._exit_stack is None)
3120
+ es = self._exit_stack = contextlib.AsyncExitStack()
3121
+ await es.__aenter__()
3122
+ try:
3123
+ await self._async_enter_contexts()
3124
+ except Exception: # noqa
3125
+ await es.__aexit__(*sys.exc_info())
3126
+ raise
3127
+ return self
3058
3128
 
3129
+ @ta.final
3059
3130
  async def __aexit__(self, exc_type, exc_val, exc_tb):
3060
3131
  if (es := self._exit_stack) is None:
3061
3132
  return None
3062
- await self._async_exit_contexts()
3133
+ try:
3134
+ await self._async_exit_contexts()
3135
+ except Exception: # noqa
3136
+ await es.__aexit__(*sys.exc_info())
3137
+ raise
3063
3138
  return await es.__aexit__(exc_type, exc_val, exc_tb)
3064
3139
 
3140
+ async def _async_enter_contexts(self) -> None:
3141
+ pass
3142
+
3065
3143
  async def _async_exit_contexts(self) -> None:
3066
3144
  pass
3067
3145
 
@@ -4078,9 +4156,10 @@ class ThreadWorker(ExitStacked, abc.ABC):
4078
4156
 
4079
4157
  #
4080
4158
 
4081
- def __enter__(self: ThreadWorkerT) -> ThreadWorkerT:
4159
+ @contextlib.contextmanager
4160
+ def _exit_stacked_init_wrapper(self) -> ta.Iterator[None]:
4082
4161
  with self._lock:
4083
- return super().__enter__() # noqa
4162
+ yield
4084
4163
 
4085
4164
  #
4086
4165
 
ominfra/scripts/manage.py CHANGED
@@ -173,20 +173,41 @@ def get_home_dir() -> str:
173
173
  #
174
174
 
175
175
 
176
- def get_config_dir() -> str:
177
- return os.path.join(get_home_dir(), 'config')
176
+ class HomePaths:
177
+ def __init__(self, home_dir: ta.Optional[str] = None) -> None:
178
+ super().__init__()
179
+
180
+ if home_dir is None:
181
+ home_dir = get_home_dir()
182
+ self._home_dir = home_dir
183
+
184
+ @property
185
+ def home_dir(self) -> str:
186
+ return self._home_dir
178
187
 
188
+ @property
189
+ def config_dir(self) -> str:
190
+ return os.path.join(self._home_dir, 'config')
191
+
192
+ @property
193
+ def log_dir(self) -> str:
194
+ return os.path.join(self._home_dir, 'log')
179
195
 
180
- def get_run_dir() -> str:
181
- return os.path.join(get_home_dir(), 'run')
196
+ @property
197
+ def run_dir(self) -> str:
198
+ return os.path.join(self._home_dir, 'run')
182
199
 
200
+ @property
201
+ def shadow_dir(self) -> str:
202
+ return os.path.join(self._home_dir, 'shadow')
183
203
 
184
- def get_shadow_dir() -> str:
185
- return os.path.join(get_home_dir(), 'shadow')
204
+ @property
205
+ def state_dir(self) -> str:
206
+ return os.path.join(self._home_dir, 'state')
186
207
 
187
208
 
188
- def get_state_dir() -> str:
189
- return os.path.join(get_home_dir(), 'state')
209
+ def get_home_paths() -> HomePaths:
210
+ return HomePaths()
190
211
 
191
212
 
192
213
  ##
@@ -5511,20 +5532,64 @@ DEFAULT_CONFIG_RENDERER = SwitchedConfigRenderer(DEFAULT_CONFIG_RENDERERS)
5511
5532
 
5512
5533
 
5513
5534
  class ExitStacked:
5535
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
5536
+ super().__init_subclass__(**kwargs)
5537
+
5538
+ for a in ('__enter__', '__exit__'):
5539
+ for b in cls.__bases__:
5540
+ if b is ExitStacked:
5541
+ continue
5542
+ try:
5543
+ fn = getattr(b, a)
5544
+ except AttributeError:
5545
+ pass
5546
+ else:
5547
+ if fn is not getattr(ExitStacked, a):
5548
+ raise TypeError(f'ExitStacked subclass {cls} must not not override {a} via {b}')
5549
+
5514
5550
  _exit_stack: ta.Optional[contextlib.ExitStack] = None
5515
5551
 
5552
+ @contextlib.contextmanager
5553
+ def _exit_stacked_init_wrapper(self) -> ta.Iterator[None]:
5554
+ """
5555
+ Overridable wrapper around __enter__ which deliberately does not have access to an _exit_stack yet. Intended for
5556
+ things like wrapping __enter__ in a lock.
5557
+ """
5558
+
5559
+ yield
5560
+
5561
+ @ta.final
5516
5562
  def __enter__(self: ExitStackedT) -> ExitStackedT:
5517
- check.state(self._exit_stack is None)
5518
- es = self._exit_stack = contextlib.ExitStack()
5519
- es.__enter__()
5520
- return self
5563
+ """
5564
+ Final because any contexts entered during this init must be exited if any exception is thrown, and user
5565
+ overriding would likely interfere with that. Override `_enter_contexts` for such init.
5566
+ """
5567
+
5568
+ with self._exit_stacked_init_wrapper():
5569
+ check.state(self._exit_stack is None)
5570
+ es = self._exit_stack = contextlib.ExitStack()
5571
+ es.__enter__()
5572
+ try:
5573
+ self._enter_contexts()
5574
+ except Exception: # noqa
5575
+ es.__exit__(*sys.exc_info())
5576
+ raise
5577
+ return self
5521
5578
 
5579
+ @ta.final
5522
5580
  def __exit__(self, exc_type, exc_val, exc_tb):
5523
5581
  if (es := self._exit_stack) is None:
5524
5582
  return None
5525
- self._exit_contexts()
5583
+ try:
5584
+ self._exit_contexts()
5585
+ except Exception: # noqa
5586
+ es.__exit__(*sys.exc_info())
5587
+ raise
5526
5588
  return es.__exit__(exc_type, exc_val, exc_tb)
5527
5589
 
5590
+ def _enter_contexts(self) -> None:
5591
+ pass
5592
+
5528
5593
  def _exit_contexts(self) -> None:
5529
5594
  pass
5530
5595
 
@@ -5534,20 +5599,54 @@ class ExitStacked:
5534
5599
 
5535
5600
 
5536
5601
  class AsyncExitStacked:
5602
+ def __init_subclass__(cls, **kwargs: ta.Any) -> None:
5603
+ super().__init_subclass__(**kwargs)
5604
+
5605
+ for a in ('__aenter__', '__aexit__'):
5606
+ for b in cls.__bases__:
5607
+ if b is AsyncExitStacked:
5608
+ continue
5609
+ try:
5610
+ fn = getattr(b, a)
5611
+ except AttributeError:
5612
+ pass
5613
+ else:
5614
+ if fn is not getattr(AsyncExitStacked, a):
5615
+ raise TypeError(f'AsyncExitStacked subclass {cls} must not not override {a} via {b}')
5616
+
5537
5617
  _exit_stack: ta.Optional[contextlib.AsyncExitStack] = None
5538
5618
 
5619
+ @contextlib.asynccontextmanager
5620
+ async def _async_exit_stacked_init_wrapper(self) -> ta.AsyncGenerator[None, None]:
5621
+ yield
5622
+
5623
+ @ta.final
5539
5624
  async def __aenter__(self: AsyncExitStackedT) -> AsyncExitStackedT:
5540
- check.state(self._exit_stack is None)
5541
- es = self._exit_stack = contextlib.AsyncExitStack()
5542
- await es.__aenter__()
5543
- return self
5625
+ async with self._async_exit_stacked_init_wrapper():
5626
+ check.state(self._exit_stack is None)
5627
+ es = self._exit_stack = contextlib.AsyncExitStack()
5628
+ await es.__aenter__()
5629
+ try:
5630
+ await self._async_enter_contexts()
5631
+ except Exception: # noqa
5632
+ await es.__aexit__(*sys.exc_info())
5633
+ raise
5634
+ return self
5544
5635
 
5636
+ @ta.final
5545
5637
  async def __aexit__(self, exc_type, exc_val, exc_tb):
5546
5638
  if (es := self._exit_stack) is None:
5547
5639
  return None
5548
- await self._async_exit_contexts()
5640
+ try:
5641
+ await self._async_exit_contexts()
5642
+ except Exception: # noqa
5643
+ await es.__aexit__(*sys.exc_info())
5644
+ raise
5549
5645
  return await es.__aexit__(exc_type, exc_val, exc_tb)
5550
5646
 
5647
+ async def _async_enter_contexts(self) -> None:
5648
+ pass
5649
+
5551
5650
  async def _async_exit_contexts(self) -> None:
5552
5651
  pass
5553
5652
 
@@ -13448,7 +13547,7 @@ class MainCli(ArgparseCli):
13448
13547
  @cached_nullary
13449
13548
  def config(self) -> ManageConfig:
13450
13549
  if (cf := self.config_file) is None:
13451
- cf = os.path.join(get_config_dir(), 'manage', 'manage.yml')
13550
+ cf = os.path.join(get_home_paths().config_dir, 'manage', 'manage.yml')
13452
13551
  if not os.path.isfile(cf):
13453
13552
  cf = None
13454
13553
 
ominfra/threadworkers.py CHANGED
@@ -10,6 +10,7 @@ TODO:
10
10
  - shared stop_event?
11
11
  """
12
12
  import abc
13
+ import contextlib
13
14
  import dataclasses as dc
14
15
  import threading
15
16
  import time
@@ -48,9 +49,10 @@ class ThreadWorker(ExitStacked, abc.ABC):
48
49
 
49
50
  #
50
51
 
51
- def __enter__(self: ThreadWorkerT) -> ThreadWorkerT:
52
+ @contextlib.contextmanager
53
+ def _exit_stacked_init_wrapper(self) -> ta.Iterator[None]:
52
54
  with self._lock:
53
- return super().__enter__() # noqa
55
+ yield
54
56
 
55
57
  #
56
58
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: ominfra
3
- Version: 0.0.0.dev242
3
+ Version: 0.0.0.dev244
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.dev242
16
- Requires-Dist: omlish==0.0.0.dev242
15
+ Requires-Dist: omdev==0.0.0.dev244
16
+ Requires-Dist: omlish==0.0.0.dev244
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -3,7 +3,7 @@ ominfra/__about__.py,sha256=6i1AoruFYQCd-PyhhbDQDWY2d1tiQu9nkwWr-fXAqfY,705
3
3
  ominfra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  ominfra/pyremote.py,sha256=qjY3Bj0GhuYznQ3bhqXmU9zyIVZkhD9Wv76QUG34ZME,15198
5
5
  ominfra/systemd.py,sha256=d61NVrJoItzSaqhMDgKGrQjbrxEVAujUMDsj8WggXos,1022
6
- ominfra/threadworkers.py,sha256=oX4ubZn7h932saXpRIJu2MNhBExgGGMuGhdXarZxLJw,4948
6
+ ominfra/threadworkers.py,sha256=ADWHAdvjzPxm94yJcEt5_nM7q7aahdQUNP_EGQeOWAw,4974
7
7
  ominfra/clouds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  ominfra/clouds/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  ominfra/clouds/aws/__main__.py,sha256=HXMoxEl9KHhv6zOOPQxiJAftfR2SjBqeVTYw-og9aFw,163
@@ -52,7 +52,7 @@ ominfra/manage/bootstrap.py,sha256=1RIRhVkUZjxZcZerHMg8U6xgWhhemGgPN5cDye8dQ68,4
52
52
  ominfra/manage/bootstrap_.py,sha256=B9UfR9J7mS3J54PFaSe1MQS5lCnKgxt5dDRJ9mnHYwg,656
53
53
  ominfra/manage/config.py,sha256=1y2N_8nXHBZc6YbW6BaRZoDDCTBmiHuWtTOQ7zdr5VE,184
54
54
  ominfra/manage/inject.py,sha256=_FVaMZUBKi-oObv14H77luWYCodxNJJD1t4pNQzckFE,2030
55
- ominfra/manage/main.py,sha256=sA0Kv3g4KAtRN5AKgzEF0r0g0pviKCtlUrr9SJkqmIo,4436
55
+ ominfra/manage/main.py,sha256=jWraEP0l9YwjbLuPpnYUR2PTwIcKEpaHBUk2qYnkKO0,4447
56
56
  ominfra/manage/marshal.py,sha256=WKj7IU9bo4fBMSSzT6ZMm_WFalXIJZ-V7j8oi92fNhk,305
57
57
  ominfra/manage/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  ominfra/manage/commands/base.py,sha256=LtaI0AgnplttQK7gNncNItq8yuTZQimJTaprVpZktI8,3993
@@ -112,8 +112,8 @@ ominfra/manage/targets/connection.py,sha256=rVI1YJxFClcF-sdttqWyIz9_XjPI01GUdwxY
112
112
  ominfra/manage/targets/inject.py,sha256=P4597xWM-V3I_gCt2O71OLhYQkkXtuJvkYRsIbhhMcE,1561
113
113
  ominfra/manage/targets/targets.py,sha256=7GP6UAZyJFEhpkJN6UQdpr_WN3p7C76v-s445y-WB6U,1885
114
114
  ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
- ominfra/scripts/journald2aws.py,sha256=Hub3-WL7ZzxU9-UaIB78eT9grq4XldTyd3EZmcY2ulI,164834
116
- ominfra/scripts/manage.py,sha256=REje_aRYaa1k0gXdLtZfZo6TU2K7hsR0LoCIq0BEZVI,374968
115
+ ominfra/scripts/journald2aws.py,sha256=i1WBsTvVx8XetO_Kl0hGPHGDAFhPybyMBm60bvg_Hi8,167534
116
+ ominfra/scripts/manage.py,sha256=2uU_QU9C6s1DiLz9wV_zLkfWNZZ91MZHiCIjuKLqDJw,378202
117
117
  ominfra/scripts/supervisor.py,sha256=XQGNjIHFvyy7S5uv7bQ4hOne4hqWqny1SLcNlr1vX7w,296335
118
118
  ominfra/supervisor/LICENSE.txt,sha256=ZrHY15PVR98y26Yg6iQfa-SXnUaYTDhrUsPVcEO5OKM,1874
119
119
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
@@ -156,9 +156,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
156
156
  ominfra/tailscale/cli.py,sha256=3FnJbgpLw6gInTfhERd1mDy9ijjMUGxkdYVo43Tnxx4,3555
157
157
  ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
158
158
  ominfra/tools/listresources.py,sha256=auGP1LlbBJSFKUWNvQo_UzA8IsBNZBTMwEkFFRJ4FX4,6185
159
- ominfra-0.0.0.dev242.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
160
- ominfra-0.0.0.dev242.dist-info/METADATA,sha256=LH7niglYt6yUAtKp3nsbr4-xGYyk-3JFjgMm9BNZvl4,731
161
- ominfra-0.0.0.dev242.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
162
- ominfra-0.0.0.dev242.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
163
- ominfra-0.0.0.dev242.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
164
- ominfra-0.0.0.dev242.dist-info/RECORD,,
159
+ ominfra-0.0.0.dev244.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
160
+ ominfra-0.0.0.dev244.dist-info/METADATA,sha256=E34HYzv8JQRFxgXeUiuROpXUGG9EMn6KZfNKbUMGFkY,731
161
+ ominfra-0.0.0.dev244.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
162
+ ominfra-0.0.0.dev244.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
163
+ ominfra-0.0.0.dev244.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
164
+ ominfra-0.0.0.dev244.dist-info/RECORD,,