ominfra 0.0.0.dev176__py3-none-any.whl → 0.0.0.dev178__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 +7 -8
- ominfra/manage/deploy/commands.py +4 -3
- ominfra/manage/deploy/conf.py +0 -12
- ominfra/manage/deploy/config.py +1 -2
- ominfra/manage/deploy/deploy.py +1 -38
- ominfra/manage/deploy/driver.py +71 -0
- ominfra/manage/deploy/git.py +24 -9
- ominfra/manage/deploy/inject.py +36 -8
- ominfra/manage/deploy/paths/manager.py +0 -3
- ominfra/manage/deploy/paths/owners.py +4 -10
- ominfra/manage/deploy/specs.py +5 -0
- ominfra/manage/deploy/tmp.py +9 -28
- ominfra/manage/deploy/venvs.py +2 -10
- ominfra/manage/main.py +1 -7
- ominfra/scripts/manage.py +452 -233
- ominfra/scripts/supervisor.py +205 -11
- {ominfra-0.0.0.dev176.dist-info → ominfra-0.0.0.dev178.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev176.dist-info → ominfra-0.0.0.dev178.dist-info}/RECORD +22 -21
- {ominfra-0.0.0.dev176.dist-info → ominfra-0.0.0.dev178.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev176.dist-info → ominfra-0.0.0.dev178.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev176.dist-info → ominfra-0.0.0.dev178.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev176.dist-info → ominfra-0.0.0.dev178.dist-info}/top_level.txt +0 -0
ominfra/scripts/manage.py
CHANGED
@@ -17,6 +17,7 @@ import base64
|
|
17
17
|
import collections
|
18
18
|
import collections.abc
|
19
19
|
import contextlib
|
20
|
+
import contextvars
|
20
21
|
import ctypes as ct
|
21
22
|
import dataclasses as dc
|
22
23
|
import datetime
|
@@ -1384,7 +1385,7 @@ class MainConfig:
|
|
1384
1385
|
|
1385
1386
|
@dc.dataclass(frozen=True)
|
1386
1387
|
class DeployConfig:
|
1387
|
-
|
1388
|
+
pass
|
1388
1389
|
|
1389
1390
|
|
1390
1391
|
########################################
|
@@ -4905,6 +4906,10 @@ class InjectorBinding:
|
|
4905
4906
|
key: InjectorKey
|
4906
4907
|
provider: InjectorProvider
|
4907
4908
|
|
4909
|
+
def __post_init__(self) -> None:
|
4910
|
+
check.isinstance(self.key, InjectorKey)
|
4911
|
+
check.isinstance(self.provider, InjectorProvider)
|
4912
|
+
|
4908
4913
|
|
4909
4914
|
class InjectorBindings(abc.ABC):
|
4910
4915
|
@abc.abstractmethod
|
@@ -5168,6 +5173,164 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
|
|
5168
5173
|
return pm
|
5169
5174
|
|
5170
5175
|
|
5176
|
+
###
|
5177
|
+
# scopes
|
5178
|
+
|
5179
|
+
|
5180
|
+
class InjectorScope(abc.ABC): # noqa
|
5181
|
+
def __init__(
|
5182
|
+
self,
|
5183
|
+
*,
|
5184
|
+
_i: Injector,
|
5185
|
+
) -> None:
|
5186
|
+
check.not_in(abc.ABC, type(self).__bases__)
|
5187
|
+
|
5188
|
+
super().__init__()
|
5189
|
+
|
5190
|
+
self._i = _i
|
5191
|
+
|
5192
|
+
all_seeds: ta.Iterable[_InjectorScopeSeed] = self._i.provide(InjectorKey(_InjectorScopeSeed, array=True))
|
5193
|
+
self._sks = {s.k for s in all_seeds if s.sc is type(self)}
|
5194
|
+
|
5195
|
+
#
|
5196
|
+
|
5197
|
+
@dc.dataclass(frozen=True)
|
5198
|
+
class State:
|
5199
|
+
seeds: ta.Dict[InjectorKey, ta.Any]
|
5200
|
+
prvs: ta.Dict[InjectorKey, ta.Any] = dc.field(default_factory=dict)
|
5201
|
+
|
5202
|
+
def new_state(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> State:
|
5203
|
+
vs = dict(vs)
|
5204
|
+
check.equal(set(vs.keys()), self._sks)
|
5205
|
+
return InjectorScope.State(vs)
|
5206
|
+
|
5207
|
+
#
|
5208
|
+
|
5209
|
+
@abc.abstractmethod
|
5210
|
+
def state(self) -> State:
|
5211
|
+
raise NotImplementedError
|
5212
|
+
|
5213
|
+
@abc.abstractmethod
|
5214
|
+
def enter(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> ta.ContextManager[None]:
|
5215
|
+
raise NotImplementedError
|
5216
|
+
|
5217
|
+
|
5218
|
+
class ExclusiveInjectorScope(InjectorScope, abc.ABC):
|
5219
|
+
_st: ta.Optional[InjectorScope.State] = None
|
5220
|
+
|
5221
|
+
def state(self) -> InjectorScope.State:
|
5222
|
+
return check.not_none(self._st)
|
5223
|
+
|
5224
|
+
@contextlib.contextmanager
|
5225
|
+
def enter(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> ta.Iterator[None]:
|
5226
|
+
check.none(self._st)
|
5227
|
+
self._st = self.new_state(vs)
|
5228
|
+
try:
|
5229
|
+
yield
|
5230
|
+
finally:
|
5231
|
+
self._st = None
|
5232
|
+
|
5233
|
+
|
5234
|
+
class ContextvarInjectorScope(InjectorScope, abc.ABC):
|
5235
|
+
_cv: contextvars.ContextVar
|
5236
|
+
|
5237
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
5238
|
+
super().__init_subclass__(**kwargs)
|
5239
|
+
check.not_in(abc.ABC, cls.__bases__)
|
5240
|
+
check.state(not hasattr(cls, '_cv'))
|
5241
|
+
cls._cv = contextvars.ContextVar(f'{cls.__name__}_cv')
|
5242
|
+
|
5243
|
+
def state(self) -> InjectorScope.State:
|
5244
|
+
return self._cv.get()
|
5245
|
+
|
5246
|
+
@contextlib.contextmanager
|
5247
|
+
def enter(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> ta.Iterator[None]:
|
5248
|
+
try:
|
5249
|
+
self._cv.get()
|
5250
|
+
except LookupError:
|
5251
|
+
pass
|
5252
|
+
else:
|
5253
|
+
raise RuntimeError(f'Scope already entered: {self}')
|
5254
|
+
st = self.new_state(vs)
|
5255
|
+
tok = self._cv.set(st)
|
5256
|
+
try:
|
5257
|
+
yield
|
5258
|
+
finally:
|
5259
|
+
self._cv.reset(tok)
|
5260
|
+
|
5261
|
+
|
5262
|
+
#
|
5263
|
+
|
5264
|
+
|
5265
|
+
@dc.dataclass(frozen=True)
|
5266
|
+
class ScopedInjectorProvider(InjectorProvider):
|
5267
|
+
p: InjectorProvider
|
5268
|
+
k: InjectorKey
|
5269
|
+
sc: ta.Type[InjectorScope]
|
5270
|
+
|
5271
|
+
def __post_init__(self) -> None:
|
5272
|
+
check.isinstance(self.p, InjectorProvider)
|
5273
|
+
check.isinstance(self.k, InjectorKey)
|
5274
|
+
check.issubclass(self.sc, InjectorScope)
|
5275
|
+
|
5276
|
+
def provider_fn(self) -> InjectorProviderFn:
|
5277
|
+
def pfn(i: Injector) -> ta.Any:
|
5278
|
+
st = i[self.sc].state()
|
5279
|
+
try:
|
5280
|
+
return st.prvs[self.k]
|
5281
|
+
except KeyError:
|
5282
|
+
pass
|
5283
|
+
v = ufn(i)
|
5284
|
+
st.prvs[self.k] = v
|
5285
|
+
return v
|
5286
|
+
|
5287
|
+
ufn = self.p.provider_fn()
|
5288
|
+
return pfn
|
5289
|
+
|
5290
|
+
|
5291
|
+
@dc.dataclass(frozen=True)
|
5292
|
+
class _ScopeSeedInjectorProvider(InjectorProvider):
|
5293
|
+
k: InjectorKey
|
5294
|
+
sc: ta.Type[InjectorScope]
|
5295
|
+
|
5296
|
+
def __post_init__(self) -> None:
|
5297
|
+
check.isinstance(self.k, InjectorKey)
|
5298
|
+
check.issubclass(self.sc, InjectorScope)
|
5299
|
+
|
5300
|
+
def provider_fn(self) -> InjectorProviderFn:
|
5301
|
+
def pfn(i: Injector) -> ta.Any:
|
5302
|
+
st = i[self.sc].state()
|
5303
|
+
return st.seeds[self.k]
|
5304
|
+
return pfn
|
5305
|
+
|
5306
|
+
|
5307
|
+
def bind_injector_scope(sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
5308
|
+
return as_injector_bindings(
|
5309
|
+
InjectorBinder.bind(sc, singleton=True),
|
5310
|
+
)
|
5311
|
+
|
5312
|
+
|
5313
|
+
#
|
5314
|
+
|
5315
|
+
|
5316
|
+
@dc.dataclass(frozen=True)
|
5317
|
+
class _InjectorScopeSeed:
|
5318
|
+
sc: ta.Type['InjectorScope']
|
5319
|
+
k: InjectorKey
|
5320
|
+
|
5321
|
+
def __post_init__(self) -> None:
|
5322
|
+
check.issubclass(self.sc, InjectorScope)
|
5323
|
+
check.isinstance(self.k, InjectorKey)
|
5324
|
+
|
5325
|
+
|
5326
|
+
def bind_injector_scope_seed(k: ta.Any, sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
5327
|
+
kk = as_injector_key(k)
|
5328
|
+
return as_injector_bindings(
|
5329
|
+
InjectorBinding(kk, _ScopeSeedInjectorProvider(kk, sc)),
|
5330
|
+
InjectorBinder.bind(_InjectorScopeSeed(sc, kk), array=True),
|
5331
|
+
)
|
5332
|
+
|
5333
|
+
|
5171
5334
|
###
|
5172
5335
|
# inspection
|
5173
5336
|
|
@@ -5312,13 +5475,21 @@ _INJECTOR_EAGER_ARRAY_KEY: InjectorKey[_InjectorEager] = InjectorKey(_InjectorEa
|
|
5312
5475
|
|
5313
5476
|
|
5314
5477
|
class _Injector(Injector):
|
5478
|
+
_DEFAULT_BINDINGS: ta.ClassVar[ta.List[InjectorBinding]] = []
|
5479
|
+
|
5315
5480
|
def __init__(self, bs: InjectorBindings, p: ta.Optional[Injector] = None) -> None:
|
5316
5481
|
super().__init__()
|
5317
5482
|
|
5318
5483
|
self._bs = check.isinstance(bs, InjectorBindings)
|
5319
5484
|
self._p: ta.Optional[Injector] = check.isinstance(p, (Injector, type(None)))
|
5320
5485
|
|
5321
|
-
self._pfm = {
|
5486
|
+
self._pfm = {
|
5487
|
+
k: v.provider_fn()
|
5488
|
+
for k, v in build_injector_provider_map(as_injector_bindings(
|
5489
|
+
*self._DEFAULT_BINDINGS,
|
5490
|
+
bs,
|
5491
|
+
)).items()
|
5492
|
+
}
|
5322
5493
|
|
5323
5494
|
if _INJECTOR_INJECTOR_KEY in self._pfm:
|
5324
5495
|
raise DuplicateInjectorKeyError(_INJECTOR_INJECTOR_KEY)
|
@@ -5485,6 +5656,7 @@ class InjectorBinder:
|
|
5485
5656
|
to_const: ta.Any = None,
|
5486
5657
|
to_key: ta.Any = None,
|
5487
5658
|
|
5659
|
+
in_: ta.Optional[ta.Type[InjectorScope]] = None,
|
5488
5660
|
singleton: bool = False,
|
5489
5661
|
|
5490
5662
|
eager: bool = False,
|
@@ -5494,12 +5666,12 @@ class InjectorBinder:
|
|
5494
5666
|
if isinstance(obj, cls._BANNED_BIND_TYPES):
|
5495
5667
|
raise TypeError(obj)
|
5496
5668
|
|
5497
|
-
|
5669
|
+
#
|
5498
5670
|
|
5499
5671
|
if key is not None:
|
5500
5672
|
key = as_injector_key(key)
|
5501
5673
|
|
5502
|
-
|
5674
|
+
#
|
5503
5675
|
|
5504
5676
|
has_to = (
|
5505
5677
|
to_fn is not None or
|
@@ -5529,7 +5701,7 @@ class InjectorBinder:
|
|
5529
5701
|
key = InjectorKey(type(obj))
|
5530
5702
|
del has_to
|
5531
5703
|
|
5532
|
-
|
5704
|
+
#
|
5533
5705
|
|
5534
5706
|
if tag is not None:
|
5535
5707
|
if key.tag is not None:
|
@@ -5539,7 +5711,7 @@ class InjectorBinder:
|
|
5539
5711
|
if array is not None:
|
5540
5712
|
key = dc.replace(key, array=array)
|
5541
5713
|
|
5542
|
-
|
5714
|
+
#
|
5543
5715
|
|
5544
5716
|
providers: ta.List[InjectorProvider] = []
|
5545
5717
|
if to_fn is not None:
|
@@ -5554,23 +5726,34 @@ class InjectorBinder:
|
|
5554
5726
|
raise TypeError('Must specify provider')
|
5555
5727
|
if len(providers) > 1:
|
5556
5728
|
raise TypeError('May not specify multiple providers')
|
5557
|
-
provider
|
5729
|
+
provider = check.single(providers)
|
5558
5730
|
|
5559
|
-
|
5731
|
+
#
|
5560
5732
|
|
5733
|
+
pws: ta.List[ta.Any] = []
|
5734
|
+
if in_ is not None:
|
5735
|
+
check.issubclass(in_, InjectorScope)
|
5736
|
+
check.not_in(abc.ABC, in_.__bases__)
|
5737
|
+
pws.append(functools.partial(ScopedInjectorProvider, k=key, sc=in_))
|
5561
5738
|
if singleton:
|
5562
|
-
|
5739
|
+
pws.append(SingletonInjectorProvider)
|
5740
|
+
if len(pws) > 1:
|
5741
|
+
raise TypeError('May not specify multiple provider wrappers')
|
5742
|
+
elif pws:
|
5743
|
+
provider = check.single(pws)(provider)
|
5744
|
+
|
5745
|
+
#
|
5563
5746
|
|
5564
5747
|
binding = InjectorBinding(key, provider)
|
5565
5748
|
|
5566
|
-
|
5749
|
+
#
|
5567
5750
|
|
5568
5751
|
extras: ta.List[InjectorBinding] = []
|
5569
5752
|
|
5570
5753
|
if eager:
|
5571
5754
|
extras.append(bind_injector_eager_key(key))
|
5572
5755
|
|
5573
|
-
|
5756
|
+
#
|
5574
5757
|
|
5575
5758
|
if extras:
|
5576
5759
|
return as_injector_bindings(binding, *extras)
|
@@ -5643,7 +5826,8 @@ def bind_injector_eager_key(key: ta.Any) -> InjectorBinding:
|
|
5643
5826
|
return InjectorBinding(_INJECTOR_EAGER_ARRAY_KEY, ConstInjectorProvider(_InjectorEager(as_injector_key(key))))
|
5644
5827
|
|
5645
5828
|
|
5646
|
-
|
5829
|
+
###
|
5830
|
+
# api
|
5647
5831
|
|
5648
5832
|
|
5649
5833
|
class InjectionApi:
|
@@ -5666,6 +5850,14 @@ class InjectionApi:
|
|
5666
5850
|
def override(self, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5667
5851
|
return injector_override(p, *args)
|
5668
5852
|
|
5853
|
+
# scopes
|
5854
|
+
|
5855
|
+
def bind_scope(self, sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
5856
|
+
return bind_injector_scope(sc)
|
5857
|
+
|
5858
|
+
def bind_scope_seed(self, k: ta.Any, sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
5859
|
+
return bind_injector_scope_seed(k, sc)
|
5860
|
+
|
5669
5861
|
# injector
|
5670
5862
|
|
5671
5863
|
def create_injector(self, *args: InjectorBindingOrBindings, parent: ta.Optional[Injector] = None) -> Injector:
|
@@ -5686,6 +5878,7 @@ class InjectionApi:
|
|
5686
5878
|
to_const: ta.Any = None,
|
5687
5879
|
to_key: ta.Any = None,
|
5688
5880
|
|
5881
|
+
in_: ta.Optional[ta.Type[InjectorScope]] = None,
|
5689
5882
|
singleton: bool = False,
|
5690
5883
|
|
5691
5884
|
eager: bool = False,
|
@@ -5702,6 +5895,7 @@ class InjectionApi:
|
|
5702
5895
|
to_const=to_const,
|
5703
5896
|
to_key=to_key,
|
5704
5897
|
|
5898
|
+
in_=in_,
|
5705
5899
|
singleton=singleton,
|
5706
5900
|
|
5707
5901
|
eager=eager,
|
@@ -7547,6 +7741,37 @@ class LocalCommandExecutor(CommandExecutor):
|
|
7547
7741
|
return await ce.execute(cmd)
|
7548
7742
|
|
7549
7743
|
|
7744
|
+
########################################
|
7745
|
+
# ../deploy/deploy.py
|
7746
|
+
|
7747
|
+
|
7748
|
+
DEPLOY_TAG_DATETIME_FMT = '%Y%m%dT%H%M%SZ'
|
7749
|
+
|
7750
|
+
|
7751
|
+
DeployManagerUtcClock = ta.NewType('DeployManagerUtcClock', Func0[datetime.datetime])
|
7752
|
+
|
7753
|
+
|
7754
|
+
class DeployManager:
|
7755
|
+
def __init__(
|
7756
|
+
self,
|
7757
|
+
*,
|
7758
|
+
|
7759
|
+
utc_clock: ta.Optional[DeployManagerUtcClock] = None,
|
7760
|
+
):
|
7761
|
+
super().__init__()
|
7762
|
+
|
7763
|
+
self._utc_clock = utc_clock
|
7764
|
+
|
7765
|
+
def _utc_now(self) -> datetime.datetime:
|
7766
|
+
if self._utc_clock is not None:
|
7767
|
+
return self._utc_clock() # noqa
|
7768
|
+
else:
|
7769
|
+
return datetime.datetime.now(tz=datetime.timezone.utc) # noqa
|
7770
|
+
|
7771
|
+
def make_deploy_time(self) -> DeployTime:
|
7772
|
+
return DeployTime(self._utc_now().strftime(DEPLOY_TAG_DATETIME_FMT))
|
7773
|
+
|
7774
|
+
|
7550
7775
|
########################################
|
7551
7776
|
# ../deploy/paths/paths.py
|
7552
7777
|
"""
|
@@ -7885,9 +8110,13 @@ class DeployAppSpec(DeploySpecKeyed[DeployAppKey]):
|
|
7885
8110
|
|
7886
8111
|
@dc.dataclass(frozen=True)
|
7887
8112
|
class DeploySpec(DeploySpecKeyed[DeployKey]):
|
8113
|
+
home: DeployHome
|
8114
|
+
|
7888
8115
|
apps: ta.Sequence[DeployAppSpec]
|
7889
8116
|
|
7890
8117
|
def __post_init__(self) -> None:
|
8118
|
+
check.non_empty_str(self.home)
|
8119
|
+
|
7891
8120
|
seen: ta.Set[DeployApp] = set()
|
7892
8121
|
for a in self.apps:
|
7893
8122
|
if a.app in seen:
|
@@ -8707,17 +8936,6 @@ TODO:
|
|
8707
8936
|
|
8708
8937
|
|
8709
8938
|
class DeployConfManager:
|
8710
|
-
def __init__(
|
8711
|
-
self,
|
8712
|
-
*,
|
8713
|
-
deploy_home: ta.Optional[DeployHome] = None,
|
8714
|
-
) -> None:
|
8715
|
-
super().__init__()
|
8716
|
-
|
8717
|
-
self._deploy_home = deploy_home
|
8718
|
-
|
8719
|
-
#
|
8720
|
-
|
8721
8939
|
async def _write_app_conf_file(
|
8722
8940
|
self,
|
8723
8941
|
acf: DeployAppConfFile,
|
@@ -8884,7 +9102,6 @@ class SingleDirDeployPathOwner(DeployPathOwner, abc.ABC):
|
|
8884
9102
|
self,
|
8885
9103
|
*args: ta.Any,
|
8886
9104
|
owned_dir: str,
|
8887
|
-
deploy_home: ta.Optional[DeployHome],
|
8888
9105
|
**kwargs: ta.Any,
|
8889
9106
|
) -> None:
|
8890
9107
|
super().__init__(*args, **kwargs)
|
@@ -8892,17 +9109,13 @@ class SingleDirDeployPathOwner(DeployPathOwner, abc.ABC):
|
|
8892
9109
|
check.not_in('/', owned_dir)
|
8893
9110
|
self._owned_dir: str = check.non_empty_str(owned_dir)
|
8894
9111
|
|
8895
|
-
self._deploy_home = deploy_home
|
8896
|
-
|
8897
9112
|
self._owned_deploy_paths = frozenset([DeployPath.parse(self._owned_dir + '/')])
|
8898
9113
|
|
8899
|
-
|
8900
|
-
|
8901
|
-
return os.path.join(check.non_empty_str(self._deploy_home), self._owned_dir)
|
9114
|
+
def _dir(self, home: DeployHome) -> str:
|
9115
|
+
return os.path.join(check.non_empty_str(home), self._owned_dir)
|
8902
9116
|
|
8903
|
-
|
8904
|
-
|
8905
|
-
if not os.path.isdir(d := self._dir()):
|
9117
|
+
def _make_dir(self, home: DeployHome) -> str:
|
9118
|
+
if not os.path.isdir(d := self._dir(home)):
|
8906
9119
|
os.makedirs(d, exist_ok=True)
|
8907
9120
|
return d
|
8908
9121
|
|
@@ -9442,122 +9655,6 @@ def bind_commands(
|
|
9442
9655
|
return inj.as_bindings(*lst)
|
9443
9656
|
|
9444
9657
|
|
9445
|
-
########################################
|
9446
|
-
# ../deploy/git.py
|
9447
|
-
"""
|
9448
|
-
TODO:
|
9449
|
-
- 'repos'?
|
9450
|
-
|
9451
|
-
git/github.com/wrmsr/omlish <- bootstrap repo
|
9452
|
-
- shallow clone off bootstrap into /apps
|
9453
|
-
|
9454
|
-
github.com/wrmsr/omlish@rev
|
9455
|
-
"""
|
9456
|
-
|
9457
|
-
|
9458
|
-
##
|
9459
|
-
|
9460
|
-
|
9461
|
-
class DeployGitManager(SingleDirDeployPathOwner):
|
9462
|
-
def __init__(
|
9463
|
-
self,
|
9464
|
-
*,
|
9465
|
-
deploy_home: ta.Optional[DeployHome] = None,
|
9466
|
-
atomics: AtomicPathSwapping,
|
9467
|
-
) -> None:
|
9468
|
-
super().__init__(
|
9469
|
-
owned_dir='git',
|
9470
|
-
deploy_home=deploy_home,
|
9471
|
-
)
|
9472
|
-
|
9473
|
-
self._atomics = atomics
|
9474
|
-
|
9475
|
-
self._repo_dirs: ta.Dict[DeployGitRepo, DeployGitManager.RepoDir] = {}
|
9476
|
-
|
9477
|
-
class RepoDir:
|
9478
|
-
def __init__(
|
9479
|
-
self,
|
9480
|
-
git: 'DeployGitManager',
|
9481
|
-
repo: DeployGitRepo,
|
9482
|
-
) -> None:
|
9483
|
-
super().__init__()
|
9484
|
-
|
9485
|
-
self._git = git
|
9486
|
-
self._repo = repo
|
9487
|
-
self._dir = os.path.join(
|
9488
|
-
self._git._make_dir(), # noqa
|
9489
|
-
check.non_empty_str(repo.host),
|
9490
|
-
check.non_empty_str(repo.path),
|
9491
|
-
)
|
9492
|
-
|
9493
|
-
@property
|
9494
|
-
def repo(self) -> DeployGitRepo:
|
9495
|
-
return self._repo
|
9496
|
-
|
9497
|
-
@property
|
9498
|
-
def url(self) -> str:
|
9499
|
-
if self._repo.username is not None:
|
9500
|
-
return f'{self._repo.username}@{self._repo.host}:{self._repo.path}'
|
9501
|
-
else:
|
9502
|
-
return f'https://{self._repo.host}/{self._repo.path}'
|
9503
|
-
|
9504
|
-
#
|
9505
|
-
|
9506
|
-
async def _call(self, *cmd: str) -> None:
|
9507
|
-
await asyncio_subprocesses.check_call(
|
9508
|
-
*cmd,
|
9509
|
-
cwd=self._dir,
|
9510
|
-
)
|
9511
|
-
|
9512
|
-
#
|
9513
|
-
|
9514
|
-
@async_cached_nullary
|
9515
|
-
async def init(self) -> None:
|
9516
|
-
os.makedirs(self._dir, exist_ok=True)
|
9517
|
-
if os.path.exists(os.path.join(self._dir, '.git')):
|
9518
|
-
return
|
9519
|
-
|
9520
|
-
await self._call('git', 'init')
|
9521
|
-
await self._call('git', 'remote', 'add', 'origin', self.url)
|
9522
|
-
|
9523
|
-
async def fetch(self, rev: DeployRev) -> None:
|
9524
|
-
await self.init()
|
9525
|
-
await self._call('git', 'fetch', '--depth=1', 'origin', rev)
|
9526
|
-
|
9527
|
-
#
|
9528
|
-
|
9529
|
-
async def checkout(self, spec: DeployGitSpec, dst_dir: str) -> None:
|
9530
|
-
check.state(not os.path.exists(dst_dir))
|
9531
|
-
with self._git._atomics.begin_atomic_path_swap( # noqa
|
9532
|
-
'dir',
|
9533
|
-
dst_dir,
|
9534
|
-
auto_commit=True,
|
9535
|
-
make_dirs=True,
|
9536
|
-
) as dst_swap:
|
9537
|
-
await self.fetch(spec.rev)
|
9538
|
-
|
9539
|
-
dst_call = functools.partial(asyncio_subprocesses.check_call, cwd=dst_swap.tmp_path)
|
9540
|
-
await dst_call('git', 'init')
|
9541
|
-
|
9542
|
-
await dst_call('git', 'remote', 'add', 'local', self._dir)
|
9543
|
-
await dst_call('git', 'fetch', '--depth=1', 'local', spec.rev)
|
9544
|
-
await dst_call('git', 'checkout', spec.rev, *(spec.subtrees or []))
|
9545
|
-
|
9546
|
-
def get_repo_dir(self, repo: DeployGitRepo) -> RepoDir:
|
9547
|
-
try:
|
9548
|
-
return self._repo_dirs[repo]
|
9549
|
-
except KeyError:
|
9550
|
-
repo_dir = self._repo_dirs[repo] = DeployGitManager.RepoDir(self, repo)
|
9551
|
-
return repo_dir
|
9552
|
-
|
9553
|
-
async def checkout(
|
9554
|
-
self,
|
9555
|
-
spec: DeployGitSpec,
|
9556
|
-
dst_dir: str,
|
9557
|
-
) -> None:
|
9558
|
-
await self.get_repo_dir(spec.repo).checkout(spec, dst_dir)
|
9559
|
-
|
9560
|
-
|
9561
9658
|
########################################
|
9562
9659
|
# ../deploy/paths/manager.py
|
9563
9660
|
|
@@ -9566,12 +9663,10 @@ class DeployPathsManager:
|
|
9566
9663
|
def __init__(
|
9567
9664
|
self,
|
9568
9665
|
*,
|
9569
|
-
deploy_home: ta.Optional[DeployHome],
|
9570
9666
|
deploy_path_owners: DeployPathOwners,
|
9571
9667
|
) -> None:
|
9572
9668
|
super().__init__()
|
9573
9669
|
|
9574
|
-
self._deploy_home = deploy_home
|
9575
9670
|
self._deploy_path_owners = deploy_path_owners
|
9576
9671
|
|
9577
9672
|
@cached_nullary
|
@@ -9592,37 +9687,22 @@ class DeployPathsManager:
|
|
9592
9687
|
# ../deploy/tmp.py
|
9593
9688
|
|
9594
9689
|
|
9690
|
+
class DeployHomeAtomics(Func1[DeployHome, AtomicPathSwapping]):
|
9691
|
+
pass
|
9692
|
+
|
9693
|
+
|
9595
9694
|
class DeployTmpManager(
|
9596
9695
|
SingleDirDeployPathOwner,
|
9597
|
-
AtomicPathSwapping,
|
9598
9696
|
):
|
9599
|
-
def __init__(
|
9600
|
-
self,
|
9601
|
-
*,
|
9602
|
-
deploy_home: ta.Optional[DeployHome] = None,
|
9603
|
-
) -> None:
|
9697
|
+
def __init__(self) -> None:
|
9604
9698
|
super().__init__(
|
9605
9699
|
owned_dir='tmp',
|
9606
|
-
deploy_home=deploy_home,
|
9607
9700
|
)
|
9608
9701
|
|
9609
|
-
|
9610
|
-
def _swapping(self) -> AtomicPathSwapping:
|
9702
|
+
def get_swapping(self, home: DeployHome) -> AtomicPathSwapping:
|
9611
9703
|
return TempDirAtomicPathSwapping(
|
9612
|
-
temp_dir=self._make_dir(),
|
9613
|
-
root_dir=check.non_empty_str(
|
9614
|
-
)
|
9615
|
-
|
9616
|
-
def begin_atomic_path_swap(
|
9617
|
-
self,
|
9618
|
-
kind: AtomicPathSwapKind,
|
9619
|
-
dst_path: str,
|
9620
|
-
**kwargs: ta.Any,
|
9621
|
-
) -> AtomicPathSwap:
|
9622
|
-
return self._swapping().begin_atomic_path_swap(
|
9623
|
-
kind,
|
9624
|
-
dst_path,
|
9625
|
-
**kwargs,
|
9704
|
+
temp_dir=self._make_dir(home),
|
9705
|
+
root_dir=check.non_empty_str(home),
|
9626
9706
|
)
|
9627
9707
|
|
9628
9708
|
|
@@ -10081,11 +10161,11 @@ class PyenvVersionInstaller:
|
|
10081
10161
|
full_args = [
|
10082
10162
|
os.path.join(check.not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
10083
10163
|
*conf_args,
|
10084
|
-
self.install_dir(),
|
10164
|
+
await self.install_dir(),
|
10085
10165
|
]
|
10086
10166
|
else:
|
10087
10167
|
full_args = [
|
10088
|
-
self._pyenv.exe(),
|
10168
|
+
await self._pyenv.exe(),
|
10089
10169
|
'install',
|
10090
10170
|
*conf_args,
|
10091
10171
|
]
|
@@ -10340,6 +10420,137 @@ class SystemInterpProvider(InterpProvider):
|
|
10340
10420
|
raise KeyError(version)
|
10341
10421
|
|
10342
10422
|
|
10423
|
+
########################################
|
10424
|
+
# ../deploy/git.py
|
10425
|
+
"""
|
10426
|
+
TODO:
|
10427
|
+
- 'repos'?
|
10428
|
+
|
10429
|
+
git/github.com/wrmsr/omlish <- bootstrap repo
|
10430
|
+
- shallow clone off bootstrap into /apps
|
10431
|
+
|
10432
|
+
github.com/wrmsr/omlish@rev
|
10433
|
+
"""
|
10434
|
+
|
10435
|
+
|
10436
|
+
##
|
10437
|
+
|
10438
|
+
|
10439
|
+
class DeployGitManager(SingleDirDeployPathOwner):
|
10440
|
+
def __init__(
|
10441
|
+
self,
|
10442
|
+
*,
|
10443
|
+
atomics: DeployHomeAtomics,
|
10444
|
+
) -> None:
|
10445
|
+
super().__init__(
|
10446
|
+
owned_dir='git',
|
10447
|
+
)
|
10448
|
+
|
10449
|
+
self._atomics = atomics
|
10450
|
+
|
10451
|
+
self._repo_dirs: ta.Dict[DeployGitRepo, DeployGitManager.RepoDir] = {}
|
10452
|
+
|
10453
|
+
class RepoDir:
|
10454
|
+
def __init__(
|
10455
|
+
self,
|
10456
|
+
git: 'DeployGitManager',
|
10457
|
+
repo: DeployGitRepo,
|
10458
|
+
home: DeployHome,
|
10459
|
+
) -> None:
|
10460
|
+
super().__init__()
|
10461
|
+
|
10462
|
+
self._git = git
|
10463
|
+
self._repo = repo
|
10464
|
+
self._home = home
|
10465
|
+
self._dir = os.path.join(
|
10466
|
+
self._git._make_dir(home), # noqa
|
10467
|
+
check.non_empty_str(repo.host),
|
10468
|
+
check.non_empty_str(repo.path),
|
10469
|
+
)
|
10470
|
+
|
10471
|
+
@property
|
10472
|
+
def repo(self) -> DeployGitRepo:
|
10473
|
+
return self._repo
|
10474
|
+
|
10475
|
+
@property
|
10476
|
+
def url(self) -> str:
|
10477
|
+
if self._repo.username is not None:
|
10478
|
+
return f'{self._repo.username}@{self._repo.host}:{self._repo.path}'
|
10479
|
+
else:
|
10480
|
+
return f'https://{self._repo.host}/{self._repo.path}'
|
10481
|
+
|
10482
|
+
#
|
10483
|
+
|
10484
|
+
async def _call(self, *cmd: str) -> None:
|
10485
|
+
await asyncio_subprocesses.check_call(
|
10486
|
+
*cmd,
|
10487
|
+
cwd=self._dir,
|
10488
|
+
)
|
10489
|
+
|
10490
|
+
#
|
10491
|
+
|
10492
|
+
@async_cached_nullary
|
10493
|
+
async def init(self) -> None:
|
10494
|
+
os.makedirs(self._dir, exist_ok=True)
|
10495
|
+
if os.path.exists(os.path.join(self._dir, '.git')):
|
10496
|
+
return
|
10497
|
+
|
10498
|
+
await self._call('git', 'init')
|
10499
|
+
await self._call('git', 'remote', 'add', 'origin', self.url)
|
10500
|
+
|
10501
|
+
async def fetch(self, rev: DeployRev) -> None:
|
10502
|
+
await self.init()
|
10503
|
+
await self._call('git', 'fetch', '--depth=1', 'origin', rev)
|
10504
|
+
|
10505
|
+
#
|
10506
|
+
|
10507
|
+
async def checkout(self, spec: DeployGitSpec, dst_dir: str) -> None:
|
10508
|
+
check.state(not os.path.exists(dst_dir))
|
10509
|
+
with self._git._atomics(self._home).begin_atomic_path_swap( # noqa
|
10510
|
+
'dir',
|
10511
|
+
dst_dir,
|
10512
|
+
auto_commit=True,
|
10513
|
+
make_dirs=True,
|
10514
|
+
) as dst_swap:
|
10515
|
+
await self.fetch(spec.rev)
|
10516
|
+
|
10517
|
+
dst_call = functools.partial(asyncio_subprocesses.check_call, cwd=dst_swap.tmp_path)
|
10518
|
+
await dst_call('git', 'init')
|
10519
|
+
|
10520
|
+
await dst_call('git', 'remote', 'add', 'local', self._dir)
|
10521
|
+
await dst_call('git', 'fetch', '--depth=1', 'local', spec.rev)
|
10522
|
+
await dst_call('git', 'checkout', spec.rev, *(spec.subtrees or []))
|
10523
|
+
|
10524
|
+
def get_repo_dir(
|
10525
|
+
self,
|
10526
|
+
repo: DeployGitRepo,
|
10527
|
+
home: DeployHome,
|
10528
|
+
) -> RepoDir:
|
10529
|
+
try:
|
10530
|
+
return self._repo_dirs[repo]
|
10531
|
+
except KeyError:
|
10532
|
+
repo_dir = self._repo_dirs[repo] = DeployGitManager.RepoDir(
|
10533
|
+
self,
|
10534
|
+
repo,
|
10535
|
+
home,
|
10536
|
+
)
|
10537
|
+
return repo_dir
|
10538
|
+
|
10539
|
+
async def checkout(
|
10540
|
+
self,
|
10541
|
+
spec: DeployGitSpec,
|
10542
|
+
home: DeployHome,
|
10543
|
+
dst_dir: str,
|
10544
|
+
) -> None:
|
10545
|
+
await self.get_repo_dir(
|
10546
|
+
spec.repo,
|
10547
|
+
home,
|
10548
|
+
).checkout(
|
10549
|
+
spec,
|
10550
|
+
dst_dir,
|
10551
|
+
)
|
10552
|
+
|
10553
|
+
|
10343
10554
|
########################################
|
10344
10555
|
# ../deploy/paths/inject.py
|
10345
10556
|
|
@@ -10739,18 +10950,10 @@ TODO:
|
|
10739
10950
|
|
10740
10951
|
|
10741
10952
|
class DeployVenvManager:
|
10742
|
-
def __init__(
|
10743
|
-
self,
|
10744
|
-
*,
|
10745
|
-
atomics: AtomicPathSwapping,
|
10746
|
-
) -> None:
|
10747
|
-
super().__init__()
|
10748
|
-
|
10749
|
-
self._atomics = atomics
|
10750
|
-
|
10751
10953
|
async def setup_venv(
|
10752
10954
|
self,
|
10753
10955
|
spec: DeployVenvSpec,
|
10956
|
+
home: DeployHome,
|
10754
10957
|
git_dir: str,
|
10755
10958
|
venv_dir: str,
|
10756
10959
|
) -> None:
|
@@ -10793,16 +10996,12 @@ class DeployAppManager(DeployPathOwner):
|
|
10793
10996
|
def __init__(
|
10794
10997
|
self,
|
10795
10998
|
*,
|
10796
|
-
deploy_home: ta.Optional[DeployHome] = None,
|
10797
|
-
|
10798
10999
|
conf: DeployConfManager,
|
10799
11000
|
git: DeployGitManager,
|
10800
11001
|
venvs: DeployVenvManager,
|
10801
11002
|
) -> None:
|
10802
11003
|
super().__init__()
|
10803
11004
|
|
10804
|
-
self._deploy_home = deploy_home
|
10805
|
-
|
10806
11005
|
self._conf = conf
|
10807
11006
|
self._git = git
|
10808
11007
|
self._venvs = venvs
|
@@ -10843,12 +11042,13 @@ class DeployAppManager(DeployPathOwner):
|
|
10843
11042
|
async def prepare_app(
|
10844
11043
|
self,
|
10845
11044
|
spec: DeployAppSpec,
|
11045
|
+
home: DeployHome,
|
10846
11046
|
tags: DeployTagMap,
|
10847
11047
|
) -> None:
|
10848
|
-
|
11048
|
+
check.non_empty_str(home)
|
10849
11049
|
|
10850
11050
|
def build_path(pth: DeployPath) -> str:
|
10851
|
-
return os.path.join(
|
11051
|
+
return os.path.join(home, pth.render(tags))
|
10852
11052
|
|
10853
11053
|
app_dir = build_path(self._APP_DIR)
|
10854
11054
|
deploy_dir = build_path(self._DEPLOY_DIR)
|
@@ -10858,7 +11058,7 @@ class DeployAppManager(DeployPathOwner):
|
|
10858
11058
|
|
10859
11059
|
os.makedirs(deploy_dir, exist_ok=True)
|
10860
11060
|
|
10861
|
-
deploying_link = os.path.join(
|
11061
|
+
deploying_link = os.path.join(home, 'deploys/deploying')
|
10862
11062
|
if os.path.exists(deploying_link):
|
10863
11063
|
os.unlink(deploying_link)
|
10864
11064
|
relative_symlink(
|
@@ -10905,7 +11105,7 @@ class DeployAppManager(DeployPathOwner):
|
|
10905
11105
|
# else:
|
10906
11106
|
# os.makedirs(os.path.join(dst, os.path.relpath(dp2, src)))
|
10907
11107
|
|
10908
|
-
current_link = os.path.join(
|
11108
|
+
current_link = os.path.join(home, 'deploys/current')
|
10909
11109
|
|
10910
11110
|
# if os.path.exists(current_link):
|
10911
11111
|
# mirror_symlinks(
|
@@ -10922,6 +11122,7 @@ class DeployAppManager(DeployPathOwner):
|
|
10922
11122
|
app_git_dir = os.path.join(app_dir, 'git')
|
10923
11123
|
await self._git.checkout(
|
10924
11124
|
spec.git,
|
11125
|
+
home,
|
10925
11126
|
app_git_dir,
|
10926
11127
|
)
|
10927
11128
|
|
@@ -10931,6 +11132,7 @@ class DeployAppManager(DeployPathOwner):
|
|
10931
11132
|
app_venv_dir = os.path.join(app_dir, 'venv')
|
10932
11133
|
await self._venvs.setup_venv(
|
10933
11134
|
spec.venv,
|
11135
|
+
home,
|
10934
11136
|
app_git_dir,
|
10935
11137
|
app_venv_dir,
|
10936
11138
|
)
|
@@ -10952,56 +11154,53 @@ class DeployAppManager(DeployPathOwner):
|
|
10952
11154
|
|
10953
11155
|
|
10954
11156
|
########################################
|
10955
|
-
# ../deploy/
|
11157
|
+
# ../deploy/driver.py
|
10956
11158
|
|
10957
11159
|
|
10958
|
-
|
10959
|
-
|
10960
|
-
|
10961
|
-
DeployManagerUtcClock = ta.NewType('DeployManagerUtcClock', Func0[datetime.datetime])
|
11160
|
+
class DeployDriverFactory(Func1[DeploySpec, ta.ContextManager['DeployDriver']]):
|
11161
|
+
pass
|
10962
11162
|
|
10963
11163
|
|
10964
|
-
class
|
11164
|
+
class DeployDriver:
|
10965
11165
|
def __init__(
|
10966
11166
|
self,
|
10967
11167
|
*,
|
10968
|
-
|
10969
|
-
paths: DeployPathsManager,
|
11168
|
+
spec: DeploySpec,
|
10970
11169
|
|
10971
|
-
|
10972
|
-
|
11170
|
+
deploys: DeployManager,
|
11171
|
+
paths: DeployPathsManager,
|
11172
|
+
apps: DeployAppManager,
|
11173
|
+
) -> None:
|
10973
11174
|
super().__init__()
|
10974
11175
|
|
10975
|
-
self.
|
11176
|
+
self._spec = spec
|
11177
|
+
|
11178
|
+
self._deploys = deploys
|
10976
11179
|
self._paths = paths
|
11180
|
+
self._apps = apps
|
10977
11181
|
|
10978
|
-
|
11182
|
+
async def drive_deploy(self) -> None:
|
11183
|
+
self._paths.validate_deploy_paths()
|
10979
11184
|
|
10980
|
-
|
10981
|
-
if self._utc_clock is not None:
|
10982
|
-
return self._utc_clock() # noqa
|
10983
|
-
else:
|
10984
|
-
return datetime.datetime.now(tz=datetime.timezone.utc) # noqa
|
11185
|
+
#
|
10985
11186
|
|
10986
|
-
|
10987
|
-
|
11187
|
+
hs = check.non_empty_str(self._spec.home)
|
11188
|
+
hs = os.path.expanduser(hs)
|
11189
|
+
hs = os.path.realpath(hs)
|
11190
|
+
hs = os.path.abspath(hs)
|
10988
11191
|
|
10989
|
-
|
10990
|
-
self,
|
10991
|
-
spec: DeploySpec,
|
10992
|
-
) -> None:
|
10993
|
-
self._paths.validate_deploy_paths()
|
11192
|
+
home = DeployHome(hs)
|
10994
11193
|
|
10995
11194
|
#
|
10996
11195
|
|
10997
11196
|
deploy_tags = DeployTagMap(
|
10998
|
-
self.
|
10999
|
-
|
11197
|
+
self._deploys.make_deploy_time(),
|
11198
|
+
self._spec.key(),
|
11000
11199
|
)
|
11001
11200
|
|
11002
11201
|
#
|
11003
11202
|
|
11004
|
-
for app in
|
11203
|
+
for app in self._spec.apps:
|
11005
11204
|
app_tags = deploy_tags.add(
|
11006
11205
|
app.app,
|
11007
11206
|
app.key(),
|
@@ -11010,6 +11209,7 @@ class DeployManager:
|
|
11010
11209
|
|
11011
11210
|
await self._apps.prepare_app(
|
11012
11211
|
app,
|
11212
|
+
home,
|
11013
11213
|
app_tags,
|
11014
11214
|
)
|
11015
11215
|
|
@@ -11032,12 +11232,13 @@ class DeployCommand(Command['DeployCommand.Output']):
|
|
11032
11232
|
|
11033
11233
|
@dc.dataclass(frozen=True)
|
11034
11234
|
class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]):
|
11035
|
-
|
11235
|
+
_driver_factory: DeployDriverFactory
|
11036
11236
|
|
11037
11237
|
async def execute(self, cmd: DeployCommand) -> DeployCommand.Output:
|
11038
11238
|
log.info('Deploying! %r', cmd.spec)
|
11039
11239
|
|
11040
|
-
|
11240
|
+
with self._driver_factory(cmd.spec) as driver:
|
11241
|
+
await driver.drive_deploy()
|
11041
11242
|
|
11042
11243
|
return DeployCommand.Output()
|
11043
11244
|
|
@@ -11046,6 +11247,10 @@ class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]
|
|
11046
11247
|
# ../deploy/inject.py
|
11047
11248
|
|
11048
11249
|
|
11250
|
+
class DeployInjectorScope(ContextvarInjectorScope):
|
11251
|
+
pass
|
11252
|
+
|
11253
|
+
|
11049
11254
|
def bind_deploy(
|
11050
11255
|
*,
|
11051
11256
|
deploy_config: DeployConfig,
|
@@ -11077,13 +11282,37 @@ def bind_deploy(
|
|
11077
11282
|
bind_manager(DeployManager),
|
11078
11283
|
|
11079
11284
|
bind_manager(DeployTmpManager),
|
11080
|
-
inj.bind(AtomicPathSwapping, to_key=DeployTmpManager),
|
11081
11285
|
|
11082
11286
|
bind_manager(DeployVenvManager),
|
11083
11287
|
])
|
11084
11288
|
|
11085
11289
|
#
|
11086
11290
|
|
11291
|
+
def provide_deploy_home_atomics(tmp: DeployTmpManager) -> DeployHomeAtomics:
|
11292
|
+
return DeployHomeAtomics(tmp.get_swapping)
|
11293
|
+
lst.append(inj.bind(provide_deploy_home_atomics, singleton=True))
|
11294
|
+
|
11295
|
+
#
|
11296
|
+
|
11297
|
+
def provide_deploy_driver_factory(injector: Injector, sc: DeployInjectorScope) -> DeployDriverFactory:
|
11298
|
+
@contextlib.contextmanager
|
11299
|
+
def factory(spec: DeploySpec) -> ta.Iterator[DeployDriver]:
|
11300
|
+
with sc.enter({
|
11301
|
+
inj.as_key(DeploySpec): spec,
|
11302
|
+
}):
|
11303
|
+
yield injector[DeployDriver]
|
11304
|
+
return DeployDriverFactory(factory)
|
11305
|
+
lst.append(inj.bind(provide_deploy_driver_factory, singleton=True))
|
11306
|
+
|
11307
|
+
lst.extend([
|
11308
|
+
inj.bind_scope(DeployInjectorScope),
|
11309
|
+
inj.bind_scope_seed(DeploySpec, DeployInjectorScope),
|
11310
|
+
|
11311
|
+
inj.bind(DeployDriver, in_=DeployInjectorScope),
|
11312
|
+
])
|
11313
|
+
|
11314
|
+
#
|
11315
|
+
|
11087
11316
|
lst.extend([
|
11088
11317
|
bind_command(DeployCommand, DeployCommandExecutor),
|
11089
11318
|
bind_command(InterpCommand, InterpCommandExecutor),
|
@@ -11091,10 +11320,6 @@ def bind_deploy(
|
|
11091
11320
|
|
11092
11321
|
#
|
11093
11322
|
|
11094
|
-
if (dh := deploy_config.deploy_home) is not None:
|
11095
|
-
dh = os.path.abspath(os.path.expanduser(dh))
|
11096
|
-
lst.append(inj.bind(dh, key=DeployHome))
|
11097
|
-
|
11098
11323
|
return inj.as_bindings(*lst)
|
11099
11324
|
|
11100
11325
|
|
@@ -11190,8 +11415,6 @@ def main_bootstrap(bs: MainBootstrap) -> Injector:
|
|
11190
11415
|
|
11191
11416
|
@dc.dataclass(frozen=True)
|
11192
11417
|
class ManageConfig:
|
11193
|
-
deploy_home: ta.Optional[str] = None
|
11194
|
-
|
11195
11418
|
targets: ta.Optional[ta.Mapping[str, ManageTarget]] = None
|
11196
11419
|
|
11197
11420
|
|
@@ -11223,8 +11446,6 @@ class MainCli(ArgparseCli):
|
|
11223
11446
|
|
11224
11447
|
argparse_arg('--debug', action='store_true'),
|
11225
11448
|
|
11226
|
-
argparse_arg('--deploy-home'),
|
11227
|
-
|
11228
11449
|
argparse_arg('target'),
|
11229
11450
|
argparse_arg('-f', '--command-file', action='append'),
|
11230
11451
|
argparse_arg('command', nargs='*'),
|
@@ -11237,9 +11458,7 @@ class MainCli(ArgparseCli):
|
|
11237
11458
|
debug=bool(self.args.debug),
|
11238
11459
|
),
|
11239
11460
|
|
11240
|
-
deploy_config=DeployConfig(
|
11241
|
-
deploy_home=self.args.deploy_home or self.config().deploy_home,
|
11242
|
-
),
|
11461
|
+
deploy_config=DeployConfig(),
|
11243
11462
|
|
11244
11463
|
remote_config=RemoteConfig(
|
11245
11464
|
payload_file=self.args._payload_file, # noqa
|