1# -*- coding: utf-8 -*- 2import os 3import sys 4import errno 5import xml.etree.ElementTree 6 7 8ALLOWED_TYPES = ['class', 'interface', 'struct', 'union'] 9 10 11def write_file(name, text, destdir): 12 """Write the output file for module/package <name>.""" 13 fname = os.path.join(destdir, '%s.%s' % (name, 'rst')) 14 15 if not os.path.exists(os.path.dirname(fname)): 16 try: 17 os.makedirs(os.path.dirname(fname)) 18 except OSError as exc: # Guard against race condition 19 if exc.errno != errno.EEXIST: 20 raise 21 try: 22 with open(fname, 'r') as target: 23 orig = target.read() 24 if orig == text: 25 return 26 except FileNotFoundError: 27 # Don't mind if it isn't there 28 pass 29 30 with open(fname, 'w') as target: 31 target.write(text) 32 33 34def format_heading(level, text): 35 """Create a heading of <level> [1, 2 or 3 supported].""" 36 underlining = ['=', '-', '~', ][level - 1] * len(text) 37 return '%s\n%s\n\n' % (text, underlining) 38 39 40def format_directive(package_type, package, project = None): 41 """Create the breathe directive and add the options.""" 42 directive = '.. doxygen%s:: %s\n' % (package_type, package) 43 if project: 44 directive += ' :project: %s\n' % project 45 return directive 46 47 48def create_package_file(package, package_type, package_id, package_folder, rootpath, destdir): 49 """Build the text of the file and write the file.""" 50 text = format_heading(1, '%s' % (package)) 51 text += format_directive(package_type, package) 52 53 xmlfile = os.path.join(rootpath, package_id + '.xml') 54 f = xml.etree.ElementTree.parse(os.path.join(xmlfile)) 55 56 write_file(os.path.join(package_folder, package_id), text, destdir) 57 58 59def create_modules_toc_file(key, value, destdir): 60 """Create the module's index.""" 61 text = format_heading(1, '%s' % value) 62 text += '.. toctree::\n' 63 text += ' :glob:\n\n' 64 text += ' %s/*\n' % key 65 66 write_file('%slist' % key, text, destdir) 67 68 69def get_compound_folder(rootpath, compound): 70 fxml = xml.etree.ElementTree.parse(os.path.join(rootpath, compound.get('refid')) + '.xml') 71 loc = fxml.getroot()[0].find('location') 72 dirname = os.path.basename(os.path.split(loc.get('file'))[0]) 73 return dirname 74 75 76def recurse_tree(rootpath, destdir): 77 """ 78 Look for every file in the directory tree and create the corresponding 79 ReST files. 80 """ 81 index = xml.etree.ElementTree.parse(os.path.join(rootpath, 'index.xml')) 82 83 for compound in index.getroot(): 84 if compound.get('kind') not in ALLOWED_TYPES: 85 continue 86 create_package_file(compound.findtext('name'), compound.get('kind'), 87 compound.get('refid'), get_compound_folder(rootpath, compound), 88 rootpath, destdir) 89 90def get_folders_tree(rootpath): 91 tmp = [] 92 93 # Retrieve the subfolders indexes 94 for root, _, files in os.walk(rootpath): 95 for xmlfile in files: 96 if not xmlfile.startswith('dir_'): 97 continue 98 tmp.append(xmlfile) 99 100 # Iterate on them 101 dirs = [] 102 for xmlfile in tmp: 103 data = xml.etree.ElementTree.parse(os.path.join(rootpath, xmlfile)) 104 if not data: 105 continue 106 for compound in data.getroot(): 107 name = compound.findtext('compoundname') 108 dirs.append(name) 109 110 return dirs 111 112 113def main(): 114 rootpath = './doxygen-out/xml' 115 destdir = './source/api' 116 117 if not os.path.exists(destdir): 118 os.makedirs(destdir) 119 120 dirs = sorted(get_folders_tree(rootpath)) 121 source_root = dirs[0] 122 source_dirs = dirs[1:] 123 out_dirs = [os.path.basename(d) for d in dirs] 124 125 # TODO Handle only one level subfolders 126 for key in out_dirs: 127 ddir = os.path.join(destdir, key) 128 if not os.path.exists(ddir): 129 os.makedirs(ddir) 130 create_modules_toc_file(key, key.capitalize(), destdir) 131 recurse_tree(rootpath, destdir) 132 133 134# So program can be started with "python -m breathe.apidoc ..." 135if __name__ == "__main__": 136 main() 137