BlockIt
library.py
Go to the documentation of this file.
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 )
 All Classes Namespaces Files Functions Variables Properties