Skip to content

Commit

Permalink
Merge pull request #46 from online-judge-tools/feature/filter
Browse files Browse the repository at this point in the history
Use external formatters
  • Loading branch information
kmyk authored Aug 27, 2020
2 parents c2d3bcf + ed6b15c commit fce8d60
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 17 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ The following template files are prepared as builtin of `oj-template` command.
- `generate.py`: random case generator in Python
- `generate.cpp`: random case generator in C++

The builtin templates invoke [`clang-format` command](https://clang.llvm.org/docs/ClangFormat.html) and [`yapf` command](https://github.com/google/yapf) when they exist.
Please install them too if you want to generate better formatted code.


### Generating random cases

Expand Down
31 changes: 22 additions & 9 deletions onlinejudge_template/generator/_main.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
import pathlib
from logging import getLogger
from typing import *

import appdirs
import mako.lookup
import mako.template
import pkg_resources

import onlinejudge_template.generator.hook as hook
from onlinejudge_template.types import *

logger = getLogger(__name__)

def run(analyzed: AnalyzerResult, *, template_file: str) -> bytes:
"""
:raises: mako.exceptions.MakoException
"""

data: Dict[str, Any] = {
'analyzed': analyzed,
'config': {},
}
def _get_template(template_file: str) -> mako.template.Template:
directories = [
str(pathlib.Path(appdirs.user_config_dir('online-judge-tools')) / 'template'),
pkg_resources.resource_filename('onlinejudge_template_resources', 'template'),
Expand All @@ -29,4 +25,21 @@ def run(analyzed: AnalyzerResult, *, template_file: str) -> bytes:
with open(path, "rb") as fh:
lookup.put_string(template_file, fh.read())
template = lookup.get_template(template_file)
return template.render(data=data)
logger.info('use template file: %s', template.filename)
return template


def run(analyzed: AnalyzerResult, *, template_file: str) -> bytes:
"""
:raises: mako.exceptions.MakoException
"""

data: Dict[str, Any] = {
'analyzed': analyzed,
'config': {},
}
hook._prepare_hook(data=data)
template = _get_template(template_file)
rendered = template.render(data=data)
rendered = hook._execute_hook(rendered, data=data)
return rendered
36 changes: 36 additions & 0 deletions onlinejudge_template/generator/hook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import shlex
import subprocess
import sys
import traceback
from logging import getLogger
from typing import *

logger = getLogger(__name__)


def _prepare_hook(*, data: Dict[str, Any]) -> None:
data['hook'] = []


def register_filter_command(command: List[str], *, data: Dict[str, Any]) -> None:
if not command:
raise ValueError('command is empty')
if data['hook']:
raise RuntimeError('hook is already registered')
data['hook'].extend(command)


def _execute_hook(rendered: bytes, *, data: Dict[str, Any]) -> bytes:
if not data['hook']:
return rendered
logger.info('execute filter command: $ %s', ' '.join(map(shlex.quote, data['hook'])))
try:
return subprocess.check_output(data['hook'], input=rendered, stderr=sys.stderr)
except Exception as e:
logger.exception(e)
return b'\n'.join([
traceback.format_exc().encode(),
b'',
b'Generated code (before processed by the filter):',
rendered,
])
26 changes: 22 additions & 4 deletions onlinejudge_template_resources/template/generate.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
<%!
import json
import os
import platform
import shutil
from logging import getLogger

import onlinejudge_template.generator.cplusplus as cplusplus
import onlinejudge_template.generator.about as about
import onlinejudge_template.generator.hook as hook
%>\
<%
data['config']['rep_macro'] = 'REP'
data['config']['using_namespace_std'] = True
data['config']['long_long_int'] = 'int64_t'
if platform.system() == 'Linux' and "clang" not in os.environ.get("CXX", "g++"):
logger = getLogger(__name__)
data["config"]["rep_macro"] = "REP"
data["config"]["using_namespace_std"] = True
data["config"]["long_long_int"] = "int64_t"
if platform.system() == "Linux" and "clang" not in os.environ.get("CXX", "g++"):
include = "#include <bits/stdc++.h>"
else:
include = "\n".join([
"#include <iostream>",
"#include <string>",
"#include <vector>",
])
if not shutil.which("clang-format"):
logger.warning("clang-format is not installed. If you want to generate well-formatted code, please install it. If you use Ubuntu, you can run $ sudo apt install clang-format")
else:
format_config = {
"BasedOnStyle": "Google",
"IndentWidth": 4,
"ColumnLimit": 9999,
"ForEachMacros": ["REP", "REP3", "REP_R", "REP3R"],
}
hook.register_filter_command(["clang-format", "--style", json.dumps(format_config)], data=data)
%>\
${include}
#define REP(i, n) for (int i = 0; (i) < (int)(n); ++ (i))
Expand Down
15 changes: 15 additions & 0 deletions onlinejudge_template_resources/template/generate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
<%!
import shutil
from logging import getLogger

import onlinejudge_template.generator.python as python
import onlinejudge_template.generator.about as about
import onlinejudge_template.generator.hook as hook
%>\
<%
logger = getLogger(__name__)
if not shutil.which("yapf"):
logger.warning("yapf is not installed. If you want to generate well-formatted code, please install it. You can use $ pip3 install yapf")
else:
format_config = "{" + ", ".join([
"BASED_ON_STYLE: google",
"COLUMN_LIMIT: 9999",
]) + "}"
hook.register_filter_command(["yapf", "--style", format_config], data=data)
%>\
#!/usr/bin/env python3
# usage: $ oj generate-input 'python3 generate.py'
Expand Down
23 changes: 19 additions & 4 deletions onlinejudge_template_resources/template/main.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,38 @@
<%!
import json
import os
import platform
import shutil
from logging import getLogger

import onlinejudge_template.generator.cplusplus as cplusplus
import onlinejudge_template.generator.topcoder as topcoder
import onlinejudge_template.generator.about as about
import onlinejudge_template.generator.hook as hook
%>\
<%
data['config']['rep_macro'] = 'REP'
data['config']['using_namespace_std'] = True
data['config']['long_long_int'] = 'int64_t'
if platform.system() == 'Linux' and "clang" not in os.environ.get("CXX", "g++"):
logger = getLogger(__name__)
data["config"]["rep_macro"] = "REP"
data["config"]["using_namespace_std"] = True
data["config"]["long_long_int"] = "int64_t"
if platform.system() == "Linux" and "clang" not in os.environ.get("CXX", "g++"):
include = "#include <bits/stdc++.h>"
else:
include = "\n".join([
"#include <iostream>",
"#include <string>",
"#include <vector>",
])
if not shutil.which("clang-format"):
logger.warning("clang-format is not installed. If you want to generate well-formatted code, please install it. If you use Ubuntu, you can run $ sudo apt install clang-format")
else:
format_config = {
"BasedOnStyle": "Google",
"IndentWidth": 4,
"ColumnLimit": 9999,
"ForEachMacros": ["REP", "REP3", "REP_R", "REP3R"],
}
hook.register_filter_command(["clang-format", "--style", json.dumps(format_config)], data=data)
%>\
${include}
#define REP(i, n) for (int i = 0; (i) < (int)(n); ++ (i))
Expand Down
15 changes: 15 additions & 0 deletions onlinejudge_template_resources/template/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
<%!
import shutil
from logging import getLogger

import onlinejudge_template.generator.python as python
import onlinejudge_template.generator.about as about
import onlinejudge_template.generator.hook as hook
%>\
<%
logger = getLogger(__name__)
if not shutil.which("yapf"):
logger.warning("yapf is not installed. If you want to generate well-formatted code, please install it. You can use $ pip3 install yapf")
else:
format_config = "{" + ", ".join([
"BASED_ON_STYLE: google",
"COLUMN_LIMIT: 9999",
]) + "}"
hook.register_filter_command(["yapf", "--style", format_config], data=data)
%>\
#!/usr/bin/env python3
# from typing import *
Expand Down

0 comments on commit fce8d60

Please sign in to comment.