Files
PAT/scripts/build.py
T
2019-11-23 22:11:55 +08:00

216 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#! /usr/bin/env python3
"""
Build markdown files from different sources
"""
import os
import re
import config
import argparse
import logging
from subprocess import run, PIPE
logging.basicConfig(format="[%(level)s] %(filename)s:%(lineno): %(message)s")
class FileBuilder:
"""
build a markdown file.
"""
def __init__(self, category, index, other_platforms):
self._github = "https://github.com/OliverLew/PAT/blob/master"
self._gh_pages = "https://oliverlew.github.io/PAT"
self.c = category
self.i = index
self._other_platforms = other_platforms
self._permalink = "{}/{}.html".format(config.category[self.c], self.i)
self._filename = os.path.join(config.post_dir,
"{}{}.md".format(self.c, self.i))
self._text_file = os.path.join(config.text_dir,
"{}{}.md".format(self.c, self.i))
self._expl_file = os.path.join(config.analysis_dir,
"{}{}.md".format(self.c, self.i))
def _yaml_frontmatter(self, date=None, title=None, tags=None):
"""
create the yaml front matter for markdown files
"""
categories = config.category[self.c]
# Check validity
if re.match(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}', date) is None:
logging.info("{}{}: " +
"date should be 'YYYY-MM-DD HH:MM[:SS +/-TTTT]'" +
"date is now: {}".format(self.c, self.i, date))
exit(1)
if not isinstance(title, str):
logging.info("{}{}: title should be string" +
"title is now: {}".format(self.c, self.i, title))
exit(1)
if not isinstance(categories, str):
logging.info("{}{}: categories should be a string" +
"categories is now: {}".format(self.c, self.i, categories))
exit(1)
if not isinstance(tags, list):
logging.info("{}{}: tags should be a list" +
"tags is now: {}".format(self.c, self.i, tags))
exit(1)
frontmatter = "---\n"
frontmatter += "layout: post\n"
frontmatter += "date: {}\n".format(date)
frontmatter += "title: \"{}\"\n".format(title)
frontmatter += "categories: {}\n".format(categories)
frontmatter += "tags: [{}]\n".format(', '.join(tags))
frontmatter += "permalink: {}\n".format(self._permalink)
frontmatter += "---"
return frontmatter
def _read_text(self):
"""
Open the html file and read title and content
"""
text = self._text_file
lines = open(text).readlines()
title = "{level} {index}. {title} {lang}".format(
level=config.cat_string[self.c],
index=self.i,
title=lines[1].rstrip(),
lang="(C语言实现)")
content_md = "".join(lines[3:])
return title, content_md
def _read_code(self):
"""
read code file from master branch
"""
code_rel_path = os.path.join(config.code_dir[self.c],
"{}.c".format(self.i))
github_file_url = os.path.join(self._github, code_rel_path)
result = run(["git", "show", "master:" + code_rel_path],
# check=True,
stdout=PIPE,
stderr=PIPE)
if result.returncode == 0:
raw_code = result.stdout.decode("utf-8")
code = raw_code[raw_code.index("#include"):]
return code, github_file_url
return None, None
def _read_date_tags_expl(self):
"""
parse explanation part.
The file contains:
<!--
date
tags
-->
actual anylasis.
Hence the return has three parts.
"""
expl_file = self._expl_file
try:
expl = open(expl_file).readlines()
except FileNotFoundError:
print("No analysis file: {}".format(expl_file))
return None, None, None
if len(expl) < 4:
print(expl_file + ": ")
print("analysis file should be at least 4 lines long:")
print("date, tags, surrounding html comment and content(optional)")
exit(1)
date = expl[1].strip('\n')
if re.match(r'', date) is None:
print("date should be in the pattern of")
print("'YYYY-MM-DD HH:MM:SS +/-TTTT'")
exit(1)
tags = expl[2].strip('\n').split(',')
return date, tags, "".join(expl[4:])
def build(self):
"""
write everything to a final markdown file
"""
title, problemcontent = self._read_text()
code, code_url = self._read_code()
if code is None:
return
date, tags, expl = self._read_date_tags_expl()
if expl is None:
return
yaml = self._yaml_frontmatter(date, title, tags)
with open(self._filename, 'w') as md_file:
print("Building {}".format(self._filename))
md_file.write("{}\n\n".format(yaml))
md_file.write("## 题目\n\n" +
"{{% include_relative {} %}}".format(
os.path.join(config.text_reldir,
"{}{}.md".format(self.c, self.i))) +
"\n\n## 思路\n\n" +
"{{% include_relative {} %}}".format(
os.path.join(config.analysis_reldir,
"{}{}.md".format(self.c, self.i))) +
"\n\n## 代码\n\n" +
"[Github最新代码]({}),欢迎交流\n\n".format(code_url))
md_file.write("```c\n{{% raw %}}{}{{% endraw %}}```".format(code))
if self._other_platforms:
other_file = "{}/{}{}.md".format(config.other_dir, self.c, self.i)
with open(other_file, 'w') as md_file:
print("Building {} for other platforms".format(other_file))
md_file.write(
"### 我的PAT系列文章更新重心已移至Github," +
"欢迎来看PAT题解的小伙伴请到" +
"[Github Pages]({})".format(self._gh_pages) +
"浏览最新内容" +
"([本篇文章链接]({}/{}))。".format(self._gh_pages,
self._permalink) +
"此处文章目前已更新至与" +
"Github Pages同步。欢迎star我的" +
"[repo](https://github.com/OliverLew/PAT)。\n\n" +
"## 题目\n\n{}\n\n".format(problemcontent) +
"## 思路\n\n{}\n".format(expl) +
"## 代码\n\n" +
"[最新代码@github]({}),欢迎交流\n".format(code_url) +
"```c\n{}```".format(code)
)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="""A script to combine the
html problem content, markdown file and the source code into a final
markdown file for jekyll blog""")
parser.add_argument('ids', nargs="+",
metavar="<problem-id>",
help="[abt][0-9]{4}, or 'all' for all problems.")
parser.add_argument('-o', '--other-platforms', action='store_true',
help='If generate files for other platforms')
args = parser.parse_args()
if not os.path.exists(config.post_dir):
os.mkdir(config.post_dir)
if 'all' in args.ids:
for c in config.indexes.keys():
for i in config.indexes[c]:
builder = FileBuilder(c, i, args.other_platforms)
builder.build()
else:
for ID in args.ids:
if re.match(r"[abt]\d{4}", ID):
category = ID[0]
index = int(ID[1:])
if index in config.indexes[category]:
builder = FileBuilder(category,
index,
args.other_platforms)
builder.build()