Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
#!/usr/bin/env python3
import os,subprocess,sys,re,pprint,glob,getopt

from psClasses import *
### Global Lists and Directories
SRCDIR ="%s/src/" % os.getenv("CMSSW_BASE")
ServerDict = {}
BuilFilesList = []
ModuleTable = {}
ModuleList = []
buildTree = BuildTreeNodeList()
serverQueues = queueList()


### Functions

def getBuildFiles():
  for cDir,subDirs,files in os.walk(SRCDIR):
    for f in files:
      if re.match(r"BuildFile.xml",f):
        BuilFilesList.append("%s/%s" %(cDir,f) )    
        break
      if re.match(r"BuildFile",f):
        BuilFilesList.append("%s/%s" %(cDir,f) )    
        break

def fillModuleRecord(bFile):
  bNameRegEx=r"file=[\"']*(?P<binNames>[a-zA-Z0-9\._\-\*,;\s]+)[\"']*"
  dirInfo=os.path.dirname(bFile).replace(SRCDIR,"")
  module=dirInfo.split("/")[0]
  subModule="%s/%s" % (module,dirInfo.split("/")[1])
  stdLibName=dirInfo.replace("/","").replace("plugin","Plugin")
  f=open(bFile,"r")
  deps=[]
  line=f.readline()
  libNames=[]
  binNames=[]
  buildFiles=[]
  while line:
    if re.search(r"<use.*",line):
      depName=re.search(r"name=[\"']*(?P<depName>([a-zA-Z0-9]+/[a-zA-Z0-9]+|[a-zA-z0-9._\-]+))[\"']*",line).group("depName")
      os.path.exists("%s/%s" % (SRCDIR,depName)) and deps.append(depName)
    elif re.search(r"\s+<lib ",line):
      libName=re.search(r"name=[\"']*(?P<libName>[a-zA-Z0-9]*)[\"']*",line).group("libName")
      libNames.append(libName == "1" and stdLibName or libName)
    elif re.search(r"<library",line):   
      try:
        libName=re.search(r"name=[\"']*(?P<libName>[a-zA-Z0-9]*)[\"']*",line).group("libName")
      except:
        libName=re.search(r"file=[\"']*(?P<libName>[a-zA-Z0-9_]*).*",line).group("libName")
      libNames.append(libName)
      buildFiles.append(re.search(bNameRegEx,line).group("binNames"))
    elif re.search(r"<bin",line):
      try:
        binNames.append(re.search(r"name=[\"']*(?P<binName>[a-zA-Z0-9_\-]+)[\"']*",line).group("binName"))
      except:
        binNames.append(re.search(r"file=[\"']*(?P<binName>[a-zA-Z0-9_\-]+).*[\"']*",line).group("binName"))
      buildFiles.append(re.search(bNameRegEx,line).group("binNames"))
    line=f.readline()
  f.close()
  dirInfoBFiles= len(dirInfo.split("/"))==2 and "%s/src" % dirInfo or dirInfo
  ## Separating lilst of files to have a complete list of individual source files
  for sep in " \t,;":
    bf2=[]
    for bF1 in [bF.split(sep) for bF in buildFiles]:
      bf2+=bF1
    buildFiles=bf2
  ## Expanding * to file names
  bf2=[]
  for bF1 in [glob.glob("%s/%s" % (dirInfoBFiles,bF)) for bF in buildFiles if os.path.exists("%s/%s" % (dirInfoBFiles,bF)) or "*" in bF ]:
    bf2+=bF1
  bf2=dict.fromkeys(bf2)
  buildFiles=bf2.keys() 
  libNames+=binNames
  return [module,subModule,deps,libNames,buildFiles,len(deps),len(buildFiles)/len(libNames)]

def fillModuleTable():
  for f in BuilFilesList:
    record=fillModuleRecord(f)
    ModuleTable.setdefault(record[0],{}).setdefault(record[1],[]).append(record[2:]+[0])
    ModuleList.append(record)


