xref: /petsc/doc/build_man_pages.py (revision 34c645fd3b0199e05bec2fcc32d3597bfeb7f4f2)
11b37a2a7SPierre Jolivet#!/usr/bin/env python3
23564227fSBarry Smith""" Loops through all the source using doctext to generate the manual pages"""
33564227fSBarry Smith
43564227fSBarry Smithimport os
53564227fSBarry Smithimport re
63564227fSBarry Smithimport subprocess
73564227fSBarry Smithimport pathlib
83564227fSBarry Smith
93564227fSBarry Smithdef findlmansec(file):
103564227fSBarry Smith    mansec = None
113564227fSBarry Smith    submansec = None
123564227fSBarry Smith    with open(file) as mklines:
133564227fSBarry Smith      #print(file)
144b64c689SBarry Smith      submansecl = [line for line in mklines if (line.find('SUBMANSEC') > -1 and line.find('BFORT') == -1)]
153564227fSBarry Smith      if submansecl:
16*34c645fdSBarry Smith        submansec = re.sub(r'[ ]*/\* [ ]*SUBMANSEC[ ]*=[ ]*','',submansecl[0]).strip('\n').strip('*/').strip()
173564227fSBarry Smith        if submansec == submansecl[0].strip('\n'):
183564227fSBarry Smith          submansec = re.sub('SUBMANSEC[ ]*=[ ]*','',submansecl[0]).strip('\n').strip()
193564227fSBarry Smith        #print(':SUBMANSEC:'+submansec)
203564227fSBarry Smith        return submansec
213564227fSBarry Smith    with open(file) as mklines:
223564227fSBarry Smith      mansecl = [line for line in mklines if line.startswith('MANSEC')]
233564227fSBarry Smith      if mansecl:
243564227fSBarry Smith        mansec = re.sub('MANSEC[ ]*=[ ]*','',mansecl[0]).strip('\n').strip()
253564227fSBarry Smith        #print(':MANSEC:'+mansec)
263564227fSBarry Smith        return mansec
273564227fSBarry Smith    return None
283564227fSBarry Smith
293564227fSBarry Smithdef processdir(petsc_dir, dir, doctext):
303564227fSBarry Smith  '''Runs doctext on each source file in the directory'''
313564227fSBarry Smith  #print('Processing '+dir)
323564227fSBarry Smith  #print('build_man_pages: Using doctext '+doctext)
333564227fSBarry Smith  loc = os.path.join(petsc_dir,'doc')
343564227fSBarry Smith  doctext_path = os.path.join(petsc_dir,'doc','manualpages','doctext')
353564227fSBarry Smith  lmansec = None
363564227fSBarry Smith  if os.path.isfile(os.path.join(dir,'makefile')):
373564227fSBarry Smith    lmansec = findlmansec(os.path.join(dir,'makefile'))
383564227fSBarry Smith
395a0a9f49SBarry Smith  numberErrors = 0
403564227fSBarry Smith  for file in os.listdir(dir):
413564227fSBarry Smith    llmansec = lmansec
423564227fSBarry Smith    if os.path.isfile(os.path.join(dir,file)) and pathlib.Path(file).suffix in ['.c', '.cxx', '.h', '.cu', '.cpp', '.hpp']:
433564227fSBarry Smith      #print('Processing '+file)
443564227fSBarry Smith      if not llmansec:
453564227fSBarry Smith        llmansec = findlmansec(os.path.join(dir,file))
463564227fSBarry Smith        if not llmansec: continue
473564227fSBarry Smith      if not os.path.isdir(os.path.join(loc,'manualpages',llmansec)): os.mkdir(os.path.join(loc,'manualpages',llmansec))
483564227fSBarry Smith
493564227fSBarry Smith      command = [doctext,
503564227fSBarry Smith                 '-myst',
513564227fSBarry Smith                 '-mpath',    os.path.join(loc,'manualpages',llmansec),
523564227fSBarry Smith                 '-heading',  'PETSc',
533564227fSBarry Smith                 '-defn',     os.path.join(loc,'manualpages','doctext','myst.def'),
543564227fSBarry Smith                 '-indexdir', '../'+llmansec,
553564227fSBarry Smith                 '-index',    os.path.join(loc,'manualpages','manualpages.cit'),
563564227fSBarry Smith                 '-locdir',   dir[len(petsc_dir)+1:]+'/',
573564227fSBarry Smith                 '-Wargdesc', os.path.join(loc,'manualpages','doctext','doctextcommon.txt'),
583564227fSBarry Smith                 file]
593564227fSBarry Smith      #print(command)
605a0a9f49SBarry Smith      sp = subprocess.run(command, cwd=dir, capture_output=True, encoding='UTF-8', check=True)
615a0a9f49SBarry Smith      if sp.stdout and sp.stdout.find('WARNING') > -1:
625a0a9f49SBarry Smith        print(sp.stdout)
635a0a9f49SBarry Smith        numberErrors = numberErrors + 1
645a0a9f49SBarry Smith      if sp.stderr and sp.stderr.find('WARNING') > -1:
655a0a9f49SBarry Smith        print(sp.stderr)
665a0a9f49SBarry Smith        numberErrors = numberErrors + 1
675a0a9f49SBarry Smith  return numberErrors
685a0a9f49SBarry Smith
693564227fSBarry Smith
703564227fSBarry Smithdef processkhash(T, t, KeyType, ValType, text):
713564227fSBarry Smith  '''Replaces T, t, KeyType, and ValType in text (from include/petsc/private/hashset.txt) with a set of supported values'''
723564227fSBarry Smith  import re
733564227fSBarry Smith  return re.sub('<ValType>',ValType,re.sub('<KeyType>',KeyType,re.sub('<t>',t,re.sub('<T>',T,text))))
743564227fSBarry Smith
753564227fSBarry Smithdef main(petsc_dir, doctext):
763564227fSBarry Smith  # generate source code for manual pages for PETSc khash functions
773564227fSBarry Smith  text = ''
783564227fSBarry Smith  for f in ['hashset.txt', 'hashmap.txt']:
793564227fSBarry Smith    with open(os.path.join(petsc_dir,'include','petsc','private',f)) as mklines:
803564227fSBarry Smith      text = mklines.read()
813564227fSBarry Smith      with open(os.path.join(petsc_dir,'include','petsc','private',f+'.h'),mode='w') as khash:
823564227fSBarry Smith        khash.write(processkhash('I','i','PetscInt','',text))
833564227fSBarry Smith        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','',text))
843564227fSBarry Smith        khash.write(processkhash('I','i','PetscInt','PetscInt',text))
853564227fSBarry Smith        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','PetscInt',text))
863564227fSBarry Smith        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','PetscScalar',text))
873564227fSBarry Smith        khash.write(processkhash('IV','iv','PetscInt','PetscScalar',text))
883564227fSBarry Smith        khash.write(processkhash('Obj','obj','PetscInt64','PetscObject',text))
893564227fSBarry Smith
903564227fSBarry Smith  # generate the .md files for the manual pages from all the PETSc source code
915a0a9f49SBarry Smith  try:
925a0a9f49SBarry Smith    os.unlink(os.path.join(petsc_dir,'doc','manualpages','manualpages.cit'))
935a0a9f49SBarry Smith  except:
945a0a9f49SBarry Smith    pass
955a0a9f49SBarry Smith  numberErrors = 0
963564227fSBarry Smith  for dirpath, dirnames, filenames in os.walk(os.path.join(petsc_dir),topdown=True):
973564227fSBarry Smith    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')]
985a0a9f49SBarry Smith    numberErrors = numberErrors + processdir(petsc_dir,dirpath,doctext)
995a0a9f49SBarry Smith  if numberErrors:
1005a0a9f49SBarry Smith    raise RuntimeError('Stopping document build since errors were detected in generating manual pages')
1013564227fSBarry Smith
1023564227fSBarry Smith  # generate list of all manual pages
1033564227fSBarry Smith  with open(os.path.join(petsc_dir,'doc','manualpages','htmlmap'),mode='w') as map:
1043564227fSBarry Smith    with open(os.path.join(petsc_dir,'doc','manualpages','manualpages.cit')) as cit:
105*34c645fdSBarry Smith      map.write(re.sub(r'man\+../','man+manualpages/',cit.read()))
1063564227fSBarry Smith    with open(os.path.join(petsc_dir,'doc','manualpages','mpi.www.index')) as mpi:
1073564227fSBarry Smith      map.write(mpi.read())
1083564227fSBarry Smith
1093564227fSBarry Smithif __name__ == "__main__":
1103564227fSBarry Smith  # TODO Accept doctext from command line
1113564227fSBarry Smith  main(os.path.abspath(os.environ['PETSC_DIR']))
112