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