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