Skip to content

Commit

Permalink
Add config
Browse files Browse the repository at this point in the history
  • Loading branch information
kzrnm committed Mar 17, 2022
1 parent 12ff5f4 commit d57f765
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 31 deletions.
13 changes: 11 additions & 2 deletions .verify-helper/docs/static/document.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ CXXFLAGS = ["-std=c++17", "-Wall", "-g", "-fsanitize=undefined", "-D_GLIBCXX_DEB

### C# の設定

設定項目はありません。

[SourceExpander](https://github.com/kzrnm/SourceExpander) を使用して各種機能を実現します。

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

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


`.verify-helper/config.toml` というファイルを作って以下のように設定を書くと各種設定ができます。

- static_embedding: `dotnet-source-expand``--static-embedding` オプション
- enable_bundle_projects: `bundle` が正常に動作する `csproj`

``` toml
[[languages.csharp]]
static_embedding = "// embed"
enable_bundle_projects = ["examples/csharpsx/Tests/Tests.csproj"]
```
### Nim の設定

`.verify-helper/config.toml` というファイルを作って以下のように設定を書くと、コンパイルの際に変換する言語 (例: `c`, `cpp`) やそのオプションを指定できます。
Expand Down
13 changes: 11 additions & 2 deletions .verify-helper/docs/static/document.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ There is no config now.

### Settings for C#

There is no config now.

`oj-verify` and `oj-bundle` work with [SourceExpander](https://github.com/kzrnm/SourceExpander).

Requied settings
Expand All @@ -54,6 +52,17 @@ Requied settings

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

You can specify compilers and options with writing `.verify-helper/config.toml` as below.

- static_embedding: `dotnet-source-expand` with `--static-embedding` option
- enable_bundle_projects: List of `csproj` file that `bundle` work correctly.

``` toml
[[languages.csharp]]
static_embedding = "// embed"
enable_bundle_projects = ["examples/csharpsx/Tests/Tests.csproj"]
```

### Settings for Nim

You can specify options and targets (e.g. `c` `cpp`) with writing `.verify-helper/config.toml` as below.
Expand Down
95 changes: 68 additions & 27 deletions onlinejudge_verify/languages/csharp.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,44 @@
from typing import *

import onlinejudge_verify.languages.special_comments as special_comments
from onlinejudge_verify.config import get_config
from onlinejudge_verify.languages.models import Language, LanguageEnvironment

logger = getLogger(__name__)


@overload
def check_output(command: List[str], *, text: Literal[True]) -> str:
...


@overload
def check_output(command: List[str], *, text: Literal[False]) -> bytes:
...


@overload
def check_output(command: List[str]) -> bytes:
...


def check_output(command: List[str], *, text: bool = False) -> Union[bytes, str]:
try:
return subprocess.check_output(command, text=text)
except (subprocess.CalledProcessError) as e:
logger.error('raise subprocess.CalledProcessError')
logger.info(' stdout: %s', e.stdout)
logger.info(' stderr: %s', e.stderr)
raise


@functools.lru_cache(maxsize=1)
def _check_dotnet_version() -> None:
if not shutil.which('dotnet'):
raise RuntimeError('`dotnet` not in $PATH')
command = ['dotnet', '--version']
logger.info('$ %s', ' '.join(command))
res = subprocess.check_output(command, text=True).strip()
res = check_output(command, text=True).strip()
logger.info('dotnet version: %s', res)
if distutils.version.LooseVersion(res) <= distutils.version.LooseVersion("6"):
raise RuntimeError("oj-verify needs .NET 6 SDK or newer")
Expand All @@ -34,7 +60,7 @@ def _check_expander_console() -> None:
raise RuntimeError('`dotnet-source-expand` not in $PATH. Run `dotnet tool install -g SourceExpander.Console`')
command = ['dotnet-source-expand', 'version']
logger.info('$ %s', ' '.join(command))
res = subprocess.check_output(command, text=True).strip()
res = check_output(command, text=True).strip()
logger.info('dotnet-source-expand version: %s', res)
if distutils.version.LooseVersion(res) < distutils.version.LooseVersion("5"):
raise RuntimeError('`dotnet-source-expand` version must be 5.0.0 or newer. Update SourceExpander.Console. `dotnet tool update -g SourceExpander.Console`')
Expand Down Expand Up @@ -63,7 +89,7 @@ def enumerate_library(lines: List[str]):
if len(sp) >= 2:
yield EmbeddedLibrary(sp[0], sp[1])

res = list(enumerate_library(subprocess.check_output(command, encoding='utf-8').strip().splitlines()))
res = list(enumerate_library(check_output(command, text=True).strip().splitlines()))
logger.debug('libraries: %s', res)
return res

Expand All @@ -72,7 +98,7 @@ def enumerate_library(lines: List[str]):
def _check_embedded_existing(csproj_path: pathlib.Path) -> None:
command = ['dotnet', 'build', str(csproj_path)]
logger.info('$ %s', ' '.join(command))
subprocess.check_output(command)
check_output(command)
l = _list_embedded(csproj_path)
if len(l) == 0:
raise RuntimeError('Library needs SourceExpander.Embedder')
Expand Down Expand Up @@ -106,24 +132,6 @@ def _resolve_csproj(path: pathlib.Path) -> Optional[pathlib.Path]:
return _resolve_csproj(path.parent)


@functools.lru_cache(maxsize=None)
def _expand_code_dict(csproj_path: pathlib.Path) -> Dict[pathlib.Path, str]:
_check_expander_console()
command = ['dotnet-source-expand', 'expand-all', str(csproj_path)]
logger.info('$ %s', ' '.join(command))
json_res = subprocess.check_output(command)
return {pathlib.Path(t['FilePath']): t['ExpandedCode'] for t in json.loads(json_res)}


@functools.lru_cache(maxsize=None)
def _expand_code(path: pathlib.Path) -> bytes:
_check_expander_console()
csproj_path = _resolve_csproj(path)
_check_no_embedder(csproj_path)
d = _expand_code_dict(csproj_path)
return d[path].encode('utf-8')


class DependencyInfo:
def __init__(self, filename: str, dependencies: List[str], typenames: Set[str]) -> None:
self.filename = filename
Expand All @@ -143,7 +151,7 @@ def _dependency_info_list(csproj_path: pathlib.Path) -> List[DependencyInfo]:

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


Expand Down Expand Up @@ -173,7 +181,17 @@ def _get_target_framework(csproj_path: pathlib.Path) -> str:
return target


class CSharpConfig:
def __init__(self, config: Dict[str, Any]) -> None:
root = config.get('languages', {}).get('csharp', {})
self.static_embedding: Optional[str] = root.get('static_embedding', None)


class CSharpLanguageEnvironment(LanguageEnvironment):
def __init__(self, config: CSharpConfig) -> None:
super().__init__()
self.config = config

@staticmethod
def _create_runner_project(code: bytes, target_framework: str, output_dir):
os.makedirs(str(output_dir), exist_ok=True)
Expand All @@ -194,11 +212,11 @@ def compile(self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib
_check_env(path)
target_framework = _get_target_framework(_resolve_csproj(path))
logger.info('build: TargetFramework = %s', target_framework)
self._create_runner_project(_expand_code(path), target_framework, output_dir)
self._create_runner_project(self._expand_code(path, self.config.static_embedding), target_framework, output_dir)

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

def get_execute_command(self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib.Path) -> List[str]:
path = path.resolve()
Expand All @@ -207,8 +225,31 @@ def get_execute_command(self, path: pathlib.Path, *, basedir: pathlib.Path, temp
_check_env(path)
return [str(output_dir / 'bin' / 'runner')]

@functools.lru_cache(maxsize=None)
def _expand_code_dict(self, csproj_path: pathlib.Path) -> Dict[pathlib.Path, str]:
_check_expander_console()
command = ['dotnet-source-expand', 'expand-all', str(csproj_path)]
if self.static_embedding:
command.extend(['--static-embedding', self.static_embedding])
logger.info('$ %s', ' '.join(command))
json_res = check_output(command)
return {pathlib.Path(t['FilePath']): t['ExpandedCode'] for t in json.loads(json_res)}

@functools.lru_cache(maxsize=None)
def _expand_code(self, path: pathlib.Path) -> bytes:
_check_expander_console()
csproj_path = _resolve_csproj(path)
_check_no_embedder(csproj_path)
d = self._expand_code_dict(csproj_path)
return d[path].encode('utf-8')


class CSharpLanguage(Language):
def __init__(self) -> None:
super().__init__()
self.config = CSharpConfig(get_config())
self.environment = CSharpLanguageEnvironment(self.config)

def list_attributes(self, path: pathlib.Path, *, basedir: pathlib.Path) -> Dict[str, Any]:
path = path.resolve()
attributes: Dict[str, Any] = special_comments.list_special_comments(path)
Expand All @@ -224,7 +265,7 @@ def list_dependencies(self, path: pathlib.Path, *, basedir: pathlib.Path) -> Lis
def bundle(self, path: pathlib.Path, *, basedir: pathlib.Path, options: Dict[str, Any]) -> bytes:
path = path.resolve()
_check_env(path)
return _expand_code(path)
return self.environment._expands_code(path, self.config.static_embedding)

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

0 comments on commit d57f765

Please sign in to comment.