ominfra 0.0.0.dev178__py3-none-any.whl → 0.0.0.dev179__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/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),
|