xref: /petsc/doc/build_man_pages.py (revision 67de2c8aaebf457db47b77de7beae8eecd9be82b)
1#!/usr/bin/env python
2""" Loops through all the source using doctext to generate the manual pages"""
3
4import os
5import re
6import subprocess
7import pathlib
8
9def findlmansec(file):
10    mansec = None
11    submansec = None
12    with open(file) as mklines:
13      #print(file)
14      submansecl = [line for line in mklines if line.find('SUBMANSEC') > -1]
15      if submansecl:
16        submansec = re.sub('[ ]*/\* [ ]*SUBMANSEC[ ]*=[ ]*','',submansecl[0]).strip('\n').strip('*/').strip()
17        if submansec == submansecl[0].strip('\n'):
18          submansec = re.sub('SUBMANSEC[ ]*=[ ]*','',submansecl[0]).strip('\n').strip()
19        #print(':SUBMANSEC:'+submansec)
20        return submansec
21    with open(file) as mklines:
22      mansecl = [line for line in mklines if line.startswith('MANSEC')]
23      if mansecl:
24        mansec = re.sub('MANSEC[ ]*=[ ]*','',mansecl[0]).strip('\n').strip()
25        #print(':MANSEC:'+mansec)
26        return mansec
27    return None
28
29def processdir(petsc_dir, dir, doctext):
30  '''Runs doctext on each source file in the directory'''
31  #print('Processing '+dir)
32  #print('build_man_pages: Using doctext '+doctext)
33  loc = os.path.join(petsc_dir,'doc')
34  doctext_path = os.path.join(petsc_dir,'doc','manualpages','doctext')
35  lmansec = None
36  if os.path.isfile(os.path.join(dir,'makefile')):
37    lmansec = findlmansec(os.path.join(dir,'makefile'))
38
39  for file in os.listdir(dir):
40    llmansec = lmansec
41    if os.path.isfile(os.path.join(dir,file)) and pathlib.Path(file).suffix in ['.c', '.cxx', '.h', '.cu', '.cpp', '.hpp']:
42      #print('Processing '+file)
43      if not llmansec:
44        llmansec = findlmansec(os.path.join(dir,file))
45        if not llmansec: continue
46      if not os.path.isdir(os.path.join(loc,'manualpages',llmansec)): os.mkdir(os.path.join(loc,'manualpages',llmansec))
47
48      command = [doctext,
49                 '-myst',
50                 '-mpath',    os.path.join(loc,'manualpages',llmansec),
51                 '-heading',  'PETSc',
52                 '-defn',     os.path.join(loc,'manualpages','doctext','myst.def'),
53                 '-indexdir', '../'+llmansec,
54                 '-index',    os.path.join(loc,'manualpages','manualpages.cit'),
55                 '-locdir',   dir[len(petsc_dir)+1:]+'/',
56                 '-Wargdesc', os.path.join(loc,'manualpages','doctext','doctextcommon.txt'),
57                 file]
58      #print(command)
59      subprocess.run(command, cwd=dir, check=True)
60
61def processkhash(T, t, KeyType, ValType, text):
62  '''Replaces T, t, KeyType, and ValType in text (from include/petsc/private/hashset.txt) with a set of supported values'''
63  import re
64  return re.sub('<ValType>',ValType,re.sub('<KeyType>',KeyType,re.sub('<t>',t,re.sub('<T>',T,text))))
65
66def main(petsc_dir, doctext):
67  # generate source code for manual pages for PETSc khash functions
68  text = ''
69  for f in ['hashset.txt', 'hashmap.txt']:
70    with open(os.path.join(petsc_dir,'include','petsc','private',f)) as mklines:
71      text = mklines.read()
72      with open(os.path.join(petsc_dir,'include','petsc','private',f+'.h'),mode='w') as khash:
73        khash.write(processkhash('I','i','PetscInt','',text))
74        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','',text))
75        khash.write(processkhash('I','i','PetscInt','PetscInt',text))
76        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','PetscInt',text))
77        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','PetscScalar',text))
78        khash.write(processkhash('IV','iv','PetscInt','PetscScalar',text))
79        khash.write(processkhash('Obj','obj','PetscInt64','PetscObject',text))
80
81  # generate the .md files for the manual pages from all the PETSc source code
82  for dirpath, dirnames, filenames in os.walk(os.path.join(petsc_dir),topdown=True):
83    dirnames[:] = [d for d in dirnames if d not in ['tests', 'tutorials', 'doc', 'output', 'ftn-custom', 'f90-custom', 'ftn-auto', 'f90-mod', 'binding', 'binding', 'config', 'lib', '.git', 'share', 'systems'] and not d.startswith('arch')]
84    processdir(petsc_dir,dirpath,doctext)
85
86  # generate list of all manual pages
87  with open(os.path.join(petsc_dir,'doc','manualpages','htmlmap'),mode='w') as map:
88    with open(os.path.join(petsc_dir,'doc','manualpages','manualpages.cit')) as cit:
89      map.write(re.sub('man\+../','man+manualpages/',cit.read()))
90    with open(os.path.join(petsc_dir,'doc','manualpages','mpi.www.index')) as mpi:
91      map.write(mpi.read())
92
93if __name__ == "__main__":
94  # TODO Accept doctext from command line
95  main(os.path.abspath(os.environ['PETSC_DIR']))
96