BlockIt
|
00001 #............................................................................ 00002 # Copyright (c) 2009,2010,2011 David Car, david.car7@gmail.com 00003 # 00004 # This program is free software; you can redistribute it and/or modify it under 00005 # the terms of the GNU General Public License as published by the Free Software 00006 # Foundation; either version 2 of the License, or (at your option) any later 00007 # version. 00008 # 00009 # This program is distributed in the hope that it will be useful, but WITHOUT 00010 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00011 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00012 # 00013 # You should have received a copy of the GNU General Public License along with 00014 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00015 # Place, Suite 330, Boston, MA 02111-1307 USA 00016 #.......................................................................... 00017 __all__ = ['FortranLibrary', 00018 'FortranCacheManager', 00019 'getAllLibKeys', 00020 'libCheck'] 00021 00022 from blockit.library import Library, CacheManager 00023 from blocks import * 00024 from blockit.tables import * 00025 00026 import os 00027 import sys 00028 import time 00029 import glob 00030 import pickle 00031 00032 #................................................................................ 00033 # Helper functions 00034 #................................................................................ 00035 def getAllLibKeys(lib): 00036 '''Returns a triple of the sets of library keys: (file names, template 00037 lists, template instantiations). Strips the 'METADATA' key. 00038 00039 ''' 00040 _keys = lib.keys() 00041 _keys = set(_keys) 00042 files = set([key for key in _keys if key.lower().endswith('.f90t') or 00043 key.lower().endswith('.f90') or 00044 key.lower().endswith('.inc')]) 00045 tempLists = set([key for key in _keys if key.endswith('/templates')]) 00046 tables = set( [ key for key in _keys 00047 if key in ( 'HASHTABLE', 'SYMBOLTABLE' ) ] ) 00048 00049 templates = _keys 00050 for x in (files, tempLists, tables): 00051 templates = templates.difference( x ) 00052 00053 #python2.6 only templates = _keys.difference(files, tempLists, tables) 00054 templates.discard('METADATA') 00055 00056 return (files, tempLists, templates, tables) 00057 00058 def libCheck(lib): 00059 '''Verify that the library has all instantiated templates are associated 00060 with a file and that all files exist. 00061 00062 ''' 00063 failed = False 00064 files, tempLists, templates, tables = getAllLibKeys(lib) 00065 00066 print '.'*80 00067 print 'Verifying Library Integrity'.center(80) 00068 print '.'*80 00069 00070 print 'Found %d files'%(len(files),) 00071 print 'Found %d template lists'%(len(tempLists),) 00072 print 'Found %d template instantiations'%(len(templates),) 00073 00074 for f in files: 00075 try: 00076 _listing = lib[f+'/templates'] 00077 tempLists.discard(f+'/templates') 00078 for temp in _listing: 00079 try: 00080 templates.discard(temp) 00081 except: 00082 print '''%s is missing from database for file 00083 %s'''%(temp[:10]+'...'+temp[temp.rfind('/'):], f) 00084 except: 00085 pass 00086 00087 if len(tempLists) > 0: 00088 failed = True 00089 print "Found %d orphaned template listings"%(len(tempLists),) 00090 for temp in tempLists: 00091 print '-> %s is orphaned'%(temp,) 00092 00093 if len(templates) > 0: 00094 failed = True 00095 print "Found %d orphaned templates"%(len(templates),) 00096 for temp in templates: 00097 print '-> %s is orphaned'%(temp[:20]+'...'+temp[temp.rfind('/'):],) 00098 00099 if not failed: 00100 print 'No orphan template listings found' 00101 print 'No orphan templates found' 00102 print 'Passed verification' 00103 else: 00104 print 'Verification failed' 00105 00106 print '.'*80 00107 return (tempLists, templates) 00108 00109 #................................................................................ 00110 class FortranLibrary(Library): 00111 '''Extends blockit.library.Library class to include template storage. 00112 00113 ''' 00114 00115 VERSION = '1.4' 00116 def __init__(self, name, blockList): 00117 super(FortranLibrary, self).__init__(name, blockList) 00118 00119 def getFile( self, name, hsh, checkHash=True ): 00120 '''Gets a File block from the database. 00121 00122 name : the file name 00123 hsh : the hash of the file to check against the one stored in the 00124 library. 00125 00126 ''' 00127 _blk = None 00128 _hsh, _tree = self._lib.get( name, ( None, None ) ) 00129 if _tree is not None: 00130 #...................................................................... 00131 # Sanity check to make sure the hash matches with the key name 00132 # hash (only if checkHash is True) 00133 #...................................................................... 00134 if checkHash: 00135 _blk = ( hsh == _hsh ) and self.unpackTree( _tree ) or None 00136 else: 00137 _blk = self.unpackTree( _tree ) 00138 00139 if _blk: 00140 _blk = ( _blk.version() == FortranBlock.VERSION ) and _blk or None 00141 00142 return _blk 00143 00144 def storeFile(self, blk): 00145 '''Saves a AFile block to the database. 00146 00147 ''' 00148 #......................................................................... 00149 # Check if the file has instaniated templates. If so, must remove 00150 # them for the library since its being restored and therefore most 00151 # likely has changed 00152 #......................................................................... 00153 _tempList = self._lib.get(blk.sourceFileName()+'/templates', []) 00154 for _temp in _tempList: 00155 try: 00156 self._lib.pop(_temp) 00157 except: 00158 pass 00159 00160 if _tempList: self._lib.pop(blk.sourceFileName()+'/templates') 00161 self._lib[blk.sourceFileName()] = (blk.hash(), blk.getDictTree()) 00162 00163 def getTemplate(self, name): 00164 '''Get an instantiated template from the library. 00165 00166 ''' 00167 _tree = self._lib.get(name, None) 00168 if _tree: 00169 return self.unpackTree(_tree) 00170 return _tree 00171 00172 def storeTemplate(self, blk): 00173 '''Store an instantiated template in the library''' 00174 00175 #...................................................................... 00176 # Get the AFile blk that encapsulates this template 00177 #...................................................................... 00178 blk.fromLib = False 00179 _parentFile = blk.upTo(AFile) 00180 if _parentFile is None: 00181 raise Exception('''Template is not contained within a file. Cannot 00182 generate library key''') 00183 00184 _ky = _parentFile.sourceFileName()+'/templates' 00185 _tempList = self._lib.get(_ky, None) 00186 if _tempList is None: 00187 self._lib[_ky] = [blk.hash()] 00188 elif blk.hash() not in _tempList: 00189 _tempList.append(blk.hash()) 00190 self._lib[_ky] = _tempList 00191 00192 self._lib[blk.hash()] = blk.getDictTree() 00193 00194 def storeHashTable(self, table): 00195 '''Store dictionary of filenames and their hash values. 00196 00197 ''' 00198 if not isinstance( table, SymbolTable ): 00199 _table = SymbolTable() 00200 _table.update(table) 00201 self._lib[ 'HASHTABLE' ] = _table 00202 else: 00203 self._lib[ 'HASHTABLE' ] = table 00204 00205 def getHashTable(self): 00206 '''Retrieve the file hash table from the library. 00207 00208 ''' 00209 return self._lib.get( 'HASHTABLE', SymbolTable() ) 00210 00211 def storeSymbolTable(self, table): 00212 '''Store dictionary of all the symbols. 00213 00214 ''' 00215 if not isinstance( table, SymbolTable ): 00216 _table = SymbolTable() 00217 _table.update(table) 00218 self._lib[ 'SYMBOLTABLE' ] = _table 00219 else: 00220 self._lib[ 'SYMBOLTABLE' ] = table 00221 00222 def getSymbolTable(self): 00223 '''Retrieve the symbol table from the library. 00224 00225 ''' 00226 return self._lib.get( 'SYMBOLTABLE', SymbolTable() ) 00227 00228 def _upgradeLib( self ): 00229 '''Function called when a library version number is less than the the 00230 current codes version number for the library. 00231 00232 ''' 00233 print '''MESSAGE: Library needs to be rebuilt due to new metadata for 00234 blocks and the library itself. Sorry for the inconvenience.''' 00235 if self.VERSION < '1.4': self._lib.clear() 00236 00237 def __iadd__(self, other): 00238 '''Intelligently merge two FortranLibrary instances. 00239 00240 ''' 00241 raise NotImplementedError("Stub: Need to finish this method") 00242 00243 @staticmethod 00244 def genKey(blk): 00245 '''Static method to generate an instantiated Template block key for 00246 the library. The key is generated from the parent file's hash as 00247 follows: 00248 00249 <parent file hash value>/templates 00250 00251 Input 00252 ----- 00253 blk : an instantiated template block 00254 00255 ''' 00256 00257 if not isinstance(blk, Template): 00258 return Library.genKey(blk) 00259 00260 _parentFile = blk.upTo(AFile) 00261 if _parentFile is None: 00262 raise Exception('''Template is not contained within a file. Cannot 00263 generate library key''') 00264 00265 return _parentFile.hash()+'/templates' 00266 00267 #================================================================================ 00268 class FortranCacheManager( CacheManager ): 00269 00270 def genCacheName( self, blk ): 00271 '''Generate the cache file name from a block. 00272 00273 ''' 00274 parentFile = blk.upTo( AFile ) 00275 parentFileName = os.path.abspath( parentFile.sourceFileName() ) 00276 parentBaseName = os.path.basename( parentFileName ) 00277 parentDir = os.path.dirname( parentFileName ) 00278 cachedDir = os.path.join( parentDir, ( '.' + parentBaseName ) ) 00279 if not os.path.exists( cachedDir ): 00280 try: 00281 os.mkdir( cachedDir ) 00282 except: 00283 e = sys.exc_info()[1] 00284 sys.stderr.write( 00285 '''Cannot find directory for %s%s''' % ( parentFileName, os.linesep ) ) 00286 sys.stderr.write('Error: %s%s''' % ( e, 00287 os.linesep ) ) 00288 00289 cacheName = os.path.join( cachedDir, blk.name() + self._ext ) 00290 return ( self.checkStat( parentFileName, 00291 cacheName ), 00292 cacheName ) 00293 00294 def checkStat( self, parent, cache ): 00295 '''Check if the cache is newer than its source file and return 00296 boolean. 00297 00298 ''' 00299 if os.path.exists( cache ): 00300 fileInfo = os.stat( parent ) 00301 cacheInfo = os.stat( cache) 00302 return ( fileInfo.st_ctime < cacheInfo.st_ctime, True ) 00303 return ( False, False )