import logging
import os
import posixpath
import re
import shutil
import time
import urllib.parse
from zipfile import ZipFile
import jieba3
from sphinx.search import SearchLanguage
logging.basicConfig(level=logging.INFO)
use_doc_reading = os.getenv('USE_DOC_READING', 'yes')
repo_namespace = os.getenv('REPO_NAMESPACE', 'HiSpark')
repo_path = os.getenv('REPO_PATH')
repo_host = os.getenv('REPO_HOST', 'gitee.com')
repo_branch = os.getenv('REPO_BRANCH', 'master')
cur_path = os.path.dirname(__file__)
url_root_prefix = os.getenv('OBS_ROOT_KEY', 'repos')
gitee_view_mode = os.getenv('GITEE_VIEW_MODE', 'blob')
project = 'HiSpark编程指南'
author = repo_namespace
release = repo_branch
extensions = [
'myst_parser',
'sphinx_rtd_theme',
'sphinx_copybutton'
]
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
language = 'zh_CN'
html_favicon = '../_static/img/favicon.ico'
html_static_path = ['../_static']
html_theme = "sphinx_rtd_theme"
html_theme_options = {
'logo_only': False,
'prev_next_buttons_location': 'bottom',
}
myst_enable_extensions = ["colon_fence"]
source_suffix = {
'.rst': 'restructuredtext',
'.md': 'markdown'
}
html_css_files = [
'css/custom.css',
]
html_context = {
'repo_host': repo_host,
'repo_namespace': repo_namespace,
'repo_path': repo_path,
'gitee_pageview_mode': gitee_view_mode,
'repo_branch': repo_branch,
'versions_url': f'/{url_root_prefix.strip("/")}/version_ctrl/hispark_version.js',
'url_root_prefix': url_root_prefix,
'repo_type': 'gitee' if 'gitee' in repo_host else 'inner',
'use_doc_reading': use_doc_reading,
'logo_url': 'img/hisilicon.svg',
'show_copyright': False,
'show_sphinx': False,
}
a_tag_re_matcher = re.compile(r'<a name=[\\]?"[^"]+[\\]?"></a>')
img_tag_re_matcher = re.compile(r'<img\b[^>]{0,200}src="([^"]+)"[^>]{0,200}>')
md_link_matcher = re.compile(r'\[[^\]]+\]\([^\)]+\.md[^\)]{0,200}\)|<a href="[^>]+\.md">[^<]+</a>')
def builder_inited(app):
if app.builder.name == 'latex':
return
html_context[
'zip_filename'] = f'{repo_path}-{app.config.language}-{release}.zip'
env = app.builder.templates.environment
env.filters['toctree_handler'] = lambda content: a_tag_re_matcher.sub('', content)
def remove_md_href(content):
for md_link in md_link_matcher.findall(content):
if md_link.startswith('<a'):
text = md_link.split('>')[1].split('<')[0]
else:
text = md_link.split(']')[0].lstrip('[')
content = content.replace(md_link, text)
return content
def handle_zh_images(app, page_name, template_name, context, doctree):
"""适配中文名称的图片"""
if 'body' not in context or not isinstance(context['body'], str):
return
body_lines = context['body'].splitlines()
out_dir_img_path = os.path.join(app.outdir, app.builder.imagedir)
if not os.path.isdir(out_dir_img_path):
os.makedirs(out_dir_img_path, mode=0o700, exist_ok=True)
body_change = False
for index, html_line in enumerate(body_lines):
temp_line = html_line
for img_src_val in img_tag_re_matcher.findall(html_line):
if img_src_val.startswith((app.builder.imgpath, 'http')):
continue
unquote_path = urllib.parse.unquote(img_src_val)
relative_path, filename = os.path.split(unquote_path)
if relative_path.startswith('figures'):
img_relative_path = os.path.join(
os.path.split(page_name)[0], relative_path)
else:
img_relative_path = relative_path
src_img_file = os.path.join(app.builder.srcdir, img_relative_path, filename)
dst_file_path = os.path.join(out_dir_img_path, filename)
if not os.path.isfile(dst_file_path):
shutil.copy(src_img_file, dst_file_path)
if not relative_path:
temp_line = temp_line.replace(
img_src_val,
posixpath.join(app.builder.imgpath, img_src_val))
else:
posix_img_path = posixpath.join(app.builder.imgpath,
urllib.parse.quote(filename))
temp_line = temp_line.replace(img_src_val, posix_img_path)
body_change = True
if body_change:
body_lines[index] = temp_line
if body_change:
context['body'] = '\n'.join(body_lines)
def after_build(app, exception):
"""去除菜单栏点击滚动事件"""
static_js_path = os.path.join(app.outdir, '_static', 'js')
if not os.path.isdir(static_js_path):
return
theme_js_path = os.path.join(static_js_path, 'theme.js')
if not os.path.isfile(theme_js_path):
return
with open(theme_js_path, encoding='utf-8') as fr:
origin_js_content = fr.read()
with open(theme_js_path, 'w', encoding='utf-8') as fw:
fw.write(origin_js_content.replace(
't[0].scrollIntoView()', '')
)
search_index_js_path = os.path.join(app.outdir, 'searchindex.js')
if os.path.isfile(search_index_js_path):
with open(search_index_js_path, encoding='utf-8') as fr:
search_index_js_content = fr.read()
with open(search_index_js_path, 'w', encoding='utf-8') as fw:
fw.write(
a_tag_re_matcher.sub('', search_index_js_content)
)
start_time = time.time()
filepath = os.path.join(cur_path, html_context['zip_filename'])
if os.path.isfile(filepath):
os.remove(filepath)
logging.info('pack zip file starting: %s', filepath)
with ZipFile(filepath, mode='w') as zf:
for root, _, files in os.walk(app.outdir):
logging.info('packing dir path: %s, files: %s', root, len(files))
for fn in files:
real_path = os.path.join(root, fn)
arc_name = os.path.relpath(real_path, start=app.outdir)
zf.write(real_path, arcname=arc_name)
end_time = time.time()
shutil.move(filepath, os.path.join(app.outdir, html_context['zip_filename']))
logging.info('pack html zip take seconds: %s', end_time - start_time)
def source_read_handler(app, docname, content):
for index, text in enumerate(content):
content[index] = remove_md_href(text)
class ChineseSearch(SearchLanguage):
lang = 'zh'
jieba = jieba3.jieba3()
def split(self, input_content):
return list(set(self.jieba.cut_text(input_content)))
def setup(app):
app.connect('builder-inited', builder_inited)
app.connect('source-read', source_read_handler)
app.connect('html-page-context', handle_zh_images)
app.connect('build-finished', after_build)
app.add_search_language(ChineseSearch)
latex_table_style = ['standard', 'nocolorrows']
latex_elements = {
'papersise': 'a4paper',
'sphinxsetup': 'verbatimforcewraps=true',
'figure_align': 'H',
'preamble': r"""
\usepackage{longtable} % 长表格包
\usepackage{array}
\setcounter{tocdetph}{2} % 目录层级
\setcounter{secnumdepth}{6} % 章节标题层级
"""
}