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