xref: /petsc/doc/conf.py (revision c3b34e8a033ac2eae760bfa25d5dd353c7b9f646)
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# prevents incorrect WARNING: duplicate citation for key "xxxx" warnings
90suppress_warnings = ['bibtex.duplicate_citation']
91
92# -- Options for HTML output ---------------------------------------------------
93
94html_theme = 'pydata_sphinx_theme'
95
96html_logo_light = os.path.join('images', 'logos', 'PETSc_TAO_logos', 'PETSc-TAO', 'web', 'PETSc-TAO_RGB.svg')
97html_logo_dark = os.path.join('images', 'logos', 'PETSc_TAO_logos', 'PETSc-TAO', 'web', 'PETSc-TAO_RGB_white.svg')
98
99html_static_path = ['_static', html_logo_light, html_logo_dark]
100
101# use much smaller font for h1, h2 etc. They are absurdly large in the standard style
102# https://pydata-sphinx-theme.readthedocs.io/en/v0.12.0/user_guide/styling.html
103html_css_files = [
104    'css/custom.css',
105]
106
107html_theme_options = {
108    "icon_links": [
109        {
110            "name": "GitLab",
111            "url": "https://gitlab.com/petsc/petsc",
112            "icon": "fab fa-gitlab",
113        },
114    ],
115    "use_edit_page_button": True,
116    "footer_items": ["copyright", "sphinx-version", "last-updated"],
117#    "secondary_sidebar_items" : ["edit-this-page"],
118     "header_links_before_dropdown": 10,
119    "logo": {
120        "image_light": os.path.basename(html_logo_light),
121        "image_dark": os.path.basename(html_logo_dark)
122    },
123    "navigation_with_keys":True
124}
125
126try:
127  git_ref = subprocess.check_output(["git", "rev-parse", "HEAD"]).rstrip()
128  git_ref_release = subprocess.check_output(["git", "rev-parse", "origin/release"]).rstrip()
129  edit_branch = "release" if git_ref == git_ref_release else "main"
130except subprocess.CalledProcessError:
131  print("WARNING: determining branch for page edit links failed")
132  edit_branch = "main"
133
134html_context = {
135    "github_url": "https://gitlab.com",
136    "github_user": "petsc",
137    "github_repo": "petsc",
138    "github_version": edit_branch,
139    "doc_path": "doc",
140}
141
142html_logo = html_logo_light
143html_favicon = os.path.join('images', 'logos', 'PETSc_TAO_logos', 'PETSc', 'petsc_favicon.png')
144html_last_updated_fmt = r'%Y-%m-%dT%H:%M:%S%z (' + git_describe_version + ')'
145
146
147# -- Options for LaTeX output --------------------------------------------------
148latex_engine = 'xelatex'
149
150# How to arrange the documents into LaTeX files, building only the manual.
151latex_documents = [
152        ('manual/index', 'manual.tex', 'PETSc/TAO Users Manual', author, 'manual', False)
153        ]
154
155latex_additional_files = [
156    'images/manual/anl_tech_report/ArgonneLogo.pdf',
157    'images/manual/anl_tech_report/ArgonneReportTemplateLastPage.pdf',
158    'images/manual/anl_tech_report/ArgonneReportTemplatePage2.pdf',
159    'manual/anl_tech_report/first.inc',
160    'manual/anl_tech_report/last.inc',
161]
162
163latex_elements = {
164    'maketitle': r'\newcommand{\techreportversion}{%s}' % version +
165r'''
166\input{first.inc}
167''',
168    'printindex': r'''
169\printindex
170\input{last.inc}
171''',
172    'fontpkg': r'''
173\setsansfont{DejaVu Sans}
174\setmonofont{DejaVu Sans Mono}
175''',
176    'tableofcontents' : r''
177}
178
179
180# -- Setup and event callbacks -------------------------------------------------
181
182def setup(app):
183        app.connect('builder-inited', builder_init_handler)
184        app.connect('build-finished', build_finished_handler)
185
186
187def builder_init_handler(app):
188    if app.builder.name.endswith('html'):
189        _build_classic_docs(app, 'pre')
190        _update_htmlmap_links(app)
191
192
193def build_finished_handler(app, exception):
194    if app.builder.name.endswith('html'):
195        _build_classic_docs(app, 'post')
196        build_petsc4py_docs(app)
197        _fix_links(app, exception)
198        _fix_man_page_edit_links(app, exception)
199        fix_pydata_margins.fix_pydata_margins(app.outdir)
200        if app.builder.name == 'dirhtml':
201            _add_man_page_redirects(app, exception)
202        # remove sources for manual pages since they are automatically generated and should not be looked at on the website
203        if os.path.isdir(os.path.join(app.outdir,'_sources','manualpages')):
204            shutil.rmtree(os.path.join(app.outdir,'_sources','manualpages'))
205        if app.builder.name == 'html':
206            print("==========================================================================")
207            print("    open %s/index.html in your browser to view the documentation " % app.outdir)
208            print("==========================================================================")
209
210def _add_man_page_redirects(app, exception):
211    if exception is None:
212        import time
213        print("============================================")
214        print("    Adding man pages redirects")
215        x = time.clock_gettime(time.CLOCK_REALTIME)
216        add_man_page_redirects.add_man_page_redirects(app.outdir)
217        print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
218        print("============================================")
219
220def _build_classic_docs(app, stage):
221    '''Builds the .md versions of the manual pages and the .html version of the source code'''
222    build_classic_docs.main(stage,app.outdir)
223
224def _fix_man_page_edit_links(app, exception):
225    if exception is None:
226        import time
227        print("============================================")
228        print("    Fixing manual page edit links")
229        x = time.clock_gettime(time.CLOCK_REALTIME)
230        fix_man_page_edit_links.fix_man_page_edit_links(app.outdir)
231        print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
232        print("============================================")
233
234#
235#   The following two scripts are needed because the Sphinx html and dirhtml builds save the output html
236#   files at different levels of the directory hierarchy. file.rst -> file.html with html but
237#   file.rst -> file/index.html with dirhtml and we want both to work correctly using relative links.
238
239def _fix_links(app, exception):
240    """We need to manage our own relative paths in the User's Manual for the source code files which
241       are auto-generated by c2html outside of Sphinx so Sphinx cannot directly handle those links for use.
242       We use the string PETSC_DOC_OUT_ROOT_PLACEHOLDER in URLs in the Sphinx .rst files as a stand in
243       for the root directory that needs to be constructed based on if the Sphinx build is html or dirhtml
244    """
245    if exception is None:
246        import time
247        print("============================================")
248        print("    Fixing relative links")
249        x = time.clock_gettime(time.CLOCK_REALTIME)
250        make_links_relative.make_links_relative(app.outdir)
251        print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
252        print("============================================")
253
254
255def _update_htmlmap_links(app):
256    """htmlmap maps from manualpage names to relative locations in the generated documentation directory
257       hierarchy. The format of the directory location needs to be different for the Sphinx html and dirhtml
258       builds
259    """
260    import time
261    print("============================================")
262    print("    Updating htmlmap")
263    x = time.clock_gettime(time.CLOCK_REALTIME)
264    update_htmlmap_links.update_htmlmap_links(app.builder,os.path.join('manualpages','htmlmap'))
265    print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
266    print("============================================")
267
268def build_petsc4py_docs(app):
269    petsc_dir = os.path.dirname(os.path.abspath(os.path.join(__file__,'..')))
270    petsc_arch = 'arch-classic-docs'
271
272    # petsc4py needs to be built to build petsc4py docs via introspection
273    command = ['make', 'all',
274               'PETSC_DIR=%s' % petsc_dir,
275               'PETSC_ARCH=%s' % petsc_arch]
276    import time
277    print('==============================================')
278    print('Building library to make petsc4py docs')
279    print(command)
280    x = time.clock_gettime(time.CLOCK_REALTIME)
281    subprocess.run(command, cwd=petsc_dir, check=True)
282    print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
283    print('==============================================')
284
285    command = ['make', 'website',
286               'PETSC_DIR=%s' % petsc_dir,
287               'PETSC_ARCH=%s' % petsc_arch,
288               'LOC=%s' % app.outdir]
289    print('============================================')
290    print('Building petsc4py docs')
291    print(command)
292    x = time.clock_gettime(time.CLOCK_REALTIME)
293    subprocess.run(command, cwd=os.path.join(petsc_dir,'src','binding','petsc4py'), check=True)
294    print("Time: "+str(time.clock_gettime(time.CLOCK_REALTIME) - x))
295    print('============================================')
296