xref: /petsc/doc/build_man_pages.py (revision a16d7c54a90597f5c8be70e4d1d8614d0ec77e42)
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:
1634c645fdSBarry 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
29*7f019730SBarry Smithdef processdir(petsc_dir, build_dir, dir, doctext):
303564227fSBarry Smith  '''Runs doctext on each source file in the directory'''
313564227fSBarry Smith  #print('Processing '+dir)
32*7f019730SBarry Smith  doctext_path = os.path.join(build_dir,'manualpages','doctext')
333564227fSBarry Smith  lmansec = None
343564227fSBarry Smith  if os.path.isfile(os.path.join(dir,'makefile')):
353564227fSBarry Smith    lmansec = findlmansec(os.path.join(dir,'makefile'))
363564227fSBarry Smith
375a0a9f49SBarry Smith  numberErrors = 0
383564227fSBarry Smith  for file in os.listdir(dir):
393564227fSBarry Smith    llmansec = lmansec
403564227fSBarry Smith    if os.path.isfile(os.path.join(dir,file)) and pathlib.Path(file).suffix in ['.c', '.cxx', '.h', '.cu', '.cpp', '.hpp']:
413564227fSBarry Smith      #print('Processing '+file)
423564227fSBarry Smith      if not llmansec:
433564227fSBarry Smith        llmansec = findlmansec(os.path.join(dir,file))
443564227fSBarry Smith        if not llmansec: continue
45*7f019730SBarry Smith      if not os.path.isdir(os.path.join(build_dir,'manualpages',llmansec)): os.mkdir(os.path.join(build_dir,'manualpages',llmansec))
463564227fSBarry Smith
473564227fSBarry Smith      command = [doctext,
483564227fSBarry Smith                 '-myst',
49*7f019730SBarry Smith                 '-mpath',    os.path.join(build_dir,'manualpages',llmansec),
503564227fSBarry Smith                 '-heading',  'PETSc',
51*7f019730SBarry Smith                 '-defn',     os.path.join(build_dir,'manualpages','doctext','myst.def'),
523564227fSBarry Smith                 '-indexdir', '../'+llmansec,
53*7f019730SBarry Smith                 '-index',    os.path.join(build_dir,'manualpages','manualpages.cit'),
543564227fSBarry Smith                 '-locdir',   dir[len(petsc_dir)+1:]+'/',
55*7f019730SBarry Smith                 '-Wargdesc', os.path.join(build_dir,'manualpages','doctext','doctextcommon.txt'),
563564227fSBarry Smith                 file]
575a0a9f49SBarry Smith      sp = subprocess.run(command, cwd=dir, capture_output=True, encoding='UTF-8', check=True)
585a0a9f49SBarry Smith      if sp.stdout and sp.stdout.find('WARNING') > -1:
595a0a9f49SBarry Smith        print(sp.stdout)
605a0a9f49SBarry Smith        numberErrors = numberErrors + 1
615a0a9f49SBarry Smith      if sp.stderr and sp.stderr.find('WARNING') > -1:
625a0a9f49SBarry Smith        print(sp.stderr)
635a0a9f49SBarry Smith        numberErrors = numberErrors + 1
645a0a9f49SBarry Smith  return numberErrors
655a0a9f49SBarry Smith
663564227fSBarry Smith
673564227fSBarry Smithdef processkhash(T, t, KeyType, ValType, text):
683564227fSBarry Smith  '''Replaces T, t, KeyType, and ValType in text (from include/petsc/private/hashset.txt) with a set of supported values'''
693564227fSBarry Smith  import re
703564227fSBarry Smith  return re.sub('<ValType>',ValType,re.sub('<KeyType>',KeyType,re.sub('<t>',t,re.sub('<T>',T,text))))
713564227fSBarry Smith
72*7f019730SBarry Smithdef main(petsc_dir, build_dir, doctext):
733564227fSBarry Smith  # generate source code for manual pages for PETSc khash functions
743564227fSBarry Smith  text = ''
753564227fSBarry Smith  for f in ['hashset.txt', 'hashmap.txt']:
763564227fSBarry Smith    with open(os.path.join(petsc_dir,'include','petsc','private',f)) as mklines:
773564227fSBarry Smith      text = mklines.read()
783564227fSBarry Smith      with open(os.path.join(petsc_dir,'include','petsc','private',f+'.h'),mode='w') as khash:
793564227fSBarry Smith        khash.write(processkhash('I','i','PetscInt','',text))
803564227fSBarry Smith        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','',text))
813564227fSBarry Smith        khash.write(processkhash('I','i','PetscInt','PetscInt',text))
823564227fSBarry Smith        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','PetscInt',text))
833564227fSBarry Smith        khash.write(processkhash('IJ','ij','struct {PetscInt i, j;}','PetscScalar',text))
843564227fSBarry Smith        khash.write(processkhash('IV','iv','PetscInt','PetscScalar',text))
853564227fSBarry Smith        khash.write(processkhash('Obj','obj','PetscInt64','PetscObject',text))
863564227fSBarry Smith
873564227fSBarry Smith  # generate the .md files for the manual pages from all the PETSc source code
885a0a9f49SBarry Smith  try:
89*7f019730SBarry Smith    os.unlink(os.path.join(build_dir,'manualpages','manualpages.cit'))
905a0a9f49SBarry Smith  except:
915a0a9f49SBarry Smith    pass
925a0a9f49SBarry Smith  numberErrors = 0
933564227fSBarry Smith  for dirpath, dirnames, filenames in os.walk(os.path.join(petsc_dir),topdown=True):
946dd63270SBarry Smith    dirnames[:] = [d for d in dirnames if d not in ['tests', 'tutorials', 'doc', 'output', 'ftn-custom', 'ftn-auto', 'ftn-mod', 'binding', 'binding', 'config', 'lib', '.git', 'share', 'systems'] and not d.startswith('arch')]
95*7f019730SBarry Smith    numberErrors = numberErrors + processdir(petsc_dir,build_dir,dirpath,doctext)
965a0a9f49SBarry Smith  if numberErrors:
975a0a9f49SBarry Smith    raise RuntimeError('Stopping document build since errors were detected in generating manual pages')
983564227fSBarry Smith
993564227fSBarry Smith  # generate list of all manual pages
100*7f019730SBarry Smith  with open(os.path.join(build_dir,'manualpages','htmlmap'),mode='w') as map:
101*7f019730SBarry Smith    with open(os.path.join(build_dir,'manualpages','manualpages.cit')) as cit:
10234c645fdSBarry Smith      map.write(re.sub(r'man\+../','man+manualpages/',cit.read()))
103*7f019730SBarry Smith    with open(os.path.join(build_dir,'manualpages','mpi.www.index')) as mpi:
1043564227fSBarry Smith      map.write(mpi.read())
105