1#!/usr/bin/env python 2import re, os, sys, shutil 3 4if os.environ.has_key('PETSC_DIR'): 5 PETSC_DIR = os.environ['PETSC_DIR'] 6else: 7 fd = file(os.path.join('conf','petscvariables')) 8 a = fd.readline() 9 a = fd.readline() 10 PETSC_DIR = a.split('=')[1][0:-1] 11 fd.close() 12 13if os.environ.has_key('PETSC_ARCH'): 14 PETSC_ARCH = os.environ['PETSC_ARCH'] 15else: 16 fd = file(os.path.join('conf','petscvariables')) 17 a = fd.readline() 18 PETSC_ARCH = a.split('=')[1][0:-1] 19 fd.close() 20 21print '*** using PETSC_DIR='+PETSC_DIR+' PETSC_ARCH='+PETSC_ARCH+' ***' 22sys.path.insert(0, os.path.join(PETSC_DIR, 'config')) 23sys.path.insert(0, os.path.join(PETSC_DIR, 'config', 'BuildSystem')) 24 25import script 26 27try: 28 WindowsError 29except NameError: 30 WindowsError = None 31 32class Installer(script.Script): 33 def __init__(self, clArgs = None): 34 import RDict 35 argDB = RDict.RDict(None, None, 0, 0, readonly = True) 36 if os.environ.has_key('PETSC_DIR'): 37 PETSC_DIR = os.environ['PETSC_DIR'] 38 else: 39 fd = file(os.path.join('conf','petscvariables')) 40 a = fd.readline() 41 a = fd.readline() 42 PETSC_DIR = a.split('=')[1][0:-1] 43 fd.close() 44 argDB.saveFilename = os.path.join(PETSC_DIR, PETSC_ARCH, 'conf', 'RDict.db') 45 argDB.load() 46 script.Script.__init__(self, argDB = argDB) 47 self.copies = [] 48 return 49 50 def setupModules(self): 51 self.setCompilers = self.framework.require('config.setCompilers', None) 52 self.arch = self.framework.require('PETSc.utilities.arch', None) 53 self.petscdir = self.framework.require('PETSc.utilities.petscdir', None) 54 self.makesys = self.framework.require('PETSc.utilities.Make', None) 55 self.compilers = self.framework.require('config.compilers', None) 56 return 57 58 def setup(self): 59 script.Script.setup(self) 60 self.framework = self.loadConfigure() 61 self.setupModules() 62 return 63 64 def setupDirectories(self): 65 self.rootDir = self.petscdir.dir 66 self.installDir = self.framework.argDB['prefix'] 67 self.arch = self.arch.arch 68 self.rootIncludeDir = os.path.join(self.rootDir, 'include') 69 self.archIncludeDir = os.path.join(self.rootDir, self.arch, 'include') 70 self.rootConfDir = os.path.join(self.rootDir, 'conf') 71 self.archConfDir = os.path.join(self.rootDir, self.arch, 'conf') 72 self.rootBinDir = os.path.join(self.rootDir, 'bin') 73 self.archBinDir = os.path.join(self.rootDir, self.arch, 'bin') 74 self.archLibDir = os.path.join(self.rootDir, self.arch, 'lib') 75 self.installIncludeDir = os.path.join(self.installDir, 'include') 76 self.installConfDir = os.path.join(self.installDir, 'conf') 77 self.installLibDir = os.path.join(self.installDir, 'lib') 78 self.installBinDir = os.path.join(self.installDir, 'bin') 79 80 self.make = self.makesys.make+' '+self.makesys.flags 81 self.ranlib = self.compilers.RANLIB 82 self.libSuffix = self.compilers.AR_LIB_SUFFIX 83 return 84 85 def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2): 86 """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). 87 88 The destination directory must not already exist. 89 If exception(s) occur, an shutil.Error is raised with a list of reasons. 90 91 If the optional symlinks flag is true, symbolic links in the 92 source tree result in symbolic links in the destination tree; if 93 it is false, the contents of the files pointed to by symbolic 94 links are copied. 95 """ 96 copies = [] 97 names = os.listdir(src) 98 if not os.path.exists(dst): 99 os.makedirs(dst) 100 elif not os.path.isdir(dst): 101 raise shutil.Error, 'Destination is not a directory' 102 errors = [] 103 for name in names: 104 srcname = os.path.join(src, name) 105 dstname = os.path.join(dst, name) 106 try: 107 if symlinks and os.path.islink(srcname): 108 linkto = os.readlink(srcname) 109 os.symlink(linkto, dstname) 110 elif os.path.isdir(srcname): 111 copies.extend(self.copytree(srcname, dstname, symlinks)) 112 else: 113 copyFunc(srcname, dstname) 114 copies.append((srcname, dstname)) 115 # XXX What about devices, sockets etc.? 116 except (IOError, os.error), why: 117 errors.append((srcname, dstname, str(why))) 118 # catch the Error from the recursive copytree so that we can 119 # continue with other files 120 except shutil.Error, err: 121 errors.extend(err.args[0]) 122 try: 123 shutil.copystat(src, dst) 124 except OSError, e: 125 if WindowsError is not None and isinstance(e, WindowsError): 126 # Copying file access times may fail on Windows 127 pass 128 else: 129 errors.extend((src, dst, str(e))) 130 if errors: 131 raise shutil.Error, errors 132 return copies 133 134 def installIncludes(self): 135 self.copies.extend(self.copytree(self.rootIncludeDir, self.installIncludeDir)) 136 self.copies.extend(self.copytree(self.archIncludeDir, self.installIncludeDir)) 137 return 138 139 def copyConf(self, src, dst): 140 if os.path.isdir(dst): 141 dst = os.path.join(dst, os.path.basename(src)) 142 lines = [] 143 oldFile = open(src, 'r') 144 for line in oldFile.readlines(): 145 # paths generated by configure could be different link-path than whats used by user, so fix both 146 line = re.sub(re.escape(os.path.join(self.rootDir, self.arch)), self.installDir, line) 147 line = re.sub(re.escape(os.path.realpath(os.path.join(self.rootDir, self.arch))), self.installDir, line) 148 line = re.sub(re.escape(os.path.join(self.rootDir, 'bin')), self.installBinDir, line) 149 line = re.sub(re.escape(os.path.realpath(os.path.join(self.rootDir, 'bin'))), self.installBinDir, line) 150 line = re.sub(re.escape(os.path.join(self.rootDir, 'include')), self.installIncludeDir, line) 151 line = re.sub(re.escape(os.path.realpath(os.path.join(self.rootDir, 'include'))), self.installIncludeDir, line) 152 # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 153 line = re.sub('\$\{PETSC_DIR\}/\$\{PETSC_ARCH\}', self.installDir, line) 154 line = re.sub('PETSC_ARCH=\$\{PETSC_ARCH\}', '', line) 155 line = re.sub('\$\{PETSC_DIR\}', self.installDir, line) 156 lines.append(line) 157 oldFile.close() 158 newFile = open(dst, 'w') 159 newFile.write(''.join(lines)) 160 newFile.close() 161 shutil.copystat(src, dst) 162 return 163 164 def installConf(self): 165 # rootConfDir can have a duplicate petscvariables - so processing it first removes the appropriate duplicate file. 166 self.copies.extend(self.copytree(self.rootConfDir, self.installConfDir, copyFunc = self.copyConf)) 167 self.copies.extend(self.copytree(self.archConfDir, self.installConfDir)) 168 # Just copyConf() a couple of files manually [as the rest of the files should not be modified] 169 for file in ['petscrules', 'petscvariables']: 170 self.copyConf(os.path.join(self.archConfDir,file),os.path.join(self.installConfDir,file)) 171 return 172 173 def installBin(self): 174 self.copies.extend(self.copytree(self.rootBinDir, self.installBinDir)) 175 self.copies.extend(self.copytree(self.archBinDir, self.installBinDir)) 176 return 177 178 def copyLib(self, src, dst): 179 '''Run ranlib on the destination library if it is an archive''' 180 shutil.copy2(src, dst) 181 if os.path.splitext(dst)[1] == '.'+self.libSuffix: 182 self.executeShellCommand(self.ranlib+' '+dst) 183 return 184 185 def installLib(self): 186 self.copies.extend(self.copytree(self.archLibDir, self.installLibDir, copyFunc = self.copyLib)) 187 return 188 189 def createUninstaller(self): 190 uninstallscript = os.path.join(self.installConfDir, 'uninstall.py') 191 f = open(uninstallscript, 'w') 192 # Could use the Python AST to do this 193 f.write('#!'+sys.executable+'\n') 194 f.write('import os\n') 195 196 f.write('copies = '+repr(self.copies)) 197 f.write(''' 198for src, dst in copies: 199 if os.path.exists(dst): 200 os.remove(dst) 201''') 202 f.close() 203 os.chmod(uninstallscript,0744) 204 return 205 206 def outputHelp(self): 207 print '''\ 208==================================== 209Install complete. It is useable with PETSC_DIR=%s [and no more PETSC_ARCH]. 210Now to check if the libraries are working do (in current directory): 211make PETSC_DIR=%s test 212====================================\ 213''' % (self.installDir,self.installDir) 214 return 215 216 def run(self): 217 self.setup() 218 self.setupDirectories() 219 if os.path.exists(self.installDir) and os.path.samefile(self.installDir, os.path.join(self.rootDir,self.arch)): 220 print '********************************************************************' 221 print 'Install directory is current directory; nothing needs to be done' 222 print '********************************************************************' 223 return 224 print '*** Installing PETSc at',self.installDir, ' ***' 225 if not os.path.exists(self.installDir): 226 try: 227 os.makedirs(self.installDir) 228 except: 229 print '********************************************************************' 230 print 'Unable to create', self.installDir, 'Perhaps you need to do "sudo make install"' 231 print '********************************************************************' 232 return 233 if not os.path.isdir(os.path.realpath(self.installDir)): 234 print '********************************************************************' 235 print 'Specified prefix', self.installDir, 'is not a directory. Cannot proceed!' 236 print '********************************************************************' 237 return 238 if not os.access(self.installDir, os.W_OK): 239 print '********************************************************************' 240 print 'Unable to write to ', self.installDir, 'Perhaps you need to do "sudo make install"' 241 print '********************************************************************' 242 return 243 self.installIncludes() 244 self.installConf() 245 self.installBin() 246 self.installLib() 247 output,err,ret = self.executeShellCommand(self.make+' PETSC_ARCH=""'+' PETSC_DIR='+self.installDir+' ARCHFLAGS= shared mpi4py petsc4py') 248 print output+err 249 # this file will mess up the make test run since it resets PETSC_ARCH when PETSC_ARCH needs to be null now 250 os.unlink(os.path.join(self.rootDir,'conf','petscvariables')) 251 fd = file(os.path.join('conf','petscvariables'),'w') 252 fd.close() 253 # if running as root then change file ownership back to user 254 if os.environ.has_key('SUDO_USER'): 255 os.chown(os.path.join(self.rootDir,'conf','petscvariables'),int(os.environ['SUDO_UID']),int(os.environ['SUDO_GID'])) 256 self.createUninstaller() 257 self.outputHelp() 258 return 259 260if __name__ == '__main__': 261 Installer(sys.argv[1:]).run() 262 # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 263 delfiles=['RDict.db','RDict.log','build.log','default.log','build.log.bkp','default.log.bkp'] 264 for delfile in delfiles: 265 if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 266 os.remove(delfile) 267