1#!/usr/bin/env python 2import re, os, sys, shutil 3 4configDir = os.path.abspath('config') 5sys.path.insert(0, configDir) 6bsDir = os.path.abspath(os.path.join(configDir, 'BuildSystem')) 7sys.path.insert(0, bsDir) 8 9import script 10 11class Installer(script.Script): 12 def __init__(self, clArgs = None): 13 import RDict 14 script.Script.__init__(self, clArgs, RDict.RDict()) 15 self.copies = [] 16 return 17 18 def setupHelp(self, help): 19 import nargs 20 21 script.Script.setupHelp(self, help) 22 help.addArgument('Installer', '-rootDir=<path>', nargs.Arg(None, None, 'Install Root Directory')) 23 help.addArgument('Installer', '-installDir=<path>', nargs.Arg(None, None, 'Install Target Directory')) 24 help.addArgument('Installer', '-arch=<type>', nargs.Arg(None, None, 'Architecture type')) 25 help.addArgument('Installer', '-ranlib=<prog>', nargs.Arg(None, 'ranlib', 'Ranlib program')) 26 help.addArgument('Installer', '-make=<prog>', nargs.Arg(None, 'make', 'Make program')) 27 help.addArgument('Installer', '-libSuffix=<ext>', nargs.Arg(None, 'make', 'The static library suffix')) 28 return 29 30 def setupDirectories(self): 31 self.rootDir = os.path.abspath(self.argDB['rootDir']) 32 self.installDir = os.path.abspath(self.argDB['installDir']) 33 self.arch = os.path.abspath(self.argDB['arch']) 34 self.ranlib = os.path.abspath(self.argDB['ranlib']) 35 self.make = os.path.abspath(self.argDB['make']) 36 self.libSuffix = os.path.abspath(self.argDB['libSuffix']) 37 self.rootIncludeDir = os.path.join(self.rootDir, 'include') 38 self.archIncludeDir = os.path.join(self.rootDir, self.arch, 'include') 39 self.rootConfDir = os.path.join(self.rootDir, 'conf') 40 self.archConfDir = os.path.join(self.rootDir, self.arch, 'conf') 41 self.rootBinDir = os.path.join(self.rootDir, 'bin') 42 self.archBinDir = os.path.join(self.rootDir, self.arch, 'bin') 43 self.archLibDir = os.path.join(self.rootDir, self.arch, 'lib') 44 self.installIncludeDir = os.path.join(self.installDir, 'include') 45 self.installConfDir = os.path.join(self.installDir, 'conf') 46 self.installLibDir = os.path.join(self.installDir, 'lib') 47 self.installBinDir = os.path.join(self.installDir, 'bin') 48 return 49 50 def copytree(self, src, dst, symlinks = False, copyFunc = shutil.copy2): 51 """Recursively copy a directory tree using copyFunc, which defaults to shutil.copy2(). 52 53 The destination directory must not already exist. 54 If exception(s) occur, an shutil.Error is raised with a list of reasons. 55 56 If the optional symlinks flag is true, symbolic links in the 57 source tree result in symbolic links in the destination tree; if 58 it is false, the contents of the files pointed to by symbolic 59 links are copied. 60 """ 61 copies = [] 62 names = os.listdir(src) 63 if not os.path.exists(dst): 64 os.makedirs(dst) 65 elif not os.path.isdir(dst): 66 raise shutil.Error, 'Destination is not a directory' 67 errors = [] 68 for name in names: 69 srcname = os.path.join(src, name) 70 dstname = os.path.join(dst, name) 71 try: 72 if symlinks and os.path.islink(srcname): 73 linkto = os.readlink(srcname) 74 os.symlink(linkto, dstname) 75 elif os.path.isdir(srcname): 76 copies.extend(self.copytree(srcname, dstname, symlinks)) 77 else: 78 copyFunc(srcname, dstname) 79 copies.append((srcname, dstname)) 80 # XXX What about devices, sockets etc.? 81 except (IOError, os.error), why: 82 errors.append((srcname, dstname, str(why))) 83 # catch the Error from the recursive copytree so that we can 84 # continue with other files 85 except shutil.Error, err: 86 errors.extend(err.args[0]) 87 try: 88 shutil.copystat(src, dst) 89 except WindowsError: 90 # can't copy file access times on Windows 91 pass 92 except OSError, why: 93 errors.extend((src, dst, str(why))) 94 if errors: 95 raise shutil.Error, errors 96 return copies 97 98 def installIncludes(self): 99 self.copies.extend(self.copytree(self.rootIncludeDir, self.installIncludeDir)) 100 self.copies.extend(self.copytree(self.archIncludeDir, self.installIncludeDir)) 101 return 102 103 def copyConf(self, src, dst): 104 if os.path.isdir(dst): 105 dst = os.path.join(dst, os.path.basename(src)) 106 lines = [] 107 oldFile = open(src, 'r') 108 for line in oldFile.readlines(): 109 line = re.sub(os.path.join(self.rootDir, self.arch), self.installDir, line) 110 line = re.sub(self.rootDir, self.installDir, line) 111 # paths generated by configure could be different link-path than whats used by user 112 line = re.sub(os.path.realpath(os.path.join(self.rootDir, self.arch)), self.installDir, line) 113 line = re.sub(os.path.realpath(self.rootDir), self.installDir, line) 114 # remove PETSC_DIR/PETSC_ARCH variables from conf-makefiles. They are no longer necessary 115 line = re.sub('\$\{PETSC_DIR\}/\$\{PETSC_ARCH\}', self.installDir, line) 116 line = re.sub('PETSC_ARCH=\$\{PETSC_ARCH\}', '', line) 117 line = re.sub('\$\{PETSC_DIR\}', self.installDir, line) 118 lines.append(line) 119 oldFile.close() 120 newFile = open(dst, 'w') 121 newFile.write(''.join(lines)) 122 newFile.close() 123 shutil.copystat(src, dst) 124 return 125 126 def installConf(self): 127 self.copies.extend(self.copytree(self.rootConfDir, self.installConfDir, copyFunc = self.copyConf)) 128 self.copies.extend(self.copytree(self.archConfDir, self.installConfDir, copyFunc = self.copyConf)) 129 return 130 131 def installBin(self): 132 self.copies.extend(self.copytree(self.rootBinDir, self.installBinDir)) 133 self.copies.extend(self.copytree(self.archBinDir, self.installBinDir)) 134 return 135 136 def copyLib(self, src, dst): 137 '''Run ranlib on the destination library if it is an archive''' 138 shutil.copy2(src, dst) 139 if os.path.splitext(dst)[1] == '.'+self.libSuffix: 140 self.executeShellCommand(self.ranlib+' '+dst) 141 return 142 143 def installLib(self): 144 self.copies.extend(self.copytree(self.archLibDir, self.installLibDir, copyFunc = self.copyLib)) 145 return 146 147 def createUninstaller(self): 148 uninstallscript = os.path.join(self.installConfDir, 'uninstall.py') 149 f = open(uninstallscript, 'w') 150 # Could use the Python AST to do this 151 f.write('#!'+sys.executable+'\n') 152 f.write('import os\n') 153 154 f.write('copies = '+repr(self.copies)) 155 f.write(''' 156for src, dst in copies: 157 if os.path.exists(dst): 158 os.remove(dst) 159''') 160 f.close() 161 os.chmod(uninstallscript,0744) 162 return 163 164 def outputHelp(self): 165 print ''' 166If using sh/bash, do the following: 167 PETSC_DIR=%s; export PETSC_DIR 168 unset PETSC_ARCH 169If using csh/tcsh, do the following: 170 setenv PETSC_DIR %s 171 unsetenv PETSC_ARCH 172Now run the testsuite to verify the install with the following: 173 make test 174''' % (self.installDir, self.installDir) 175 return 176 177 def run(self): 178 self.setup() 179 self.setupDirectories() 180 if os.path.exists(self.installDir) and os.path.samefile(self.installDir, os.path.join(self.rootDir,self.arch)): 181 print '********************************************************************' 182 print 'Install directory is current directory; nothing needs to be done' 183 print '********************************************************************' 184 return 185 print 'Installing PETSc at',self.installDir 186 if not os.path.exists(self.installDir): 187 try: 188 os.makedirs(self.installDir) 189 except: 190 print '********************************************************************' 191 print 'Unable to create', self.installDir, 'Perhaps you need to do "sudo make install"' 192 print '********************************************************************' 193 return 194 if not os.path.isdir(os.path.realpath(self.installDir)): 195 print '********************************************************************' 196 print 'Specified prefix', self.installDir, 'is not a directory. Cannot proceed!' 197 print '********************************************************************' 198 return 199 if not os.access(self.installDir, os.W_OK): 200 print '********************************************************************' 201 print 'Unable to write to ', self.installDir, 'Perhaps you need to do "sudo make install"' 202 print '********************************************************************' 203 return 204 self.installIncludes() 205 self.installConf() 206 self.installBin() 207 self.installLib() 208 self.executeShellCommand(self.make+' PETSC_ARCH=""'+' PETSC_DIR='+self.installDir+' shared') 209 self.createUninstaller() 210 self.outputHelp() 211 return 212 213if __name__ == '__main__': 214 Installer(sys.argv[1:]).run() 215 # temporary hack - delete log files created by BuildSystem - when 'sudo make install' is invoked 216 delfiles=['RDict.db','RDict.log','build.log','default.log','build.log.bkp','default.log.bkp'] 217 for delfile in delfiles: 218 if os.path.exists(delfile) and (os.stat(delfile).st_uid==0): 219 os.remove(delfile) 220