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 line = line.replace(self.rootDir, self.installDir) 275 # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 276 line = line.replace('${PETSC_DIR}/${PETSC_ARCH}', self.installDir) 277 line = line.replace('PETSC_ARCH=${PETSC_ARCH}', '') 278 line = line.replace('${PETSC_DIR}', self.installDir) 279 lines.append(line) 280 oldFile.close() 281 newFile = open(src, 'w') 282 newFile.write(''.join(lines)) 283 newFile.close() 284 return 285 286 def fixConf(self): 287 import shutil 288 for file in ['rules', 'variables','petscrules', 'petscvariables']: 289 self.fixConfFile(os.path.join(self.destConfDir,file)) 290 self.fixConfFile(os.path.join(self.destLibDir,'pkgconfig','PETSc.pc')) 291 self.fixConfFile(os.path.join(self.destIncludeDir,'petscconf.h')) 292 return 293 294 def createUninstaller(self): 295 uninstallscript = os.path.join(self.destConfDir, 'uninstall.py') 296 f = open(uninstallscript, 'w') 297 # Could use the Python AST to do this 298 f.write('#!'+sys.executable+'\n') 299 f.write('import os\n') 300 301 f.write('copies = '+repr(self.copies).replace(self.destDir,self.installDir)) 302 f.write(''' 303for src, dst in copies: 304 if os.path.exists(dst): 305 os.remove(dst) 306''') 307 f.close() 308 os.chmod(uninstallscript,0744) 309 return 310 311 def installIncludes(self): 312 exclude = ['makefile'] 313 if not hasattr(self.compilers.setCompilers, 'FC'): 314 exclude.append('finclude') 315 if not self.mpi.usingMPIUni: 316 exclude.append('mpiuni') 317 self.copies.extend(self.copytree(self.rootIncludeDir, self.destIncludeDir,exclude = exclude)) 318 self.copies.extend(self.copytree(self.archIncludeDir, self.destIncludeDir)) 319 return 320 321 def installConf(self): 322 self.copies.extend(self.copytree(self.rootConfDir, self.destConfDir, exclude = ['uncrustify.cfg','bfort-base.txt','bfort-petsc.txt','bfort-mpi.txt','test.log'])) 323 self.copies.extend(self.copytree(self.archConfDir, self.destConfDir, exclude = ['sowing', 'configure.log.bkp','configure.log','make.log','gmake.log','test.log','error.log'])) 324 return 325 326 def installBin(self): 327 exclude = ['bfort','bib2html','doc2lt','doctext','mapnames', 'pstogif','pstoxbm','tohtml'] 328 self.copies.extend(self.copytree(self.archBinDir, self.destBinDir, exclude = exclude )) 329 exclude = ['maint'] 330 if not self.mpi.usingMPIUni: 331 exclude.append('petsc-mpiexec.uni') 332 self.setCompilers.pushLanguage('C') 333 if not self.setCompilers.isWindows(self.setCompilers.getCompiler(),self.log): 334 exclude.append('win32fe') 335 self.setCompilers.popLanguage() 336 self.copies.extend(self.copytree(self.rootBinDir, self.destBinDir, exclude = exclude )) 337 return 338 339 def installShare(self): 340 self.copies.extend(self.copytree(self.rootShareDir, self.destShareDir)) 341 examplesdir=os.path.join(self.destShareDir,'petsc','examples') 342 if os.path.exists(examplesdir): 343 shutil.rmtree(examplesdir) 344 os.mkdir(examplesdir) 345 os.mkdir(os.path.join(examplesdir,'src')) 346 self.copyExamples(self.rootSrcDir,examplesdir) 347 self.copyConfig(self.rootDir,examplesdir) 348 self.fixExamplesMakefile(os.path.join(examplesdir,'gmakefile.test')) 349 return 350 351 def copyLib(self, src, dst): 352 '''Run ranlib on the destination library if it is an archive. Also run install_name_tool on dylib on Mac''' 353 # Symlinks (assumed local) are recreated at dst 354 if os.path.islink(src): 355 linkto = os.readlink(src) 356 try: 357 os.remove(dst) # In case it already exists 358 except OSError: 359 pass 360 os.symlink(linkto, dst) 361 return 362 # Do not install object files 363 if not os.path.splitext(src)[1] == '.o': 364 shutil.copy2(src, dst) 365 if os.path.splitext(dst)[1] == '.'+self.arLibSuffix: 366 self.executeShellCommand(self.ranlib+' '+dst) 367 if os.path.splitext(dst)[1] == '.dylib' and os.path.isfile('/usr/bin/install_name_tool'): 368 [output,err,flg] = self.executeShellCommand("otool -D "+src) 369 oldname = output[output.find("\n")+1:] 370 installName = oldname.replace(self.archDir, self.installDir) 371 self.executeShellCommand('/usr/bin/install_name_tool -id ' + installName + ' ' + dst) 372 # preserve the original timestamps - so that the .a vs .so time order is preserved 373 shutil.copystat(src,dst) 374 return 375 376 def installLib(self): 377 self.copies.extend(self.copytree(self.archLibDir, self.destLibDir, copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 378 self.copies.extend(self.copytree(os.path.join(self.archLibDir,'pkgconfig'), os.path.join(self.destLibDir,'pkgconfig'), copyFunc = self.copyLib, exclude = ['.DIR'],recurse = 0)) 379 return 380 381 382 def outputInstallDone(self): 383 print '''\ 384==================================== 385Install complete. 386Now to check if the libraries are working do (in current directory): 387make PETSC_DIR=%s PETSC_ARCH="" test 388====================================\ 389''' % (self.installDir) 390 return 391 392 def outputDestDirDone(self): 393 print '''\ 394==================================== 395Copy to DESTDIR %s is now complete. 396Before use - please copy/install over to specified prefix: %s 397====================================\ 398''' % (self.destDir,self.installDir) 399 return 400 401 def runsetup(self): 402 self.setup() 403 self.setupDirectories() 404 self.checkPrefix() 405 self.checkDestdir() 406 return 407 408 def runcopy(self): 409 if self.destDir == self.installDir: 410 print '*** Installing PETSc at prefix location:',self.destDir, ' ***' 411 else: 412 print '*** Copying PETSc to DESTDIR location:',self.destDir, ' ***' 413 if not os.path.exists(self.destDir): 414 try: 415 os.makedirs(self.destDir) 416 except: 417 print '********************************************************************' 418 print 'Unable to create', self.destDir, 'Perhaps you need to do "sudo make install"' 419 print '********************************************************************' 420 sys.exit(1) 421 self.installIncludes() 422 self.installConf() 423 self.installBin() 424 self.installLib() 425 self.installShare() 426 return 427 428 def runfix(self): 429 self.fixConf() 430 return 431 432 def rundone(self): 433 self.createUninstaller() 434 if self.destDir == self.installDir: 435 self.outputInstallDone() 436 else: 437 self.outputDestDirDone() 438 return 439 440 def run(self): 441 self.runsetup() 442 self.runcopy() 443 self.runfix() 444 self.rundone() 445 return 446 447if __name__ == '__main__': 448 Installer(sys.argv[1:]).run() 449 # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 450 delfiles=['RDict.db','RDict.log','buildsystem.log','default.log','buildsystem.log.bkp','default.log.bkp'] 451 for delfile in delfiles: 452 if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 453 os.remove(delfile) 454