Module mobilecodemanager
[hide private]
[frames] | no frames]

Source Code for Module mobilecodemanager

  1  # -*- coding: utf-8 -*- 
  2   
  3  ############################################################################ 
  4  # mobilecodemanager.py 
  5  # 
  6  # Class that manages the mobile codes stored on server. 
  7  # 
  8  # (C) 2008 Likya Software Ltd. 
  9  ############################################################################ 
 10   
 11  import os, sys, md5 
 12  import glob, tarfile, zipfile 
 13  import cStringIO 
 14   
 15  from constants import Constants 
 16  from util import Util 
 17   
18 -class MobileCodeManager(object):
19
20 - def __init__(self, worker):
21 ''' 22 Creates a new instance of MobileCodeManager, which is responsible for 23 moving mobile codes between application server and clients. 24 25 @param worker: Parent worker of this manager. 26 ''' 27 self._worker = worker 28 # Cache for remote code requests, keyed according to distribution name 29 # and path. 30 self._remoteCodeCache = {} 31 # Cache for file lists that correspons to distributions and paths 32 self._fileListCache = {}
33
34 - def clearCaches(self):
35 ''' 36 Clears internal caches used in mobile code manager. 37 ''' 38 self._remoteCodeCache = {} 39 self._fileListCache = {}
40
41 - def pathMD5(self, distribution, path):
42 ''' 43 Computes MD5 for a group of files. 44 45 @type distribution: string 46 @param distribution: String that represents the distribution name. 47 @type path: string 48 @param path: Directory name that will be exported as mobile code. This 49 should be in UNIX semantics. 50 ''' 51 # Just make sure that our parameters are str, not unicode, as this may 52 # lead to unknown errors deep inside zipfile module. 53 distribution = str(distribution) 54 path = str(path) 55 # We'll return hex digest of this hash: 56 md5hash = md5.new() 57 58 for nextFile in self._fileList(distribution, path): 59 fileName = os.path.join(self._worker.directory(), 60 Constants.WORK_DIRECTORY, 61 distribution, 62 nextFile) 63 packageItem = os.stat(fileName) 64 # Hash using file name and file size, actual contents are expensive to compute 65 md5hash.update(os.path.basename(fileName)) 66 md5hash.update('%s' % packageItem.st_size) 67 68 digest = md5hash.hexdigest() 69 70 return digest
71
72 - def pathPackage(self, distribution, path):
73 ''' 74 Returns compressed package data for the given distribution and path. 75 76 @type distribution: string 77 @param distribution: String that represents the distribution name. 78 @type path: string 79 @param path: Directory name that will be exported as mobile code. This 80 should be in UNIX semantics. 81 ''' 82 # Just make sure that our parameters are str, not unicode, as this may 83 # lead to unknown errors deep inside zipfile module. 84 distribution = str(distribution) 85 path = str(path) 86 # Try the cache first 87 try: 88 return self._remoteCodeCache[(distribution, path)] 89 except KeyError: 90 pass 91 92 # In memory buffer for compressed package 93 buffer = cStringIO.StringIO() 94 95 # New package that will be created in memory 96 newPkg = zipfile.ZipFile(buffer, 'w') 97 98 fileList = self._fileList(distribution, path) 99 100 for distFile in fileList: 101 packageItem = open(os.path.join(self._worker.directory(), 102 Constants.WORK_DIRECTORY, 103 distribution, 104 distFile), 'rb') 105 # Add the file to the package 106 newPkg.writestr(distFile, packageItem.read()) 107 ##open("/home/dia/ttt.txt", "a").write(" ---> elapsed %s\n" % (time.time() - a)) 108 109 # We are done with our in memory package 110 newPkg.close() 111 # Get in memory file contents 112 contents = buffer.getvalue() 113 # Close object and discard memory buffer 114 buffer.close() 115 # Cache result 116 self._remoteCodeCache[(distribution, path)] = contents 117 # Return result package 118 return contents
119
120 - def _fileList(self, distribution, path):
121 ''' 122 Returns a list of files under distribution I{distribution} requested by 123 I{path}. List is ordered according to file name. UNIX file semantics are 124 used for representing file names. 125 126 @type distribution: string 127 @param distribution: String that represents the distribution name. 128 @type path: string 129 @param path: Directory name that will be exported as mobile code. This 130 should be in UNIX semantics. 131 ''' 132 # Just make sure that our parameters are str, not unicode, as this may 133 # lead to unknown errors deep inside zipfile module. 134 distribution = str(distribution) 135 path = str(path) 136 # Try the cache first 137 try: 138 return self._fileListCache[(distribution, path)] 139 except KeyError: 140 pass 141 142 retval = [] 143 144 distDir = os.path.join(self._worker.directory(), Constants.WORK_DIRECTORY, distribution) 145 fileList = Util.globRecursively(distDir) 146 147 # First normally traverse distribution directory, add files that 148 # are in requested "path" 149 for candFile in fileList: 150 fileName = candFile[len(distDir)+1:] 151 if fileName.startswith(path.replace('/', os.path.sep) + os.path.sep): 152 retval.append(fileName) 153 154 # Then search for intermediate __init__.py[oc] files, they are needed 155 # when importing mobile code. 156 pathElements = path.split('/') 157 for index in xrange(len(pathElements)): 158 initPyZipPath = os.path.join(*(pathElements[:index] + ['__init__.py' + Constants.PY_COMPILED_EXT])) 159 initPyPath = distDir + os.path.sep + initPyZipPath 160 if initPyPath in fileList: 161 retval.append(initPyZipPath) 162 163 # Sort resulting array 164 retval.sort() 165 # Store result in cache 166 self._fileListCache[(distribution, path)] = retval 167 return retval
168