From 8659f3f133ba19630a6ca66f1ed48b9f8c677881 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Wed, 4 Dec 2013 23:41:51 +0100 Subject: [PATCH] [DEV] add multiple repo documentation generation --- lutin.py | 4 +- lutinDoc.py | 89 ++++++++++++++++++++++++++++++-- lutinDocHtml.py | 101 ++++++++++++++++++++++++++---------- lutinModule.py | 133 ++++++++++++++++++++++++++++-------------------- lutinTarget.py | 28 ++++++++-- 5 files changed, 268 insertions(+), 87 deletions(-) diff --git a/lutin.py b/lutin.py index 9579bf0..07954c3 100755 --- a/lutin.py +++ b/lutin.py @@ -41,9 +41,11 @@ def usage(): print " Clean all (same as previous)" print " dump" print " Dump all the module dependency and properties" + print " doc" + print " Create documentation of all module that is mark as availlable on it" listOfAllModule = lutinModule.ListAllModuleWithDesc() for mod in listOfAllModule: - print " " + mod[0] + " / " + mod[0] + "-clean / " + mod[0] + "-dump" + print " " + mod[0] + " / " + mod[0] + "-clean / " + mod[0] + "-dump" + mod[0] + "-doc" print " " + mod[1] print " ex: " + sys.argv[0] + " all --target=Android all -t Windows -m debug all" exit(0) diff --git a/lutinDoc.py b/lutinDoc.py index c5ee045..f727036 100644 --- a/lutinDoc.py +++ b/lutinDoc.py @@ -17,10 +17,11 @@ class doc: def __init__(self, moduleName): self.moduleName = moduleName self.listClass = dict() + self.listEnum = dict() self.listVariable = dict() self.listFunction = dict() self.listNamepsaces = dict() - + self.target = None ## ## @brief Add a File at the parsing system @@ -32,9 +33,11 @@ class doc: try: metaData = CppHeaderParser.CppHeader(filename) except CppHeaderParser.CppParseError, e: - debug.error(" can not parse the file: '" + filename + "' error : " + e) + debug.warning(" can not parse the file: '" + filename + "' error : " + str(e)) return False + #debug.info(str(metaData.enums)) + # add all classes : for element in metaData.classes: localClass = metaData.classes[element] @@ -47,6 +50,20 @@ class doc: else: self.listClass[className] = localClass + # add all enums: + for localEnum in metaData.enums: + if localEnum['namespace'] == '': + enumName = localEnum['name'] + else: + enumName = localEnum['namespace'] + "::" + localEnum['name'] + enumName = enumName.replace("::::", "::") + if enumName in self.listEnum.keys(): + debug.warning("Might merge enum : '" + enumName + "' file : " + filename) + else: + self.listEnum[enumName] = localEnum + + # add all namaspace: + # add all namespaces: # add all global vars: @@ -60,7 +77,9 @@ class doc: ## @param[in] destFolder Destination folder. ## @param[in] mode (optinnal) generation output mode {html, markdown ...} ## - def generate_documantation(self, destFolder, mode="html"): + def generate_documantation(self, target, destFolder, mode="html"): + # local store of the target + self.target = target if mode == "html": if lutinDocHtml.generate(self, destFolder) == False: debug.warning("Generation Documentation :'" + mode + "' ==> return an error for " + self.moduleName) @@ -69,7 +88,9 @@ class doc: None else: debug.error("Unknow Documantation mode generation :'" + mode + "'") + self.target = None return False + self.target = None return True ## @@ -110,4 +131,66 @@ class doc: break; debug.verbose("find childs : " + str(list)) return list + + ## + ## @brief trnsform the classname in a generic link (HTML) + ## @param[in] elementName Name of the class requested + ## @return [className, link] + ## + def get_class_link(self, elementName): + if elementName == "const" \ + or elementName == "enum" \ + or elementName == "void" \ + or elementName == "char" \ + or elementName == "char32_t" \ + or elementName == "float" \ + or elementName == "double" \ + or elementName == "bool" \ + or elementName == "int8_t" \ + or elementName == "uint8_t" \ + or elementName == "int16_t" \ + or elementName == "uint16_t" \ + or elementName == "int32_t" \ + or elementName == "uint32_t" \ + or elementName == "int64_t" \ + or elementName == "uint64_t" \ + or elementName == "int" \ + or elementName == "T" \ + or elementName == "CLASS_TYPE" \ + or elementName[:5] == "std::" \ + or elementName[:6] == "appl::" \ + or elementName == "&" \ + or elementName == "*" \ + or elementName == "**": + return [elementName, ""] + if elementName in self.listClass.keys(): + link = elementName.replace(":","_") + ".html" + return [elementName, link] + elif elementName in self.listEnum.keys(): + link = elementName.replace(":","_") + ".html" + return [elementName, link] + else: + return self.target.doc_get_link(elementName) + return [elementName, ""] + + ## + ## @brief trnsform the classname in a generic link (HTML) (external access ==> from target) + ## @param[in] elementName Name of the class requested + ## @return [className, link] + ## + def get_class_link_from_target(self, elementName): + # reject when auto call : + if self.target != None: + return [elementName, ""] + # search in local list : + if elementName in self.listClass.keys(): + link = elementName.replace(":","_") + ".html" + return [elementName, "../" + self.moduleName + "/" + link] + elif elementName in self.listEnum.keys(): + link = elementName.replace(":","_") + ".html" + return [elementName, "../" + self.moduleName + "/" + link] + # did not find : + return [elementName, ""] + + diff --git a/lutinDocHtml.py b/lutinDocHtml.py index 2aa6c7d..5b3b794 100644 --- a/lutinDocHtml.py +++ b/lutinDocHtml.py @@ -24,14 +24,14 @@ def replace_storage_keyword(match): def display_color(valBase): # storage keyword : - p = re.compile("(inline|const|class|virtual|private|public|protected|friend|const|extern|auto|register|static|unsigned|signed|volatile|char|double|float|int|long|short|void|typedef|struct|union|enum)") + p = re.compile("(inline|const|class|virtual|private|public|protected|friend|const|extern|auto|register|static|volatile|typedef|struct|union|enum)") val = p.sub(replace_storage_keyword, valBase) # type : p = re.compile("(bool|BOOL|char(16_t|32_t)?|double|float|u?int(8|16|32|64|128)?(_t)?|long|short|signed|size_t|unsigned|void|(I|U)(8|16|32|64|128))") val = p.sub(replace_type, val) return val, len(valBase) -def display_type(type, localClassName): +def display_type(type, myDoc): type = type.replace("inline ", "") lenght = 0; isFirst = True @@ -43,12 +43,10 @@ def display_type(type, localClassName): lenght += 1 isFirst = False # check if the element in internal at the current lib - if element[:len(localClassName)] == localClassName: - out += "" + element + "" + name, link = myDoc.get_class_link(element) + if len(link) != 0: + out += "" + name + "" lenght += len(element) - # check if the element is in local Lib: - elif False: - None # Ckeck if the variable in a standard class: elif element in global_class_link.keys(): out += "" + element + "" @@ -148,7 +146,7 @@ def white_space(size) : ret += " " return ret -def displayReductFunction(function, file, classement, sizeReturn, sizefunction, localClassName) : +def display_reduct_function(function, file, classement, sizeReturn, sizefunction, myDoc) : file.write(classement + " ") lenght = len(classement)+1; if function['destructor'] : @@ -158,7 +156,7 @@ def displayReductFunction(function, file, classement, sizeReturn, sizefunction, file.write(white_space(sizeReturn+1)) lenght += sizeReturn+1; else : - typeData, typeLen = display_type(function["rtnType"], localClassName); + typeData, typeLen = display_type(function["rtnType"], myDoc); file.write(typeData) file.write(white_space(sizeReturn+1 - typeLen)) lenght += sizeReturn+1; @@ -172,7 +170,7 @@ def displayReductFunction(function, file, classement, sizeReturn, sizefunction, file.write(",
") file.write(white_space(parameterPos)) - typeData, typeLen = display_type(param["type"], localClassName); + typeData, typeLen = display_type(param["type"], myDoc); file.write(typeData) if param['name'] != "": file.write(" ") @@ -182,7 +180,7 @@ def displayReductFunction(function, file, classement, sizeReturn, sizefunction, file.write("
") -def displayFunction(namespace, function, file, classement, sizeReturn, sizefunction, localClassName) : +def displayFunction(namespace, function, file, classement, sizeReturn, sizefunction, myDoc) : lineData = "" if ( function['constructor'] == True \ or function['destructor'] == True \ @@ -201,7 +199,7 @@ def displayFunction(namespace, function, file, classement, sizeReturn, sizefunct elif function['constructor'] : lenght = 0; else : - typeData, typeLen = display_type(function["rtnType"], localClassName); + typeData, typeLen = display_type(function["rtnType"], myDoc); file.write(typeData + " ") lenght = typeLen+1; @@ -212,7 +210,7 @@ def displayFunction(namespace, function, file, classement, sizeReturn, sizefunct if isFirst == False: file.write(",\n") file.write(white_space(parameterPos)) - typeData, typeLen = display_type(param["type"], localClassName); + typeData, typeLen = display_type(param["type"], myDoc); file.write(typeData) if param['name'] != "": file.write(" ") @@ -253,13 +251,13 @@ def generate(myDoc, outFolder) : genericHeader += "\n" genericHeader += "\n" genericHeader += " \n" - genericHeader += " Ewol Library\n" + genericHeader += " " + myDoc.moduleName+ " Library\n" genericHeader += " \n" genericHeader += "\n" genericHeader += "\n" genericHeader += "
\n" genericHeader += "
\n" - genericHeader += "

