mirror of https://github.com/openXC7/prjxray.git
180 lines
5.7 KiB
Python
180 lines
5.7 KiB
Python
import logging
|
|
import os
|
|
|
|
from recommonmark import transform
|
|
"""
|
|
Allow linking of Markdown documentation from the source code tree into the Sphinx
|
|
documentation tree.
|
|
|
|
The Markdown documents will have links relative to the source code root, rather
|
|
than the place they are now linked too - this code fixes these paths up.
|
|
|
|
We also want links from two Markdown documents found in the Sphinx docs to
|
|
work, so that is also fixed up.
|
|
"""
|
|
|
|
|
|
def path_contains(parent_path, child_path):
|
|
"""Check a path contains another path.
|
|
|
|
>>> path_contains("a/b", "a/b")
|
|
True
|
|
>>> path_contains("a/b", "a/b/")
|
|
True
|
|
>>> path_contains("a/b", "a/b/c")
|
|
True
|
|
>>> path_contains("a/b", "c")
|
|
False
|
|
>>> path_contains("a/b", "c/b")
|
|
False
|
|
>>> path_contains("a/b", "c/../a/b/d")
|
|
True
|
|
>>> path_contains("../a/b", "../a/b/d")
|
|
True
|
|
>>> path_contains("../a/b", "../a/c")
|
|
False
|
|
>>> path_contains("a", "abc")
|
|
False
|
|
>>> path_contains("aa", "abc")
|
|
False
|
|
"""
|
|
# Append a separator to the end of both paths to work around the fact that
|
|
# os.path.commonprefix does character by character comparisons rather than
|
|
# path segment by path segment.
|
|
parent_path = os.path.join(os.path.normpath(parent_path), '')
|
|
child_path = os.path.join(os.path.normpath(child_path), '')
|
|
common_path = os.path.commonprefix((parent_path, child_path))
|
|
return common_path == parent_path
|
|
|
|
|
|
def relative(parent_dir, child_path):
|
|
"""Get the relative between a path that contains another path."""
|
|
child_dir = os.path.dirname(child_path)
|
|
assert path_contains(parent_dir, child_dir), "{} not inside {}".format(
|
|
child_path, parent_dir)
|
|
return os.path.relpath(child_path, start=parent_dir)
|
|
|
|
|
|
class MarkdownCodeSymlinks(transform.AutoStructify, object):
|
|
docs_root_dir = os.path.realpath(os.path.dirname(__file__))
|
|
code_root_dir = os.path.realpath(os.path.join(docs_root_dir, "..", ".."))
|
|
|
|
mapping = {
|
|
'docs2code': {},
|
|
'code2docs': {},
|
|
}
|
|
|
|
@classmethod
|
|
def relative_code(cls, url):
|
|
"""Get a value relative to the code directory."""
|
|
return relative(cls.code_root_dir, url)
|
|
|
|
@classmethod
|
|
def relative_docs(cls, url):
|
|
"""Get a value relative to the docs directory."""
|
|
return relative(cls.docs_root_dir, url)
|
|
|
|
@classmethod
|
|
def add_mapping(cls, docs_rel, code_rel):
|
|
assert docs_rel not in cls.mapping['docs2code'], """\
|
|
Assertion error! Document already in mapping!
|
|
New Value: {}
|
|
Current Value: {}
|
|
""".format(docs_rel, cls.mapping['docs2code'][docs_rel])
|
|
assert code_rel not in cls.mapping['code2docs'], """\
|
|
Assertion error! Document already in mapping!
|
|
New Value: {}
|
|
Current Value: {}
|
|
""".format(docs_rel, cls.mapping['code2docs'][code_rel])
|
|
|
|
cls.mapping['docs2code'][docs_rel] = code_rel
|
|
cls.mapping['code2docs'][code_rel] = docs_rel
|
|
|
|
@classmethod
|
|
def find_links(cls):
|
|
"""Walk the docs dir and find links to docs in the code dir."""
|
|
for root, dirs, files in os.walk(cls.docs_root_dir):
|
|
for fname in files:
|
|
fpath = os.path.abspath(os.path.join(root, fname))
|
|
|
|
if not os.path.islink(fpath):
|
|
continue
|
|
|
|
link_path = os.path.join(root, os.readlink(fpath))
|
|
# Is link outside the code directory?
|
|
if not path_contains(cls.code_root_dir, link_path):
|
|
continue
|
|
|
|
# Is link internal to the docs directory?
|
|
if path_contains(cls.docs_root_dir, link_path):
|
|
continue
|
|
|
|
docs_rel = cls.relative_docs(fpath)
|
|
code_rel = cls.relative_code(link_path)
|
|
|
|
cls.add_mapping(docs_rel, code_rel)
|
|
import pprint
|
|
pprint.pprint(cls.mapping)
|
|
|
|
@property
|
|
def url_resolver(self):
|
|
return self._url_resolver
|
|
|
|
@url_resolver.setter
|
|
def url_resolver(self, value):
|
|
print(self, value)
|
|
|
|
# Resolve a link from one markdown to another document.
|
|
def _url_resolver(self, ourl):
|
|
"""Resolve a URL found in a markdown file."""
|
|
assert self.docs_root_dir == os.path.realpath(self.root_dir), """\
|
|
Configuration error! Document Root != Current Root
|
|
Document Root: {}
|
|
Current Root: {}
|
|
""".format(self.docs_root_dir, self.root_dir)
|
|
|
|
src_path = os.path.abspath(self.document['source'])
|
|
src_dir = os.path.dirname(src_path)
|
|
dst_path = os.path.abspath(os.path.join(self.docs_root_dir, ourl))
|
|
dst_rsrc = os.path.relpath(dst_path, start=src_dir)
|
|
|
|
src_rdoc = self.relative_docs(src_path)
|
|
|
|
print
|
|
print("url_resolver")
|
|
print(src_path)
|
|
print(dst_path)
|
|
print(dst_rsrc)
|
|
print(src_rdoc)
|
|
|
|
# Is the source document a linked one?
|
|
if src_rdoc not in self.mapping['docs2code']:
|
|
# Don't do any rewriting on non-linked markdown.
|
|
url = ourl
|
|
|
|
# Is the destination also inside docs?
|
|
elif dst_rsrc not in self.mapping['code2docs']:
|
|
# Return a path to the GitHub repo.
|
|
url = "{}/blob/master/{}".format(
|
|
self.config['github_code_repo'], dst_rsrc)
|
|
else:
|
|
url = os.path.relpath(
|
|
os.path.join(
|
|
self.docs_root_dir, self.mapping['code2docs'][dst_rsrc]),
|
|
start=src_dir)
|
|
base_url, ext = os.path.splitext(url)
|
|
assert ext in (".md",
|
|
".markdown"), ("Unknown extension {}".format(ext))
|
|
url = "{}.html".format(base_url)
|
|
|
|
print("---")
|
|
print(ourl)
|
|
print(url)
|
|
print
|
|
return url
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import doctest
|
|
doctest.testmod()
|