11
11
from typing import *
12
12
13
13
import onlinejudge_verify .languages .special_comments as special_comments
14
+ from onlinejudge_verify .config import get_config
14
15
from onlinejudge_verify .languages .models import Language , LanguageEnvironment
15
16
16
17
logger = getLogger (__name__ )
17
18
18
19
20
+ @overload
21
+ def check_output (command : List [str ], * , text : Literal [True ]) -> str :
22
+ ...
23
+
24
+
25
+ @overload
26
+ def check_output (command : List [str ], * , text : Literal [False ]) -> bytes :
27
+ ...
28
+
29
+
30
+ @overload
31
+ def check_output (command : List [str ]) -> bytes :
32
+ ...
33
+
34
+
35
+ def check_output (command : List [str ], * , text : bool = False ) -> Union [bytes , str ]:
36
+ try :
37
+ return subprocess .check_output (command , text = text )
38
+ except (subprocess .CalledProcessError ) as e :
39
+ logger .error ('raise subprocess.CalledProcessError' )
40
+ logger .info (' stdout: %s' , e .stdout )
41
+ logger .info (' stderr: %s' , e .stderr )
42
+ raise
43
+
44
+
19
45
@functools .lru_cache (maxsize = 1 )
20
46
def _check_dotnet_version () -> None :
21
47
if not shutil .which ('dotnet' ):
22
48
raise RuntimeError ('`dotnet` not in $PATH' )
23
49
command = ['dotnet' , '--version' ]
24
50
logger .info ('$ %s' , ' ' .join (command ))
25
- res = subprocess . check_output (command , text = True ).strip ()
51
+ res = check_output (command , text = True ).strip ()
26
52
logger .info ('dotnet version: %s' , res )
27
53
if distutils .version .LooseVersion (res ) <= distutils .version .LooseVersion ("6" ):
28
54
raise RuntimeError ("oj-verify needs .NET 6 SDK or newer" )
@@ -34,7 +60,7 @@ def _check_expander_console() -> None:
34
60
raise RuntimeError ('`dotnet-source-expand` not in $PATH. Run `dotnet tool install -g SourceExpander.Console`' )
35
61
command = ['dotnet-source-expand' , 'version' ]
36
62
logger .info ('$ %s' , ' ' .join (command ))
37
- res = subprocess . check_output (command , text = True ).strip ()
63
+ res = check_output (command , text = True ).strip ()
38
64
logger .info ('dotnet-source-expand version: %s' , res )
39
65
if distutils .version .LooseVersion (res ) < distutils .version .LooseVersion ("5" ):
40
66
raise RuntimeError ('`dotnet-source-expand` version must be 5.0.0 or newer. Update SourceExpander.Console. `dotnet tool update -g SourceExpander.Console`' )
@@ -63,7 +89,7 @@ def enumerate_library(lines: List[str]):
63
89
if len (sp ) >= 2 :
64
90
yield EmbeddedLibrary (sp [0 ], sp [1 ])
65
91
66
- res = list (enumerate_library (subprocess . check_output (command , encoding = 'utf-8' ).strip ().splitlines ()))
92
+ res = list (enumerate_library (check_output (command , text = True ).strip ().splitlines ()))
67
93
logger .debug ('libraries: %s' , res )
68
94
return res
69
95
@@ -72,7 +98,7 @@ def enumerate_library(lines: List[str]):
72
98
def _check_embedded_existing (csproj_path : pathlib .Path ) -> None :
73
99
command = ['dotnet' , 'build' , str (csproj_path )]
74
100
logger .info ('$ %s' , ' ' .join (command ))
75
- subprocess . check_output (command )
101
+ check_output (command )
76
102
l = _list_embedded (csproj_path )
77
103
if len (l ) == 0 :
78
104
raise RuntimeError ('Library needs SourceExpander.Embedder' )
@@ -106,24 +132,6 @@ def _resolve_csproj(path: pathlib.Path) -> Optional[pathlib.Path]:
106
132
return _resolve_csproj (path .parent )
107
133
108
134
109
- @functools .lru_cache (maxsize = None )
110
- def _expand_code_dict (csproj_path : pathlib .Path ) -> Dict [pathlib .Path , str ]:
111
- _check_expander_console ()
112
- command = ['dotnet-source-expand' , 'expand-all' , str (csproj_path )]
113
- logger .info ('$ %s' , ' ' .join (command ))
114
- json_res = subprocess .check_output (command )
115
- return {pathlib .Path (t ['FilePath' ]): t ['ExpandedCode' ] for t in json .loads (json_res )}
116
-
117
-
118
- @functools .lru_cache (maxsize = None )
119
- def _expand_code (path : pathlib .Path ) -> bytes :
120
- _check_expander_console ()
121
- csproj_path = _resolve_csproj (path )
122
- _check_no_embedder (csproj_path )
123
- d = _expand_code_dict (csproj_path )
124
- return d [path ].encode ('utf-8' )
125
-
126
-
127
135
class DependencyInfo :
128
136
def __init__ (self , filename : str , dependencies : List [str ], typenames : Set [str ]) -> None :
129
137
self .filename = filename
@@ -143,7 +151,7 @@ def _dependency_info_list(csproj_path: pathlib.Path) -> List[DependencyInfo]:
143
151
144
152
command = ['dotnet-source-expand' , 'dependency' , '-p' , str (csproj_path )]
145
153
logger .info ('$ %s' , ' ' .join (command ))
146
- res = subprocess . check_output (command )
154
+ res = check_output (command )
147
155
return json .loads (res , object_hook = lambda d : DependencyInfo (d ['FileName' ], d ['Dependencies' ], set (d ['TypeNames' ])))
148
156
149
157
@@ -173,7 +181,17 @@ def _get_target_framework(csproj_path: pathlib.Path) -> str:
173
181
return target
174
182
175
183
184
+ class CSharpConfig :
185
+ def __init__ (self , config : Dict [str , Any ]) -> None :
186
+ root = config .get ('languages' , {}).get ('csharp' , {})
187
+ self .static_embedding : Optional [str ] = root .get ('static_embedding' , None )
188
+
189
+
176
190
class CSharpLanguageEnvironment (LanguageEnvironment ):
191
+ def __init__ (self , config : CSharpConfig ) -> None :
192
+ super ().__init__ ()
193
+ self .config = config
194
+
177
195
@staticmethod
178
196
def _create_runner_project (code : bytes , target_framework : str , output_dir ):
179
197
os .makedirs (str (output_dir ), exist_ok = True )
@@ -194,11 +212,11 @@ def compile(self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib
194
212
_check_env (path )
195
213
target_framework = _get_target_framework (_resolve_csproj (path ))
196
214
logger .info ('build: TargetFramework = %s' , target_framework )
197
- self ._create_runner_project (_expand_code (path ), target_framework , output_dir )
215
+ self ._create_runner_project (self . _expand_code (path ), target_framework , output_dir )
198
216
199
217
command = ['dotnet' , 'build' , str (output_dir / 'runner.csproj' ), '-c' , 'Release' , '-o' , str (output_dir / 'bin' )]
200
218
logger .info ('$ %s' , ' ' .join (command ))
201
- subprocess . check_output (command )
219
+ check_output (command )
202
220
203
221
def get_execute_command (self , path : pathlib .Path , * , basedir : pathlib .Path , tempdir : pathlib .Path ) -> List [str ]:
204
222
path = path .resolve ()
@@ -207,8 +225,31 @@ def get_execute_command(self, path: pathlib.Path, *, basedir: pathlib.Path, temp
207
225
_check_env (path )
208
226
return [str (output_dir / 'bin' / 'runner' )]
209
227
228
+ @functools .lru_cache (maxsize = None )
229
+ def _expand_code_dict (self , csproj_path : pathlib .Path ) -> Dict [pathlib .Path , str ]:
230
+ _check_expander_console ()
231
+ command = ['dotnet-source-expand' , 'expand-all' , str (csproj_path )]
232
+ if self .config .static_embedding :
233
+ command .extend (['--static-embedding' , self .config .static_embedding ])
234
+ logger .info ('$ %s' , ' ' .join (command ))
235
+ json_res = check_output (command )
236
+ return {pathlib .Path (t ['FilePath' ]): t ['ExpandedCode' ] for t in json .loads (json_res )}
237
+
238
+ @functools .lru_cache (maxsize = None )
239
+ def _expand_code (self , path : pathlib .Path ) -> bytes :
240
+ _check_expander_console ()
241
+ csproj_path = _resolve_csproj (path )
242
+ _check_no_embedder (csproj_path )
243
+ d = self ._expand_code_dict (csproj_path )
244
+ return d [path ].encode ('utf-8' )
245
+
210
246
211
247
class CSharpLanguage (Language ):
248
+ def __init__ (self ) -> None :
249
+ super ().__init__ ()
250
+ self .config = CSharpConfig (get_config ())
251
+ self .environment = CSharpLanguageEnvironment (self .config )
252
+
212
253
def list_attributes (self , path : pathlib .Path , * , basedir : pathlib .Path ) -> Dict [str , Any ]:
213
254
path = path .resolve ()
214
255
attributes : Dict [str , Any ] = special_comments .list_special_comments (path )
@@ -224,7 +265,7 @@ def list_dependencies(self, path: pathlib.Path, *, basedir: pathlib.Path) -> Lis
224
265
def bundle (self , path : pathlib .Path , * , basedir : pathlib .Path , options : Dict [str , Any ]) -> bytes :
225
266
path = path .resolve ()
226
267
_check_env (path )
227
- return _expand_code (path )
268
+ return self . environment . _expands_code (path , self . config . static_embedding )
228
269
229
270
def list_environments (self , path : pathlib .Path , * , basedir : pathlib .Path ) -> Sequence [CSharpLanguageEnvironment ]:
230
- return [CSharpLanguageEnvironment () ]
271
+ return [self . environment ]
0 commit comments