Skip to content

Commit

Permalink
Merge pull request #70 from tossy310/markdownify
Browse files Browse the repository at this point in the history
Add markdownify_full #69
  • Loading branch information
hiroshi-cl authored May 5, 2020
2 parents b80f753 + 3f1ed13 commit 8548df4
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 1 deletion.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ script:
- cd example && rime help
- rime test && rime clean
- rime htmlify_full && rime clean
- rime markdownify_full && rime clean
notifications:
email:
on_success: never
Expand Down
1 change: 1 addition & 0 deletions example/PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
## You can load plugins here.
use_plugin('wikify')
use_plugin('htmlify_full')
use_plugin('markdownify_full')
2 changes: 1 addition & 1 deletion rime/plugins/htmlify_full.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def _GenerateHtmlFullOne(self, problem, ui):
cell_judge = HTMLIFY_CELL_NA

# Done.
html = ('<tr><td>{}</td><td>{}</td><td{}</td><td{}</td>'
html = (u'<tr><td>{}</td><td>{}</td><td{}</td><td{}</td>'
'<td{}</td><td{}</td><td{}<td></tr>\n'.format(
title, assignees, cell_solutions, cell_input,
cell_output, cell_validator, cell_judge))
Expand Down
315 changes: 315 additions & 0 deletions rime/plugins/markdownify_full.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

import codecs
import getpass
import hashlib
import os
import os.path
import socket
import sys

if sys.version_info[0] == 2:
import commands as builtin_commands # NOQA
else:
import subprocess as builtin_commands

from rime.basic import codes as basic_codes # NOQA
from rime.basic import consts # NOQA
import rime.basic.targets.project # NOQA
from rime.basic import test # NOQA
from rime.core import commands as rime_commands # NOQA
from rime.core import targets # NOQA
from rime.core import taskgraph # NOQA

MARKDOWNIFY_EMOJI_GOOD = ' :white_check_mark: '
MARKDOWNIFY_EMOJI_NOTBAD = ' :large_blue_diamond: '
MARKDOWNIFY_EMOJI_BAD = ' :x: '
MARKDOWNIFY_EMOJI_NA = ' :wavy_dash: '


def SafeUnicode(s):
if sys.version_info.major == 2 and not isinstance(s, unicode): # NOQA
s = s.decode('utf-8')
return s


def GetFileSize(dir, filename):
filepath = os.path.join(dir, filename)
if os.path.exists(filepath):
return '%dB' % os.path.getsize(filepath)
else:
return '-'


def GetFileHash(dir, filename):
filepath = os.path.join(dir, filename)
if os.path.exists(filepath):
f = open(filepath)
r = f.read()
f.close()
return hashlib.md5(SafeUnicode(r).encode('utf-8')).hexdigest()
else:
return ''


def GetMarkdownifyFileComment(dir, filename):
filepath = os.path.join(dir, filename)
if os.path.exists(filepath):
f = open(filepath)
r = f.read().strip()
f.close()
return SafeUnicode(r).replace('\n', '<br>')
else:
return ''


class Project(targets.registry.Project):
@taskgraph.task_method
def MarkdownifyFull(self, ui):
markdownFull = yield self._GenerateMarkdownFull(ui)
codecs.open("summary.md", 'w', 'utf8').write(markdownFull)
yield None

@taskgraph.task_method
def _GenerateMarkdownFull(self, ui):
if not ui.options.skip_clean:
yield self.Clean(ui)

# Get system information.
rev = SafeUnicode(builtin_commands.getoutput(
'git show -s --oneline').replace('\n', ' ').replace('\r', ' '))
username = getpass.getuser()
hostname = socket.gethostname()

header = u'# Project Status\n\n'
info = u'このファイルは markdownify_full plugin により自動生成されています '
info += (u'(rev.%(rev)s, uploaded by %(username)s @ %(hostname)s)\n\n'
% {'rev': rev, 'username': username, 'hostname': hostname})
footer = u''

# Generate content.
markdown = u'## Summary\n\n'
markdown += (
u'問題|担当|解答|入力|出力|入検|出検\n'
':---|:---|:---|:---|:---|:---|:---\n'
)

markdownFull = u'## Detail\n\n'

results = yield taskgraph.TaskBranch([
self._GenerateMarkdownFullOne(problem, ui)
for problem in self.problems])
(markdownResults, markdownFullResults) = zip(*results)
markdown += ''.join(markdownResults) + '\n'
markdownFull += ''.join(markdownFullResults)

cc = os.getenv('CC', 'gcc')
cxx = os.getenv('CXX', 'g++')
java_home = os.getenv('JAVA_HOME')
if java_home is not None:
java = os.path.join(java_home, 'bin/java')
javac = os.path.join(java_home, 'bin/javac')
else:
java = 'java'
javac = 'javac'
environments = '## Environments\n\n'
environments += (
'- gcc\n\t- ' +
builtin_commands.getoutput('{0} --version'.format(cc)) +
'\n')
environments += (
'- g++\n\t- ' +
builtin_commands.getoutput('{0} --version'.format(cxx)) +
'\n')
environments += (
'- javac\n\t- ' +
builtin_commands.getoutput('{0} -version'.format(javac)) +
'\n')
environments += (
'- java\n\t- ' +
builtin_commands.getoutput('{0} -version'.format(java)) +
'\n')
environments += '\n'

errors = ''
if ui.errors.HasError() or ui.errors.HasWarning():
errors = '## Error Messages\n\n'
if ui.errors.HasError():
errors += '- ERROR:\n'
for e in ui.errors.errors:
errors += '\t- ' + e + '\n'
if ui.errors.HasWarning():
errors += '- WARNING:\n'
for e in ui.errors.warnings:
errors += '\t- ' + e + '\n'
errors += '\n'

yield (
header + info + markdown + environments + errors + markdownFull
+ footer)

@taskgraph.task_method
def _GenerateMarkdownFullOne(self, problem, ui):
yield problem.Build(ui)

# Get status.
title = SafeUnicode(problem.title) or 'No Title'
assignees = problem.assignees
if isinstance(assignees, list):
assignees = ','.join(assignees)
assignees = SafeUnicode(assignees)

# Get various information about the problem.
markdownFull = '### ' + title + '\n\n'
solutions = sorted(problem.solutions, key=lambda x: x.name)
solutionnames = [solution.name for solution in solutions]

captions = [
name.replace('-', ' ').replace('_', ' ') for name in solutionnames]
markdownFull += ('|'.join(
['testcase', 'in', 'diff', 'md5'] + captions +
['Comments']) + '\n')
markdownFull += '|:---' * (5 + len(captions)) + '\n'

dics = {}
for testcase in problem.testset.ListTestCases():
testname = os.path.splitext(os.path.basename(testcase.infile))[0]
dics[testname] = {}
results = []
for solution in solutions:
name = solution.name
test_result = (yield problem.testset.TestSolution(solution, ui))[0]
results.append(test_result)
for (testcase, result) in test_result.results.items():
testname = os.path.splitext(
os.path.basename(testcase.infile))[0]
dics.setdefault(testname, {})[name] = (
result.verdict, result.time)
testnames = sorted(dics.keys())
lists = []
for testname in testnames:
cols = []
for name in solutionnames:
cols.append(dics[testname].get(
name, (test.TestCaseResult.NA, None)))
lists.append((testname, cols))
rows = []
dir = problem.testset.out_dir
for casename, cols in lists:
rows.append(
'|'.join(
[
casename.replace('_', ' ').replace('-', ' '),
GetFileSize(dir, casename + consts.IN_EXT),
GetFileSize(dir, casename + consts.DIFF_EXT),
'`%s`' % GetFileHash(dir, casename + consts.IN_EXT)[:7]
] +
[self._GetMarkdownifyMessage(*t) for t in cols] +
[GetMarkdownifyFileComment(dir, casename + '.comment')]
) +
'\n')
markdownFull += ''.join(rows) + '\n'

# Fetch test results.
# results = yield problem.Test(ui)

# Get various information about the problem.
num_solutions = len(results)
num_tests = len(problem.testset.ListTestCases())
correct_solution_results = [result for result in results
if result.solution.IsCorrect()]
num_corrects = len(correct_solution_results)
num_incorrects = num_solutions - num_corrects
num_agreed = len([result for result in correct_solution_results
if result.expected])
need_custom_judge = problem.need_custom_judge

# Solutions:
if num_corrects >= 2:
cell_solutions = MARKDOWNIFY_EMOJI_GOOD
elif num_corrects >= 1:
cell_solutions = MARKDOWNIFY_EMOJI_NOTBAD
else:
cell_solutions = MARKDOWNIFY_EMOJI_BAD
cell_solutions += '%d+%d' % (num_corrects, num_incorrects)

# Input:
if num_tests >= 20:
cell_input = MARKDOWNIFY_EMOJI_GOOD + str(num_tests)
else:
cell_input = MARKDOWNIFY_EMOJI_BAD + str(num_tests)

# Output:
if num_corrects >= 2 and num_agreed == num_corrects:
cell_output = MARKDOWNIFY_EMOJI_GOOD
elif num_agreed >= 2:
cell_output = MARKDOWNIFY_EMOJI_NOTBAD
else:
cell_output = MARKDOWNIFY_EMOJI_BAD
cell_output += '%d/%d' % (num_agreed, num_corrects)

# Validator:
if problem.testset.validators:
cell_validator = MARKDOWNIFY_EMOJI_GOOD
else:
cell_validator = MARKDOWNIFY_EMOJI_BAD

# Judge:
if need_custom_judge:
custom_judges = [
judge for judge in problem.testset.judges
if judge.__class__ != basic_codes.InternalDiffCode]
if custom_judges:
cell_judge = MARKDOWNIFY_EMOJI_GOOD
else:
cell_judge = MARKDOWNIFY_EMOJI_BAD
else:
cell_judge = MARKDOWNIFY_EMOJI_NA

# Done.
markdown = (u'{}|{}|{}|{}|{}|{}|{}\n'.format(
title, assignees, cell_solutions, cell_input,
cell_output, cell_validator, cell_judge))

yield (markdown, markdownFull)

def _GetMarkdownifyMessage(self, verdict, time):
if verdict is test.TestCaseResult.NA:
return MARKDOWNIFY_EMOJI_NA + str(verdict)
elif time is None:
return MARKDOWNIFY_EMOJI_BAD + str(verdict)
else:
return MARKDOWNIFY_EMOJI_GOOD + '%.2fs' % (time)


class MarkdownifyFull(rime_commands.CommandBase):
def __init__(self, parent):
super(MarkdownifyFull, self).__init__(
'markdownify_full',
'',
'Markdownify full plugin',
'',
parent)
self.AddOptionEntry(rime_commands.OptionEntry(
's', 'skip_clean', 'skip_clean', bool, False, None,
'Skip cleaning generated files up.'
))

def Run(self, obj, args, ui):
if args:
ui.console.PrintError(
'Extra argument passed to markdownify_full command!')
return None

if isinstance(obj, Project):
return obj.MarkdownifyFull(ui)

ui.console.PrintError(
'Markdownify_full is not supported for the specified target.')
return None


targets.registry.Override('Project', Project)

rime_commands.registry.Add(MarkdownifyFull)
36 changes: 36 additions & 0 deletions tests/plugins_test/test_markdownify_full.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import unittest

import mock

from rime.plugins import markdownify_full
from rime.util import struct


class TestMarkdownifyProject(unittest.TestCase):
def test_do_clean(self):
ui = mock.MagicMock()
ui.options = struct.Struct({'skip_clean': False})
project = markdownify_full.Project('project', 'base_dir', None)
project.problems = []
project.Clean = mock.MagicMock()

task_graph = project._GenerateMarkdownFull(ui)
task_graph.Continue()

project.Clean.called_once_with(ui)

def test_skip_clean(self):
ui = mock.MagicMock()
ui.options = struct.Struct({'skip_clean': True})
project = markdownify_full.Project('project', 'base_dir', None)
project.problems = []
project.Clean = mock.MagicMock()

task_graph = project._GenerateMarkdownFull(ui)
task_graph.Continue()

project.Clean.assert_not_called()


if __name__ == '__main__':
unittest.main()

0 comments on commit 8548df4

Please sign in to comment.