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