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