1111from typing import *
1212
1313import onlinejudge_verify .languages .special_comments as special_comments
14+ from onlinejudge_verify .config import get_config
1415from onlinejudge_verify .languages .models import Language , LanguageEnvironment
1516
1617logger = getLogger (__name__ )
1718
1819
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+
1945@functools .lru_cache (maxsize = 1 )
2046def _check_dotnet_version () -> None :
2147 if not shutil .which ('dotnet' ):
2248 raise RuntimeError ('`dotnet` not in $PATH' )
2349 command = ['dotnet' , '--version' ]
2450 logger .info ('$ %s' , ' ' .join (command ))
25- res = subprocess . check_output (command , text = True ).strip ()
51+ res = check_output (command , text = True ).strip ()
2652 logger .info ('dotnet version: %s' , res )
2753 if distutils .version .LooseVersion (res ) <= distutils .version .LooseVersion ("6" ):
2854 raise RuntimeError ("oj-verify needs .NET 6 SDK or newer" )
@@ -34,7 +60,7 @@ def _check_expander_console() -> None:
3460 raise RuntimeError ('`dotnet-source-expand` not in $PATH. Run `dotnet tool install -g SourceExpander.Console`' )
3561 command = ['dotnet-source-expand' , 'version' ]
3662 logger .info ('$ %s' , ' ' .join (command ))
37- res = subprocess . check_output (command , text = True ).strip ()
63+ res = check_output (command , text = True ).strip ()
3864 logger .info ('dotnet-source-expand version: %s' , res )
3965 if distutils .version .LooseVersion (res ) < distutils .version .LooseVersion ("5" ):
4066 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]):
6389 if len (sp ) >= 2 :
6490 yield EmbeddedLibrary (sp [0 ], sp [1 ])
6591
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 ()))
6793 logger .debug ('libraries: %s' , res )
6894 return res
6995
@@ -72,7 +98,7 @@ def enumerate_library(lines: List[str]):
7298def _check_embedded_existing (csproj_path : pathlib .Path ) -> None :
7399 command = ['dotnet' , 'build' , str (csproj_path )]
74100 logger .info ('$ %s' , ' ' .join (command ))
75- subprocess . check_output (command )
101+ check_output (command )
76102 l = _list_embedded (csproj_path )
77103 if len (l ) == 0 :
78104 raise RuntimeError ('Library needs SourceExpander.Embedder' )
@@ -106,24 +132,6 @@ def _resolve_csproj(path: pathlib.Path) -> Optional[pathlib.Path]:
106132 return _resolve_csproj (path .parent )
107133
108134
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-
127135class DependencyInfo :
128136 def __init__ (self , filename : str , dependencies : List [str ], typenames : Set [str ]) -> None :
129137 self .filename = filename
@@ -143,7 +151,7 @@ def _dependency_info_list(csproj_path: pathlib.Path) -> List[DependencyInfo]:
143151
144152 command = ['dotnet-source-expand' , 'dependency' , '-p' , str (csproj_path )]
145153 logger .info ('$ %s' , ' ' .join (command ))
146- res = subprocess . check_output (command )
154+ res = check_output (command )
147155 return json .loads (res , object_hook = lambda d : DependencyInfo (d ['FileName' ], d ['Dependencies' ], set (d ['TypeNames' ])))
148156
149157
@@ -173,7 +181,17 @@ def _get_target_framework(csproj_path: pathlib.Path) -> str:
173181 return target
174182
175183
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+
176190class CSharpLanguageEnvironment (LanguageEnvironment ):
191+ def __init__ (self , config : CSharpConfig ) -> None :
192+ super ().__init__ ()
193+ self .config = config
194+
177195 @staticmethod
178196 def _create_runner_project (code : bytes , target_framework : str , output_dir ):
179197 os .makedirs (str (output_dir ), exist_ok = True )
@@ -194,11 +212,11 @@ def compile(self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib
194212 _check_env (path )
195213 target_framework = _get_target_framework (_resolve_csproj (path ))
196214 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 )
198216
199217 command = ['dotnet' , 'build' , str (output_dir / 'runner.csproj' ), '-c' , 'Release' , '-o' , str (output_dir / 'bin' )]
200218 logger .info ('$ %s' , ' ' .join (command ))
201- subprocess . check_output (command )
219+ check_output (command )
202220
203221 def get_execute_command (self , path : pathlib .Path , * , basedir : pathlib .Path , tempdir : pathlib .Path ) -> List [str ]:
204222 path = path .resolve ()
@@ -207,8 +225,31 @@ def get_execute_command(self, path: pathlib.Path, *, basedir: pathlib.Path, temp
207225 _check_env (path )
208226 return [str (output_dir / 'bin' / 'runner' )]
209227
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+
210246
211247class CSharpLanguage (Language ):
248+ def __init__ (self ) -> None :
249+ super ().__init__ ()
250+ self .config = CSharpConfig (get_config ())
251+ self .environment = CSharpLanguageEnvironment (self .config )
252+
212253 def list_attributes (self , path : pathlib .Path , * , basedir : pathlib .Path ) -> Dict [str , Any ]:
213254 path = path .resolve ()
214255 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
224265 def bundle (self , path : pathlib .Path , * , basedir : pathlib .Path , options : Dict [str , Any ]) -> bytes :
225266 path = path .resolve ()
226267 _check_env (path )
227- return _expand_code (path )
268+ return self . environment . _expand_code (path )
228269
229270 def list_environments (self , path : pathlib .Path , * , basedir : pathlib .Path ) -> Sequence [CSharpLanguageEnvironment ]:
230- return [CSharpLanguageEnvironment () ]
271+ return [self . environment ]
0 commit comments