00001 #!/usr/local/bin/python 00002 # 00003 # Copyright 2002 00004 # by 00005 # The Board of Trustees of the 00006 # Leland Stanford Junior University. 00007 # All rights reserved. 00008 # 00009 00010 """Version retrieval utility class 00011 00012 Contents: 00013 00014 Provides accessor methods to retrieve version information from 00015 both the software and hardware. 00016 Displays version info from loaded libraries. 00017 Used for troubleshooting problems. 00018 00019 Overview: 00020 00021 Each driver on VxWorks side and each module on the client side 00022 provides its version number through functions. When the function 00023 cmd.getVersions() is called the command server packetizes this 00024 information and sends it over the socket to the command client 00025 which gets decoded into a tuple. The getModuleVersions() function 00026 converts this tuple to a dictionary and adds the python module 00027 versions to it. 00028 00029 Usage: 00030 00031 To retrieve version information one can write:: 00032 00033 python versions.py 00034 00035 or 00036 00037 import versions 00038 versions.Gversions.getModuleVersions() 00039 """ 00040 00041 __facility__ = "Online" 00042 __abstract__ = "Version retrieval utility" 00043 __author__ = "Selim Tuvi <stuvi@slac.stanford.edu> SLAC - GLAST I&T/Online" 00044 __date__ = ("$Date: 2006/07/03 21:03:14 $").split(' ')[1] 00045 __version__ = "$Revision: 2.35 $" 00046 __release__ = "$Name: R04-12-00 $" 00047 __credits__ = "SLAC" 00048 00049 import LATTE.copyright_SLAC 00050 00051 00052 import sha 00053 import marshal 00054 import inspect 00055 import os 00056 import sys 00057 import glob 00058 import logging as log 00059 import compiler 00060 00061 ROOT_DIR_ENVS = ['LATTE_ROOT','VXW_ROOT','LAT_ROOT','INT_ROOT','ACD_ROOT','CAL_ROOT','TKR_ROOT','ELX_ROOT','TRG_ROOT'] 00062 00063 class Gversions(object): 00064 def getModuleVersions(ocs=None): 00065 """Static class method which returns a dictionary of modules 00066 with their versions. 00067 00068 \param ocs GOCS node 00069 00070 \return Dictionary of modules with their versions 00071 """ 00072 ignoreList = [ 'scipy.gplt','ROOT' 00073 #'__main__','_xmlplus','cPickle','pickle','sre','urllib', 00074 #'xml','_xmlplus','xml.parsers.expat', 'xml.parsers.pyexpat', 00075 #'pyexpat' 00076 ] 00077 versions = {} 00078 if ocs is not None: 00079 (server_version, server_revision) = ocs.getVersion() 00080 versions['OCS(server)'] = '%d.%d' %(server_version, server_revision) 00081 for (name, data) in ocs.cmxAsBuilt().items(): 00082 package = data[0] 00083 version = data[1] 00084 #user = data[2] 00085 #time = data[3] 00086 versions['%s[%s]' % (package, name)] = version 00087 startupScriptInfo = ocs.getStartupScriptInfo() 00088 if startupScriptInfo is not None: 00089 versions[startupScriptInfo[0]] = startupScriptInfo[1] 00090 mstrList = sys.modules.keys() 00091 mstrList.sort() 00092 for mStr in mstrList: 00093 if mStr in ignoreList: continue 00094 m = sys.modules[mStr] 00095 if hasattr(m, '__version__'): 00096 v = Gversions.extractVersion(str(getattr(m, '__version__'))) 00097 if v.strip() != '' or Gversions.isModuleInReleases(m): 00098 versions[mStr] = v 00099 elif Gversions.isModuleInReleases(m): 00100 versions[mStr] = '' 00101 00102 versions['Python'] = str(hex(sys.hexversion)) 00103 try: 00104 import qt 00105 versions['Qt'] = qt.QT_VERSION_STR 00106 except: pass 00107 try: 00108 import sip 00109 if 'SIP_VERSION' in dir(sip): 00110 versions['SIP'] = hex(sip.SIP_VERSION) 00111 except: pass 00112 try: 00113 if 'PYQT_VERSION_STR' in dir(qt): 00114 versions['PyQt'] = qt.PYQT_VERSION_STR 00115 else: 00116 versions['PyQt'] = qt.PYQT_VERSION 00117 except: pass 00118 return versions 00119 getModuleVersions = staticmethod(getModuleVersions) 00120 00121 def isModuleInReleases(m, rootDirEnvs=None): 00122 if rootDirEnvs is None: 00123 rootDirEnvs = ROOT_DIR_ENVS 00124 if hasattr(m, '__file__'): 00125 srcFile = inspect.getsourcefile(m) 00126 if srcFile is not None: 00127 srcFile = os.path.normpath(os.path.normcase(srcFile)) 00128 for rootDirEnv in rootDirEnvs: 00129 if os.environ.has_key(rootDirEnv): 00130 rootDir = os.path.normpath(os.path.normcase(os.environ[rootDirEnv].strip())) 00131 if srcFile.startswith(rootDir): 00132 return True 00133 return False 00134 isModuleInReleases = staticmethod(isModuleInReleases) 00135 00136 00137 def extractVersion(verStr): 00138 """Static class method which extracts the version string from the CVS 00139 keyword string, if that's what it appears to be. If it doesn't, just 00140 return the input.""" 00141 colon = verStr.find(':') 00142 if colon != -1: 00143 dollar = verStr.find('$', colon) 00144 if dollar != -1: 00145 return verStr[colon+2:dollar-1] 00146 return verStr 00147 extractVersion = staticmethod(extractVersion) 00148 00149 def calcDigest(filePath): 00150 digest = sha.new() 00151 f = file(filePath, 'rb') 00152 data = f.read(65536) 00153 while len(data) != 0: 00154 digest.update(data) 00155 data = f.read(65536) 00156 f.close() 00157 #return digest.hexdigest() 00158 return digest.digest() 00159 calcDigest = staticmethod(calcDigest) 00160 00161 00162 def getModuleDigests(): 00163 ignoreList = ['scipy.gplt','ROOT'] 00164 digests = {} 00165 mstrList = sys.modules.keys() 00166 mstrList.sort() 00167 for mStr in mstrList: 00168 if mStr in ignoreList: continue 00169 m = sys.modules[mStr] 00170 if hasattr(m, '__version__') and hasattr(m, '__file__'): 00171 srcFile = inspect.getsourcefile(m) 00172 digest_value = Gversions.calcDigest(srcFile) 00173 if digest_value is not None: 00174 digests[mStr] = digest_value 00175 return digests 00176 getModuleDigests = staticmethod(getModuleDigests) 00177 00178 def getReleaseFromDigest(digestDataFile=None, rootDirEnv='LATTE_ROOT'): 00179 if os.environ.has_key(rootDirEnv): 00180 rootDir = os.environ[rootDirEnv].strip() 00181 else: 00182 rootDir = '' 00183 if digestDataFile == None and rootDir == '': 00184 raise RuntimeError, "Can not find the digest database file at the indicated location: $%s" % rootDirEnv 00185 elif digestDataFile == None: 00186 digestDataFile = os.path.join(rootDir, 'digestData') 00187 f = file(digestDataFile,'rb') 00188 try: 00189 dc = marshal.load(f) 00190 except ValueError: 00191 log.exception("") 00192 Gversions.logBadMarshalDataMessage() 00193 return 00194 exec(dc) 00195 return _digestData._release 00196 getReleaseFromDigest = staticmethod(getReleaseFromDigest) 00197 00198 def logBadMarshalDataMessage(): 00199 log.error("If the above exception is a 'bad marshal data' error,") 00200 log.error("it is likely that you need to update one or more of the") 00201 log.error("digestData files pointed to by the XXX_ROOT environment") 00202 log.error("variables. To create the digestData file, enter the") 00203 log.error("following command for each of the XXX_ROOT that you have:") 00204 log.error("%%ONLINE_ROOT%%\LATTE\setup\createDigestData %%XXX_ROOT%% %s XXX_00_00_00" % sys.prefix) 00205 logBadMarshalDataMessage = staticmethod(logBadMarshalDataMessage) 00206 00207 def verifyModuleDigests(digestDataFile=None, rootDirEnv='LATTE_ROOT', additionalFilesToVerify=[]): 00208 ignoreList = ['scipy.gplt','ROOT'] 00209 failedModules = [] 00210 rootDir = '' 00211 if os.environ.has_key(rootDirEnv): 00212 rootDir = os.environ[rootDirEnv].strip() 00213 if digestDataFile == None and rootDir == '': 00214 raise RuntimeError, "Can not find the digest database file at the indicated location: $%s" % rootDirEnv 00215 elif digestDataFile == None: 00216 digestDataFile = os.path.join(rootDir, 'digestData') 00217 f = file(digestDataFile,'rb') 00218 try: 00219 dc = marshal.load(f) 00220 except ValueError: 00221 log.exception("") 00222 Gversions.logBadMarshalDataMessage() 00223 return (None, []) 00224 exec(dc) 00225 mstrList = sys.modules.keys() 00226 mstrList.sort() 00227 for mStr in mstrList: 00228 if mStr in ignoreList: continue 00229 #raw_input("Entering %s}" % mStr) 00230 m = sys.modules[mStr] 00231 if hasattr(m, '__file__'): 00232 srcFile = inspect.getsourcefile(m) 00233 if srcFile is not None: 00234 srcFile = os.path.normpath(os.path.normcase(srcFile)) 00235 if srcFile.startswith(os.path.normpath(os.path.normcase(rootDir))): 00236 found = False 00237 for (filename, digest) in _digestData._digests.items(): 00238 if srcFile == os.path.normpath(os.path.normcase(filename)): 00239 found = True 00240 digest_value = Gversions.calcDigest(srcFile) 00241 if digest_value is None or digest != digest_value: 00242 failedModules.append(mStr) 00243 break 00244 if not found: 00245 failedModules.append(mStr) 00246 #raw_input("Exiting %s}" % mStr) 00247 00248 for fileSpec in additionalFilesToVerify: 00249 for filePath in glob.glob(fileSpec): 00250 normPath = os.path.normpath(os.path.normcase(filePath)) 00251 if normPath.startswith(os.path.normpath(os.path.normcase(rootDir))): 00252 for (filename, digest) in _digestData._digests.items(): 00253 if normPath == os.path.normpath(os.path.normcase(filename)): 00254 digest_value = Gversions.calcDigest(normPath) 00255 if digest_value is None or digest != digest_value: 00256 failedModules.append(os.path.split(filePath)[1]) 00257 break 00258 00259 return (_digestData._release, failedModules) 00260 verifyModuleDigests = staticmethod(verifyModuleDigests) 00261 00262 def findVersionSymbol(filePath): 00263 """\brief Find the __version__ symbol in the file. 00264 00265 \param filePath Full path of the module source code 00266 00267 \return Version number or None if not found. 00268 """ 00269 found = False 00270 try: 00271 ast = compiler.parseFile(filePath) 00272 for node in ast.node.nodes: 00273 if node.__class__.__name__ == 'Assign': 00274 if sys.hexversion > 0x20305f0: 00275 if node.asList()[0].asList()[0] == '__version__': 00276 version = node.asList()[1].asList()[0] 00277 else: 00278 continue 00279 else: 00280 if node.asList()[0][0] == '__version__': 00281 version = node.asList()[1][0] 00282 else: 00283 continue 00284 if type(version) is str and version.startswith('$Revision:'): 00285 return Gversions.extractVersion(version) 00286 else: 00287 #print "*** %s: __version__ symbol found but does not begin with $Revision:" % filePath 00288 return None 00289 except: 00290 log.exception("Error in parsing file: %s" % filePath) 00291 00292 if not found: 00293 #print "*** %s: Missing __version__" % filePath 00294 return None 00295 findVersionSymbol = staticmethod(findVersionSymbol) 00296 00297 def verifyFileDigests(path=None, rootDirEnv='LATTE_ROOT', digestDataFile=None): 00298 skipVersionCheck = {'LATTE_ROOT': ['sipconfig.py', 'pyqtconfig.py', 'testAppNoVersion.py']} 00299 failedFiles = [] 00300 rootDir = '' 00301 if os.environ.has_key(rootDirEnv): 00302 rootDir = os.environ[rootDirEnv].strip() 00303 if path is None and rootDir == '': 00304 raise RuntimeError, "Can not determine which path to verify" 00305 elif path is None: 00306 path = rootDir 00307 #digests = Gversions.collectDigests(path) 00308 if digestDataFile is None and rootDir == '': 00309 msg = "Can not find the digest database file at the indicated location: $%s" % rootDirEnv 00310 log.error(msg) 00311 raise RuntimeError, msg 00312 elif digestDataFile is None: 00313 digestDataFile = os.path.join(rootDir, 'digestData') 00314 f = file(digestDataFile,'rb') 00315 try: 00316 dc = marshal.load(f) 00317 except ValueError: 00318 log.exception("") 00319 Gversions.logBadMarshalDataMessage() 00320 return (None, []) 00321 exec(dc) 00322 for (filename, digest) in _digestData._digests.items(): 00323 if os.path.exists(filename): 00324 fileDigest = Gversions.calcDigest(filename) 00325 if digest != fileDigest: 00326 failedFiles.append(filename) 00327 if os.path.splitext(filename)[1] == '.py': 00328 if rootDirEnv in skipVersionCheck: 00329 if os.path.split(filename)[1] in skipVersionCheck[rootDirEnv]: 00330 continue 00331 if Gversions.findVersionSymbol(filename) is None: 00332 failedFiles.append(filename) 00333 else: 00334 failedFiles.append(filename) 00335 return (_digestData._release, failedFiles) 00336 verifyFileDigests = staticmethod(verifyFileDigests) 00337 00338 def collectDigests(path): 00339 def collectDigests2(digests, dir, files): 00340 ignoredDirs = ['CVS', 'cfitsio_swig'] 00341 validExtensions = ['.py','.exe','.xml','.vx','.o'] 00342 l = len(files) 00343 for i in range(l-1,-1,-1): 00344 if files[i] in ignoredDirs: 00345 del files[i] 00346 else: 00347 fullFilename = os.path.normpath(os.path.join(dir, files[i])) 00348 if not os.path.isdir(fullFilename) and not os.path.islink(fullFilename): 00349 if os.path.splitext(files[i])[1].lower() in validExtensions: 00350 digest = Gversions.calcDigest(fullFilename) 00351 if digest is not None: 00352 if digests.has_key(fullFilename): 00353 print "DUPLICATE ENTRY DETECTED:", fullFilename 00354 else: 00355 digests[fullFilename] = digest 00356 else: 00357 print "NO DIGEST FOR", files[i] 00358 digests = {} 00359 path = os.path.normpath(os.path.abspath(path)) 00360 if os.path.isdir(path): 00361 os.path.walk(path, collectDigests2, digests) 00362 #~ for (file, digest) in digests.items(): 00363 #~ print file #, repr(digest) 00364 #~ x = digests.keys() 00365 #~ x.sort() 00366 #~ for f in x: 00367 #~ print f 00368 return digests 00369 else: 00370 return None 00371 collectDigests = staticmethod(collectDigests) 00372 00373 00374 def getHardwareVersions(lat, xbrd=None): 00375 """Static class method which retrieves 00376 hardware versions. 00377 00378 Keyword arguments: 00379 00380 cmd -- optional command client (default None) 00381 00382 """ 00383 versions = {} 00384 glt = None 00385 if xbrd is not None: glt = xbrd.GLT 00386 if glt is not None: 00387 glt.initialize() 00388 # set trigger mask to allow commanding 00389 glt.disableMask() 00390 save_busy_disable = glt.busy_disable 00391 glt.busy_disable = 0x0 00392 gtemVersions = [] 00393 gcrcVersions = [] 00394 gtrcVersions = [] 00395 for (temId, tem) in lat.TEM.items(): 00396 try: 00397 temVer = int((tem.status >> 16) & 0x3F) 00398 if temVer not in gtemVersions: 00399 gtemVersions.append(temVer) 00400 for (cccId, ccc) in tem.CCC.items(): 00401 for (crcId, crc) in ccc.CRC.items(): 00402 try: 00403 crcVer = int((crc.config >> 12) & 7) 00404 if crcVer not in gcrcVersions: 00405 gcrcVersions.append(crcVer) 00406 except: pass 00407 for (tccId, tcc) in tem.TCC.items(): 00408 for (trcId, trc) in tcc.TRC.items(): 00409 try: 00410 trcVer = int((trc.csr >> 34) & 0x0F) 00411 if trcVer not in gtrcVersions: 00412 gtrcVersions.append(trcVer) 00413 except: pass 00414 except: pass 00415 if len(gtemVersions) > 1: 00416 versions['TEM'] = str(gtemVersions) 00417 elif len(gtemVersions) == 1: 00418 versions['TEM'] = str(gtemVersions[0]) 00419 if len(gcrcVersions) > 1: 00420 versions['GCRC'] = str(gcrcVersions) 00421 elif len(gcrcVersions) == 1: 00422 versions['GCRC'] = str(gcrcVersions[0]) 00423 if len(gtrcVersions) > 1: 00424 versions['GTRC'] = str(gtrcVersions) 00425 elif len(gtrcVersions) == 1: 00426 versions['GTRC'] = str(gtrcVersions[0]) 00427 aem = lat.AEM 00428 if aem is not None: 00429 try: 00430 versions['AEM'] = str(aem.configuration & 0xFF) 00431 garcVersions = [] 00432 gafeVersions = [] 00433 for (arcId, arc) in aem.ARC.items(): 00434 try: 00435 arcVer = str(arc.garc_version) 00436 if arcVer not in garcVersions: 00437 garcVersions.append(arcVer) 00438 for (afeId, afe) in arc.AFE.items(): 00439 try: 00440 afeVer = afe.vers_addr 00441 if afeVer not in gafeVersions: 00442 gafeVersions.append(afeVer) 00443 except: pass 00444 except: pass 00445 if len(garcVersions) > 1: 00446 versions['GARC'] = str(garcVersions) 00447 elif len(garcVersions) == 1: 00448 versions['GARC'] = str(garcVersions[0]) 00449 if len(gafeVersions) > 1: 00450 versions['GAFE'] = str(gafeVersions) 00451 elif len(gafeVersions) == 1: 00452 versions['GAFE'] = str(gafeVersions[0]) 00453 except: pass 00454 if glt is not None: 00455 glt = xbrd.GLT 00456 glt.enableMask() 00457 glt.busy_disable = save_busy_disable 00458 #except IOError: 00459 # pass 00460 return versions 00461 getHardwareVersions = staticmethod(getHardwareVersions) 00462 00463 def printVersions(ocs, lat=None, xbrd=None): 00464 print "\nCurrent Release: %s\n" % Gversions.getReleaseFromDigest() 00465 print "%-30s %10.10s" % ("Module", "Version") 00466 print "%-30s %10.10s" % ("--------", "-------") 00467 versions = Gversions.getModuleVersions(ocs) 00468 modList = versions.keys() 00469 modList.sort() 00470 for module in modList: 00471 print "%-30s %10.10s" % (module, versions[module]) 00472 if lat is not None: 00473 hw_versions = Gversions.getHardwareVersions(lat, xbrd) 00474 if hw_versions != {}: 00475 print 00476 print "%-30s %10.10s" % ("Component", "Version") 00477 print "%-30s %10.10s" % ("---------", "-------") 00478 for (hw_comp, version) in hw_versions.items(): 00479 print "%-30s %10.10s" % (hw_comp, version) 00480 printVersions = staticmethod(printVersions) 00481 00482 if __name__ == '__main__': 00483 # Imports here are specified so that the versions for 00484 # all loaded modules can be retrieved. Add any additional 00485 # module imports here if they are to be reported in the 00486 # output of versions.bat 00487 # In order for all module versions to be reported, the __all__ 00488 # variable in __init__.py of each package needs to be fully 00489 # populated. 00490 from LATTE.client import * 00491 from LATTE.database import * 00492 from LATTE.browser import * 00493 from LATTE.client import * 00494 from LATTE.consumer import * 00495 from LATTE.dispatch import * 00496 from LATTE.gosed import * 00497 from LATTE.logger import * 00498 from LATTE.monitoring import * 00499 from LATTE.monitoring.tools import * 00500 from LATTE.power import * 00501 from LATTE.runcontrol import * 00502 from LATTE.start import * 00503 from LATTE.tests import * 00504 from LATTE.tools import * 00505 from LATTE.trigger import * 00506 00507 import LDF 00508 import qt 00509 import sihippo 00510 import cfitsio 00511 00512 options = gOptions.Options(['server'], ['schema']) 00513 try: 00514 options.parse() 00515 except Exception, msg: 00516 options.usage(str(msg)) 00517 else: 00518 cmd = gCmdCli.CmdCli() 00519 ocs = gOCS.GOCS(cmd) 00520 if options.schema is not None: 00521 lat = gLAT.GLAT(cmd) 00522 lat.readSchema(options.schema) 00523 xbrd = gXBR.GXBRD(cmd) 00524 xbrd.readSchema(options.schema) 00525 else: 00526 lat = None 00527 xbrd = None 00528 cmd.connect(options.server) 00529 Gversions.printVersions(ocs, lat, xbrd) 00530 cmd.disconnect()