#!/usr/bin/env python import re, os, sys, shutil configDir = os.path.abspath('config') sys.path.insert(0, configDir) bsDir = os.path.abspath(os.path.join(configDir, 'BuildSystem')) sys.path.insert(0, bsDir) import script class Installer(script.Script): def __init__(self, clArgs = None): import RDict script.Script.__init__(self, clArgs, RDict.RDict()) self.copies = [] return def setupHelp(self, help): import nargs script.Script.setupHelp(self, help) help.addArgument('Installer', '-rootDir=', nargs.Arg(None, None, 'Install Root Directory')) help.addArgument('Installer', '-installDir=', nargs.Arg(None, None, 'Install Target Directory')) help.addArgument('Installer', '-arch=', nargs.Arg(None, None, 'Architecture type')) help.addArgument('Installer', '-ranlib=', nargs.Arg(None, 'ranlib', 'Ranlib program')) help.addArgument('Installer', '-make=', nargs.Arg(None, 'make', 'Make program')) help.addArgument('Installer', '-libSuffix=', nargs.Arg(None, 'make', 'The static library suffix')) return def setupDirectories(self): self.rootDir = os.path.abspath(self.argDB['rootDir']) self.installDir = os.path.abspath(self.argDB['installDir']) self.arch = os.path.abspath(self.argDB['arch']) self.ranlib = os.path.abspath(self.argDB['ranlib']) self.make = os.path.abspath(self.argDB['make']) self.libSuffix = os.path.abspath(self.argDB['libSuffix']) self.rootIncludeDir = os.path.join(self.rootDir, 'include') self.archIncludeDir = os.path.join(self.rootDir, self.arch, 'include') self.rootConfDir = os.path.join(self.rootDir, 'conf') self.archConfDir = os.path.join(self.rootDir, self.arch, 'conf') self.rootBinDir = os.path.join(self.rootDir, 'bin') self.archBinDir = os.path.join(self.rootDir, self.arch, 'bin') self.archLibDir = os.path.join(self.rootDir, self.arch, 'lib') self.installIncludeDir = os.path.join(self.installDir, 'include') self.installConfDir = os.path.join(self.installDir, 'conf') self.installLibDir = os.path.join(self.installDir, 'lib') self.installBinDir = os.path.join(self.installDir, 'bin') return def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2): """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). The destination directory must not already exist. If exception(s) occur, an shutil.Error is raised with a list of reasons. If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic links are copied. """ copies = [] names = os.listdir(src) if not os.path.exists(dst): os.makedirs(dst) elif not os.path.isdir(dst): raise shutil.Error, 'Destination is not a directory' errors = [] for name in names: srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: if symlinks and os.path.islink(srcname): linkto = os.readlink(srcname) os.symlink(linkto, dstname) elif os.path.isdir(srcname): copies.extend(self.copytree(srcname, dstname, symlinks)) else: copyFunc(srcname, dstname) copies.append((srcname, dstname)) # XXX What about devices, sockets etc.? except (IOError, os.error), why: errors.append((srcname, dstname, str(why))) # catch the Error from the recursive copytree so that we can # continue with other files except shutil.Error, err: errors.extend(err.args[0]) try: shutil.copystat(src, dst) except WindowsError: # can't copy file access times on Windows pass except OSError, why: errors.extend((src, dst, str(why))) if errors: raise shutil.Error, errors return copies def installIncludes(self): self.copies.extend(self.copytree(self.rootIncludeDir, self.installIncludeDir)) self.copies.extend(self.copytree(self.archIncludeDir, self.installIncludeDir)) return def copyConf(self, src, dst): if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) lines = [] oldFile = open(src, 'r') for line in oldFile.readlines(): line = re.sub(os.path.join(self.rootDir, self.arch), self.installDir, line) line = re.sub(self.rootDir, self.installDir, line) # paths generated by configure could be different link-path than whats used by user line = re.sub(os.path.realpath(os.path.join(self.rootDir, self.arch)), self.installDir, line) line = re.sub(os.path.realpath(self.rootDir), self.installDir, line) # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary line = re.sub('\$\{PETSC_DIR\}/\$\{PETSC_ARCH\}', self.installDir, line) line = re.sub('PETSC_ARCH=\$\{PETSC_ARCH\}', '', line) line = re.sub('\$\{PETSC_DIR\}', self.installDir, line) lines.append(line) oldFile.close() newFile = open(dst, 'w') newFile.write(''.join(lines)) newFile.close() shutil.copystat(src, dst) return def installConf(self): self.copies.extend(self.copytree(self.rootConfDir, self.installConfDir, copyFunc = self.copyConf)) self.copies.extend(self.copytree(self.archConfDir, self.installConfDir, copyFunc = self.copyConf)) return def installBin(self): self.copies.extend(self.copytree(self.rootBinDir, self.installBinDir)) self.copies.extend(self.copytree(self.archBinDir, self.installBinDir)) return def copyLib(self, src, dst): '''Run ranlib on the destination library if it is an archive''' shutil.copy2(src, dst) if os.path.splitext(dst)[1] == '.'+self.libSuffix: self.executeShellCommand(self.ranlib+' '+dst) return def installLib(self): self.copies.extend(self.copytree(self.archLibDir, self.installLibDir, copyFunc = self.copyLib)) return def createUninstaller(self): uninstallscript = os.path.join(self.installConfDir, 'uninstall.py') f = open(uninstallscript, 'w') # Could use the Python AST to do this f.write('#!'+sys.executable+'\n') f.write('import os\n') f.write('copies = '+repr(self.copies)) f.write(''' for src, dst in copies: if os.path.exists(dst): os.remove(dst) ''') f.close() os.chmod(uninstallscript,0744) return def outputHelp(self): print ''' If using sh/bash, do the following: PETSC_DIR=%s; export PETSC_DIR unset PETSC_ARCH If using csh/tcsh, do the following: setenv PETSC_DIR %s unsetenv PETSC_ARCH Now run the testsuite to verify the install with the following: make test ''' % (self.installDir, self.installDir) return def run(self): self.setup() self.setupDirectories() if os.path.exists(self.installDir) and os.path.samefile(self.installDir, os.path.join(self.rootDir,self.arch)): print '********************************************************************' print 'Install directory is current directory; nothing needs to be done' print '********************************************************************' return print 'Installing PETSc at',self.installDir if not os.path.exists(self.installDir): try: os.makedirs(self.installDir) except: print '********************************************************************' print 'Unable to create', self.installDir, 'Perhaps you need to do "sudo make install"' print '********************************************************************' return if not os.path.isdir(os.path.realpath(self.installDir)): print '********************************************************************' print 'Specified prefix', self.installDir, 'is not a directory. Cannot proceed!' print '********************************************************************' return if not os.access(self.installDir, os.W_OK): print '********************************************************************' print 'Unable to write to ', self.installDir, 'Perhaps you need to do "sudo make install"' print '********************************************************************' return self.installIncludes() self.installConf() self.installBin() self.installLib() self.executeShellCommand(self.make+' PETSC_ARCH=""'+' PETSC_DIR='+self.installDir+' shared') self.createUninstaller() self.outputHelp() return if __name__ == '__main__': Installer(sys.argv[1:]).run() # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked delfiles=['RDict.db','RDict.log','build.log','default.log','build.log.bkp','default.log.bkp'] for delfile in delfiles: if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): os.remove(delfile)