diff --git a/.gitignore b/.gitignore index f726c3778..7f9768b13 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,9 @@ build/ # Ignore the standard local gitdist override file /.gitdist + +# Python environment +venv + +# Pycharm settings +.idea \ No newline at end of file diff --git a/tribits/doc/sphinx/Makefile b/tribits/doc/sphinx/Makefile new file mode 100644 index 000000000..d4bb2cbb9 --- /dev/null +++ b/tribits/doc/sphinx/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tribits/doc/sphinx/conf.py b/tribits/doc/sphinx/conf.py new file mode 100644 index 000000000..bc6097c0a --- /dev/null +++ b/tribits/doc/sphinx/conf.py @@ -0,0 +1,56 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('.')) + + +# -- Project information ----------------------------------------------------- + +project = 'TriBITS' +copyright = '2021, Roscoe A. Bartlett' +author = 'Roscoe A. Bartlett' + +# The full version, including alpha/beta/rc tags +doc_path = f"{os.sep}".join(os.path.abspath(__file__).split(os.sep)[:-2]) +git_ver = os.path.join(doc_path, 'build_ref', 'TribitsGitVersion.txt') +with open(git_ver, 'r') as git_file: + release = git_file.read().split('\n')[0] + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx_rtd_theme'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] \ No newline at end of file diff --git a/tribits/doc/sphinx/index.rst b/tribits/doc/sphinx/index.rst new file mode 100644 index 000000000..dc73c704a --- /dev/null +++ b/tribits/doc/sphinx/index.rst @@ -0,0 +1,10 @@ +Welcome to TriBITS's documentation! +=================================== + +.. toctree:: + :maxdepth: 3 + :caption: Contents: + + build_ref_rst + users_guide_rst + maintainers_guide_rst diff --git a/tribits/doc/sphinx/make.bat b/tribits/doc/sphinx/make.bat new file mode 100644 index 000000000..922152e96 --- /dev/null +++ b/tribits/doc/sphinx/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/tribits/doc/sphinx/sphinx_rst_generator.py b/tribits/doc/sphinx/sphinx_rst_generator.py new file mode 100644 index 000000000..46472499d --- /dev/null +++ b/tribits/doc/sphinx/sphinx_rst_generator.py @@ -0,0 +1,141 @@ +import os +import subprocess +import sys + +try: + doc_path = f"{os.sep}".join(os.path.abspath(__file__).split(os.sep)[:-2]) + sys.path.append(doc_path) + project_path = f"{os.sep}".join(os.path.abspath(__file__).split(os.sep)[:-4]) + sys.path.append(project_path) +except Exception as e: + print(f"Can not add project path to system path! Exiting!\nERROR: {e}") + exit(1) + + +class SphinxRstGenerator: + def __init__(self): + self.paths = { + 'mainteiners_guide': { + 'src': os.path.join(doc_path, 'guides', 'maintainers_guide', 'TribitsMaintainersGuide.rst'), + 'src_path': os.path.join(doc_path, 'guides', 'maintainers_guide'), + 'final_path': os.path.join(doc_path, 'sphinx', 'maintainers_guide_rst.rst')}, + 'users_guide': { + 'src': os.path.join(doc_path, 'guides', 'users_guide', 'TribitsUsersGuide.rst'), + 'src_path': os.path.join(doc_path, 'guides', 'users_guide'), + 'final_path': os.path.join(doc_path, 'sphinx', 'users_guide_rst.rst')}, + 'build_ref': { + 'src': os.path.join(doc_path, 'build_ref', 'TribitsBuildReference.rst'), + 'src_path': os.path.join(doc_path, 'build_ref'), + 'final_path': os.path.join(doc_path, 'sphinx', 'build_ref_rst.rst')}} + self.sphinx_path = os.path.abspath(os.path.join(doc_path, 'sphinx')) + self.build_docs() + + @staticmethod + def build_docs() -> None: + """ Builds TriBITS documentation based on shell scripts + """ + build_script_path = os.path.join(doc_path, 'build_docs.sh') + current_working_dir = os.path.split(build_script_path)[0] + subprocess.call(build_script_path, cwd=current_working_dir) + + @staticmethod + def is_rst_file(file_path: str) -> bool: + """ Checks if file_path has .rst extension and if file_path is a file + """ + if os.path.splitext(file_path)[-1] == '.rst' and os.path.isfile(file_path): + return True + return False + + @staticmethod + def save_rst(file_path: str, file_content: str) -> None: + """ Saves .rst file with given pathh and content + """ + with open(file_path, 'w') as dest_file: + dest_file.write(file_content) + + @staticmethod + def get_src_path_from_parent() -> str: + pass + + def generate_rst(self, source_file: str, final_path: str = None, src_path: str = None, + start_path: str = None) -> list: + """ Generate corect links in .rst files, so Sphinx can find them + """ + if final_path is None: + overwrite_source = True + else: + overwrite_source = False + + if src_path is None: + src_file_path = self.get_src_path_from_parent() + else: + src_file_path = src_path + + file_content, includes = self.change_paths_and_get_includes(source_file=source_file, + src_file_path=src_file_path, start_path=start_path) + + if overwrite_source: + self.save_rst(file_path=source_file, file_content=file_content) + else: + self.save_rst(file_path=final_path, file_content=file_content) + + return includes + + def change_paths_and_get_includes(self, source_file: str, src_file_path: str, start_path: str) -> tuple: + """ Changes paths in source file, to be relative to sphinx_path or parent .rst document. + Returns a tuple with .rst file content and includes(absolute_path, relative_to) + """ + with open(source_file, 'r') as src_file: + source_file_str = src_file.read() + source_file_list = list() + include_file_list = list() + for line in source_file_str.split('\n'): + splitted_line = line.split() + if 'include::' in splitted_line: + incl_index = splitted_line.index('include::') + path_index = incl_index + 1 + if len(splitted_line) > path_index: + new_line = splitted_line[:path_index] + abs_path = os.path.abspath(os.path.join(src_file_path, splitted_line[path_index])) + if self.is_rst_file(file_path=abs_path): + include_file_list.append((abs_path, src_file_path)) + rel_path_from_sphinx_dir = os.path.relpath(path=abs_path, start=start_path) + new_line.append(rel_path_from_sphinx_dir) + new_line = ' '.join(new_line) + source_file_list.append(new_line) + else: + source_file_list.append(line) + else: + source_file_list.append(line) + abs_path_str = '\n'.join(source_file_list) + + return abs_path_str, include_file_list + + def main(self): + child_rst = list() + for doc_name, sources in self.paths.items(): + includes = self.generate_rst(source_file=sources.get('src'), src_path=sources.get('src_path'), + final_path=sources.get('final_path'), start_path=self.sphinx_path) + child_rst.extend(includes) + + grand_child_rst = list() + for child in child_rst: + includes_grand = self.generate_rst(source_file=child[0], src_path=os.path.split(child[0])[0], + start_path=self.sphinx_path) + grand_child_rst.extend(includes_grand) + + grand_grand_child_rst = list() + for grand_child in grand_child_rst: + includes_grand_grand = self.generate_rst(source_file=grand_child[0], + src_path=os.path.split(grand_child[0])[0], + start_path=self.sphinx_path) + grand_grand_child_rst.extend(includes_grand_grand) + + if not grand_grand_child_rst: + print('DONE! ALL GOOD!') + else: + print('NOT DONE!') + + +if __name__ == '__main__': + SphinxRstGenerator().main()