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