xref: /petsc/doc/conf.py (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
1# Configuration file for the Sphinx documentation builder.
2#
3# For information on options, see
4#   http://www.sphinx-doc.org/en/master/config
5#
6
7import os
8import sys
9import subprocess
10import re
11import datetime
12import shutil
13
14sys.path.append(os.getcwd())
15sys.path.append(os.path.abspath('./ext'))
16
17import add_man_page_redirects
18import build_classic_docs
19import fix_man_page_edit_links
20import make_links_relative
21import update_htmlmap_links
22import fix_pydata_margins
23
24
25if not os.path.isdir("images"):
26    print("-----------------------------------------------------------------------------")
27    print("ERROR")
28    print("images directory does not seem to exist.")
29    print("To clone the required repository, try")
30    print("   make images")
31    print("-----------------------------------------------------------------------------")
32    raise Exception("Aborting because images missing")
33
34
35# -- Project information -------------------------------------------------------
36
37project = 'PETSc'
38copyright = '1991-%d, UChicago Argonne, LLC and the PETSc Development Team' % datetime.date.today().year
39author = 'The PETSc Development Team'
40
41with open(os.path.join('..', 'include', 'petscversion.h'),'r') as version_file:
42    buf = version_file.read()
43    petsc_release_flag = re.search(' PETSC_VERSION_RELEASE[ ]*([0-9]*)',buf).group(1)
44    major_version      = re.search(' PETSC_VERSION_MAJOR[ ]*([0-9]*)',buf).group(1)
45    minor_version      = re.search(' PETSC_VERSION_MINOR[ ]*([0-9]*)',buf).group(1)
46    subminor_version   = re.search(' PETSC_VERSION_SUBMINOR[ ]*([0-9]*)',buf).group(1)
47
48    git_describe_version = subprocess.check_output(['git', 'describe', '--always']).strip().decode('utf-8')
49    if petsc_release_flag == '0':
50        version = git_describe_version
51        release = git_describe_version
52    else:
53        version = '.'.join([major_version, minor_version])
54        release = '.'.join([major_version,minor_version,subminor_version])
55
56
57# -- General configuration -----------------------------------------------------
58
59# The information on the next line must also be the same in requirements.txt
60needs_sphinx='5.3'
61nitpicky = True  # checks internal links. For external links, use "make linkcheck"
62master_doc = 'index'
63templates_path = ['_templates']
64exclude_patterns = ['_build*', 'images', 'Thumbs.db', '.DS_Store','community/meetings/pre-2023']
65highlight_language = 'c'
66numfig = True
67
68# -- Extensions ----------------------------------------------------------------
69
70extensions = [
71    'sphinx_copybutton',
72    'sphinx_design',
73    'sphinxcontrib.bibtex',
74    'sphinxcontrib.katex',
75    'sphinxcontrib.rsvgconverter',
76    'myst_parser',
77    'html5_petsc',
78    'sphinx_remove_toctrees',
79]
80
81copybutton_prompt_text = '$ '
82
83bibtex_bibfiles = ['petsc.bib']
84
85myst_enable_extensions = ["fieldlist", "dollarmath", "amsmath", "deflist"]
86
87remove_from_toctrees = ['manualpages/*/[A-Z]*','changes/2*','changes/3*']
88
89# -- Options for HTML output ---------------------------------------------------
90
91html_theme = 'pydata_sphinx_theme'
92
93html_logo_light = os.path.join('images', 'logos', 'PETSc_TAO_logos', 'PETSc-TAO', 'web', 'PETSc-TAO_RGB.svg')
94html_logo_dark = os.path.join('images', 'logos', 'PETSc_TAO_logos', 'PETSc-TAO', 'web', 'PETSc-TAO_RGB_white.svg')
95
96html_static_path = ['_static', html_logo_light, html_logo_dark]
97
98# use much smaller font for h1, h2 etc. They are absurdly large in the standard style
99# https://pydata-sphinx-theme.readthedocs.io/en/v0.12.0/user_guide/styling.html
100html_css_files = [
101    'css/custom.css',
102]
103
104html_theme_options = {
105    "icon_links": [
106        {
107            "name": "GitLab",
108            "url": "https://gitlab.com/petsc/petsc",
109            "icon": "fab fa-gitlab",
110        },
111    ],
112    "use_edit_page_button": True,
113    "footer_items": ["copyright", "sphinx-version", "last-updated"],
114#    "secondary_sidebar_items" : ["edit-this-page"],
115     "header_links_before_dropdown": 10,
116    "logo": {
117        "image_light": os.path.basename(html_logo_light),
118        "image_dark": os.path.basename(html_logo_dark)
119    }
120}
121
122try:
123  git_ref = subprocess.check_output(["git", "rev-parse", "HEAD"]).rstrip()
124  git_ref_release = subprocess.check_output(["git", "rev-parse", "origin/release"]).rstrip()
125  edit_branch = "release" if git_ref == git_ref_release else "main"
126except subprocess.CalledProcessError:
127  print("WARNING: determining branch for page edit links failed")
128  edit_branch = "main"
129
130html_context = {
131    "github_url": "https://gitlab.com",
132    "github_user": "petsc",
133    "github_repo": "petsc",
134    "github_version": edit_branch,
135    "doc_path": "doc",
136}
137
138html_logo = html_logo_light
139html_favicon = os.path.join('images', 'logos', 'PETSc_TAO_logos', 'PETSc', 'petsc_favicon.png')
140html_last_updated_fmt = r'%Y-%m-%dT%H:%M:%S%z (' + git_describe_version + ')'
141
142
143# -- Options for LaTeX output --------------------------------------------------
144latex_engine = 'xelatex'
145
146# How to arrange the documents into LaTeX files, building only the manual.
147latex_documents = [
148        ('manual/index', 'manual.tex', 'PETSc/TAO Users Manual', author, 'manual', False)
149        ]
150
151latex_additional_files = [
152    'images/manual/anl_tech_report/ArgonneLogo.pdf',
153    'images/manual/anl_tech_report/ArgonneReportTemplateLastPage.pdf',
154    'images/manual/anl_tech_report/ArgonneReportTemplatePage2.pdf',
155    'manual/anl_tech_report/first.inc',
156    'manual/anl_tech_report/last.inc',
157]
158
159latex_elements = {
160    'maketitle': r'\newcommand{\techreportversion}{%s}' % version +
161r'''
162\input{first.inc}
163''',
164    'printindex': r'''
165\printindex
166\input{last.inc}
167''',
168    'fontpkg': r'''
169\setsansfont{DejaVu Sans}
170\setmonofont{DejaVu Sans Mono}
171''',
172    'tableofcontents' : r''
173}
174
175
176# -- Setup and event callbacks -------------------------------------------------
177
178def setup(app):
179        app.connect('builder-inited', builder_init_handler)
180        app.connect('build-finished', build_finished_handler)
181
182
183def builder_init_handler(app):
184    if app.builder.name.endswith('html'):
185        _build_classic_docs(app, 'pre')
186        _update_htmlmap_links(app)
187
188
189def build_finished_handler(app, exception):
190    if app.builder.name.endswith('html'):
191        _build_classic_docs(app, 'post')
192        build_petsc4py_docs(app)
193        _fix_links(app, exception)
194        _fix_man_page_edit_links(app, exception)
195        fix_pydata_margins.fix_pydata_margins(app.outdir)
196        if app.builder.name == 'dirhtml':
197            _add_man_page_redirects(app, exception)
198        # remove sources for manual pages since they are automatically generated and should not be looked at on the website
199        if os.path.isdir(os.path.join(app.outdir,'_sources','manualpages')):
200            shutil.rmtree(os.path.join(app.outdir,'_sources','manualpages'))
201        if app.builder.name == 'html':
202            print("==========================================================================")
203            print("    open %s/index.html in your browser to view the documentation " % app.outdir)
204            print("==========================================================================")
205
206def _add_man_page_redirects(app, exception):
207    if exception is None:
208        import time
209        print("============================================")
210        print("    Adding man pages redirects")
211        x = time.clock_gettime(time.CLOCK_REALTIME)
212        add_man_page_redirects.add_man_page_redirects(app.outdir)
213        print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
214        print("============================================")
215
216def _build_classic_docs(app, stage):
217    '''Builds the .md versions of the manual pages and the .html version of the source code'''
218    build_classic_docs.main(stage,app.outdir)
219
220def _fix_man_page_edit_links(app, exception):
221    if exception is None:
222        import time
223        print("============================================")
224        print("    Fixing manual page edit links")
225        x = time.clock_gettime(time.CLOCK_REALTIME)
226        fix_man_page_edit_links.fix_man_page_edit_links(app.outdir)
227        print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
228        print("============================================")
229
230#
231#   The following two scripts are needed because the Sphinx html and dirhtml builds save the output html
232#   files at different levels of the directory hierarchy. file.rst -> file.html with html but
233#   file.rst -> file/index.html with dirhtml and we want both to work correctly using relative links.
234
235def _fix_links(app, exception):
236    """We need to manage our own relative paths in the User's Manual for the source code files which
237       are auto-generated by c2html outside of Sphinx so Sphinx cannot directly handle those links for use.
238       We use the string PETSC_DOC_OUT_ROOT_PLACEHOLDER in URLs in the Sphinx .rst files as a stand in
239       for the root directory that needs to be constructed based on if the Sphinx build is html or dirhtml
240    """
241    if exception is None:
242        import time
243        print("============================================")
244        print("    Fixing relative links")
245        x = time.clock_gettime(time.CLOCK_REALTIME)
246        make_links_relative.make_links_relative(app.outdir)
247        print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
248        print("============================================")
249
250
251def _update_htmlmap_links(app):
252    """htmlmap maps from manualpage names to relative locations in the generated documentation directory
253       hierarchy. The format of the directory location needs to be different for the Sphinx html and dirhtml
254       builds
255    """
256    import time
257    print("============================================")
258    print("    Updating htmlmap")
259    x = time.clock_gettime(time.CLOCK_REALTIME)
260    update_htmlmap_links.update_htmlmap_links(app.builder,os.path.join('manualpages','htmlmap'))
261    print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
262    print("============================================")
263
264def build_petsc4py_docs(app):
265    petsc_dir = os.path.dirname(os.path.abspath(os.path.join(__file__,'..')))
266    petsc_arch = 'arch-classic-docs'
267
268    # petsc4py needs to be built to build petsc4py docs via introspection
269    command = ['make', 'all',
270               'PETSC_DIR=%s' % petsc_dir,
271               'PETSC_ARCH=%s' % petsc_arch]
272    import time
273    print('==============================================')
274    print('Building library to make petsc4py docs')
275    print(command)
276    x = time.clock_gettime(time.CLOCK_REALTIME)
277    subprocess.run(command, cwd=petsc_dir, check=True)
278    print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
279    print('==============================================')
280
281    command = ['make', 'website',
282               'PETSC_DIR=%s' % petsc_dir,
283               'PETSC_ARCH=%s' % petsc_arch,
284               'LOC=%s' % app.outdir]
285    print('============================================')
286    print('Building petsc4py docs')
287    print(command)
288    x = time.clock_gettime(time.CLOCK_REALTIME)
289    subprocess.run(command, cwd=os.path.join(petsc_dir,'src','binding','petsc4py'), check=True)
290    print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
291    print('============================================')
292