1
- import os
2
1
import sys
2
+ from pathlib import Path
3
+ from typing import Generator , Tuple
3
4
4
5
from .ffi import ffi , load_hostfxr
5
- from .util import check_result , find_dotnet_root
6
+ from .types import Runtime , RuntimeInfo , StrOrPath
7
+ from .util import check_result
6
8
7
9
__all__ = ["DotnetCoreRuntime" ]
8
10
11
+ _IS_SHUTDOWN = False
9
12
10
- class DotnetCoreRuntime :
11
- def __init__ (self , runtime_config : str , dotnet_root : str ):
12
- self ._dotnet_root = dotnet_root or find_dotnet_root ()
13
+
14
+ class DotnetCoreRuntime (Runtime ):
15
+ def __init__ (self , runtime_config : Path , dotnet_root : Path , ** params : str ):
16
+ if _IS_SHUTDOWN :
17
+ raise RuntimeError ("Runtime can not be reinitialized" )
18
+
19
+ self ._dotnet_root = Path (dotnet_root )
13
20
self ._dll = load_hostfxr (self ._dotnet_root )
14
- self ._is_finalized = False
21
+ self ._is_initialized = False
15
22
self ._handle = _get_handle (self ._dll , self ._dotnet_root , runtime_config )
16
23
self ._load_func = _get_load_func (self ._dll , self ._handle )
17
24
25
+ for key , value in params .items ():
26
+ self [key ] = value
27
+
28
+ # TODO: Get version
29
+ self ._version = "<undefined>"
30
+
18
31
@property
19
- def dotnet_root (self ) -> str :
32
+ def dotnet_root (self ) -> Path :
20
33
return self ._dotnet_root
21
34
22
35
@property
23
- def is_finalized (self ) -> bool :
24
- return self ._is_finalized
36
+ def is_initialized (self ) -> bool :
37
+ return self ._is_initialized
38
+
39
+ @property
40
+ def is_shutdown (self ) -> bool :
41
+ return _IS_SHUTDOWN
25
42
26
43
def __getitem__ (self , key : str ) -> str :
44
+ if self .is_shutdown :
45
+ raise RuntimeError ("Runtime is shut down" )
27
46
buf = ffi .new ("char_t**" )
28
47
res = self ._dll .hostfxr_get_runtime_property_value (
29
48
self ._handle , encode (key ), buf
@@ -34,15 +53,17 @@ def __getitem__(self, key: str) -> str:
34
53
return decode (buf [0 ])
35
54
36
55
def __setitem__ (self , key : str , value : str ) -> None :
37
- if self .is_finalized :
38
- raise RuntimeError ("Already finalized " )
56
+ if self .is_initialized :
57
+ raise RuntimeError ("Already initialized " )
39
58
40
59
res = self ._dll .hostfxr_set_runtime_property_value (
41
60
self ._handle , encode (key ), encode (value )
42
61
)
43
62
check_result (res )
44
63
45
- def __iter__ (self ):
64
+ def __iter__ (self ) -> Generator [Tuple [str , str ], None , None ]:
65
+ if self .is_shutdown :
66
+ raise RuntimeError ("Runtime is shut down" )
46
67
max_size = 100
47
68
size_ptr = ffi .new ("size_t*" )
48
69
size_ptr [0 ] = max_size
@@ -51,25 +72,26 @@ def __iter__(self):
51
72
values_ptr = ffi .new ("char_t*[]" , max_size )
52
73
53
74
res = self ._dll .hostfxr_get_runtime_properties (
54
- self ._dll . _handle , size_ptr , keys_ptr , values_ptr
75
+ self ._handle , size_ptr , keys_ptr , values_ptr
55
76
)
56
77
check_result (res )
57
78
58
79
for i in range (size_ptr [0 ]):
59
80
yield (decode (keys_ptr [i ]), decode (values_ptr [i ]))
60
81
61
- def get_callable (self , assembly_path : str , typename : str , function : str ):
82
+ def get_callable (self , assembly_path : StrOrPath , typename : str , function : str ):
62
83
# TODO: Maybe use coreclr_get_delegate as well, supported with newer API
63
84
# versions of hostfxr
64
- self ._is_finalized = True
85
+ self ._is_initialized = True
65
86
66
87
# Append assembly name to typename
67
- assembly_name , _ = os .path .splitext (os .path .basename (assembly_path ))
88
+ assembly_path = Path (assembly_path )
89
+ assembly_name = assembly_path .stem
68
90
typename = f"{ typename } , { assembly_name } "
69
91
70
92
delegate_ptr = ffi .new ("void**" )
71
93
res = self ._load_func (
72
- encode (assembly_path ),
94
+ encode (str ( assembly_path ) ),
73
95
encode (typename ),
74
96
encode (function ),
75
97
ffi .NULL ,
@@ -79,27 +101,39 @@ def get_callable(self, assembly_path: str, typename: str, function: str):
79
101
check_result (res )
80
102
return ffi .cast ("component_entry_point_fn" , delegate_ptr [0 ])
81
103
104
+ def _check_initialized (self ) -> None :
105
+ if self ._handle is None :
106
+ raise RuntimeError ("Runtime is shut down" )
107
+ elif not self ._is_initialized :
108
+ raise RuntimeError ("Runtime is not initialized" )
109
+
82
110
def shutdown (self ) -> None :
83
111
if self ._handle is not None :
84
112
self ._dll .hostfxr_close (self ._handle )
85
113
self ._handle = None
86
114
87
- def __del__ (self ):
88
- self .shutdown ()
115
+ def info (self ):
116
+ return RuntimeInfo (
117
+ kind = "CoreCLR" ,
118
+ version = self ._version ,
119
+ initialized = self ._handle is not None ,
120
+ shutdown = self ._handle is None ,
121
+ properties = dict (self ) if not _IS_SHUTDOWN else {},
122
+ )
89
123
90
124
91
- def _get_handle (dll , dotnet_root : str , runtime_config : str ):
125
+ def _get_handle (dll , dotnet_root : StrOrPath , runtime_config : StrOrPath ):
92
126
params = ffi .new ("hostfxr_initialize_parameters*" )
93
127
params .size = ffi .sizeof ("hostfxr_initialize_parameters" )
94
128
# params.host_path = ffi.new("char_t[]", encode(sys.executable))
95
129
params .host_path = ffi .NULL
96
- dotnet_root_p = ffi .new ("char_t[]" , encode (dotnet_root ))
130
+ dotnet_root_p = ffi .new ("char_t[]" , encode (str ( Path ( dotnet_root )) ))
97
131
params .dotnet_root = dotnet_root_p
98
132
99
133
handle_ptr = ffi .new ("hostfxr_handle*" )
100
134
101
135
res = dll .hostfxr_initialize_for_runtime_config (
102
- encode (runtime_config ), params , handle_ptr
136
+ encode (str ( Path ( runtime_config )) ), params , handle_ptr
103
137
)
104
138
check_result (res )
105
139
@@ -119,16 +153,16 @@ def _get_load_func(dll, handle):
119
153
120
154
if sys .platform == "win32" :
121
155
122
- def encode (string ):
156
+ def encode (string : str ):
123
157
return string
124
158
125
- def decode (char_ptr ):
159
+ def decode (char_ptr ) -> str :
126
160
return ffi .string (char_ptr )
127
161
128
162
else :
129
163
130
- def encode (string ):
164
+ def encode (string : str ):
131
165
return string .encode ("utf8" )
132
166
133
- def decode (char_ptr ):
167
+ def decode (char_ptr ) -> str :
134
168
return ffi .string (char_ptr ).decode ("utf8" )
0 commit comments