#!/usr/bin/env python3 import os import sys import logging import shutil LOGGER = logging.getLogger() LOGGER.setLevel(logging.DEBUG) handler = logging.StreamHandler(sys.stderr) handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)8s: %(message)s') handler.setFormatter(formatter) LOGGER.addHandler(handler) class DoxygenGenerator: def _construct_path(self, relative_to, *paths): if relative_to == "sources": return os.path.join(self.sources_dir, *paths) if relative_to == "binary": return os.path.join(self.working_dir, *paths) raise Exception("_path") def __init__(self, dir_sources, dir_binary, dir_tocopy): self.sources_dir = os.path.abspath(dir_sources) self.working_dir = os.path.abspath(dir_binary) self.dir_tocopy = dir_tocopy # relative to sources self._check_valid() LOGGER.info("${CMAKE_SOURCES_DIR} = %s", self.sources_dir) LOGGER.info("working directory = %s", self.working_dir) LOGGER.info("Module directories = %s", ", ".join(self.dir_tocopy)) LOGGER.info("Pruning contents of the working directory") for fs_obj in os.listdir(self.working_dir): to_delete = os.path.join(self.working_dir, fs_obj) shutil.rmtree(to_delete) if len(os.listdir(self.working_dir)) > 0: LOGGER.error("Pruning unsuccessful") raise Exception("something was left after the prune") def run(self): for tocopy in self.dir_tocopy: self._copy_single(tocopy) self._add_directives(tocopy) def _copy_single(self, directory): module_name = directory.split("/")[0] LOGGER.info("%s: Copying ${CMAKE_SOURCES_DIR}/%s -> CWD/%s", module_name, directory, directory) src = self._construct_path("sources", directory) dst = self._construct_path("binary", directory) shutil.copytree(src, dst) def _add_directives(self, directory): module_name = directory.split("/")[0] LOGGER.info("%s: Rewriting sources in CWD/%s", module_name, directory) directory = self._construct_path("binary", directory) self._walk(directory, self._add_directive_callback, module_name=module_name) @staticmethod def _add_directive_callback(filepath, **kwargs): with open(filepath, 'r') as f: original_content = f.read() with open(filepath, 'w') as f: f.write(""" /** \\addtogroup %s * @{ */ """ % kwargs["module_name"]) f.write(original_content) f.write("/** @}*/") def _walk(self, root, callback, **kwargs): for root, dirs, files in os.walk(root): # dirpath = root.split(os.sep) for file in files: filepath = os.path.join(root, file) LOGGER.debug("%s: Applying doxygen directives to %s", kwargs["module_name"], os.path.relpath(filepath, self.working_dir)) callback(filepath, **kwargs) def _check_valid(self): EXCEPTION_MISSING = "Directory {} ({}) does not exist." EXCEPTION_SAME = "Directories {} points to the same location ({})" if not os.path.isdir(self.sources_dir): raise Exception(EXCEPTION_MISSING.format("CMAKE_SOURCES_DIR", self.sources_dir)) if not os.path.isdir(self.working_dir): raise Exception(EXCEPTION_MISSING.format("CMAKE_BINARY_DIR", self.working_dir)) if self.sources_dir == self.working_dir: raise Exception(EXCEPTION_SAME.format(["CMAKE_BINARY_DIR", "CMAKE_SOURCES_DIR"], self.sources_dir)) for path in self.dir_tocopy: if not os.path.isdir(os.path.join(self.sources_dir, path)): raise Exception(EXCEPTION_MISSING.format("INPUT_DIR", "$CMAKE_SOURCES_DIR/" + self.dir_tocopy)) if __name__ == '__main__': if len(sys.argv) != 4: sys.exit(1) dir_sources = sys.argv[1] dir_working = sys.argv[2] dir_tocopy = sys.argv[3].strip().split() DoxygenGenerator(dir_sources, dir_working, dir_tocopy).run()