def fillBuildTree():    
  global serverQueues
  finished=False
  Count=0
  while not finished and Count < 7:
    finished=True
    for item in  ModuleList:
      if len(item[2]) == 0:
        for lib in item[3]:
          if not buildTree.findLib(lib):
            buildTree.append(BuildTreeNode(libname=lib,module=item[0],submodule=item[1],weight=item[6],srvqueue=serverQueues))
      else:      
        deps=item[2]
        libs=item[3]
        for lib in libs:
          pNode=buildTree.findLib(lib)
          if not pNode:
            node=BuildTreeNode(libname=lib,module=item[0],submodule=item[1],weight=item[6],srvqueue=serverQueues)
          else:
            continue
          for dep in deps:
            dpNode=buildTree.findDep(dep)
            if dpNode is not None:
              if dpNode not in node.DependsOn:
                node.DependsOn.append(dpNode)
              if node not in dpNode.AreDependent:
                dpNode.AreDependent.append(node)
            elif len(glob.glob("%s%s/BuildFile*" %(SRCDIR,dep))) == 0 :
              continue
            else:
              finished=False
              if Count==6:
                print "WARNING: Traversed The tree %d times and still there are some missing dependencies and no buildFile found for them: %s" % (Count,dep)
    Count += 1
    
def checkBuildOrder():
  concatenatedLog=[]
  for srv in serverQueues.keys():
    for i in serverQueues[srv].ThreadLog:
      concatenatedLog.append(i[:2])
  concatenatedLog.sort(cmp = lambda x,y: cmp(x[0],y[0]))
  seenLibs=[]
  Result=True
  for lib in concatenatedLog:
    node=buildTree.findLib(lib[1])
    seenLibs.append(lib[1])
    failedDeps=[]
    for depNode in node.DependsOn:
      if depNode.LibName not in seenLibs:
        failedDeps.append(lib)
        Result=False
  return (Result,failedDeps)
  
####
# Main Program
####
  
if not os.getenv("CMSSW_BASE"):
  print "No CMSSW Environment detected"
  sys.exit(os.EX_CONFIG)
 
if __name__ == "__main__":

  """
hosts
  """
  try:
    opts, args = getopt.getopt(sys.argv[1:], "j:n:")
  except getopt.GetoptError, err:
    # print help information and exit:
    print str(err) # will print something like "option -a not recognized"
    sys.exit(2)
  cores = -1
  jay =-1  
  hosts=[arg.replace(","," ") for arg in args]
  for o, a in opts:
    if o == "-j":
        jay = int(a)
    elif o == "-n":
        cores = int(a)
    else:
        assert False, "unhandled option"

  if cores == -1:
    print "Assuming 4 cores servers"
    cores = 4  
  
  if jay == -1:
    print "Assuming 2 threads per job"
    jay = 2
  
  if len(hosts) == 0:
    print "No servers listed"
    sys.exit(1)
  
  for srv in hosts:
    retcode=call(["ping","-c 1",srv],stdout=open("/dev/null"),stderr=open("/dev/null"))
    if retcode is not 0:
      print "Server %s is unreachable" % srv
      sys.exit(retcode)
    
  
  serverQueues = queueList(hosts,cores,jay)
  getBuildFiles()
  fillModuleTable()
  fillBuildTree()
  #print buildTree[1]
  #buildTree.BThread.start()
  #print enumerate()
  print "Setting up caches"
  nullFile=open("/dev/null")
  call(['scram','build','-r','-n'],stdout=nullFile,stderr=nullFile,cwd=os.path.realpath(os.path.curdir))
  nullFile.close()
  print "Starting threads"
  buildTree.startThreads()
  a=len(enumerate())
  while a > 1:
    #print "Running Threads = %d" % a
    a=len(enumerate())
    time.sleep(1)
  for srv in serverQueues.keys():
    for i in serverQueues[srv].ThreadLog:
      print i[2]    
  r,failedLibs = checkBuildOrder()
  print "DepBuild Check %s, failed libs: \n...%s" % (r and "Succeded" or "Failed","\n...".join(failedLibs))