buildframework/helium/tools/common/python/lib/dependancygraph.py
changeset 1 be27ed110b50
child 179 d8ac696cc51f
equal deleted inserted replaced
0:044383f39525 1:be27ed110b50
       
     1 #============================================================================ 
       
     2 #Name        : dependancygraph.py
       
     3 #Part of     : Helium 
       
     4 
       
     5 #Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     6 #All rights reserved.
       
     7 #This component and the accompanying materials are made available
       
     8 #under the terms of the License "Eclipse Public License v1.0"
       
     9 #which accompanies this distribution, and is available
       
    10 #at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
    11 #
       
    12 #Initial Contributors:
       
    13 #Nokia Corporation - initial contribution.
       
    14 #
       
    15 #Contributors:
       
    16 #
       
    17 #Description:
       
    18 #===============================================================================
       
    19 
       
    20 import os
       
    21 import amara
       
    22 import codecs
       
    23 import zipfile
       
    24 from Ft.Lib import Uri
       
    25 
       
    26 class Library:
       
    27     def __init__(self, name, license, version=''):
       
    28         self.name = name
       
    29         self.license = license
       
    30         self.version = version
       
    31         self.requires = []
       
    32 
       
    33 class ModuleGroup:
       
    34     def __init__(self):
       
    35         self.libraries = {}
       
    36     def addConf(self, name, des, color):
       
    37         self.libraries[name] = (des, [], color)
       
    38     def addLibrary(self, conf, library):
       
    39         for lib in self.getLibraries(conf):
       
    40             if lib.name.lower() == library.name.lower():
       
    41                 lib.license = library.license
       
    42                 return
       
    43         self.getLibraries(conf).append(library)
       
    44     def getLibraries(self, conf):
       
    45         (_, libs, _) = self.libraries[conf]
       
    46         return libs
       
    47     def getDescription(self, conf):
       
    48         (des, _, _) = self.libraries[conf]
       
    49         return des
       
    50     def getColor(self, conf):
       
    51         (_, _, color) = self.libraries[conf]
       
    52         return color
       
    53 
       
    54 COLORS = ['pink', 'red', 'lightblue', 'orange', 'green', 'yellow', 'turquoise', 'limegreen']
       
    55 
       
    56 class ReadIvyConfig:
       
    57     def __init__(self, ivyfilename):
       
    58         self.ivyfilename = ivyfilename
       
    59         self.ivyxml = amara.parse(Uri.OsPathToUri(ivyfilename))
       
    60         self.group = ModuleGroup()
       
    61 
       
    62     def readConfigurations(self):
       
    63         for conf in self.ivyxml['ivy-module'].configurations.conf:
       
    64             color = COLORS.pop()
       
    65             self.group.addConf(conf.name, conf.description, color)
       
    66 
       
    67     def readModules(self):
       
    68         license = ''
       
    69         for module in self.ivyxml['ivy-module'].dependencies.xml_children:
       
    70             if hasattr(module, 'data'):
       
    71                 if 'License:' in module.data:
       
    72                     license = module.data.strip()
       
    73             elif hasattr(module, 'name'):
       
    74                 modulename = module.name.replace('-', '_')
       
    75             
       
    76                 if module.org != 'SWEPT':
       
    77                     self.group.addLibrary(module.conf, Library(modulename, license))
       
    78                     license = ''
       
    79 
       
    80     def readSubModules(self):
       
    81         for module in self.ivyxml['ivy-module'].dependencies.xml_children:
       
    82             if hasattr(module, 'name'):
       
    83                 if 'jars' in module.name:
       
    84                     ivydir = os.path.dirname(self.ivyfilename)
       
    85                     ivydir = os.path.join(ivydir, 'modules')
       
    86                     ivyjarfile = os.path.join(ivydir, module.name + '-1.0.ivy.xml')
       
    87                     ivymodulexml = amara.parse(Uri.OsPathToUri(ivyjarfile))
       
    88                     license = ''
       
    89                     for artifact in ivymodulexml['ivy-module'].publications.xml_children:
       
    90                         if hasattr(artifact, 'data'):
       
    91                             if 'License:' in artifact.data:
       
    92                                 license = artifact.data.strip()
       
    93                         elif hasattr(artifact, 'name'):
       
    94                             bits = artifact.name.split('-')
       
    95                             name = bits[0]
       
    96                             version = ''
       
    97                             if len(bits) > 1:
       
    98                                 version = bits[1]
       
    99                             self.group.addLibrary(module.conf, Library(name, license, version))
       
   100                             license = ''
       
   101 
       
   102 PYTHON_GROUP = True
       
   103 SUBCON_PYTHON_GROUP = False
       
   104 
       
   105 def readEggs(libraries, dirtosearch, internaldir):
       
   106     libraries.addConf(PYTHON_GROUP, 'Python libs', libraries.getColor('core_install'))
       
   107     libraries.addConf(SUBCON_PYTHON_GROUP, 'Python subcon libs', libraries.getColor('subcon'))
       
   108     
       
   109     for x in [os.walk(dirtosearch, topdown=False), os.walk(internaldir, topdown=False)]:
       
   110         for root, _, files in x:
       
   111             notinsubcon = os.path.normpath(internaldir) in os.path.normpath(root)
       
   112             
       
   113             for fname in files:
       
   114                 filename = os.path.join(root, fname)
       
   115                 if fname == 'PKG-INFO':
       
   116                     pkgmetafile = open(filename)
       
   117                     library = readPkgInfo(pkgmetafile)
       
   118                     pkgmetafile.close()
       
   119                     
       
   120                     requirefilename = os.path.join(filename, '..', 'requires.txt')
       
   121                     if os.path.exists(requirefilename):
       
   122                         requiresfile = open(requirefilename)
       
   123                         readRequiresFile(requiresfile, library)
       
   124                         requiresfile.close()
       
   125                         
       
   126                     libraries.addLibrary(notinsubcon, library)
       
   127                     
       
   128                 if os.path.isfile(filename) and fname.endswith('.egg'):
       
   129                     eggfile = zipfile.ZipFile(filename, 'r', zipfile.ZIP_DEFLATED)
       
   130                     
       
   131                     data = eggfile.read('EGG-INFO/PKG-INFO')
       
   132                     
       
   133                     library = readPkgInfo(data.split('\n'))
       
   134                     
       
   135                     if 'EGG-INFO/requires.txt' in eggfile.namelist():
       
   136                         requiresdata = eggfile.read('EGG-INFO/requires.txt')
       
   137                         readRequiresFile(requiresdata.split('\n'), library)
       
   138                         
       
   139                     libraries.addLibrary(notinsubcon, library)
       
   140                     
       
   141                     eggfile.close()
       
   142 
       
   143 def readRequiresFile(data, library):
       
   144     for line in data:
       
   145         line = line.strip()
       
   146         if line != '' and not (line.startswith('[') and line.endswith(']')):
       
   147             library.requires.append(line.split('>=')[0].strip())
       
   148 
       
   149 def readPkgInfo(data):
       
   150     name = ''
       
   151     version = ''
       
   152     license = ''
       
   153     license2 = ''
       
   154   
       
   155     for line in data:
       
   156         if 'Name:' in line:
       
   157             name = line.strip().replace('Name: ', '')
       
   158         if 'Version:' in line:
       
   159             version = line.strip().replace('Version: ', '')
       
   160         if 'License:' in line:
       
   161             license = line.strip().replace('License: ', '')                    
       
   162         if 'Classifier: License :: ' in line:
       
   163             license2 = license2 + ' ' + line.strip().replace('Classifier: License :: ', '').replace('OSI Approved :: ', '')
       
   164     
       
   165     if license.lower() == 'unknown' or license == '' or license2 != '':
       
   166         license = license2
       
   167     
       
   168     return Library(name, license, version)
       
   169 
       
   170 def addLicensesColors(graphdata, group):
       
   171     newgraphdata = []
       
   172     for line in graphdata:
       
   173         newline = line
       
   174         for conf in group.libraries:
       
   175             for module in group.getLibraries(conf):
       
   176                 if module.name.lower() in line.lower() and 'label=' in line:
       
   177                     newline = line.replace('label=', 'color=%s,label=' % group.getColor(conf))
       
   178                     
       
   179                     if module.license != '':
       
   180                         newline = newline.replace("\"];", "|%s\"];" % module.license)
       
   181                     
       
   182                     break
       
   183         newgraphdata.append(newline)
       
   184     return newgraphdata
       
   185     
       
   186 def createKey(group):
       
   187     key = """subgraph cluster1 {
       
   188     label = "Key";
       
   189     style=filled;
       
   190     color=lightgrey;
       
   191     """
       
   192     
       
   193     for conf in group.libraries:
       
   194         if conf != PYTHON_GROUP and conf != SUBCON_PYTHON_GROUP:
       
   195             key = key + "\"%s: %s\" [style=filled,color=%s];" % (conf, group.getDescription(conf), group.getColor(conf))
       
   196     
       
   197     key = key + "}"
       
   198     return key
       
   199 
       
   200 def createGraph(ivyxmlfilename, graphfilename, dirtosearch, internaldir, subcon):
       
   201     readivy = ReadIvyConfig(ivyxmlfilename)
       
   202     readivy.readConfigurations()
       
   203     readivy.readModules()
       
   204     readivy.readSubModules()
       
   205     
       
   206     group = readivy.group
       
   207     
       
   208     readEggs(group, dirtosearch, internaldir)
       
   209     
       
   210     key = createKey(group)
       
   211     
       
   212     graphdata = loadGraphFile(graphfilename)
       
   213     
       
   214     newgraphdata = addLicensesColors(graphdata, group)
       
   215     
       
   216     #add key to graph
       
   217     newgraphdata[-1] = newgraphdata[-1].replace('}', key + '\n}')
       
   218     
       
   219     graphwritefile = codecs.open(graphfilename, 'w', 'utf8')
       
   220     graphwritefile.writelines(newgraphdata)
       
   221     graphwritefile.close()
       
   222     
       
   223     linkPythonLibs(group, graphfilename, subcon)
       
   224 
       
   225 def loadGraphFile(graphfilename):
       
   226     destgraphfile = codecs.open(graphfilename, 'r', 'utf8')
       
   227     graphdata = []
       
   228     for line in destgraphfile:
       
   229         graphdata.append(line)
       
   230     destgraphfile.close()
       
   231     return graphdata
       
   232 
       
   233 def addToGraph(graphfilenametoadd, destgraphfilename):
       
   234     graphdata = loadGraphFile(destgraphfilename)
       
   235     
       
   236     graphfile = codecs.open(graphfilenametoadd, 'r', 'utf8')
       
   237     graphdatatoadd = ''
       
   238     for line in graphfile:
       
   239         line = line.replace('digraph {', '')
       
   240         graphdatatoadd = graphdatatoadd + line
       
   241     graphfile.close()
       
   242     
       
   243     graphdata[-1] = graphdata[-1].replace('}', graphdatatoadd)
       
   244     
       
   245     graphwritefile = codecs.open(destgraphfilename, 'w', 'utf8')
       
   246     graphwritefile.writelines(graphdata)
       
   247     graphwritefile.close()
       
   248 
       
   249 def linkPythonLibs(libraries, destgraphfilename, subcon):    
       
   250     graphdata = loadGraphFile(destgraphfilename)
       
   251   
       
   252     output = "helium_ant -> helium_python;\n"
       
   253     
       
   254     if subcon:
       
   255         list = [SUBCON_PYTHON_GROUP]
       
   256     else:
       
   257         list = [SUBCON_PYTHON_GROUP, PYTHON_GROUP]
       
   258     
       
   259     for group in list:
       
   260         for lib in libraries.getLibraries(group):
       
   261             output = output + ("helium_python -> \"%s\";\n" % lib.name)
       
   262             output = output + ("\"%s\" [style=filled,shape=record,color=%s,label=\"%s %s|%s\"];\n" % (lib.name, libraries.getColor(group), lib.name, lib.version, lib.license))
       
   263             
       
   264             for require in lib.requires:
       
   265                 output = output + ("\"%s\" -> \"%s\";\n" % (lib.name, require))
       
   266     
       
   267     graphdata.reverse()
       
   268     for line in graphdata:
       
   269         if line.strip() == '':
       
   270             graphdata.pop(0)
       
   271         else:
       
   272             break
       
   273     graphdata.reverse()
       
   274     
       
   275     graphdata[-1] = graphdata[-1].replace('}', output + '}')
       
   276     
       
   277     graphwritefile = codecs.open(destgraphfilename, 'w', 'utf8')
       
   278     graphwritefile.writelines(graphdata)
       
   279     graphwritefile.close()
       
   280 
       
   281 def externalDependancies(database, output):
       
   282     out = open(output, 'w')
       
   283     db = amara.parse(Uri.OsPathToUri(database))
       
   284     out.write('digraph G {\n')
       
   285     for p in db.antDatabase.project:
       
   286         items = []
       
   287         if hasattr(p, 'property'):
       
   288             for prop in p.property:
       
   289                 if 'external' + os.sep in os.path.abspath(str(prop.defaultValue)):
       
   290                     items.append(str(prop.defaultValue))
       
   291         if hasattr(p, 'fileDependency'):
       
   292             for dep in p.fileDependency:
       
   293                 dep = str(dep).split(' ')[0]
       
   294                 if 'external' + os.sep in os.path.abspath(str(dep)):
       
   295                     items.append(str(dep))
       
   296                     
       
   297         items = set(items)
       
   298         for i in items:
       
   299             out.write('\"%s\" -> \"%s\"\n' % (str(p.name), i.replace(os.environ['HELIUM_HOME'], 'helium').replace(os.sep, '/')))
       
   300     out.write('}')                
       
   301     out.close()
       
   302 
       
   303 def appendLogs(t, p, output, macro=False):
       
   304     if hasattr(t, 'signal'):
       
   305         for signal in t.signal:
       
   306             if macro:
       
   307                 output.append("\"%s\" [fontname=\"Times-Italic\"];" % str(t.name))
       
   308             output.append('subgraph \"cluster%s\" {label = \"%s\"; \"%s\"}\n' % (str(p.name), str(p.name), str(t.name)))
       
   309             s = str(signal).split(',')
       
   310             if len(s) > 1:
       
   311                 if s[1] == 'now':
       
   312                     color = 'red'
       
   313                 elif s[1] == 'defer':
       
   314                     color = 'yellow'
       
   315                 else:
       
   316                     color = 'green'
       
   317                 output.append('subgraph \"cluster%s\" {color=%s;style=filled;label = \"Failbuild: %s\"; \"%s\"}\n' % (str(s[1]), color, str(s[1]), str(s[0])))
       
   318             output.append('\"%s\" -> \"%s\" [style=dotted]\n' % (str(t.name), str(s[0])))
       
   319     if hasattr(t, 'log'):
       
   320         for log in t.log:
       
   321             logdir = '/output/logs/'
       
   322             logname = os.path.basename(str(log))
       
   323             if not ('**' in logname):
       
   324                 logname = logname.replace('*', '${sysdef.configuration}').replace('--logfile=', '')
       
   325                 if not logdir in logname:
       
   326                     logname = logdir + logname
       
   327                 logname = logname.replace(os.sep, '/')
       
   328                 
       
   329                 if macro:
       
   330                     output.append("\"%s\" [fontname=\"Times-Italic\"];" % str(t.name))
       
   331                 output.append('subgraph \"cluster%s\" {label = \"%s\"; \"%s\"}\n' % (str(p.name), str(p.name), str(t.name)))
       
   332                 output.append('\"%s\" -> \"%s\"\n' % (str(t.name), logname))
       
   333 
       
   334 def findLogFiles(database, output):
       
   335     out = open(output, 'w')
       
   336     db = amara.parse(Uri.OsPathToUri(database))
       
   337     out.write('digraph G {\n')
       
   338     output = []
       
   339     
       
   340     for p in db.antDatabase.project:
       
   341         if hasattr(p, 'macro'):
       
   342             for t in p.macro:
       
   343                 appendLogs(t, p, output, True)
       
   344         if hasattr(p, 'target'):
       
   345             for t in p.target:
       
   346                 appendLogs(t, p, output)
       
   347     for l in set(output):
       
   348         out.write(l)
       
   349     out.write('}')                
       
   350     out.close()