Skip to content

Commit 4a13c59

Browse files
committed
Add config
1 parent c41c5a7 commit 4a13c59

File tree

3 files changed

+85
-38
lines changed

3 files changed

+85
-38
lines changed

.verify-helper/docs/static/document.ja.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ CXXFLAGS = ["-std=c++17", "-Wall", "-g", "-fsanitize=undefined", "-D_GLIBCXX_DEB
4343

4444
### C# の設定
4545

46-
設定項目はありません。
47-
4846
[SourceExpander](https://github.com/kzrnm/SourceExpander) を使用して各種機能を実現します。
4947

5048
必須設定
@@ -54,6 +52,15 @@ CXXFLAGS = ["-std=c++17", "-Wall", "-g", "-fsanitize=undefined", "-D_GLIBCXX_DEB
5452

5553
具体的な設定は [examples/csharpsx](https://github.com/online-judge-tools/verification-helper/tree/master/examples/csharpsx) を参照。
5654

55+
56+
`.verify-helper/config.toml` というファイルを作って以下のように設定を書くと各種設定ができます。
57+
58+
- static_embedding: `dotnet-source-expand``--static-embedding` オプション
59+
60+
``` toml
61+
[[languages.csharp]]
62+
static_embedding = "// embed"
63+
```
5764
### Nim の設定
5865

5966
`.verify-helper/config.toml` というファイルを作って以下のように設定を書くと、コンパイルの際に変換する言語 (例: `c`, `cpp`) やそのオプションを指定できます。

.verify-helper/docs/static/document.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,6 @@ There is no config now.
4343

4444
### Settings for C#
4545

46-
There is no config now.
47-
4846
`oj-verify` and `oj-bundle` work with [SourceExpander](https://github.com/kzrnm/SourceExpander).
4947

5048
Requied settings
@@ -54,6 +52,15 @@ Requied settings
5452

5553
For the details refer to [examples/csharpsx](https://github.com/online-judge-tools/verification-helper/tree/master/examples/csharpsx).
5654

55+
You can specify compilers and options with writing `.verify-helper/config.toml` as below.
56+
57+
- static_embedding: `dotnet-source-expand` with `--static-embedding` option
58+
59+
``` toml
60+
[[languages.csharp]]
61+
static_embedding = "// embed"
62+
```
63+
5764
### Settings for Nim
5865

5966
You can specify options and targets (e.g. `c` `cpp`) with writing `.verify-helper/config.toml` as below.

onlinejudge_verify/languages/csharp.py

Lines changed: 67 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,44 @@
1111
from typing import *
1212

1313
import onlinejudge_verify.languages.special_comments as special_comments
14+
from onlinejudge_verify.config import get_config
1415
from onlinejudge_verify.languages.models import Language, LanguageEnvironment
1516

1617
logger = 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)
2046
def _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]):
7298
def _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')
@@ -84,13 +110,6 @@ def _check_env(path: pathlib.Path):
84110
_check_embedded_existing(_resolve_csproj(path))
85111

86112

87-
@functools.lru_cache(maxsize=None)
88-
def _check_no_embedder(csproj_path: pathlib.Path) -> None:
89-
root = ET.parse(csproj_path).getroot()
90-
if root.find('.//PackageReference[@Include="SourceExpander.Embedder"]'):
91-
logger.error(" Test project(%s) has `SourceExpander.Embedder` reference. Libraries and tests should not be in same project.", str(csproj_path))
92-
93-
94113
@functools.lru_cache(maxsize=None)
95114
def _resolve_csproj(path: pathlib.Path) -> Optional[pathlib.Path]:
96115
path = path.resolve()
@@ -106,24 +125,6 @@ def _resolve_csproj(path: pathlib.Path) -> Optional[pathlib.Path]:
106125
return _resolve_csproj(path.parent)
107126

108127

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-
127128
class DependencyInfo:
128129
def __init__(self, filename: str, dependencies: List[str], typenames: Set[str]) -> None:
129130
self.filename = filename
@@ -143,7 +144,7 @@ def _dependency_info_list(csproj_path: pathlib.Path) -> List[DependencyInfo]:
143144

144145
command = ['dotnet-source-expand', 'dependency', '-p', str(csproj_path)]
145146
logger.info('$ %s', ' '.join(command))
146-
res = subprocess.check_output(command)
147+
res = check_output(command)
147148
return json.loads(res, object_hook=lambda d: DependencyInfo(d['FileName'], d['Dependencies'], set(d['TypeNames'])))
148149

149150

@@ -173,7 +174,17 @@ def _get_target_framework(csproj_path: pathlib.Path) -> str:
173174
return target
174175

175176

177+
class CSharpConfig:
178+
def __init__(self, config: Dict[str, Any]) -> None:
179+
root = config.get('languages', {}).get('csharp', {})
180+
self.static_embedding: Optional[str] = root.get('static_embedding', None)
181+
182+
176183
class CSharpLanguageEnvironment(LanguageEnvironment):
184+
def __init__(self, config: CSharpConfig) -> None:
185+
super().__init__()
186+
self.config = config
187+
177188
@staticmethod
178189
def _create_runner_project(code: bytes, target_framework: str, output_dir):
179190
os.makedirs(str(output_dir), exist_ok=True)
@@ -194,11 +205,11 @@ def compile(self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib
194205
_check_env(path)
195206
target_framework = _get_target_framework(_resolve_csproj(path))
196207
logger.info('build: TargetFramework = %s', target_framework)
197-
self._create_runner_project(_expand_code(path), target_framework, output_dir)
208+
self._create_runner_project(self._expand_code(path), target_framework, output_dir)
198209

199210
command = ['dotnet', 'build', str(output_dir / 'runner.csproj'), '-c', 'Release', '-o', str(output_dir / 'bin')]
200211
logger.info('$ %s', ' '.join(command))
201-
subprocess.check_output(command)
212+
check_output(command)
202213

203214
def get_execute_command(self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib.Path) -> List[str]:
204215
path = path.resolve()
@@ -207,8 +218,30 @@ def get_execute_command(self, path: pathlib.Path, *, basedir: pathlib.Path, temp
207218
_check_env(path)
208219
return [str(output_dir / 'bin' / 'runner')]
209220

221+
@functools.lru_cache(maxsize=None)
222+
def _expand_code_dict(self, csproj_path: pathlib.Path) -> Dict[pathlib.Path, str]:
223+
_check_expander_console()
224+
command = ['dotnet-source-expand', 'expand-all', str(csproj_path)]
225+
if self.config.static_embedding:
226+
command.extend(['--static-embedding', self.config.static_embedding])
227+
logger.info('$ %s', ' '.join(command))
228+
json_res = check_output(command)
229+
return {pathlib.Path(t['FilePath']): t['ExpandedCode'] for t in json.loads(json_res)}
230+
231+
@functools.lru_cache(maxsize=None)
232+
def _expand_code(self, path: pathlib.Path) -> bytes:
233+
_check_expander_console()
234+
csproj_path = _resolve_csproj(path)
235+
d = self._expand_code_dict(csproj_path)
236+
return d[path].encode('utf-8')
237+
210238

211239
class CSharpLanguage(Language):
240+
def __init__(self) -> None:
241+
super().__init__()
242+
self.config = CSharpConfig(get_config())
243+
self.environment = CSharpLanguageEnvironment(self.config)
244+
212245
def list_attributes(self, path: pathlib.Path, *, basedir: pathlib.Path) -> Dict[str, Any]:
213246
path = path.resolve()
214247
attributes: Dict[str, Any] = special_comments.list_special_comments(path)
@@ -224,7 +257,7 @@ def list_dependencies(self, path: pathlib.Path, *, basedir: pathlib.Path) -> Lis
224257
def bundle(self, path: pathlib.Path, *, basedir: pathlib.Path, options: Dict[str, Any]) -> bytes:
225258
path = path.resolve()
226259
_check_env(path)
227-
return _expand_code(path)
260+
return self.environment._expand_code(path)
228261

229262
def list_environments(self, path: pathlib.Path, *, basedir: pathlib.Path) -> Sequence[CSharpLanguageEnvironment]:
230-
return [CSharpLanguageEnvironment()]
263+
return [self.environment]

0 commit comments

Comments
 (0)