11import os
2- import shutil
32import sys
3+ from typing import Optional
44
55from .ffi import ffi , load_hostfxr
6- from .util import check_result
6+ from .util import check_result , find_dotnet_root
77
8- __all__ = ["HostFxr " ]
8+ __all__ = ["DotnetCoreRuntime " ]
99
1010
11- class HostFxr :
12- # TODO: Allow generating runtime_config
13- def __init__ (self , runtime_config , dotnet_root = None ):
14- self ._handle = None
11+ class DotnetCoreRuntime :
12+ def __init__ (self , runtime_config : str , dotnet_root : Optional [str ] = None ):
13+ self ._dotnet_root = dotnet_root or find_dotnet_root ()
14+ self ._dll = load_hostfxr (self ._dotnet_root )
15+ self ._is_finalized = False
16+ self ._handle = _get_handle (self ._dll , self ._dotnet_root , runtime_config )
17+ self ._load_func = _get_load_func (self ._dll , self ._handle )
1518
16- if not dotnet_root :
17- dotnet_root = os .environ .get ("DOTNET_ROOT" , None )
19+ @property
20+ def dotnet_root (self ):
21+ return self ._dotnet_root
1822
19- if not dotnet_root and sys .platform == "win32" :
20- # On Windows, the host library is stored separately from dotnet.exe for x86
21- if sys .maxsize > 2 ** 32 :
22- possible_root = os .path .join (os .environ .get ("ProgramFiles" ), "dotnet" )
23- else :
24- possible_root = os .path .join (
25- os .environ .get ("ProgramFiles(x86)" ), "dotnet"
26- )
23+ @property
24+ def is_finalized (self ):
25+ return self ._is_finalized
2726
28- if os .path .isdir (possible_root ):
29- dotnet_root = possible_root
27+ def __getitem__ (self , key : str ) -> str :
28+ buf = ffi .new ("char_t**" )
29+ res = self ._dll .hostfxr_get_runtime_property_value (
30+ self ._handle , encode (key ), buf
31+ )
32+ if res != 0 :
33+ raise KeyError (key )
3034
31- if not dotnet_root :
32- dotnet_path = shutil .which ("dotnet" )
33- if not dotnet_path :
34- raise RuntimeError ("Can not determine dotnet root" )
35+ return decode (buf [0 ])
3536
36- try :
37- # Pypy does not provide os.readlink right now
38- if hasattr (os , "readlink" ):
39- dotnet_tmp_path = os .readlink (dotnet_path )
40- else :
41- dotnet_tmp_path = dotnet_path
37+ def __setitem__ (self , key : str , value : str ) -> None :
38+ if self .is_finalized :
39+ raise RuntimeError ("Already finalized" )
4240
43- if os .path .isabs (dotnet_tmp_path ):
44- dotnet_path = dotnet_tmp_path
45- else :
46- dotnet_path = os .path .abspath (
47- os .path .join (os .path .dirname (dotnet_path ), dotnet_tmp_path )
48- )
49- except OSError :
50- pass
41+ res = self ._dll .hostfxr_set_runtime_property_value (
42+ self ._handle , encode (key ), encode (value )
43+ )
44+ check_result (res )
5145
52- dotnet_root = os .path .dirname (dotnet_path )
46+ def __iter__ (self ):
47+ max_size = 100
48+ size_ptr = ffi .new ("size_t*" )
49+ size_ptr [0 ] = max_size
5350
54- self . _dll = load_hostfxr ( dotnet_root )
55- self . _dotnet_root = dotnet_root
51+ keys_ptr = ffi . new ( "char_t*[]" , max_size )
52+ values_ptr = ffi . new ( "char_t*[]" , max_size )
5653
57- self ._handle = _get_handle (self ._dll , self ._dotnet_root , runtime_config )
58- self ._load_func = _get_load_func (self ._dll , self ._handle )
54+ res = self ._fxr ._dll .hostfxr_get_runtime_properties (
55+ self ._fxr ._handle , size_ptr , keys_ptr , values_ptr
56+ )
57+ check_result (res )
58+
59+ for i in range (size_ptr [0 ]):
60+ yield (decode (keys_ptr [i ]), decode (values_ptr [i ]))
5961
6062 def get_callable (self , assembly_path , typename , function ):
63+ # TODO: Maybe use coreclr_get_delegate as well, supported with newer API
64+ # versions of hostfxr
65+ self ._is_finalized = True
66+
6167 # Append assembly name to typename
6268 assembly_name , _ = os .path .splitext (os .path .basename (assembly_path ))
6369 typename = f"{ typename } , { assembly_name } "
@@ -82,47 +88,6 @@ def shutdown(self):
8288 def __del__ (self ):
8389 self .shutdown ()
8490
85- @property
86- def props (self ):
87- return HostFxrProps (self )
88-
89-
90- class HostFxrProps :
91- def __init__ (self , fxr ):
92- self ._fxr = fxr
93-
94- def __getitem__ (self , key ):
95- buf = ffi .new ("char_t**" )
96- res = self ._fxr ._dll .hostfxr_get_runtime_property_value (
97- self ._fxr ._handle , encode (key ), buf
98- )
99- if res != 0 :
100- raise KeyError (key )
101-
102- return decode (buf [0 ])
103-
104- def __setitem__ (self , key , value ):
105- res = self ._fxr ._dll .hostfxr_set_runtime_property_value (
106- self ._fxr ._handle , encode (key ), encode (value )
107- )
108- check_result (res )
109-
110- def __iter__ (self ):
111- max_size = 100
112- size_ptr = ffi .new ("size_t*" )
113- size_ptr [0 ] = max_size
114-
115- keys_ptr = ffi .new ("char_t*[]" , max_size )
116- values_ptr = ffi .new ("char_t*[]" , max_size )
117-
118- res = self ._fxr ._dll .hostfxr_get_runtime_properties (
119- self ._fxr ._handle , size_ptr , keys_ptr , values_ptr
120- )
121- check_result (res )
122-
123- for i in range (size_ptr [0 ]):
124- yield (decode (keys_ptr [i ]), decode (values_ptr [i ]))
125-
12691
12792def _get_handle (dll , dotnet_root , runtime_config ):
12893 params = ffi .new ("hostfxr_initialize_parameters*" )
0 commit comments