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