From 44dbcdd56d0a472aa2f13a109ada4dffdb0c2506 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Fri, 28 Oct 2016 00:06:05 +0200 Subject: [PATCH] [DEV] add a dependency graph generator lutin dependency:LD ; dot -Tsvg dependency.dot -o dependency.svg ; firefox dependency.svg --- bin/lutin | 45 ++++++++++++--------- lutin/module.py | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ lutin/target.py | 33 +++++++++++++++- 3 files changed, 160 insertions(+), 19 deletions(-) diff --git a/bin/lutin b/bin/lutin index d2840d4..50d2196 100755 --- a/bin/lutin +++ b/bin/lutin @@ -69,6 +69,15 @@ def usage(full=False): print(" clean all (same as previous)") print(" " + color['green'] + "dump" + color['default']) print(" Dump all the module dependency and properties") + print(" " + color['green'] + "dependency" + color['default']) + print(" generate a file dependency.dot that represent all the dependency link") + print(" Select what in included: 'dependency:LPBDK'") + print(" L: Library") + print(" P: Pre-build") + print(" D: Data") + print(" B: Binary") + print(" K: Package") + print(" eg: lutin dependency:LD ; dot -Tsvg dependency.dot -o dependency.svg ; firefox dependency.svg") print(" " + color['green'] + "gcov" + color['default']) print(" Parse all the code of the library with the gcov resolution") listOfAllModule = module.list_all_module_with_desc() @@ -169,18 +178,18 @@ def check_boolean(value): def parseGenericArg(argument, active): debug.extreme_verbose("parse arg : " + argument.get_option_name() + " " + argument.get_arg() + " active=" + str(active)) if argument.get_option_name() == "help": - if active==False: + if active == False: usage() return True if argument.get_option_name() == "HELP": - if active==False: + if active == False: usage(True) return True if argument.get_option_name() == "list-module": - if active==False: - listOfModule = module.list_all_module() + if active == False: + list_of_module = module.list_all_module() retValue = "" - for moduleName in listOfModule: + for moduleName in list_of_module: if retValue != "": retValue += " " retValue += moduleName @@ -188,10 +197,10 @@ def parseGenericArg(argument, active): exit(0) return True if argument.get_option_name() == "list-target": - if active==False: - listOfTarget = target.list_all_target() + if active == False: + list_of_target = target.list_all_target() retValue = "" - for targetName in listOfTarget: + for targetName in list_of_target: if retValue != "": retValue += " " retValue += targetName @@ -199,61 +208,61 @@ def parseGenericArg(argument, active): exit(0) return True elif argument.get_option_name()=="jobs": - if active==True: + if active == True: multiprocess.set_core_number(int(argument.get_arg())) return True elif argument.get_option_name()=="depth": - if active==True: + if active == True: env.set_parse_depth(int(argument.get_arg())) return True elif argument.get_option_name() == "verbose": - if active==True: + if active == True: debug.set_level(int(argument.get_arg())) return True elif argument.get_option_name() == "color": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: debug.enable_color() else: debug.disable_color() return True elif argument.get_option_name() == "force-build": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: env.set_force_mode(True) else: env.set_force_mode(False) return True elif argument.get_option_name() == "pretty": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: env.set_print_pretty_mode(True) else: env.set_print_pretty_mode(False) return True elif argument.get_option_name() == "force-optimisation": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: env.set_force_optimisation(True) else: env.set_force_optimisation(False) return True elif argument.get_option_name() == "isolate-system": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: env.set_isolate_system(True) else: env.set_isolate_system(False) return True elif argument.get_option_name() == "force-strip": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: env.set_force_strip_mode(True) else: env.set_force_strip_mode(False) return True elif argument.get_option_name() == "warning": - if active==True: + if active == True: if check_boolean(argument.get_arg()) == True: env.set_warning_mode(True) else: diff --git a/lutin/module.py b/lutin/module.py index f14d110..8a7456c 100644 --- a/lutin/module.py +++ b/lutin/module.py @@ -1285,6 +1285,107 @@ class Module: print('-----------------------------------------------') return True + def check_rules(self, type, rules): + if ( ( type == 'LIBRARY' \ + or type == 'LIBRARY_DYNAMIC' \ + or type == 'LIBRARY_STATIC' ) \ + and "L" not in rules ) \ + or ( type == 'DATA' \ + and "D" not in rules ) \ + or ( type == 'PREBUILD'\ + and "P" not in rules ) \ + or ( type == 'PACKAGE'\ + and "K" not in rules) \ + or ( ( type == 'BINARY' \ + or type == 'BINARY_SHARED' \ + or type == 'BINARY_STAND_ALONE')\ + and "B" not in rules ) : + return True + return False + + # TODO: Add to simplify the display the possibility to check if an element already depend in dependency of an element ??? + def dependency_generate(self, target, tmp_file, step, rules): + debug.print_element("dot", "dependency.dot", "<<<", self._name) + if self.check_rules(self._type, rules) == True: + return + if step == 1: + if self._type == 'DATA': + tmp_file.write(' node [\n'); + tmp_file.write(' shape=Mdiamond;\n'); + tmp_file.write(' style=filled;\n'); + tmp_file.write(' color=red;\n'); + tmp_file.write(' ];\n'); + elif self._type == 'PREBUILD': + tmp_file.write(' node [\n'); + tmp_file.write(' shape=square;\n'); + tmp_file.write(' style=filled;\n'); + tmp_file.write(' color=gray;\n'); + tmp_file.write(' ];\n'); + elif self._type == 'LIBRARY' \ + or self._type == 'LIBRARY_DYNAMIC' \ + or self._type == 'LIBRARY_STATIC': + tmp_file.write(' node [\n'); + tmp_file.write(' shape=ellipse;\n'); + tmp_file.write(' style=filled;\n'); + tmp_file.write(' color=lightblue;\n'); + tmp_file.write(' ];\n'); + elif self._type == 'BINARY' \ + or self._type == 'BINARY_SHARED' \ + or self._type == 'BINARY_STAND_ALONE': + tmp_file.write(' node [\n'); + tmp_file.write(' shape=rectangle;\n'); + tmp_file.write(' style=filled;\n'); + tmp_file.write(' color=green;\n'); + tmp_file.write(' ];\n'); + elif self._type == 'PACKAGE': + return + tmp_file.write(' ' + copy.deepcopy(self._name).replace('-','_')+ ';\n'); + else: + for elem in self._depends: + debug.verbose("add depend on: " + elem); + tmp_module = None + try: + tmp_module = target.get_module(elem) + except: + target.load_if_needed(elem, optionnal=True) + try: + tmp_module = target.get_module(elem) + except: + debug.verbose(" ==> get error"); + if tmp_module == None: + debug.verbose(" ==> notFound"); + continue + if self.check_rules(tmp_module._type, rules) == True: + debug.verbose(" ==> not in rules"); + continue + tmp_file.write(' ' + copy.deepcopy(self._name).replace('-','_') + ' -> ' + copy.deepcopy(elem).replace('-','_') + ';\n'); + for elem in self._depends_optionnal: + elem = elem[0] + debug.verbose("add depend on: " + elem); + tmp_module = None + try: + tmp_module = target.get_module(elem) + except: + target.load_if_needed(elem, optionnal=True) + try: + tmp_module = target.get_module(elem) + except: + debug.verbose(" ==> get error"); + if tmp_module == None: + debug.verbose(" ==> notFound"); + continue + if self.check_rules(tmp_module._type, rules) == True: + debug.verbose(" ==> not in rules"); + continue + tmp_file.write(' ' + copy.deepcopy(self._name).replace('-','_') + ' -> ' + copy.deepcopy(elem).replace('-','_') + ';\n'); + """ + tmp_file.write(' module_' + self._name.replace('-','_') + ' {\n'); + tmp_file.write(' style=filled;\n'); + tmp_file.write(' color=blue;\n'); + tmp_file.write(' label="' + self._name + '";\n'); + tmp_file.write(' }\n'); + """ + ## ## @brief Get packaging property variable ## @param[in] self (handle) Class handle diff --git a/lutin/target.py b/lutin/target.py index 6653ace..4293c8d 100644 --- a/lutin/target.py +++ b/lutin/target.py @@ -653,11 +653,42 @@ class Target: for mod in self.module_list: mod.display() return + if name[:10] == "dependency": + if len(name) > 10: + rules = name.split(":")[1] + else: + rules = "LBDPK" + # L for library + # B for binary + # D for Data + # P for prebuild + # K for package + debug.print_element("dot", "", "---", "dependency.dot") + self.load_all() + tmp_file = open("dependency.dot", 'w') + tmp_file.write('digraph G {\n') + tmp_file.write(' rankdir=\"LR\";\n') + for mod in self.module_list: + mod.dependency_generate(self, tmp_file, 1, rules) + # TODO : do it better ==> system library hook (do a oad of all avillable system library) + tmp_file.write(' node [\n'); + tmp_file.write(' shape=square;\n'); + tmp_file.write(' style=filled;\n'); + tmp_file.write(' color=gray;\n'); + tmp_file.write(' ];\n'); + # TODO : End hook + for mod in self.module_list: + mod.dependency_generate(self, tmp_file, 2, rules) + tmp_file.write('}\n') + tmp_file.flush() + tmp_file.close() + debug.print_element("dot", "", "---", "dependency.dot") + return if name == "all": debug.info("build all") self.load_all() for mod in self.module_list: - if self._name=="Android": + if self._name == "Android": if mod.get_type() == "PACKAGE": mod.build(self, None) else: