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