mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
205 lines
6.8 KiB
Python
205 lines
6.8 KiB
Python
from __future__ import print_function
|
|
import os
|
|
import sys
|
|
import shutil
|
|
import json
|
|
from glob import glob
|
|
from typing import Dict, List
|
|
from functools import lru_cache
|
|
|
|
tools_docs_path = os.path.abspath(os.path.dirname(__file__))
|
|
idapython_path = os.path.abspath(os.path.join(tools_docs_path, "..", ".."))
|
|
idasrc_path = os.path.abspath(os.path.join(idapython_path, "..", "..", ".."))
|
|
|
|
import idc
|
|
|
|
from argparse import ArgumentParser
|
|
parser = ArgumentParser()
|
|
parser.add_argument("-o", "--output", required=True)
|
|
parser.add_argument("-m", "--modules", required=True)
|
|
parser.add_argument("-s", "--include-source-for-modules", required=True)
|
|
parser.add_argument("-x", "--exclude-modules-from-searchable-index", required=True)
|
|
parser.add_argument("-v", "--verbose", default=False, action="store_true")
|
|
parser.add_argument("-M", "--markdown", default=False, action="store_true", help="Output to Markdown, not HTML")
|
|
|
|
args = parser.parse_args(idc.ARGV[1:])
|
|
|
|
args.modules = args.modules.split(",")
|
|
args.include_source_for_modules = args.include_source_for_modules.split(",")
|
|
args.exclude_modules_from_searchable_index = args.exclude_modules_from_searchable_index.split(",")
|
|
|
|
try:
|
|
# pdoc location
|
|
pdoc_path = os.path.join(idasrc_path, "third_party", "pdoc", "pdoc-240411")
|
|
sys.path.append(pdoc_path)
|
|
sys.path.append(tools_docs_path) # for the custom epytext
|
|
import pdoc
|
|
except ImportError as e:
|
|
import traceback
|
|
idc.msg("Couldn't import module %s\n" % traceback.format_exc())
|
|
idc.qexit(-1)
|
|
|
|
# --------------------------------------------------------------------------
|
|
def gen_docs():
|
|
sys.path.insert(0, os.path.join(idapython_path, "tools"))
|
|
|
|
# trash existing doc
|
|
if os.path.isdir(args.output):
|
|
shutil.rmtree(args.output)
|
|
|
|
# generate new doc
|
|
build_documentation()
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
# This is a ripoff of pdoc's cli.py, w/ minor adjustments
|
|
def gen_lunr_search(modules: List[pdoc.Module],
|
|
index_docstrings: bool,
|
|
template_config: dict):
|
|
"""Generate index.js for search"""
|
|
|
|
def trim_docstring(docstring):
|
|
return re.sub(r'''
|
|
\s+| # whitespace sequences
|
|
\s+[-=~]{3,}\s+| # title underlines
|
|
^[ \t]*[`~]{3,}\w*$| # code blocks
|
|
\s*[`#*]+\s*| # common markdown chars
|
|
\s*([^\w\d_>])\1\s*| # sequences of punct of the same kind
|
|
\s*</?\w*[^>]*>\s* # simple HTML tags
|
|
''', ' ', docstring, flags=re.VERBOSE | re.MULTILINE)
|
|
|
|
def recursive_add_to_index(dobj):
|
|
info = {
|
|
'ref': dobj.refname,
|
|
'url': to_url_id(dobj.module),
|
|
}
|
|
if index_docstrings:
|
|
info['doc'] = trim_docstring(dobj.docstring)
|
|
if isinstance(dobj, pdoc.Function):
|
|
info['func'] = 1
|
|
index.append(info)
|
|
for member_dobj in getattr(dobj, 'doc', {}).values():
|
|
recursive_add_to_index(member_dobj)
|
|
|
|
@lru_cache()
|
|
def to_url_id(module):
|
|
url = module.url()
|
|
if url not in url_cache:
|
|
url_cache[url] = len(url_cache)
|
|
return url_cache[url]
|
|
|
|
index: List[Dict] = []
|
|
url_cache: Dict[str, int] = {}
|
|
for top_module in modules:
|
|
recursive_add_to_index(top_module)
|
|
urls = sorted(url_cache.keys(), key=url_cache.__getitem__)
|
|
|
|
main_path = args.output
|
|
with open(os.path.join(main_path, 'index.js'), "w", encoding="utf-8") as f:
|
|
f.write("URLS=")
|
|
json.dump(urls, f, indent=0, separators=(',', ':'))
|
|
f.write(";\nINDEX=")
|
|
json.dump(index, f, indent=0, separators=(',', ':'))
|
|
|
|
# Generate search.html
|
|
with open(os.path.join(main_path, 'doc-search.html'), "w", encoding="utf-8") as f:
|
|
rendered_template = pdoc._render_template('/search.mako', **template_config)
|
|
f.write(rendered_template)
|
|
|
|
|
|
# --------------------------------------------------------------------------
|
|
def build_documentation():
|
|
|
|
# import all modules
|
|
def docfilter(obj):
|
|
# print("OBJ: %s" % str(obj))
|
|
if obj.name in [
|
|
"thisown",
|
|
"SWIG_PYTHON_LEGACY_BOOL",
|
|
]:
|
|
return False
|
|
return True
|
|
|
|
modules = []
|
|
for module in args.modules:
|
|
print("Loading: %s" % module)
|
|
modules.append(pdoc.Module(module, docfilter=docfilter))
|
|
|
|
print(" {} module{} in the list.".format(
|
|
len(modules), "" if len(modules) == 1 else "s"))
|
|
|
|
pdoc.link_inheritance()
|
|
|
|
#
|
|
# ida_*.[html|md]
|
|
#
|
|
def all_modules(module_collection):
|
|
for module in module_collection:
|
|
yield module
|
|
|
|
yield from all_modules(module.submodules())
|
|
|
|
pdoc.tpl_lookup.directories.insert(0, os.path.join(tools_docs_path, "templates"))
|
|
show_source_code = set(args.include_source_for_modules)
|
|
for module in all_modules(modules):
|
|
print("Processing: %s" % module.name)
|
|
|
|
if args.markdown:
|
|
contents = module.md(
|
|
show_source_code=module.name in show_source_code,
|
|
search_prefix=module.name)
|
|
else:
|
|
contents = module.html(
|
|
show_source_code=module.name in show_source_code,
|
|
search_prefix=module.name)
|
|
|
|
path = os.path.join(args.output, module.url())
|
|
# close your eyes
|
|
if args.markdown and path.endswith(".html"):
|
|
path = path[:-5] + ".md"
|
|
|
|
dirname = os.path.dirname(path)
|
|
os.makedirs(dirname, exist_ok=True)
|
|
|
|
print("Writing: %s" % path)
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
f.write(contents)
|
|
|
|
if not args.markdown:
|
|
|
|
#
|
|
# doc-search.html, index.js
|
|
#
|
|
template_config = {}
|
|
gen_lunr_search(
|
|
[mod for mod in modules if mod.name not in args.exclude_modules_from_searchable_index],
|
|
index_docstrings=True,
|
|
template_config=pdoc._get_config(**template_config).get('lunr_search'))
|
|
|
|
#
|
|
# index.html
|
|
#
|
|
path = os.path.join(args.output, "index.html")
|
|
class fake_module_t(object):
|
|
def __init__(self, name, url):
|
|
self.name = name
|
|
self._url = url
|
|
def url(self):
|
|
return self._url
|
|
|
|
index_module = fake_module_t("index", "index.html")
|
|
html = pdoc._render_template('/index.mako', module=index_module, modules=modules)
|
|
with open(path, "w", encoding="utf-8") as f:
|
|
f.write(html)
|
|
|
|
# --------------------------------------------------------------------------
|
|
def main():
|
|
print("Generating documentation.....")
|
|
gen_docs()
|
|
print("Documentation generated!")
|
|
|
|
# --------------------------------------------------------------------------
|
|
if __name__ == "__main__":
|
|
main()
|
|
qexit(0)
|