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