ominfra 0.0.0.dev178__py3-none-any.whl → 0.0.0.dev179__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- ominfra/manage/deploy/driver.py +7 -16
- ominfra/manage/deploy/inject.py +53 -19
- ominfra/manage/deploy/interp.py +2 -2
- ominfra/manage/deploy/venvs.py +2 -2
- ominfra/scripts/manage.py +788 -653
- ominfra/scripts/supervisor.py +31 -30
- {ominfra-0.0.0.dev178.dist-info → ominfra-0.0.0.dev179.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev178.dist-info → ominfra-0.0.0.dev179.dist-info}/RECORD +12 -12
- {ominfra-0.0.0.dev178.dist-info → ominfra-0.0.0.dev179.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev178.dist-info → ominfra-0.0.0.dev179.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev178.dist-info → ominfra-0.0.0.dev179.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev178.dist-info → ominfra-0.0.0.dev179.dist-info}/top_level.txt +0 -0
ominfra/scripts/manage.py
CHANGED
@@ -5126,30 +5126,6 @@ def as_injector_bindings(*args: InjectorBindingOrBindings) -> InjectorBindings:
|
|
5126
5126
|
##
|
5127
5127
|
|
5128
5128
|
|
5129
|
-
@dc.dataclass(frozen=True)
|
5130
|
-
class OverridesInjectorBindings(InjectorBindings):
|
5131
|
-
p: InjectorBindings
|
5132
|
-
m: ta.Mapping[InjectorKey, InjectorBinding]
|
5133
|
-
|
5134
|
-
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
5135
|
-
for b in self.p.bindings():
|
5136
|
-
yield self.m.get(b.key, b)
|
5137
|
-
|
5138
|
-
|
5139
|
-
def injector_override(p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5140
|
-
m: ta.Dict[InjectorKey, InjectorBinding] = {}
|
5141
|
-
|
5142
|
-
for b in as_injector_bindings(*args).bindings():
|
5143
|
-
if b.key in m:
|
5144
|
-
raise DuplicateInjectorKeyError(b.key)
|
5145
|
-
m[b.key] = b
|
5146
|
-
|
5147
|
-
return OverridesInjectorBindings(p, m)
|
5148
|
-
|
5149
|
-
|
5150
|
-
##
|
5151
|
-
|
5152
|
-
|
5153
5129
|
def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey, InjectorProvider]:
|
5154
5130
|
pm: ta.Dict[InjectorKey, InjectorProvider] = {}
|
5155
5131
|
am: ta.Dict[InjectorKey, ta.List[InjectorProvider]] = {}
|
@@ -5173,6 +5149,31 @@ def build_injector_provider_map(bs: InjectorBindings) -> ta.Mapping[InjectorKey,
|
|
5173
5149
|
return pm
|
5174
5150
|
|
5175
5151
|
|
5152
|
+
###
|
5153
|
+
# overrides
|
5154
|
+
|
5155
|
+
|
5156
|
+
@dc.dataclass(frozen=True)
|
5157
|
+
class OverridesInjectorBindings(InjectorBindings):
|
5158
|
+
p: InjectorBindings
|
5159
|
+
m: ta.Mapping[InjectorKey, InjectorBinding]
|
5160
|
+
|
5161
|
+
def bindings(self) -> ta.Iterator[InjectorBinding]:
|
5162
|
+
for b in self.p.bindings():
|
5163
|
+
yield self.m.get(b.key, b)
|
5164
|
+
|
5165
|
+
|
5166
|
+
def injector_override(p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5167
|
+
m: ta.Dict[InjectorKey, InjectorBinding] = {}
|
5168
|
+
|
5169
|
+
for b in as_injector_bindings(*args).bindings():
|
5170
|
+
if b.key in m:
|
5171
|
+
raise DuplicateInjectorKeyError(b.key)
|
5172
|
+
m[b.key] = b
|
5173
|
+
|
5174
|
+
return OverridesInjectorBindings(p, m)
|
5175
|
+
|
5176
|
+
|
5176
5177
|
###
|
5177
5178
|
# scopes
|
5178
5179
|
|
@@ -5197,7 +5198,7 @@ class InjectorScope(abc.ABC): # noqa
|
|
5197
5198
|
@dc.dataclass(frozen=True)
|
5198
5199
|
class State:
|
5199
5200
|
seeds: ta.Dict[InjectorKey, ta.Any]
|
5200
|
-
|
5201
|
+
provisions: ta.Dict[InjectorKey, ta.Any] = dc.field(default_factory=dict)
|
5201
5202
|
|
5202
5203
|
def new_state(self, vs: ta.Mapping[InjectorKey, ta.Any]) -> State:
|
5203
5204
|
vs = dict(vs)
|
@@ -5277,11 +5278,11 @@ class ScopedInjectorProvider(InjectorProvider):
|
|
5277
5278
|
def pfn(i: Injector) -> ta.Any:
|
5278
5279
|
st = i[self.sc].state()
|
5279
5280
|
try:
|
5280
|
-
return st.
|
5281
|
+
return st.provisions[self.k]
|
5281
5282
|
except KeyError:
|
5282
5283
|
pass
|
5283
5284
|
v = ufn(i)
|
5284
|
-
st.
|
5285
|
+
st.provisions[self.k] = v
|
5285
5286
|
return v
|
5286
5287
|
|
5287
5288
|
ufn = self.p.provider_fn()
|
@@ -5305,9 +5306,7 @@ class _ScopeSeedInjectorProvider(InjectorProvider):
|
|
5305
5306
|
|
5306
5307
|
|
5307
5308
|
def bind_injector_scope(sc: ta.Type[InjectorScope]) -> InjectorBindingOrBindings:
|
5308
|
-
return
|
5309
|
-
InjectorBinder.bind(sc, singleton=True),
|
5310
|
-
)
|
5309
|
+
return InjectorBinder.bind(sc, singleton=True)
|
5311
5310
|
|
5312
5311
|
|
5313
5312
|
#
|
@@ -5847,6 +5846,8 @@ class InjectionApi:
|
|
5847
5846
|
def as_bindings(self, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5848
5847
|
return as_injector_bindings(*args)
|
5849
5848
|
|
5849
|
+
# overrides
|
5850
|
+
|
5850
5851
|
def override(self, p: InjectorBindings, *args: InjectorBindingOrBindings) -> InjectorBindings:
|
5851
5852
|
return injector_override(p, *args)
|
5852
5853
|
|
@@ -6705,6 +6706,9 @@ class TempDirAtomicPathSwapping(AtomicPathSwapping):
|
|
6705
6706
|
# ../../../omdev/interp/types.py
|
6706
6707
|
|
6707
6708
|
|
6709
|
+
##
|
6710
|
+
|
6711
|
+
|
6708
6712
|
# See https://peps.python.org/pep-3149/
|
6709
6713
|
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
6710
6714
|
('debug', 'd'),
|
@@ -6736,6 +6740,9 @@ class InterpOpts:
|
|
6736
6740
|
return s, cls(**kw)
|
6737
6741
|
|
6738
6742
|
|
6743
|
+
##
|
6744
|
+
|
6745
|
+
|
6739
6746
|
@dc.dataclass(frozen=True)
|
6740
6747
|
class InterpVersion:
|
6741
6748
|
version: Version
|
@@ -6761,6 +6768,9 @@ class InterpVersion:
|
|
6761
6768
|
return None
|
6762
6769
|
|
6763
6770
|
|
6771
|
+
##
|
6772
|
+
|
6773
|
+
|
6764
6774
|
@dc.dataclass(frozen=True)
|
6765
6775
|
class InterpSpecifier:
|
6766
6776
|
specifier: Specifier
|
@@ -6788,12 +6798,25 @@ class InterpSpecifier:
|
|
6788
6798
|
return self.contains(iv)
|
6789
6799
|
|
6790
6800
|
|
6801
|
+
##
|
6802
|
+
|
6803
|
+
|
6791
6804
|
@dc.dataclass(frozen=True)
|
6792
6805
|
class Interp:
|
6793
6806
|
exe: str
|
6794
6807
|
version: InterpVersion
|
6795
6808
|
|
6796
6809
|
|
6810
|
+
########################################
|
6811
|
+
# ../../../omdev/interp/uv/inject.py
|
6812
|
+
|
6813
|
+
|
6814
|
+
def bind_interp_uv() -> InjectorBindings:
|
6815
|
+
lst: ta.List[InjectorBindingOrBindings] = []
|
6816
|
+
|
6817
|
+
return inj.as_bindings(*lst)
|
6818
|
+
|
6819
|
+
|
6797
6820
|
########################################
|
6798
6821
|
# ../../configs.py
|
6799
6822
|
|
@@ -7707,6 +7730,50 @@ class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
7707
7730
|
return ret.decode().strip()
|
7708
7731
|
|
7709
7732
|
|
7733
|
+
########################################
|
7734
|
+
# ../../../omdev/interp/providers/base.py
|
7735
|
+
"""
|
7736
|
+
TODO:
|
7737
|
+
- backends
|
7738
|
+
- local builds
|
7739
|
+
- deadsnakes?
|
7740
|
+
- uv
|
7741
|
+
- loose versions
|
7742
|
+
"""
|
7743
|
+
|
7744
|
+
|
7745
|
+
##
|
7746
|
+
|
7747
|
+
|
7748
|
+
class InterpProvider(abc.ABC):
|
7749
|
+
name: ta.ClassVar[str]
|
7750
|
+
|
7751
|
+
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
7752
|
+
super().__init_subclass__(**kwargs)
|
7753
|
+
if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
|
7754
|
+
sfx = 'InterpProvider'
|
7755
|
+
if not cls.__name__.endswith(sfx):
|
7756
|
+
raise NameError(cls)
|
7757
|
+
setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
|
7758
|
+
|
7759
|
+
@abc.abstractmethod
|
7760
|
+
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
|
7761
|
+
raise NotImplementedError
|
7762
|
+
|
7763
|
+
@abc.abstractmethod
|
7764
|
+
def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
|
7765
|
+
raise NotImplementedError
|
7766
|
+
|
7767
|
+
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
7768
|
+
return []
|
7769
|
+
|
7770
|
+
async def install_version(self, version: InterpVersion) -> Interp:
|
7771
|
+
raise TypeError
|
7772
|
+
|
7773
|
+
|
7774
|
+
InterpProviders = ta.NewType('InterpProviders', ta.Sequence[InterpProvider])
|
7775
|
+
|
7776
|
+
|
7710
7777
|
########################################
|
7711
7778
|
# ../bootstrap.py
|
7712
7779
|
|
@@ -8841,7 +8908,92 @@ class InterpInspector:
|
|
8841
8908
|
return ret
|
8842
8909
|
|
8843
8910
|
|
8844
|
-
|
8911
|
+
########################################
|
8912
|
+
# ../../../omdev/interp/resolvers.py
|
8913
|
+
|
8914
|
+
|
8915
|
+
@dc.dataclass(frozen=True)
|
8916
|
+
class InterpResolverProviders:
|
8917
|
+
providers: ta.Sequence[ta.Tuple[str, InterpProvider]]
|
8918
|
+
|
8919
|
+
|
8920
|
+
class InterpResolver:
|
8921
|
+
def __init__(
|
8922
|
+
self,
|
8923
|
+
providers: InterpResolverProviders,
|
8924
|
+
) -> None:
|
8925
|
+
super().__init__()
|
8926
|
+
|
8927
|
+
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers.providers)
|
8928
|
+
|
8929
|
+
async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
8930
|
+
lst = [
|
8931
|
+
(i, si)
|
8932
|
+
for i, p in enumerate(self._providers.values())
|
8933
|
+
for si in await p.get_installed_versions(spec)
|
8934
|
+
if spec.contains(si)
|
8935
|
+
]
|
8936
|
+
|
8937
|
+
slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
|
8938
|
+
if not slst:
|
8939
|
+
return None
|
8940
|
+
|
8941
|
+
bi, bv = slst[-1]
|
8942
|
+
bp = list(self._providers.values())[bi]
|
8943
|
+
return (bp, bv)
|
8944
|
+
|
8945
|
+
async def resolve(
|
8946
|
+
self,
|
8947
|
+
spec: InterpSpecifier,
|
8948
|
+
*,
|
8949
|
+
install: bool = False,
|
8950
|
+
) -> ta.Optional[Interp]:
|
8951
|
+
tup = await self._resolve_installed(spec)
|
8952
|
+
if tup is not None:
|
8953
|
+
bp, bv = tup
|
8954
|
+
return await bp.get_installed_version(bv)
|
8955
|
+
|
8956
|
+
if not install:
|
8957
|
+
return None
|
8958
|
+
|
8959
|
+
tp = list(self._providers.values())[0] # noqa
|
8960
|
+
|
8961
|
+
sv = sorted(
|
8962
|
+
[s for s in await tp.get_installable_versions(spec) if s in spec],
|
8963
|
+
key=lambda s: s.version,
|
8964
|
+
)
|
8965
|
+
if not sv:
|
8966
|
+
return None
|
8967
|
+
|
8968
|
+
bv = sv[-1]
|
8969
|
+
return await tp.install_version(bv)
|
8970
|
+
|
8971
|
+
async def list(self, spec: InterpSpecifier) -> None:
|
8972
|
+
print('installed:')
|
8973
|
+
for n, p in self._providers.items():
|
8974
|
+
lst = [
|
8975
|
+
si
|
8976
|
+
for si in await p.get_installed_versions(spec)
|
8977
|
+
if spec.contains(si)
|
8978
|
+
]
|
8979
|
+
if lst:
|
8980
|
+
print(f' {n}')
|
8981
|
+
for si in lst:
|
8982
|
+
print(f' {si}')
|
8983
|
+
|
8984
|
+
print()
|
8985
|
+
|
8986
|
+
print('installable:')
|
8987
|
+
for n, p in self._providers.items():
|
8988
|
+
lst = [
|
8989
|
+
si
|
8990
|
+
for si in await p.get_installable_versions(spec)
|
8991
|
+
if spec.contains(si)
|
8992
|
+
]
|
8993
|
+
if lst:
|
8994
|
+
print(f' {n}')
|
8995
|
+
for si in lst:
|
8996
|
+
print(f' {si}')
|
8845
8997
|
|
8846
8998
|
|
8847
8999
|
########################################
|
@@ -9495,47 +9647,7 @@ class YumSystemPackageManager(SystemPackageManager):
|
|
9495
9647
|
|
9496
9648
|
|
9497
9649
|
########################################
|
9498
|
-
# ../../../omdev/interp/providers.py
|
9499
|
-
"""
|
9500
|
-
TODO:
|
9501
|
-
- backends
|
9502
|
-
- local builds
|
9503
|
-
- deadsnakes?
|
9504
|
-
- uv
|
9505
|
-
- loose versions
|
9506
|
-
"""
|
9507
|
-
|
9508
|
-
|
9509
|
-
##
|
9510
|
-
|
9511
|
-
|
9512
|
-
class InterpProvider(abc.ABC):
|
9513
|
-
name: ta.ClassVar[str]
|
9514
|
-
|
9515
|
-
def __init_subclass__(cls, **kwargs: ta.Any) -> None:
|
9516
|
-
super().__init_subclass__(**kwargs)
|
9517
|
-
if abc.ABC not in cls.__bases__ and 'name' not in cls.__dict__:
|
9518
|
-
sfx = 'InterpProvider'
|
9519
|
-
if not cls.__name__.endswith(sfx):
|
9520
|
-
raise NameError(cls)
|
9521
|
-
setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
|
9522
|
-
|
9523
|
-
@abc.abstractmethod
|
9524
|
-
def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
|
9525
|
-
raise NotImplementedError
|
9526
|
-
|
9527
|
-
@abc.abstractmethod
|
9528
|
-
def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
|
9529
|
-
raise NotImplementedError
|
9530
|
-
|
9531
|
-
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
9532
|
-
return []
|
9533
|
-
|
9534
|
-
async def install_version(self, version: InterpVersion) -> Interp:
|
9535
|
-
raise TypeError
|
9536
|
-
|
9537
|
-
|
9538
|
-
##
|
9650
|
+
# ../../../omdev/interp/providers/running.py
|
9539
9651
|
|
9540
9652
|
|
9541
9653
|
class RunningInterpProvider(InterpProvider):
|
@@ -9556,416 +9668,234 @@ class RunningInterpProvider(InterpProvider):
|
|
9556
9668
|
|
9557
9669
|
|
9558
9670
|
########################################
|
9559
|
-
#
|
9671
|
+
# ../../../omdev/interp/providers/system.py
|
9672
|
+
"""
|
9673
|
+
TODO:
|
9674
|
+
- python, python3, python3.12, ...
|
9675
|
+
- check if path py's are venvs: sys.prefix != sys.base_prefix
|
9676
|
+
"""
|
9560
9677
|
|
9561
9678
|
|
9562
9679
|
##
|
9563
9680
|
|
9564
9681
|
|
9565
|
-
|
9566
|
-
|
9567
|
-
|
9568
|
-
|
9569
|
-
|
9570
|
-
inj.bind(CommandRegistration(command_cls), array=True),
|
9571
|
-
]
|
9572
|
-
|
9573
|
-
if executor_cls is not None:
|
9574
|
-
lst.extend([
|
9575
|
-
inj.bind(executor_cls, singleton=True),
|
9576
|
-
inj.bind(CommandExecutorRegistration(command_cls, executor_cls), array=True),
|
9577
|
-
])
|
9682
|
+
class SystemInterpProvider(InterpProvider):
|
9683
|
+
@dc.dataclass(frozen=True)
|
9684
|
+
class Options:
|
9685
|
+
cmd: str = 'python3' # FIXME: unused lol
|
9686
|
+
path: ta.Optional[str] = None
|
9578
9687
|
|
9579
|
-
|
9688
|
+
inspect: bool = False
|
9580
9689
|
|
9690
|
+
def __init__(
|
9691
|
+
self,
|
9692
|
+
options: Options = Options(),
|
9693
|
+
*,
|
9694
|
+
inspector: ta.Optional[InterpInspector] = None,
|
9695
|
+
) -> None:
|
9696
|
+
super().__init__()
|
9581
9697
|
|
9582
|
-
|
9698
|
+
self._options = options
|
9583
9699
|
|
9700
|
+
self._inspector = inspector
|
9584
9701
|
|
9585
|
-
|
9586
|
-
class _FactoryCommandExecutor(CommandExecutor):
|
9587
|
-
factory: ta.Callable[[], CommandExecutor]
|
9702
|
+
#
|
9588
9703
|
|
9589
|
-
|
9590
|
-
|
9704
|
+
@staticmethod
|
9705
|
+
def _re_which(
|
9706
|
+
pat: re.Pattern,
|
9707
|
+
*,
|
9708
|
+
mode: int = os.F_OK | os.X_OK,
|
9709
|
+
path: ta.Optional[str] = None,
|
9710
|
+
) -> ta.List[str]:
|
9711
|
+
if path is None:
|
9712
|
+
path = os.environ.get('PATH', None)
|
9713
|
+
if path is None:
|
9714
|
+
try:
|
9715
|
+
path = os.confstr('CS_PATH')
|
9716
|
+
except (AttributeError, ValueError):
|
9717
|
+
path = os.defpath
|
9591
9718
|
|
9719
|
+
if not path:
|
9720
|
+
return []
|
9592
9721
|
|
9593
|
-
|
9722
|
+
path = os.fsdecode(path)
|
9723
|
+
pathlst = path.split(os.pathsep)
|
9594
9724
|
|
9725
|
+
def _access_check(fn: str, mode: int) -> bool:
|
9726
|
+
return os.path.exists(fn) and os.access(fn, mode)
|
9595
9727
|
|
9596
|
-
|
9597
|
-
|
9598
|
-
|
9599
|
-
|
9600
|
-
|
9601
|
-
|
9602
|
-
|
9728
|
+
out = []
|
9729
|
+
seen = set()
|
9730
|
+
for d in pathlst:
|
9731
|
+
normdir = os.path.normcase(d)
|
9732
|
+
if normdir not in seen:
|
9733
|
+
seen.add(normdir)
|
9734
|
+
if not _access_check(normdir, mode):
|
9735
|
+
continue
|
9736
|
+
for thefile in os.listdir(d):
|
9737
|
+
name = os.path.join(d, thefile)
|
9738
|
+
if not (
|
9739
|
+
os.path.isfile(name) and
|
9740
|
+
pat.fullmatch(thefile) and
|
9741
|
+
_access_check(name, mode)
|
9742
|
+
):
|
9743
|
+
continue
|
9744
|
+
out.append(name)
|
9603
9745
|
|
9604
|
-
|
9605
|
-
inj.bind_array_type(CommandExecutorRegistration, CommandExecutorRegistrations),
|
9746
|
+
return out
|
9606
9747
|
|
9607
|
-
|
9608
|
-
]
|
9748
|
+
@cached_nullary
|
9749
|
+
def exes(self) -> ta.List[str]:
|
9750
|
+
return self._re_which(
|
9751
|
+
re.compile(r'python3(\.\d+)?'),
|
9752
|
+
path=self._options.path,
|
9753
|
+
)
|
9609
9754
|
|
9610
9755
|
#
|
9611
9756
|
|
9612
|
-
def
|
9613
|
-
|
9757
|
+
async def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
|
9758
|
+
if not self._options.inspect:
|
9759
|
+
s = os.path.basename(exe)
|
9760
|
+
if s.startswith('python'):
|
9761
|
+
s = s[len('python'):]
|
9762
|
+
if '.' in s:
|
9763
|
+
try:
|
9764
|
+
return InterpVersion.parse(s)
|
9765
|
+
except InvalidVersion:
|
9766
|
+
pass
|
9767
|
+
ii = await check.not_none(self._inspector).inspect(exe)
|
9768
|
+
return ii.iv if ii is not None else None
|
9614
9769
|
|
9615
|
-
|
9770
|
+
async def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
|
9771
|
+
lst = []
|
9772
|
+
for e in self.exes():
|
9773
|
+
if (ev := await self.get_exe_version(e)) is None:
|
9774
|
+
log.debug('Invalid system version: %s', e)
|
9775
|
+
continue
|
9776
|
+
lst.append((e, ev))
|
9777
|
+
return lst
|
9616
9778
|
|
9617
9779
|
#
|
9618
9780
|
|
9619
|
-
def
|
9620
|
-
|
9621
|
-
crs: CommandExecutorRegistrations,
|
9622
|
-
) -> CommandExecutorMap:
|
9623
|
-
dct: ta.Dict[ta.Type[Command], CommandExecutor] = {}
|
9624
|
-
|
9625
|
-
cr: CommandExecutorRegistration
|
9626
|
-
for cr in crs:
|
9627
|
-
if cr.command_cls in dct:
|
9628
|
-
raise KeyError(cr.command_cls)
|
9629
|
-
|
9630
|
-
factory = functools.partial(injector.provide, cr.executor_cls)
|
9631
|
-
if main_config.debug:
|
9632
|
-
ce = factory()
|
9633
|
-
else:
|
9634
|
-
ce = _FactoryCommandExecutor(factory)
|
9635
|
-
|
9636
|
-
dct[cr.command_cls] = ce
|
9637
|
-
|
9638
|
-
return CommandExecutorMap(dct)
|
9639
|
-
|
9640
|
-
lst.extend([
|
9641
|
-
inj.bind(provide_command_executor_map, singleton=True),
|
9642
|
-
|
9643
|
-
inj.bind(LocalCommandExecutor, singleton=True, eager=main_config.debug),
|
9644
|
-
])
|
9645
|
-
|
9646
|
-
#
|
9781
|
+
async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
9782
|
+
return [ev for e, ev in await self.exe_versions()]
|
9647
9783
|
|
9648
|
-
|
9649
|
-
|
9650
|
-
|
9651
|
-
|
9784
|
+
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
9785
|
+
for e, ev in await self.exe_versions():
|
9786
|
+
if ev != version:
|
9787
|
+
continue
|
9788
|
+
return Interp(
|
9789
|
+
exe=e,
|
9790
|
+
version=ev,
|
9791
|
+
)
|
9792
|
+
raise KeyError(version)
|
9652
9793
|
|
9653
|
-
#
|
9654
9794
|
|
9655
|
-
|
9795
|
+
########################################
|
9796
|
+
# ../../../omdev/interp/pyenv/pyenv.py
|
9797
|
+
"""
|
9798
|
+
TODO:
|
9799
|
+
- custom tags
|
9800
|
+
- 'aliases'
|
9801
|
+
- https://github.com/pyenv/pyenv/pull/2966
|
9802
|
+
- https://github.com/pyenv/pyenv/issues/218 (lol)
|
9803
|
+
- probably need custom (temp?) definition file
|
9804
|
+
- *or* python-build directly just into the versions dir?
|
9805
|
+
- optionally install / upgrade pyenv itself
|
9806
|
+
- new vers dont need these custom mac opts, only run on old vers
|
9807
|
+
"""
|
9656
9808
|
|
9657
9809
|
|
9658
|
-
|
9659
|
-
# ../deploy/paths/manager.py
|
9810
|
+
##
|
9660
9811
|
|
9661
9812
|
|
9662
|
-
class
|
9813
|
+
class Pyenv:
|
9663
9814
|
def __init__(
|
9664
9815
|
self,
|
9665
9816
|
*,
|
9666
|
-
|
9817
|
+
root: ta.Optional[str] = None,
|
9667
9818
|
) -> None:
|
9819
|
+
if root is not None and not (isinstance(root, str) and root):
|
9820
|
+
raise ValueError(f'pyenv_root: {root!r}')
|
9821
|
+
|
9668
9822
|
super().__init__()
|
9669
9823
|
|
9670
|
-
self.
|
9824
|
+
self._root_kw = root
|
9671
9825
|
|
9672
|
-
@
|
9673
|
-
def
|
9674
|
-
|
9675
|
-
|
9676
|
-
for p in o.get_owned_deploy_paths():
|
9677
|
-
if p in dct:
|
9678
|
-
raise DeployPathError(f'Duplicate deploy path owner: {p}')
|
9679
|
-
dct[p] = o
|
9680
|
-
return dct
|
9826
|
+
@async_cached_nullary
|
9827
|
+
async def root(self) -> ta.Optional[str]:
|
9828
|
+
if self._root_kw is not None:
|
9829
|
+
return self._root_kw
|
9681
9830
|
|
9682
|
-
|
9683
|
-
|
9831
|
+
if shutil.which('pyenv'):
|
9832
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
9684
9833
|
|
9834
|
+
d = os.path.expanduser('~/.pyenv')
|
9835
|
+
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
9836
|
+
return d
|
9685
9837
|
|
9686
|
-
|
9687
|
-
# ../deploy/tmp.py
|
9838
|
+
return None
|
9688
9839
|
|
9840
|
+
@async_cached_nullary
|
9841
|
+
async def exe(self) -> str:
|
9842
|
+
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
9689
9843
|
|
9690
|
-
|
9691
|
-
|
9844
|
+
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
9845
|
+
if (root := await self.root()) is None:
|
9846
|
+
return []
|
9847
|
+
ret = []
|
9848
|
+
vp = os.path.join(root, 'versions')
|
9849
|
+
if os.path.isdir(vp):
|
9850
|
+
for dn in os.listdir(vp):
|
9851
|
+
ep = os.path.join(vp, dn, 'bin', 'python')
|
9852
|
+
if not os.path.isfile(ep):
|
9853
|
+
continue
|
9854
|
+
ret.append((dn, ep))
|
9855
|
+
return ret
|
9692
9856
|
|
9857
|
+
async def installable_versions(self) -> ta.List[str]:
|
9858
|
+
if await self.root() is None:
|
9859
|
+
return []
|
9860
|
+
ret = []
|
9861
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
9862
|
+
for l in s.splitlines():
|
9863
|
+
if not l.startswith(' '):
|
9864
|
+
continue
|
9865
|
+
l = l.strip()
|
9866
|
+
if not l:
|
9867
|
+
continue
|
9868
|
+
ret.append(l)
|
9869
|
+
return ret
|
9693
9870
|
|
9694
|
-
|
9695
|
-
|
9696
|
-
|
9697
|
-
|
9698
|
-
|
9699
|
-
|
9700
|
-
|
9871
|
+
async def update(self) -> bool:
|
9872
|
+
if (root := await self.root()) is None:
|
9873
|
+
return False
|
9874
|
+
if not os.path.isdir(os.path.join(root, '.git')):
|
9875
|
+
return False
|
9876
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
9877
|
+
return True
|
9701
9878
|
|
9702
|
-
def get_swapping(self, home: DeployHome) -> AtomicPathSwapping:
|
9703
|
-
return TempDirAtomicPathSwapping(
|
9704
|
-
temp_dir=self._make_dir(home),
|
9705
|
-
root_dir=check.non_empty_str(home),
|
9706
|
-
)
|
9707
9879
|
|
9880
|
+
##
|
9708
9881
|
|
9709
|
-
########################################
|
9710
|
-
# ../remote/connection.py
|
9711
9882
|
|
9883
|
+
@dc.dataclass(frozen=True)
|
9884
|
+
class PyenvInstallOpts:
|
9885
|
+
opts: ta.Sequence[str] = ()
|
9886
|
+
conf_opts: ta.Sequence[str] = ()
|
9887
|
+
cflags: ta.Sequence[str] = ()
|
9888
|
+
ldflags: ta.Sequence[str] = ()
|
9889
|
+
env: ta.Mapping[str, str] = dc.field(default_factory=dict)
|
9712
9890
|
|
9713
|
-
|
9714
|
-
|
9715
|
-
|
9716
|
-
|
9717
|
-
|
9718
|
-
self,
|
9719
|
-
|
9720
|
-
|
9721
|
-
msh: ObjMarshalerManager,
|
9722
|
-
payload_file: ta.Optional[RemoteExecutionPayloadFile] = None,
|
9723
|
-
) -> None:
|
9724
|
-
super().__init__()
|
9725
|
-
|
9726
|
-
self._spawning = spawning
|
9727
|
-
self._msh = msh
|
9728
|
-
self._payload_file = payload_file
|
9729
|
-
|
9730
|
-
#
|
9731
|
-
|
9732
|
-
@cached_nullary
|
9733
|
-
def _payload_src(self) -> str:
|
9734
|
-
return get_remote_payload_src(file=self._payload_file)
|
9735
|
-
|
9736
|
-
@cached_nullary
|
9737
|
-
def _remote_src(self) -> ta.Sequence[str]:
|
9738
|
-
return [
|
9739
|
-
self._payload_src(),
|
9740
|
-
'_remote_execution_main()',
|
9741
|
-
]
|
9742
|
-
|
9743
|
-
@cached_nullary
|
9744
|
-
def _spawn_src(self) -> str:
|
9745
|
-
return pyremote_build_bootstrap_cmd(__package__ or 'manage')
|
9746
|
-
|
9747
|
-
#
|
9748
|
-
|
9749
|
-
@contextlib.asynccontextmanager
|
9750
|
-
async def connect(
|
9751
|
-
self,
|
9752
|
-
tgt: RemoteSpawning.Target,
|
9753
|
-
bs: MainBootstrap,
|
9754
|
-
) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
9755
|
-
spawn_src = self._spawn_src()
|
9756
|
-
remote_src = self._remote_src()
|
9757
|
-
|
9758
|
-
async with self._spawning.spawn(
|
9759
|
-
tgt,
|
9760
|
-
spawn_src,
|
9761
|
-
debug=bs.main_config.debug,
|
9762
|
-
) as proc:
|
9763
|
-
res = await PyremoteBootstrapDriver( # noqa
|
9764
|
-
remote_src,
|
9765
|
-
PyremoteBootstrapOptions(
|
9766
|
-
debug=bs.main_config.debug,
|
9767
|
-
),
|
9768
|
-
).async_run(
|
9769
|
-
proc.stdout,
|
9770
|
-
proc.stdin,
|
9771
|
-
)
|
9772
|
-
|
9773
|
-
chan = RemoteChannelImpl(
|
9774
|
-
proc.stdout,
|
9775
|
-
proc.stdin,
|
9776
|
-
msh=self._msh,
|
9777
|
-
)
|
9778
|
-
|
9779
|
-
await chan.send_obj(bs)
|
9780
|
-
|
9781
|
-
rce: RemoteCommandExecutor
|
9782
|
-
async with aclosing(RemoteCommandExecutor(chan)) as rce:
|
9783
|
-
await rce.start()
|
9784
|
-
|
9785
|
-
yield rce
|
9786
|
-
|
9787
|
-
|
9788
|
-
##
|
9789
|
-
|
9790
|
-
|
9791
|
-
class InProcessRemoteExecutionConnector:
|
9792
|
-
def __init__(
|
9793
|
-
self,
|
9794
|
-
*,
|
9795
|
-
msh: ObjMarshalerManager,
|
9796
|
-
local_executor: LocalCommandExecutor,
|
9797
|
-
) -> None:
|
9798
|
-
super().__init__()
|
9799
|
-
|
9800
|
-
self._msh = msh
|
9801
|
-
self._local_executor = local_executor
|
9802
|
-
|
9803
|
-
@contextlib.asynccontextmanager
|
9804
|
-
async def connect(self) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
9805
|
-
r0, w0 = asyncio_create_bytes_channel()
|
9806
|
-
r1, w1 = asyncio_create_bytes_channel()
|
9807
|
-
|
9808
|
-
remote_chan = RemoteChannelImpl(r0, w1, msh=self._msh)
|
9809
|
-
local_chan = RemoteChannelImpl(r1, w0, msh=self._msh)
|
9810
|
-
|
9811
|
-
rch = _RemoteCommandHandler(
|
9812
|
-
remote_chan,
|
9813
|
-
self._local_executor,
|
9814
|
-
)
|
9815
|
-
rch_task = asyncio.create_task(rch.run()) # noqa
|
9816
|
-
try:
|
9817
|
-
rce: RemoteCommandExecutor
|
9818
|
-
async with aclosing(RemoteCommandExecutor(local_chan)) as rce:
|
9819
|
-
await rce.start()
|
9820
|
-
|
9821
|
-
yield rce
|
9822
|
-
|
9823
|
-
finally:
|
9824
|
-
rch.stop()
|
9825
|
-
await rch_task
|
9826
|
-
|
9827
|
-
|
9828
|
-
########################################
|
9829
|
-
# ../system/commands.py
|
9830
|
-
|
9831
|
-
|
9832
|
-
##
|
9833
|
-
|
9834
|
-
|
9835
|
-
@dc.dataclass(frozen=True)
|
9836
|
-
class CheckSystemPackageCommand(Command['CheckSystemPackageCommand.Output']):
|
9837
|
-
pkgs: ta.Sequence[str] = ()
|
9838
|
-
|
9839
|
-
def __post_init__(self) -> None:
|
9840
|
-
check.not_isinstance(self.pkgs, str)
|
9841
|
-
|
9842
|
-
@dc.dataclass(frozen=True)
|
9843
|
-
class Output(Command.Output):
|
9844
|
-
pkgs: ta.Sequence[SystemPackage]
|
9845
|
-
|
9846
|
-
|
9847
|
-
class CheckSystemPackageCommandExecutor(CommandExecutor[CheckSystemPackageCommand, CheckSystemPackageCommand.Output]):
|
9848
|
-
def __init__(
|
9849
|
-
self,
|
9850
|
-
*,
|
9851
|
-
mgr: SystemPackageManager,
|
9852
|
-
) -> None:
|
9853
|
-
super().__init__()
|
9854
|
-
|
9855
|
-
self._mgr = mgr
|
9856
|
-
|
9857
|
-
async def execute(self, cmd: CheckSystemPackageCommand) -> CheckSystemPackageCommand.Output:
|
9858
|
-
log.info('Checking system package!')
|
9859
|
-
|
9860
|
-
ret = await self._mgr.query(*cmd.pkgs)
|
9861
|
-
|
9862
|
-
return CheckSystemPackageCommand.Output(list(ret.values()))
|
9863
|
-
|
9864
|
-
|
9865
|
-
########################################
|
9866
|
-
# ../../../omdev/interp/pyenv.py
|
9867
|
-
"""
|
9868
|
-
TODO:
|
9869
|
-
- custom tags
|
9870
|
-
- 'aliases'
|
9871
|
-
- https://github.com/pyenv/pyenv/pull/2966
|
9872
|
-
- https://github.com/pyenv/pyenv/issues/218 (lol)
|
9873
|
-
- probably need custom (temp?) definition file
|
9874
|
-
- *or* python-build directly just into the versions dir?
|
9875
|
-
- optionally install / upgrade pyenv itself
|
9876
|
-
- new vers dont need these custom mac opts, only run on old vers
|
9877
|
-
"""
|
9878
|
-
|
9879
|
-
|
9880
|
-
##
|
9881
|
-
|
9882
|
-
|
9883
|
-
class Pyenv:
|
9884
|
-
def __init__(
|
9885
|
-
self,
|
9886
|
-
*,
|
9887
|
-
root: ta.Optional[str] = None,
|
9888
|
-
) -> None:
|
9889
|
-
if root is not None and not (isinstance(root, str) and root):
|
9890
|
-
raise ValueError(f'pyenv_root: {root!r}')
|
9891
|
-
|
9892
|
-
super().__init__()
|
9893
|
-
|
9894
|
-
self._root_kw = root
|
9895
|
-
|
9896
|
-
@async_cached_nullary
|
9897
|
-
async def root(self) -> ta.Optional[str]:
|
9898
|
-
if self._root_kw is not None:
|
9899
|
-
return self._root_kw
|
9900
|
-
|
9901
|
-
if shutil.which('pyenv'):
|
9902
|
-
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
9903
|
-
|
9904
|
-
d = os.path.expanduser('~/.pyenv')
|
9905
|
-
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
9906
|
-
return d
|
9907
|
-
|
9908
|
-
return None
|
9909
|
-
|
9910
|
-
@async_cached_nullary
|
9911
|
-
async def exe(self) -> str:
|
9912
|
-
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
9913
|
-
|
9914
|
-
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
9915
|
-
if (root := await self.root()) is None:
|
9916
|
-
return []
|
9917
|
-
ret = []
|
9918
|
-
vp = os.path.join(root, 'versions')
|
9919
|
-
if os.path.isdir(vp):
|
9920
|
-
for dn in os.listdir(vp):
|
9921
|
-
ep = os.path.join(vp, dn, 'bin', 'python')
|
9922
|
-
if not os.path.isfile(ep):
|
9923
|
-
continue
|
9924
|
-
ret.append((dn, ep))
|
9925
|
-
return ret
|
9926
|
-
|
9927
|
-
async def installable_versions(self) -> ta.List[str]:
|
9928
|
-
if await self.root() is None:
|
9929
|
-
return []
|
9930
|
-
ret = []
|
9931
|
-
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
9932
|
-
for l in s.splitlines():
|
9933
|
-
if not l.startswith(' '):
|
9934
|
-
continue
|
9935
|
-
l = l.strip()
|
9936
|
-
if not l:
|
9937
|
-
continue
|
9938
|
-
ret.append(l)
|
9939
|
-
return ret
|
9940
|
-
|
9941
|
-
async def update(self) -> bool:
|
9942
|
-
if (root := await self.root()) is None:
|
9943
|
-
return False
|
9944
|
-
if not os.path.isdir(os.path.join(root, '.git')):
|
9945
|
-
return False
|
9946
|
-
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
9947
|
-
return True
|
9948
|
-
|
9949
|
-
|
9950
|
-
##
|
9951
|
-
|
9952
|
-
|
9953
|
-
@dc.dataclass(frozen=True)
|
9954
|
-
class PyenvInstallOpts:
|
9955
|
-
opts: ta.Sequence[str] = ()
|
9956
|
-
conf_opts: ta.Sequence[str] = ()
|
9957
|
-
cflags: ta.Sequence[str] = ()
|
9958
|
-
ldflags: ta.Sequence[str] = ()
|
9959
|
-
env: ta.Mapping[str, str] = dc.field(default_factory=dict)
|
9960
|
-
|
9961
|
-
def merge(self, *others: 'PyenvInstallOpts') -> 'PyenvInstallOpts':
|
9962
|
-
return PyenvInstallOpts(
|
9963
|
-
opts=list(itertools.chain.from_iterable(o.opts for o in [self, *others])),
|
9964
|
-
conf_opts=list(itertools.chain.from_iterable(o.conf_opts for o in [self, *others])),
|
9965
|
-
cflags=list(itertools.chain.from_iterable(o.cflags for o in [self, *others])),
|
9966
|
-
ldflags=list(itertools.chain.from_iterable(o.ldflags for o in [self, *others])),
|
9967
|
-
env=dict(itertools.chain.from_iterable(o.env.items() for o in [self, *others])),
|
9968
|
-
)
|
9891
|
+
def merge(self, *others: 'PyenvInstallOpts') -> 'PyenvInstallOpts':
|
9892
|
+
return PyenvInstallOpts(
|
9893
|
+
opts=list(itertools.chain.from_iterable(o.opts for o in [self, *others])),
|
9894
|
+
conf_opts=list(itertools.chain.from_iterable(o.conf_opts for o in [self, *others])),
|
9895
|
+
cflags=list(itertools.chain.from_iterable(o.cflags for o in [self, *others])),
|
9896
|
+
ldflags=list(itertools.chain.from_iterable(o.ldflags for o in [self, *others])),
|
9897
|
+
env=dict(itertools.chain.from_iterable(o.env.items() for o in [self, *others])),
|
9898
|
+
)
|
9969
9899
|
|
9970
9900
|
|
9971
9901
|
# TODO: https://github.com/pyenv/pyenv/blob/master/plugins/python-build/README.md#building-for-maximum-performance
|
@@ -10093,9 +10023,10 @@ class PyenvVersionInstaller:
|
|
10093
10023
|
opts: ta.Optional[PyenvInstallOpts] = None,
|
10094
10024
|
interp_opts: InterpOpts = InterpOpts(),
|
10095
10025
|
*,
|
10026
|
+
pyenv: Pyenv,
|
10027
|
+
|
10096
10028
|
install_name: ta.Optional[str] = None,
|
10097
10029
|
no_default_opts: bool = False,
|
10098
|
-
pyenv: Pyenv = Pyenv(),
|
10099
10030
|
) -> None:
|
10100
10031
|
super().__init__()
|
10101
10032
|
|
@@ -10185,26 +10116,26 @@ class PyenvVersionInstaller:
|
|
10185
10116
|
|
10186
10117
|
|
10187
10118
|
class PyenvInterpProvider(InterpProvider):
|
10188
|
-
|
10189
|
-
|
10190
|
-
|
10119
|
+
@dc.dataclass(frozen=True)
|
10120
|
+
class Options:
|
10121
|
+
inspect: bool = False
|
10191
10122
|
|
10192
|
-
|
10193
|
-
inspector: InterpInspector = INTERP_INSPECTOR,
|
10123
|
+
try_update: bool = False
|
10194
10124
|
|
10125
|
+
def __init__(
|
10126
|
+
self,
|
10127
|
+
options: Options = Options(),
|
10195
10128
|
*,
|
10196
|
-
|
10197
|
-
|
10129
|
+
pyenv: Pyenv,
|
10130
|
+
inspector: InterpInspector,
|
10198
10131
|
) -> None:
|
10199
10132
|
super().__init__()
|
10200
10133
|
|
10201
|
-
self.
|
10134
|
+
self._options = options
|
10202
10135
|
|
10203
|
-
self.
|
10136
|
+
self._pyenv = pyenv
|
10204
10137
|
self._inspector = inspector
|
10205
10138
|
|
10206
|
-
self._try_update = try_update
|
10207
|
-
|
10208
10139
|
#
|
10209
10140
|
|
10210
10141
|
@staticmethod
|
@@ -10229,7 +10160,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
10229
10160
|
|
10230
10161
|
async def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
|
10231
10162
|
iv: ta.Optional[InterpVersion]
|
10232
|
-
if self.
|
10163
|
+
if self._options.inspect:
|
10233
10164
|
try:
|
10234
10165
|
iv = check.not_none(await self._inspector.inspect(ep)).iv
|
10235
10166
|
except Exception as e: # noqa
|
@@ -10285,7 +10216,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
10285
10216
|
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
10286
10217
|
lst = await self._get_installable_versions(spec)
|
10287
10218
|
|
10288
|
-
if self.
|
10219
|
+
if self._options.try_update and not any(v in spec for v in lst):
|
10289
10220
|
if self._pyenv.update():
|
10290
10221
|
lst = await self._get_installable_versions(spec)
|
10291
10222
|
|
@@ -10301,6 +10232,7 @@ class PyenvInterpProvider(InterpProvider):
|
|
10301
10232
|
installer = PyenvVersionInstaller(
|
10302
10233
|
inst_version,
|
10303
10234
|
interp_opts=inst_opts,
|
10235
|
+
pyenv=self._pyenv,
|
10304
10236
|
)
|
10305
10237
|
|
10306
10238
|
exe = await installer.install()
|
@@ -10308,116 +10240,344 @@ class PyenvInterpProvider(InterpProvider):
|
|
10308
10240
|
|
10309
10241
|
|
10310
10242
|
########################################
|
10311
|
-
#
|
10312
|
-
|
10313
|
-
|
10314
|
-
|
10315
|
-
|
10316
|
-
|
10243
|
+
# ../commands/inject.py
|
10244
|
+
|
10245
|
+
|
10246
|
+
##
|
10247
|
+
|
10248
|
+
|
10249
|
+
def bind_command(
|
10250
|
+
command_cls: ta.Type[Command],
|
10251
|
+
executor_cls: ta.Optional[ta.Type[CommandExecutor]],
|
10252
|
+
) -> InjectorBindings:
|
10253
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
10254
|
+
inj.bind(CommandRegistration(command_cls), array=True),
|
10255
|
+
]
|
10256
|
+
|
10257
|
+
if executor_cls is not None:
|
10258
|
+
lst.extend([
|
10259
|
+
inj.bind(executor_cls, singleton=True),
|
10260
|
+
inj.bind(CommandExecutorRegistration(command_cls, executor_cls), array=True),
|
10261
|
+
])
|
10262
|
+
|
10263
|
+
return inj.as_bindings(*lst)
|
10264
|
+
|
10265
|
+
|
10266
|
+
##
|
10267
|
+
|
10268
|
+
|
10269
|
+
@dc.dataclass(frozen=True)
|
10270
|
+
class _FactoryCommandExecutor(CommandExecutor):
|
10271
|
+
factory: ta.Callable[[], CommandExecutor]
|
10272
|
+
|
10273
|
+
def execute(self, i: Command) -> ta.Awaitable[Command.Output]:
|
10274
|
+
return self.factory().execute(i)
|
10275
|
+
|
10276
|
+
|
10277
|
+
##
|
10278
|
+
|
10279
|
+
|
10280
|
+
def bind_commands(
|
10281
|
+
*,
|
10282
|
+
main_config: MainConfig,
|
10283
|
+
) -> InjectorBindings:
|
10284
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
10285
|
+
inj.bind_array(CommandRegistration),
|
10286
|
+
inj.bind_array_type(CommandRegistration, CommandRegistrations),
|
10287
|
+
|
10288
|
+
inj.bind_array(CommandExecutorRegistration),
|
10289
|
+
inj.bind_array_type(CommandExecutorRegistration, CommandExecutorRegistrations),
|
10290
|
+
|
10291
|
+
inj.bind(build_command_name_map, singleton=True),
|
10292
|
+
]
|
10293
|
+
|
10294
|
+
#
|
10295
|
+
|
10296
|
+
def provide_obj_marshaler_installer(cmds: CommandNameMap) -> ObjMarshalerInstaller:
|
10297
|
+
return ObjMarshalerInstaller(functools.partial(install_command_marshaling, cmds))
|
10298
|
+
|
10299
|
+
lst.append(inj.bind(provide_obj_marshaler_installer, array=True))
|
10300
|
+
|
10301
|
+
#
|
10302
|
+
|
10303
|
+
def provide_command_executor_map(
|
10304
|
+
injector: Injector,
|
10305
|
+
crs: CommandExecutorRegistrations,
|
10306
|
+
) -> CommandExecutorMap:
|
10307
|
+
dct: ta.Dict[ta.Type[Command], CommandExecutor] = {}
|
10308
|
+
|
10309
|
+
cr: CommandExecutorRegistration
|
10310
|
+
for cr in crs:
|
10311
|
+
if cr.command_cls in dct:
|
10312
|
+
raise KeyError(cr.command_cls)
|
10313
|
+
|
10314
|
+
factory = functools.partial(injector.provide, cr.executor_cls)
|
10315
|
+
if main_config.debug:
|
10316
|
+
ce = factory()
|
10317
|
+
else:
|
10318
|
+
ce = _FactoryCommandExecutor(factory)
|
10319
|
+
|
10320
|
+
dct[cr.command_cls] = ce
|
10321
|
+
|
10322
|
+
return CommandExecutorMap(dct)
|
10323
|
+
|
10324
|
+
lst.extend([
|
10325
|
+
inj.bind(provide_command_executor_map, singleton=True),
|
10326
|
+
|
10327
|
+
inj.bind(LocalCommandExecutor, singleton=True, eager=main_config.debug),
|
10328
|
+
])
|
10329
|
+
|
10330
|
+
#
|
10331
|
+
|
10332
|
+
lst.extend([
|
10333
|
+
bind_command(PingCommand, PingCommandExecutor),
|
10334
|
+
bind_command(SubprocessCommand, SubprocessCommandExecutor),
|
10335
|
+
])
|
10336
|
+
|
10337
|
+
#
|
10338
|
+
|
10339
|
+
return inj.as_bindings(*lst)
|
10340
|
+
|
10341
|
+
|
10342
|
+
########################################
|
10343
|
+
# ../deploy/paths/manager.py
|
10344
|
+
|
10345
|
+
|
10346
|
+
class DeployPathsManager:
|
10347
|
+
def __init__(
|
10348
|
+
self,
|
10349
|
+
*,
|
10350
|
+
deploy_path_owners: DeployPathOwners,
|
10351
|
+
) -> None:
|
10352
|
+
super().__init__()
|
10353
|
+
|
10354
|
+
self._deploy_path_owners = deploy_path_owners
|
10355
|
+
|
10356
|
+
@cached_nullary
|
10357
|
+
def owners_by_path(self) -> ta.Mapping[DeployPath, DeployPathOwner]:
|
10358
|
+
dct: ta.Dict[DeployPath, DeployPathOwner] = {}
|
10359
|
+
for o in self._deploy_path_owners:
|
10360
|
+
for p in o.get_owned_deploy_paths():
|
10361
|
+
if p in dct:
|
10362
|
+
raise DeployPathError(f'Duplicate deploy path owner: {p}')
|
10363
|
+
dct[p] = o
|
10364
|
+
return dct
|
10365
|
+
|
10366
|
+
def validate_deploy_paths(self) -> None:
|
10367
|
+
self.owners_by_path()
|
10368
|
+
|
10369
|
+
|
10370
|
+
########################################
|
10371
|
+
# ../deploy/tmp.py
|
10372
|
+
|
10373
|
+
|
10374
|
+
class DeployHomeAtomics(Func1[DeployHome, AtomicPathSwapping]):
|
10375
|
+
pass
|
10376
|
+
|
10377
|
+
|
10378
|
+
class DeployTmpManager(
|
10379
|
+
SingleDirDeployPathOwner,
|
10380
|
+
):
|
10381
|
+
def __init__(self) -> None:
|
10382
|
+
super().__init__(
|
10383
|
+
owned_dir='tmp',
|
10384
|
+
)
|
10385
|
+
|
10386
|
+
def get_swapping(self, home: DeployHome) -> AtomicPathSwapping:
|
10387
|
+
return TempDirAtomicPathSwapping(
|
10388
|
+
temp_dir=self._make_dir(home),
|
10389
|
+
root_dir=check.non_empty_str(home),
|
10390
|
+
)
|
10391
|
+
|
10392
|
+
|
10393
|
+
########################################
|
10394
|
+
# ../remote/connection.py
|
10395
|
+
|
10396
|
+
|
10397
|
+
##
|
10398
|
+
|
10399
|
+
|
10400
|
+
class PyremoteRemoteExecutionConnector:
|
10401
|
+
def __init__(
|
10402
|
+
self,
|
10403
|
+
*,
|
10404
|
+
spawning: RemoteSpawning,
|
10405
|
+
msh: ObjMarshalerManager,
|
10406
|
+
payload_file: ta.Optional[RemoteExecutionPayloadFile] = None,
|
10407
|
+
) -> None:
|
10408
|
+
super().__init__()
|
10409
|
+
|
10410
|
+
self._spawning = spawning
|
10411
|
+
self._msh = msh
|
10412
|
+
self._payload_file = payload_file
|
10413
|
+
|
10414
|
+
#
|
10415
|
+
|
10416
|
+
@cached_nullary
|
10417
|
+
def _payload_src(self) -> str:
|
10418
|
+
return get_remote_payload_src(file=self._payload_file)
|
10419
|
+
|
10420
|
+
@cached_nullary
|
10421
|
+
def _remote_src(self) -> ta.Sequence[str]:
|
10422
|
+
return [
|
10423
|
+
self._payload_src(),
|
10424
|
+
'_remote_execution_main()',
|
10425
|
+
]
|
10426
|
+
|
10427
|
+
@cached_nullary
|
10428
|
+
def _spawn_src(self) -> str:
|
10429
|
+
return pyremote_build_bootstrap_cmd(__package__ or 'manage')
|
10430
|
+
|
10431
|
+
#
|
10432
|
+
|
10433
|
+
@contextlib.asynccontextmanager
|
10434
|
+
async def connect(
|
10435
|
+
self,
|
10436
|
+
tgt: RemoteSpawning.Target,
|
10437
|
+
bs: MainBootstrap,
|
10438
|
+
) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
10439
|
+
spawn_src = self._spawn_src()
|
10440
|
+
remote_src = self._remote_src()
|
10441
|
+
|
10442
|
+
async with self._spawning.spawn(
|
10443
|
+
tgt,
|
10444
|
+
spawn_src,
|
10445
|
+
debug=bs.main_config.debug,
|
10446
|
+
) as proc:
|
10447
|
+
res = await PyremoteBootstrapDriver( # noqa
|
10448
|
+
remote_src,
|
10449
|
+
PyremoteBootstrapOptions(
|
10450
|
+
debug=bs.main_config.debug,
|
10451
|
+
),
|
10452
|
+
).async_run(
|
10453
|
+
proc.stdout,
|
10454
|
+
proc.stdin,
|
10455
|
+
)
|
10456
|
+
|
10457
|
+
chan = RemoteChannelImpl(
|
10458
|
+
proc.stdout,
|
10459
|
+
proc.stdin,
|
10460
|
+
msh=self._msh,
|
10461
|
+
)
|
10462
|
+
|
10463
|
+
await chan.send_obj(bs)
|
10464
|
+
|
10465
|
+
rce: RemoteCommandExecutor
|
10466
|
+
async with aclosing(RemoteCommandExecutor(chan)) as rce:
|
10467
|
+
await rce.start()
|
10468
|
+
|
10469
|
+
yield rce
|
10470
|
+
|
10471
|
+
|
10472
|
+
##
|
10473
|
+
|
10474
|
+
|
10475
|
+
class InProcessRemoteExecutionConnector:
|
10476
|
+
def __init__(
|
10477
|
+
self,
|
10478
|
+
*,
|
10479
|
+
msh: ObjMarshalerManager,
|
10480
|
+
local_executor: LocalCommandExecutor,
|
10481
|
+
) -> None:
|
10482
|
+
super().__init__()
|
10483
|
+
|
10484
|
+
self._msh = msh
|
10485
|
+
self._local_executor = local_executor
|
10486
|
+
|
10487
|
+
@contextlib.asynccontextmanager
|
10488
|
+
async def connect(self) -> ta.AsyncGenerator[RemoteCommandExecutor, None]:
|
10489
|
+
r0, w0 = asyncio_create_bytes_channel()
|
10490
|
+
r1, w1 = asyncio_create_bytes_channel()
|
10491
|
+
|
10492
|
+
remote_chan = RemoteChannelImpl(r0, w1, msh=self._msh)
|
10493
|
+
local_chan = RemoteChannelImpl(r1, w0, msh=self._msh)
|
10494
|
+
|
10495
|
+
rch = _RemoteCommandHandler(
|
10496
|
+
remote_chan,
|
10497
|
+
self._local_executor,
|
10498
|
+
)
|
10499
|
+
rch_task = asyncio.create_task(rch.run()) # noqa
|
10500
|
+
try:
|
10501
|
+
rce: RemoteCommandExecutor
|
10502
|
+
async with aclosing(RemoteCommandExecutor(local_chan)) as rce:
|
10503
|
+
await rce.start()
|
10504
|
+
|
10505
|
+
yield rce
|
10506
|
+
|
10507
|
+
finally:
|
10508
|
+
rch.stop()
|
10509
|
+
await rch_task
|
10510
|
+
|
10511
|
+
|
10512
|
+
########################################
|
10513
|
+
# ../system/commands.py
|
10514
|
+
|
10515
|
+
|
10516
|
+
##
|
10517
|
+
|
10518
|
+
|
10519
|
+
@dc.dataclass(frozen=True)
|
10520
|
+
class CheckSystemPackageCommand(Command['CheckSystemPackageCommand.Output']):
|
10521
|
+
pkgs: ta.Sequence[str] = ()
|
10522
|
+
|
10523
|
+
def __post_init__(self) -> None:
|
10524
|
+
check.not_isinstance(self.pkgs, str)
|
10525
|
+
|
10526
|
+
@dc.dataclass(frozen=True)
|
10527
|
+
class Output(Command.Output):
|
10528
|
+
pkgs: ta.Sequence[SystemPackage]
|
10317
10529
|
|
10318
10530
|
|
10319
|
-
|
10531
|
+
class CheckSystemPackageCommandExecutor(CommandExecutor[CheckSystemPackageCommand, CheckSystemPackageCommand.Output]):
|
10532
|
+
def __init__(
|
10533
|
+
self,
|
10534
|
+
*,
|
10535
|
+
mgr: SystemPackageManager,
|
10536
|
+
) -> None:
|
10537
|
+
super().__init__()
|
10320
10538
|
|
10539
|
+
self._mgr = mgr
|
10321
10540
|
|
10322
|
-
|
10323
|
-
|
10324
|
-
cmd: str = 'python3'
|
10325
|
-
path: ta.Optional[str] = None
|
10541
|
+
async def execute(self, cmd: CheckSystemPackageCommand) -> CheckSystemPackageCommand.Output:
|
10542
|
+
log.info('Checking system package!')
|
10326
10543
|
|
10327
|
-
|
10328
|
-
inspector: InterpInspector = INTERP_INSPECTOR
|
10544
|
+
ret = await self._mgr.query(*cmd.pkgs)
|
10329
10545
|
|
10330
|
-
|
10546
|
+
return CheckSystemPackageCommand.Output(list(ret.values()))
|
10331
10547
|
|
10332
|
-
@staticmethod
|
10333
|
-
def _re_which(
|
10334
|
-
pat: re.Pattern,
|
10335
|
-
*,
|
10336
|
-
mode: int = os.F_OK | os.X_OK,
|
10337
|
-
path: ta.Optional[str] = None,
|
10338
|
-
) -> ta.List[str]:
|
10339
|
-
if path is None:
|
10340
|
-
path = os.environ.get('PATH', None)
|
10341
|
-
if path is None:
|
10342
|
-
try:
|
10343
|
-
path = os.confstr('CS_PATH')
|
10344
|
-
except (AttributeError, ValueError):
|
10345
|
-
path = os.defpath
|
10346
10548
|
|
10347
|
-
|
10348
|
-
|
10549
|
+
########################################
|
10550
|
+
# ../../../omdev/interp/providers/inject.py
|
10349
10551
|
|
10350
|
-
path = os.fsdecode(path)
|
10351
|
-
pathlst = path.split(os.pathsep)
|
10352
10552
|
|
10353
|
-
|
10354
|
-
|
10553
|
+
def bind_interp_providers() -> InjectorBindings:
|
10554
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
10555
|
+
inj.bind_array(InterpProvider),
|
10556
|
+
inj.bind_array_type(InterpProvider, InterpProviders),
|
10355
10557
|
|
10356
|
-
|
10357
|
-
|
10358
|
-
for d in pathlst:
|
10359
|
-
normdir = os.path.normcase(d)
|
10360
|
-
if normdir not in seen:
|
10361
|
-
seen.add(normdir)
|
10362
|
-
if not _access_check(normdir, mode):
|
10363
|
-
continue
|
10364
|
-
for thefile in os.listdir(d):
|
10365
|
-
name = os.path.join(d, thefile)
|
10366
|
-
if not (
|
10367
|
-
os.path.isfile(name) and
|
10368
|
-
pat.fullmatch(thefile) and
|
10369
|
-
_access_check(name, mode)
|
10370
|
-
):
|
10371
|
-
continue
|
10372
|
-
out.append(name)
|
10558
|
+
inj.bind(RunningInterpProvider, singleton=True),
|
10559
|
+
inj.bind(InterpProvider, to_key=RunningInterpProvider, array=True),
|
10373
10560
|
|
10374
|
-
|
10561
|
+
inj.bind(SystemInterpProvider, singleton=True),
|
10562
|
+
inj.bind(InterpProvider, to_key=SystemInterpProvider, array=True),
|
10563
|
+
]
|
10375
10564
|
|
10376
|
-
|
10377
|
-
def exes(self) -> ta.List[str]:
|
10378
|
-
return self._re_which(
|
10379
|
-
re.compile(r'python3(\.\d+)?'),
|
10380
|
-
path=self.path,
|
10381
|
-
)
|
10565
|
+
return inj.as_bindings(*lst)
|
10382
10566
|
|
10383
|
-
#
|
10384
10567
|
|
10385
|
-
|
10386
|
-
|
10387
|
-
s = os.path.basename(exe)
|
10388
|
-
if s.startswith('python'):
|
10389
|
-
s = s[len('python'):]
|
10390
|
-
if '.' in s:
|
10391
|
-
try:
|
10392
|
-
return InterpVersion.parse(s)
|
10393
|
-
except InvalidVersion:
|
10394
|
-
pass
|
10395
|
-
ii = await self.inspector.inspect(exe)
|
10396
|
-
return ii.iv if ii is not None else None
|
10568
|
+
########################################
|
10569
|
+
# ../../../omdev/interp/pyenv/inject.py
|
10397
10570
|
|
10398
|
-
async def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
|
10399
|
-
lst = []
|
10400
|
-
for e in self.exes():
|
10401
|
-
if (ev := await self.get_exe_version(e)) is None:
|
10402
|
-
log.debug('Invalid system version: %s', e)
|
10403
|
-
continue
|
10404
|
-
lst.append((e, ev))
|
10405
|
-
return lst
|
10406
10571
|
|
10407
|
-
|
10572
|
+
def bind_interp_pyenv() -> InjectorBindings:
|
10573
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
10574
|
+
inj.bind(Pyenv, singleton=True),
|
10408
10575
|
|
10409
|
-
|
10410
|
-
|
10576
|
+
inj.bind(PyenvInterpProvider, singleton=True),
|
10577
|
+
inj.bind(InterpProvider, to_key=PyenvInterpProvider, array=True),
|
10578
|
+
]
|
10411
10579
|
|
10412
|
-
|
10413
|
-
for e, ev in await self.exe_versions():
|
10414
|
-
if ev != version:
|
10415
|
-
continue
|
10416
|
-
return Interp(
|
10417
|
-
exe=e,
|
10418
|
-
version=ev,
|
10419
|
-
)
|
10420
|
-
raise KeyError(version)
|
10580
|
+
return inj.as_bindings(*lst)
|
10421
10581
|
|
10422
10582
|
|
10423
10583
|
########################################
|
@@ -10784,101 +10944,44 @@ class SshManageTargetConnector(ManageTargetConnector):
|
|
10784
10944
|
|
10785
10945
|
|
10786
10946
|
########################################
|
10787
|
-
# ../../../omdev/interp/
|
10788
|
-
|
10789
|
-
|
10790
|
-
INTERP_PROVIDER_TYPES_BY_NAME: ta.Mapping[str, ta.Type[InterpProvider]] = {
|
10791
|
-
cls.name: cls for cls in deep_subclasses(InterpProvider) if abc.ABC not in cls.__bases__ # type: ignore
|
10792
|
-
}
|
10793
|
-
|
10794
|
-
|
10795
|
-
class InterpResolver:
|
10796
|
-
def __init__(
|
10797
|
-
self,
|
10798
|
-
providers: ta.Sequence[ta.Tuple[str, InterpProvider]],
|
10799
|
-
) -> None:
|
10800
|
-
super().__init__()
|
10801
|
-
|
10802
|
-
self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
|
10803
|
-
|
10804
|
-
async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
|
10805
|
-
lst = [
|
10806
|
-
(i, si)
|
10807
|
-
for i, p in enumerate(self._providers.values())
|
10808
|
-
for si in await p.get_installed_versions(spec)
|
10809
|
-
if spec.contains(si)
|
10810
|
-
]
|
10811
|
-
|
10812
|
-
slst = sorted(lst, key=lambda t: (-t[0], t[1].version))
|
10813
|
-
if not slst:
|
10814
|
-
return None
|
10947
|
+
# ../../../omdev/interp/inject.py
|
10815
10948
|
|
10816
|
-
bi, bv = slst[-1]
|
10817
|
-
bp = list(self._providers.values())[bi]
|
10818
|
-
return (bp, bv)
|
10819
10949
|
|
10820
|
-
|
10821
|
-
|
10822
|
-
|
10823
|
-
*,
|
10824
|
-
install: bool = False,
|
10825
|
-
) -> ta.Optional[Interp]:
|
10826
|
-
tup = await self._resolve_installed(spec)
|
10827
|
-
if tup is not None:
|
10828
|
-
bp, bv = tup
|
10829
|
-
return await bp.get_installed_version(bv)
|
10950
|
+
def bind_interp() -> InjectorBindings:
|
10951
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
10952
|
+
bind_interp_providers(),
|
10830
10953
|
|
10831
|
-
|
10832
|
-
return None
|
10954
|
+
bind_interp_pyenv(),
|
10833
10955
|
|
10834
|
-
|
10956
|
+
bind_interp_uv(),
|
10835
10957
|
|
10836
|
-
|
10837
|
-
|
10838
|
-
key=lambda s: s.version,
|
10839
|
-
)
|
10840
|
-
if not sv:
|
10841
|
-
return None
|
10958
|
+
inj.bind(InterpInspector, singleton=True),
|
10959
|
+
]
|
10842
10960
|
|
10843
|
-
|
10844
|
-
return await tp.install_version(bv)
|
10961
|
+
#
|
10845
10962
|
|
10846
|
-
|
10847
|
-
|
10848
|
-
|
10849
|
-
|
10850
|
-
|
10851
|
-
|
10852
|
-
|
10963
|
+
def provide_interp_resolver_providers(injector: Injector) -> InterpResolverProviders:
|
10964
|
+
# FIXME: lol
|
10965
|
+
rps: ta.List[ta.Any] = [
|
10966
|
+
injector.provide(c)
|
10967
|
+
for c in [
|
10968
|
+
PyenvInterpProvider,
|
10969
|
+
RunningInterpProvider,
|
10970
|
+
SystemInterpProvider,
|
10853
10971
|
]
|
10854
|
-
|
10855
|
-
print(f' {n}')
|
10856
|
-
for si in lst:
|
10857
|
-
print(f' {si}')
|
10858
|
-
|
10859
|
-
print()
|
10972
|
+
]
|
10860
10973
|
|
10861
|
-
|
10862
|
-
for n, p in self._providers.items():
|
10863
|
-
lst = [
|
10864
|
-
si
|
10865
|
-
for si in await p.get_installable_versions(spec)
|
10866
|
-
if spec.contains(si)
|
10867
|
-
]
|
10868
|
-
if lst:
|
10869
|
-
print(f' {n}')
|
10870
|
-
for si in lst:
|
10871
|
-
print(f' {si}')
|
10974
|
+
return InterpResolverProviders([(rp.name, rp) for rp in rps])
|
10872
10975
|
|
10976
|
+
lst.append(inj.bind(provide_interp_resolver_providers, singleton=True))
|
10873
10977
|
|
10874
|
-
|
10875
|
-
|
10876
|
-
|
10978
|
+
lst.extend([
|
10979
|
+
inj.bind(InterpResolver, singleton=True),
|
10980
|
+
])
|
10877
10981
|
|
10878
|
-
|
10982
|
+
#
|
10879
10983
|
|
10880
|
-
|
10881
|
-
]])
|
10984
|
+
return inj.as_bindings(*lst)
|
10882
10985
|
|
10883
10986
|
|
10884
10987
|
########################################
|
@@ -10910,6 +11013,15 @@ def bind_targets() -> InjectorBindings:
|
|
10910
11013
|
return inj.as_bindings(*lst)
|
10911
11014
|
|
10912
11015
|
|
11016
|
+
########################################
|
11017
|
+
# ../../../omdev/interp/default.py
|
11018
|
+
|
11019
|
+
|
11020
|
+
@cached_nullary
|
11021
|
+
def get_default_interp_resolver() -> InterpResolver:
|
11022
|
+
return inj.create_injector(bind_interp())[InterpResolver]
|
11023
|
+
|
11024
|
+
|
10913
11025
|
########################################
|
10914
11026
|
# ../deploy/interp.py
|
10915
11027
|
|
@@ -10932,7 +11044,7 @@ class InterpCommand(Command['InterpCommand.Output']):
|
|
10932
11044
|
class InterpCommandExecutor(CommandExecutor[InterpCommand, InterpCommand.Output]):
|
10933
11045
|
async def execute(self, cmd: InterpCommand) -> InterpCommand.Output:
|
10934
11046
|
i = InterpSpecifier.parse(check.not_none(cmd.spec))
|
10935
|
-
o = check.not_none(await
|
11047
|
+
o = check.not_none(await get_default_interp_resolver().resolve(i, install=cmd.install))
|
10936
11048
|
return InterpCommand.Output(
|
10937
11049
|
exe=o.exe,
|
10938
11050
|
version=str(o.version.version),
|
@@ -10959,7 +11071,7 @@ class DeployVenvManager:
|
|
10959
11071
|
) -> None:
|
10960
11072
|
if spec.interp is not None:
|
10961
11073
|
i = InterpSpecifier.parse(check.not_none(spec.interp))
|
10962
|
-
o = check.not_none(await
|
11074
|
+
o = check.not_none(await get_default_interp_resolver().resolve(i))
|
10963
11075
|
sys_exe = o.exe
|
10964
11076
|
else:
|
10965
11077
|
sys_exe = 'python3'
|
@@ -11166,16 +11278,18 @@ class DeployDriver:
|
|
11166
11278
|
self,
|
11167
11279
|
*,
|
11168
11280
|
spec: DeploySpec,
|
11281
|
+
home: DeployHome,
|
11282
|
+
time: DeployTime,
|
11169
11283
|
|
11170
|
-
deploys: DeployManager,
|
11171
11284
|
paths: DeployPathsManager,
|
11172
11285
|
apps: DeployAppManager,
|
11173
11286
|
) -> None:
|
11174
11287
|
super().__init__()
|
11175
11288
|
|
11176
11289
|
self._spec = spec
|
11290
|
+
self._home = home
|
11291
|
+
self._time = time
|
11177
11292
|
|
11178
|
-
self._deploys = deploys
|
11179
11293
|
self._paths = paths
|
11180
11294
|
self._apps = apps
|
11181
11295
|
|
@@ -11184,17 +11298,8 @@ class DeployDriver:
|
|
11184
11298
|
|
11185
11299
|
#
|
11186
11300
|
|
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)
|
11191
|
-
|
11192
|
-
home = DeployHome(hs)
|
11193
|
-
|
11194
|
-
#
|
11195
|
-
|
11196
11301
|
deploy_tags = DeployTagMap(
|
11197
|
-
self.
|
11302
|
+
self._time,
|
11198
11303
|
self._spec.key(),
|
11199
11304
|
)
|
11200
11305
|
|
@@ -11209,7 +11314,7 @@ class DeployDriver:
|
|
11209
11314
|
|
11210
11315
|
await self._apps.prepare_app(
|
11211
11316
|
app,
|
11212
|
-
|
11317
|
+
self._home,
|
11213
11318
|
app_tags,
|
11214
11319
|
)
|
11215
11320
|
|
@@ -11247,10 +11352,57 @@ class DeployCommandExecutor(CommandExecutor[DeployCommand, DeployCommand.Output]
|
|
11247
11352
|
# ../deploy/inject.py
|
11248
11353
|
|
11249
11354
|
|
11355
|
+
##
|
11356
|
+
|
11357
|
+
|
11250
11358
|
class DeployInjectorScope(ContextvarInjectorScope):
|
11251
11359
|
pass
|
11252
11360
|
|
11253
11361
|
|
11362
|
+
def bind_deploy_scope() -> InjectorBindings:
|
11363
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
11364
|
+
inj.bind_scope(DeployInjectorScope),
|
11365
|
+
inj.bind_scope_seed(DeploySpec, DeployInjectorScope),
|
11366
|
+
|
11367
|
+
inj.bind(DeployDriver, in_=DeployInjectorScope),
|
11368
|
+
]
|
11369
|
+
|
11370
|
+
#
|
11371
|
+
|
11372
|
+
def provide_deploy_driver_factory(injector: Injector, sc: DeployInjectorScope) -> DeployDriverFactory:
|
11373
|
+
@contextlib.contextmanager
|
11374
|
+
def factory(spec: DeploySpec) -> ta.Iterator[DeployDriver]:
|
11375
|
+
with sc.enter({
|
11376
|
+
inj.as_key(DeploySpec): spec,
|
11377
|
+
}):
|
11378
|
+
yield injector[DeployDriver]
|
11379
|
+
return DeployDriverFactory(factory)
|
11380
|
+
lst.append(inj.bind(provide_deploy_driver_factory, singleton=True))
|
11381
|
+
|
11382
|
+
#
|
11383
|
+
|
11384
|
+
def provide_deploy_home(deploy: DeploySpec) -> DeployHome:
|
11385
|
+
hs = check.non_empty_str(deploy.home)
|
11386
|
+
hs = os.path.expanduser(hs)
|
11387
|
+
hs = os.path.realpath(hs)
|
11388
|
+
hs = os.path.abspath(hs)
|
11389
|
+
return DeployHome(hs)
|
11390
|
+
lst.append(inj.bind(provide_deploy_home, in_=DeployInjectorScope))
|
11391
|
+
|
11392
|
+
#
|
11393
|
+
|
11394
|
+
def provide_deploy_time(deploys: DeployManager) -> DeployTime:
|
11395
|
+
return deploys.make_deploy_time()
|
11396
|
+
lst.append(inj.bind(provide_deploy_time, in_=DeployInjectorScope))
|
11397
|
+
|
11398
|
+
#
|
11399
|
+
|
11400
|
+
return inj.as_bindings(*lst)
|
11401
|
+
|
11402
|
+
|
11403
|
+
##
|
11404
|
+
|
11405
|
+
|
11254
11406
|
def bind_deploy(
|
11255
11407
|
*,
|
11256
11408
|
deploy_config: DeployConfig,
|
@@ -11259,6 +11411,8 @@ def bind_deploy(
|
|
11259
11411
|
inj.bind(deploy_config),
|
11260
11412
|
|
11261
11413
|
bind_deploy_paths(),
|
11414
|
+
|
11415
|
+
bind_deploy_scope(),
|
11262
11416
|
]
|
11263
11417
|
|
11264
11418
|
#
|
@@ -11294,25 +11448,6 @@ def bind_deploy(
|
|
11294
11448
|
|
11295
11449
|
#
|
11296
11450
|
|
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
|
-
|
11316
11451
|
lst.extend([
|
11317
11452
|
bind_command(DeployCommand, DeployCommandExecutor),
|
11318
11453
|
bind_command(InterpCommand, InterpCommandExecutor),
|