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