1#!/usr/bin/env python 2import os, re, shutil, sys 3 4if os.environ.has_key('PETSC_DIR'): 5 PETSC_DIR = os.environ['PETSC_DIR'] 6else: 7 fd = file(os.path.join('lib','petsc','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('lib','petsc','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, 'lib','petsc','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.options.arch', None) 53 self.petscdir = self.framework.require('PETSc.options.petscdir', None) 54 self.compilers = self.framework.require('config.compilers', None) 55 self.mpi = self.framework.require('config.packages.MPI', None) 56 return 57 58 def setup(self): 59 script.Script.setup(self) 60 self.framework = self.loadConfigure() 61 self.setupModules() 62 return 63 64 def setupDirectories(self): 65 self.rootDir = self.petscdir.dir 66 self.destDir = os.path.abspath(self.argDB['destDir']) 67 self.installDir = os.path.abspath(os.path.expanduser(self.framework.argDB['prefix'])) 68 self.arch = self.arch.arch 69 self.archDir = os.path.join(self.rootDir, self.arch) 70 self.rootIncludeDir = os.path.join(self.rootDir, 'include') 71 self.archIncludeDir = os.path.join(self.rootDir, self.arch, 'include') 72 self.rootConfDir = os.path.join(self.rootDir, 'lib','petsc','conf') 73 self.archConfDir = os.path.join(self.rootDir, self.arch, 'lib','petsc','conf') 74 self.rootBinDir = os.path.join(self.rootDir, 'lib','petsc','bin') 75 self.archBinDir = os.path.join(self.rootDir, self.arch, 'bin') 76 self.archLibDir = os.path.join(self.rootDir, self.arch, 'lib') 77 self.destIncludeDir = os.path.join(self.destDir, 'include') 78 self.destConfDir = os.path.join(self.destDir, 'lib','petsc','conf') 79 self.destLibDir = os.path.join(self.destDir, 'lib') 80 self.destBinDir = os.path.join(self.destDir, 'lib','petsc','bin') 81 self.installIncludeDir = os.path.join(self.installDir, 'include') 82 self.installBinDir = os.path.join(self.installDir, 'lib','petsc','bin') 83 self.rootShareDir = os.path.join(self.rootDir, 'share') 84 self.destShareDir = os.path.join(self.destDir, 'share') 85 self.rootSrcDir = os.path.join(self.rootDir, 'src') 86 87 self.ranlib = self.compilers.RANLIB 88 self.arLibSuffix = self.compilers.AR_LIB_SUFFIX 89 return 90 91 def checkPrefix(self): 92 if not self.installDir: 93 print '********************************************************************' 94 print 'PETSc is built without prefix option. So "make install" is not appropriate.' 95 print 'If you need a prefix install of PETSc - rerun configure with --prefix option.' 96 print '********************************************************************' 97 sys.exit(1) 98 return 99 100 def checkDestdir(self): 101 if os.path.exists(self.destDir): 102 if os.path.samefile(self.destDir, self.rootDir): 103 print '********************************************************************' 104 print 'Incorrect prefix usage. Specified destDir same as current PETSC_DIR' 105 print '********************************************************************' 106 sys.exit(1) 107 if os.path.samefile(self.destDir, os.path.join(self.rootDir,self.arch)): 108 print '********************************************************************' 109 print 'Incorrect prefix usage. Specified destDir same as current PETSC_DIR/PETSC_ARCH' 110 print '********************************************************************' 111 sys.exit(1) 112 if not os.path.isdir(os.path.realpath(self.destDir)): 113 print '********************************************************************' 114 print 'Specified destDir', self.destDir, 'is not a directory. Cannot proceed!' 115 print '********************************************************************' 116 sys.exit(1) 117 if not os.access(self.destDir, os.W_OK): 118 print '********************************************************************' 119 print 'Unable to write to ', self.destDir, 'Perhaps you need to do "sudo make install"' 120 print '********************************************************************' 121 sys.exit(1) 122 return 123 124 def copyfile(self, src, dst, symlinks = False, copyFunc = shutil.copy2): 125 """Copies a single file """ 126 copies = [] 127 errors = [] 128 if not os.path.exists(dst): 129 os.makedirs(dst) 130 elif not os.path.isdir(dst): 131 raise shutil.Error, 'Destination is not a directory' 132 srcname = src 133 dstname = os.path.join(dst, os.path.basename(src)) 134 try: 135 if symlinks and os.path.islink(srcname): 136 linkto = os.readlink(srcname) 137 os.symlink(linkto, dstname) 138 else: 139 copyFunc(srcname, dstname) 140 copies.append((srcname, dstname)) 141 except (IOError, os.error), why: 142 errors.append((srcname, dstname, str(why))) 143 except shutil.Error, err: 144 errors.extend((srcname,dstname,str(err.args[0]))) 145 if errors: 146 raise shutil.Error, errors 147 return copies 148 149 def copyexamplefiles(self, src, dst, copyFunc = shutil.copy2): 150 """Copies all files, but not directories in a single file """ 151 names = os.listdir(src) 152 for name in names: 153 if not name.endswith('.html'): 154 srcname = os.path.join(src, name) 155 if os.path.isfile(srcname): 156 self.copyfile(srcname,dst) 157 158 def fixExamplesMakefile(self, src): 159 '''Change ././${PETSC_ARCH} in makefile in root petsc directory with ${PETSC_DIR}''' 160 lines = [] 161 oldFile = open(src, 'r') 162 alllines=oldFile.read() 163 oldFile.close() 164 newlines=alllines.split('\n')[0]+'\n' # Firstline 165 # Hardcode PETSC_DIR and PETSC_ARCH to avoid users doing the worng thing 166 newlines+='PETSC_DIR='+self.installDir+'\n' 167 newlines+='PETSC_ARCH=\n' 168 for line in alllines.split('\n')[1:]: 169 if line.startswith('TESTLOGFILE'): 170 newlines+='TESTLOGFILE = $(TESTDIR)/examples-install.log\n' 171 elif line.startswith('CONFIGDIR'): 172 newlines+='CONFIGDIR:=$(PETSC_DIR)/$(PETSC_ARCH)/share/petsc/examples/config\n' 173 elif line.startswith('EXAMPLESDIR'): 174 newlines+='EXAMPLESDIR:=$(PETSC_DIR)/$(PETSC_ARCH)/share/petsc/examples\n' 175 elif line.startswith('$(generatedtest)') and 'petscvariables' in line: 176 newlines+='all: test\n\n'+line+'\n' 177 else: 178 newlines+=line+'\n' 179 newFile = open(src, 'w') 180 newFile.write(newlines) 181 newFile.close() 182 return 183 184 def copyConfig(self, src, dst): 185 """Recursively copy the examples directories 186 """ 187 if not os.path.isdir(dst): 188 raise shutil.Error, 'Destination is not a directory' 189 190 self.copyfile('gmakefile.test',dst) 191 newConfigDir=os.path.join(dst,'config') # Am not renaming at present 192 if not os.path.isdir(newConfigDir): os.mkdir(newConfigDir) 193 testConfFiles="gmakegentest.py gmakegen.py testparse.py example_template.py".split() 194 testConfFiles+="petsc_harness.sh report_tests.py watchtime.sh".split() 195 testConfFiles+=["cmakegen.py"] 196 for tf in testConfFiles: 197 self.copyfile(os.path.join('config',tf),newConfigDir) 198 return 199 200 def copyExamples(self, src, dst): 201 """copy the examples directories 202 """ 203 top=os.path.relpath(src,os.path.abspath(os.curdir)) 204 for root, dirs, files in os.walk(top, topdown=False): 205 if not os.path.basename(root) == "examples": continue 206 shutil.copytree(root, os.path.join(dst,root), 207 ignore=shutil.ignore_patterns('*.dSYM')) 208 209 return 210 211 def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2, exclude = [],recurse = 1): 212 """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). 213 214 The copyFunc() you provide is only used on the top level, lower levels always use shutil.copy2 215 216 The destination directory must not already exist. 217 If exception(s) occur, an shutil.Error is raised with a list of reasons. 218 219 If the optional symlinks flag is true, symbolic links in the 220 source tree result in symbolic links in the destination tree; if 221 it is false, the contents of the files pointed to by symbolic 222 links are copied. 223 """ 224 copies = [] 225 names = os.listdir(src) 226 if not os.path.exists(dst): 227 os.makedirs(dst) 228 elif not os.path.isdir(dst): 229 raise shutil.Error, 'Destination is not a directory' 230 errors = [] 231 for name in names: 232 srcname = os.path.join(src, name) 233 dstname = os.path.join(dst, name) 234 try: 235 if symlinks and os.path.islink(srcname): 236 linkto = os.readlink(srcname) 237 os.symlink(linkto, dstname) 238 elif os.path.isdir(srcname) and recurse and not os.path.basename(srcname) in exclude: 239 copies.extend(self.copytree(srcname, dstname, symlinks,exclude = exclude)) 240 elif os.path.isfile(srcname) and not os.path.basename(srcname) in exclude: 241 copyFunc(srcname, dstname) 242 copies.append((srcname, dstname)) 243 # XXX What about devices, sockets etc.? 244 except (IOError, os.error), why: 245 errors.append((srcname, dstname, str(why))) 246 # catch the Error from the recursive copytree so that we can 247 # continue with other files 248 except shutil.Error, err: 249 errors.extend((srcname,dstname,str(err.args[0]))) 250 try: 251 shutil.copystat(src, dst) 252 except OSError, e: 253 if WindowsError is not None and isinstance(e, WindowsError): 254 # Copying file access times may fail on Windows 255 pass 256 else: 257 errors.extend((src, dst, str(e))) 258 if errors: 259 raise shutil.Error, errors 260 return copies 261 262 263 def fixConfFile(self, src): 264 lines = [] 265 oldFile = open(src, 'r') 266 for line in oldFile.readlines(): 267 # paths generated by configure could be different link-path than whats used by user, so fix both 268 line = line.replace(os.path.join(self.rootDir, self.arch), self.installDir) 269 line = line.replace(os.path.realpath(os.path.join(self.rootDir, self.arch)), self.installDir) 270 line = line.replace(os.path.join(self.rootDir, 'bin'), self.installBinDir) 271 line = line.replace(os.path.realpath(os.path.join(self.rootDir, 'bin')), self.installBinDir) 272 line = line.replace(os.path.join(self.rootDir, 'include'), self.installIncludeDir) 273 line = line.replace(os.path.realpath(os.path.join(self.rootDir, 'include')), self.installIncludeDir) 274 # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 275 line = line.replace('${PETSC_DIR}/${PETSC_ARCH}', self.installDir) 276 line = line.replace('PETSC_ARCH=${PETSC_ARCH}', '') 277 line = line.replace('${PETSC_DIR}', self.installDir) 278 lines.append(line) 279 oldFile.close() 280 newFile = open(src, 'w') 281 newFile.write(''.join(lines)) 282 newFile.close() 283 return 284 285 def fixConf(self): 286 import shutil 287 for file in ['rules', 'variables','petscrules', 'petscvariables']: 288 self.fixConfFile(os.path.join(self.destConfDir,file)) 289 self.fixConfFile(os.path.join(self.destLibDir,'pkgconfig','PETSc.pc')) 290 return 291 292 def createUninstaller(self): 293 uninstallscript = os.path.join(self.destConfDir, 'uninstall.py') 294 f = open(uninstallscript, 'w') 295 # Could use the Python AST to do this 296 f.write('#!'+sys.executable+'\n') 297 f.write('import os\n') 298 299 f.write('copies = '+repr(self.copies).replace(self.destDir,self.installDir)) 300 f.write(''' 301for src, dst in copies: 302 if os.path.exists(dst): 303 os.remove(dst) 304''') 305 f.close() 306 os.chmod(uninstallscript,0744) 307 return 308 309 def installIncludes(self): 310 exclude = ['makefile'] 311 if not hasattr(self.compilers.setCompilers, 'FC'): 312 exclude.append('finclude') 313 if not self.mpi.usingMPIUni: 314 exclude.append('mpiuni') 315 self.copies.extend(self.copytree(self.rootIncludeDir, self.destIncludeDir,exclude = exclude)) 316 self.copies.extend(self.copytree(self.archIncludeDir, self.destIncludeDir)) 317 return 318 319 def installConf(self): 320 self.copies.extend(self.copytree(self.rootConfDir, self.destConfDir, exclude = ['uncrustify.cfg','bfort-base.txt','bfort-petsc.txt','bfort-mpi.txt','test.log'])) 321 self.copies.extend(self.copytree(self.archConfDir, self.destConfDir, exclude = ['sowing', 'configure.log.bkp','configure.log','make.log','gmake.log','test.log','error.log'])) 322 return 323 324 def installBin(self): 325 exclude = ['bfort','bib2html','doc2lt','doctext','mapnames', 'pstogif','pstoxbm','tohtml'] 326 self.copies.extend(self.copytree(self.archBinDir, self.destBinDir, exclude = exclude )) 327 exclude = ['maint'] 328 if not self.mpi.usingMPIUni: 329 exclude.append('petsc-mpiexec.uni') 330 self.setCompilers.pushLanguage('C') 331 if not self.setCompilers.isWindows(self.setCompilers.getCompiler(),self.log): 332 exclude.append('win32fe') 333 self.setCompilers.popLanguage() 334 self.copies.extend(self.copytree(self.rootBinDir, self.destBinDir, exclude = exclude )) 335 return 336 337 def installShare(self): 338 self.copies.extend(self.copytree(self.rootShareDir, self.destShareDir)) 339 examplesdir=os.path.join(self.destShareDir,'petsc','examples') 340 if os.path.exists(examplesdir): 341 shutil.rmtree(examplesdir) 342 os.mkdir(examplesdir) 343 os.mkdir(os.path.join(examplesdir,'src')) 344 self.copyExamples(self.rootSrcDir,examplesdir) 345 self.copyConfig(self.rootDir,examplesdir) 346 self.fixExamplesMakefile(os.path.join(examplesdir,'gmakefile.test')) 347 return 348 349 def copyLib(self, src, dst): 350 '''Run ranlib on the destination library if it is an archive. Also run install_name_tool on dylib on Mac''' 351 # Symlinks (assumed local) are recreated at dst 352 if os.path.islink(src): 353 linkto = os.readlink(src) 354 try: 355 os.remove(dst) # In case it already exists 356 except OSError: 357 pass 358 os.symlink(linkto, dst) 359 return 360 # Do not install object files 361 if not os.path.splitext(src)[1] == '.o': 362 shutil.copy2(src, dst) 363 if os.path.splitext(dst)[1] == '.'+self.arLibSuffix: 364 self.executeShellCommand(self.ranlib+' '+dst) 365 if os.path.splitext(dst)[1] == '.dylib' and os.path.isfile('/usr/bin/install_name_tool'): 366 [output,err,flg] = self.executeShellCommand("otool -D "+src) 367 oldname = output[output.find("\n")+1:] 368 installName = oldname.replace(self.archDir, self.installDir) 369 self.executeShellCommand('/usr/bin/install_name_tool -id ' + installName + ' ' + dst) 370 # preserve the original timestamps - so that the .a vs .so time order is preserved 371 shutil.copystat(src,dst) 372 return 373 374 def installLib(self): 375 self.copies.extend(self.copytree(self.archLibDir, self.destLibDir, copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 376 self.copies.extend(self.copytree(os.path.join(self.archLibDir,'pkgconfig'), os.path.join(self.destLibDir,'pkgconfig'), copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 377 return 378 379 380 def outputInstallDone(self): 381 print '''\ 382==================================== 383Install complete. 384Now to check if the libraries are working do (in current directory): 385make PETSC_DIR=%s PETSC_ARCH="" test 386====================================\ 387''' % (self.installDir) 388 return 389 390 def outputDestDirDone(self): 391 print '''\ 392==================================== 393Copy to DESTDIR %s is now complete. 394Before use - please copy/install over to specified prefix: %s 395====================================\ 396''' % (self.destDir,self.installDir) 397 return 398 399 def runsetup(self): 400 self.setup() 401 self.setupDirectories() 402 self.checkPrefix() 403 self.checkDestdir() 404 return 405 406 def runcopy(self): 407 if self.destDir == self.installDir: 408 print '*** Installing PETSc at prefix location:',self.destDir, ' ***' 409 else: 410 print '*** Copying PETSc to DESTDIR location:',self.destDir, ' ***' 411 if not os.path.exists(self.destDir): 412 try: 413 os.makedirs(self.destDir) 414 except: 415 print '********************************************************************' 416 print 'Unable to create', self.destDir, 'Perhaps you need to do "sudo make install"' 417 print '********************************************************************' 418 sys.exit(1) 419 self.installIncludes() 420 self.installConf() 421 self.installBin() 422 self.installLib() 423 self.installShare() 424 return 425 426 def runfix(self): 427 self.fixConf() 428 return 429 430 def rundone(self): 431 self.createUninstaller() 432 if self.destDir == self.installDir: 433 self.outputInstallDone() 434 else: 435 self.outputDestDirDone() 436 return 437 438 def run(self): 439 self.runsetup() 440 self.runcopy() 441 self.runfix() 442 self.rundone() 443 return 444 445if __name__ == '__main__': 446 Installer(sys.argv[1:]).run() 447 # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 448 delfiles=['RDict.db','RDict.log','buildsystem.log','default.log','buildsystem.log.bkp','default.log.bkp'] 449 for delfile in delfiles: 450 if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 451 os.remove(delfile) 452