Ewol Library

\n" + genericHeader += "

" + myDoc.moduleName+ " Library

\n" #genericHeader += "
    \n" baseNamespace = "" for className in sorted(myDoc.listClass.iterkeys()) : @@ -281,6 +279,27 @@ def generate(myDoc, outFolder) : if baseNamespace != "": genericHeader += "
\n" + + for enumName in sorted(myDoc.listEnum.iterkeys()) : + pos = enumName.find("::") + if pos >= 0: + namespace = enumName[:pos] + rest = enumName[pos+2:] + else: + namespace = "" + rest = enumName + if baseNamespace != namespace: + if baseNamespace != "": + genericHeader += " \n" + genericHeader += "
  • " + namespace + "
  • \n" + genericHeader += "
      \n" + baseNamespace = namespace + + genericHeader += "
    • " + rest + "
    • \n" + + if baseNamespace != "": + genericHeader += "
    \n" + #genericHeader += " \n" genericHeader += "
    \n" genericHeader += "
    \n" @@ -303,9 +322,8 @@ def generate(myDoc, outFolder) : file.write(genericHeader) - file.write("

    " + className + "

    \n") - file.write("\n") - file.write("\n") + file.write("

    Class: " + className + "

    \n") + file.write("
    \n") # calculate function max size return & function name size: sizeReturn=0 sizefunction=0 @@ -324,11 +342,11 @@ def generate(myDoc, outFolder) : # TODO: ... file.write("
    \n");
     		for function in localClass["methods"]["public"]:
    -			displayReductFunction(function, file, "+ ", sizeReturn, sizefunction, className)
    +			display_reduct_function(function, file, "+ ", sizeReturn, sizefunction, myDoc)
     		for function in localClass["methods"]["protected"]:
    -			displayReductFunction(function, file, "# ", sizeReturn, sizefunction, className)
    +			display_reduct_function(function, file, "# ", sizeReturn, sizefunction, myDoc)
     		for function in localClass["methods"]["private"]:
    -			displayReductFunction(function, file, "- ", sizeReturn, sizefunction, className)
    +			display_reduct_function(function, file, "- ", sizeReturn, sizefunction, myDoc)
     		file.write("
    \n"); file.write("\n") file.write("\n") @@ -343,13 +361,15 @@ def generate(myDoc, outFolder) : if level != 0: file.write(white_space(level*4) + "+--> ") if heritedClass != className: - file.write("" + heritedClass + "\n") + name, link = myDoc.get_class_link(heritedClass) + file.write("" + name + "\n") else: file.write("" + heritedClass + "\n") level += 1; for heritedClass in heritageDown: file.write(white_space(level*4) + "+--> ") - file.write("" + heritedClass + "\n") + name, link = myDoc.get_class_link(heritedClass) + file.write("" + name + "\n") file.write("\n") file.write("
    \n") """ @@ -371,18 +391,47 @@ def generate(myDoc, outFolder) : file.write("

    Detail:

    \n") # display all the class internal functions : for function in localClass["methods"]["public"]: - displayFunction(localClass['namespace'] , function, file, "+ ", sizeReturn, sizefunction, className) + displayFunction(localClass['namespace'] , function, file, "+ ", sizeReturn, sizefunction, myDoc) file.write("\n
    \n") for function in localClass["methods"]["protected"]: - displayFunction(localClass['namespace'] , function, file, "# ", sizeReturn, sizefunction, className) + displayFunction(localClass['namespace'] , function, file, "# ", sizeReturn, sizefunction, myDoc) file.write("\n
    \n") for function in localClass["methods"]["private"]: - displayFunction(localClass['namespace'] , function, file, "- ", sizeReturn, sizefunction, className) + displayFunction(localClass['namespace'] , function, file, "- ", sizeReturn, sizefunction, myDoc) file.write("\n
    \n") file.write(genericFooter) file.close() + + for enumName in sorted(myDoc.listEnum.iterkeys()) : + localEnum = myDoc.listEnum[enumName] + debug.debug(" enum: " + enumName) + fileName = outFolder + "/" + class_name_to_file_name(enumName) + # create directory (in case) + lutinTools.CreateDirectoryOfFile(fileName); + debug.printElement("doc", myDoc.moduleName, "<==", enumName) + # open the file : + file = open(fileName, "w") + + file.write(genericHeader) + + file.write("

    Enum: " + enumName + "

    \n") + file.write("
    \n") + file.write("Value :
    \n") + file.write("\n") + + file.write(genericFooter) + + file.close() + diff --git a/lutinModule.py b/lutinModule.py index 8b0e850..a139175 100644 --- a/lutinModule.py +++ b/lutinModule.py @@ -13,19 +13,17 @@ import lutinMultiprocess import lutinEnv import lutinDoc -""" - -""" class module: - """ - Module class represent all system needed for a specific - module like - - type (bin/lib ...) - - dependency - - flags - - files - - ... - """ + + ## + ## @brief Module class represent all system needed for a specific + ## module like + ## - type (bin/lib ...) + ## - dependency + ## - flags + ## - files + ## - ... + ## def __init__(self, file, moduleName, moduleType): ## Remove all variable to prevent error of multiple deffinition of the module ... self.originFile='' @@ -37,8 +35,8 @@ class module: # Dependency list: self.depends=[] # Dependency list: - self.docPath=lutinTools.GetCurrentPath(file) - self.documentation = lutinDoc.doc(self.name) + self.docPath = "" + self.documentation = None # export PATH self.export_path=[] self.local_path=[] @@ -94,9 +92,9 @@ class module: } - ############################################################################### - ## add Some copilation flags for this module (and only this one) - ############################################################################### + ## + ## @brief Add Some copilation flags for this module (and only this one) + ## def add_extra_compile_flags(self): self.CompileFlags_CC([ "-Wall", @@ -106,9 +104,9 @@ class module: "-Wno-write-strings"]); #only for gcc : "-Wunused-variable", "-Wunused-but-set-variable", - ############################################################################### - ## remove all unneeded warning on compilation ==> for extern libs ... - ############################################################################### + ## + ## @brief remove all unneeded warning on compilation ==> for extern libs ... + ## def remove_compile_warning(self): self.CompileFlags_CC([ "-Wno-int-to-pointer-cast" @@ -118,9 +116,9 @@ class module: ]) # only for gcc :"-Wno-unused-but-set-variable" - ############################################################################### - ## Commands for running gcc to compile a m++ file. - ############################################################################### + ## + ## @brief Commands for running gcc to compile a m++ file. + ## def Compile_mm_to_o(self, file, binary, target, depancy): file_src, file_dst, file_depend, file_cmd = target.fileGenerateObject(binary,self.name,self.originFolder,file) # create the command line befor requesting start: @@ -151,9 +149,9 @@ class module: lutinMultiprocess.RunInPool(cmdLine, comment, file_cmd) return file_dst - ############################################################################### - ## Commands for running gcc to compile a m file. - ############################################################################### + ## + ## @brief Commands for running gcc to compile a m file. + ## def Compile_m_to_o(self, file, binary, target, depancy): file_src, file_dst, file_depend, file_cmd = target.fileGenerateObject(binary,self.name,self.originFolder,file) # create the command line befor requesting start: @@ -184,9 +182,9 @@ class module: lutinMultiprocess.RunInPool(cmdLine, comment, file_cmd) return file_dst - ############################################################################### - ## Commands for running gcc to compile a C++ file. - ############################################################################### + ## + ## @brief Commands for running gcc to compile a C++ file. + ## def Compile_xx_to_o(self, file, binary, target, depancy): file_src, file_dst, file_depend, file_cmd = target.fileGenerateObject(binary,self.name,self.originFolder,file) # create the command line befor requesting start: @@ -216,9 +214,9 @@ class module: lutinMultiprocess.RunInPool(cmdLine, comment, file_cmd) return file_dst - ############################################################################### - ## Commands for running gcc to compile a C file. - ############################################################################### + ## + ## @brief Commands for running gcc to compile a C file. + ## def Compile_cc_to_o(self, file, binary, target, depancy): file_src, file_dst, file_depend, file_cmd = target.fileGenerateObject(binary,self.name,self.originFolder,file) # create the command line befor requesting start: @@ -246,9 +244,9 @@ class module: return file_dst - ############################################################################### - ## Commands for running ar. - ############################################################################### + ## + ## @brief Commands for running ar. + ## def Link_to_a(self, file, binary, target, depancy): file_src, file_dst, file_depend, file_cmd = target.GenerateFile(binary, self.name,self.originFolder,file,"lib-static") #$(Q)$(TARGET_AR) $(TARGET_GLOBAL_ARFLAGS) $(PRIVATE_ARFLAGS) $@ $(PRIVATE_ALL_OBJECTS) @@ -280,9 +278,9 @@ class module: return file_dst - ############################################################################### - ## Commands for running gcc to link a shared library. - ############################################################################### + ## + ## @brief Commands for running gcc to link a shared library. + ## def Link_to_so(self, file, binary, target, depancy, libName=""): if libName=="": libName = self.name @@ -300,8 +298,8 @@ class module: target.global_flags_ld]) # check the dependency for this file : - if False==dependency.NeedRePackage(file_dst, file_src, True, file_cmd, cmdLine) \ - and False==dependency.NeedRePackage(file_dst, depancy.src, False, file_cmd, cmdLine): + if dependency.NeedRePackage(file_dst, file_src, True, file_cmd, cmdLine) == False \ + and dependency.NeedRePackage(file_dst, depancy.src, False, file_cmd, cmdLine) == False: return tmpList[1] lutinTools.CreateDirectoryOfFile(file_dst) debug.printElement("SharedLib", libName, "==>", file_dst) @@ -323,9 +321,9 @@ class module: #debug.printElement("SharedLib", self.name, "==>", tmpList[1]) - ############################################################################### - ## Commands for running gcc to link an executable. - ############################################################################### + ## + ## @brief Commands for running gcc to link an executable. + ## def Link_to_bin(self, file, binary, target, depancy): file_src, file_dst, file_depend, file_cmd = target.GenerateFile(binary, self.name,self.originFolder,file,"bin") #create comdLine : @@ -362,26 +360,34 @@ class module: lutinMultiprocess.StoreCommand(cmdLine, file_cmd) - ############################################################################### - ## Commands for copying files - ############################################################################### + ## + ## @brief Commands for copying files + ## def files_to_staging(self, binaryName, target): for element in self.files: debug.verbose("Might copy file : " + element[0] + " ==> " + element[1]) target.AddFileStaging(self.originFolder+"/"+element[0], element[1]) - ############################################################################### - ## Commands for copying files - ############################################################################### + ## + ## @brief Commands for copying files + ## def folders_to_staging(self, binaryName, target): for element in self.folders: debug.verbose("Might copy folder : " + element[0] + "==>" + element[1]) lutinTools.CopyAnythingTarget(target, self.originFolder+"/"+element[0],element[1]) - ############################################################################### - ## Create the module documentation: - ############################################################################### - def CreateDoc(self, target) : + ## + ## @brief Set the documentation availlable for this module + ## + def doc_enable(self): + self.docPath = lutinTools.GetCurrentPath(self.originFile) + self.documentation = lutinDoc.doc(self.name) + + ## + ## @brief Create the module documentation: + ## @param[in,out] target target that request generation of the documentation + ## + def doc_parse_code(self, target): if self.docPath == "": return False for root, dirnames, filenames in os.walk(self.docPath): @@ -391,9 +397,28 @@ class module: fileCompleteName = os.path.join(root, filename) debug.debug(" Find a file : '" + fileCompleteName + "'") self.documentation.add_file(fileCompleteName) + + ## + ## @brief Generate real documentation files + ## @param[in,out] target target that request generation of the documentation + ## + def doc_generate(self, target): + if self.docPath == "": + return False # Real creation of the documentation : lutinTools.RemoveFolderAndSubFolder(target.GetDocFolder(self.name)); - self.documentation.generate_documantation(target.GetDocFolder(self.name)) + self.documentation.generate_documantation(target, target.GetDocFolder(self.name)) + + + ## + ## @brief Get link on a class or an enum in all the subclasses + ## @param[in] name of the class + ## @return [real element name, link on it] + ## + def doc_get_link(self, target, elementName): + if self.docPath == "": + return [elementName, ""] + return self.documentation.get_class_link_from_target(elementName); # call here to build the module diff --git a/lutinTarget.py b/lutinTarget.py index 86f32a7..2718cc9 100644 --- a/lutinTarget.py +++ b/lutinTarget.py @@ -207,10 +207,18 @@ class Target: self.LoadIfNeeded(modName) def Build(self, name, packagesName=None): - if name == "dump": + if name == "doc": + debug.info("Documentation for all") + self.LoadAll() + print 'Doc all modules' + for mod in self.moduleList: + mod.doc_parse_code(self) + for mod in self.moduleList: + mod.doc_generate(self) + elif name == "dump": debug.info("dump all") self.LoadAll() - print 'Dump all module properties' + print 'Dump all modules properties' for mod in self.moduleList: mod.Display(self) elif name == "all": @@ -261,9 +269,23 @@ class Target: return mod.Build(self, None) elif actionName == "doc": debug.debug("Create doc module '" + moduleName + "'") - return mod.CreateDoc(self) + if mod.doc_parse_code(self) == False: + return False + return mod.doc_generate(self) debug.error("not know module name : '" + moduleName + "' to '" + actionName + "' it") + ## + ## @brief Get link on a class or an enum in all the subclasses + ## @param[in] name of the class + ## @return [real element name, link on it] + ## + def doc_get_link(self, elementName): + for mod in self.moduleList: + elementRealName, link = mod.doc_get_link(self, elementName) + if len(link) != 0: + debug.verbose("find the element : " + elementName + " ==> " + link) + return [elementRealName, link] + return [elementName, ""] __startTargetName="lutinTarget"